diff --git a/src/parser/lexer.cpp b/src/parser/lexer.cpp index 3064b2023c0..5d2aedabe66 100644 --- a/src/parser/lexer.cpp +++ b/src/parser/lexer.cpp @@ -935,6 +935,15 @@ void Lexer::skipSpace() { } } +std::optional Lexer::peekChar() const { + auto n = next(); + if (n.empty()) { + return std::nullopt; + } + + return n[0]; +} + bool Lexer::takeLParen() { if (LexCtx(next()).startsWith("("sv)) { ++pos; diff --git a/src/parser/lexer.h b/src/parser/lexer.h index 9d0cf3dddce..ac6549f0de8 100644 --- a/src/parser/lexer.h +++ b/src/parser/lexer.h @@ -78,6 +78,8 @@ struct Lexer { advance(); } + std::optional peekChar() const; + bool takeLParen(); bool peekLParen() { return Lexer(*this).takeLParen(); } diff --git a/src/parser/wast-parser.cpp b/src/parser/wast-parser.cpp index a7b0cba870a..bf8b8f643d6 100644 --- a/src/parser/wast-parser.cpp +++ b/src/parser/wast-parser.cpp @@ -169,6 +169,72 @@ Result nan(Lexer& in) { } Result result(Lexer& in) { + if (in.takeSExprStart("v128.const"sv)) { + LaneResults results(in.peekChar() == 'f' ? LaneResults::LaneType::Float + : LaneResults::LaneType::Int); + auto& lanes = results.lanes; + + if (in.takeKeyword("i8x16"sv)) { + for (int i = 0; i < 16; ++i) { + auto int_ = in.takeI8(); + if (!int_) { + return in.err("expected i8 immediate"); + } + lanes.push_back(Literal(static_cast(*int_))); + } + } else if (in.takeKeyword("i16x8"sv)) { + for (int i = 0; i < 8; ++i) { + auto int_ = in.takeI16(); + if (!int_) { + return in.err("expected i16 immediate"); + } + lanes.push_back(Literal(static_cast(*int_))); + } + } else if (in.takeKeyword("i32x4"sv)) { + for (int i = 0; i < 4; ++i) { + auto int_ = in.takeI32(); + if (!int_) { + return in.err("expected i32 immediate"); + } + lanes.push_back(Literal(static_cast(*int_))); + } + } else if (in.takeKeyword("i64x2"sv)) { + for (int i = 0; i < 2; ++i) { + auto int_ = in.takeI64(); + if (!int_) { + return in.err("expected i64 immediate"); + } + lanes.push_back(Literal(*int_)); + } + } else if (in.takeKeyword("f32x4"sv)) { + for (int i = 0; i < 4; ++i) { + if (auto f = in.takeF32()) { + lanes.push_back(Literal(*f)); + } else { + auto kind = nan(in); + CHECK_ERR(kind); + lanes.push_back(NaNResult{*kind, Type::f32}); + } + } + } else if (in.takeKeyword("f64x2"sv)) { + for (int i = 0; i < 2; ++i) { + if (auto f = in.takeF64()) { + lanes.push_back(Literal(*f)); + } else { + auto kind = nan(in); + CHECK_ERR(kind); + lanes.push_back(NaNResult{*kind, Type::f64}); + } + } + } else { + return in.err("unexpected vector shape"); + } + if (!in.takeRParen()) { + return in.err("expected end of v128.const"); + } + return results; + } + Lexer constLexer = in; auto c = const_(constLexer); // TODO: Generating and discarding errors like this can lead to quadratic @@ -198,37 +264,6 @@ Result result(Lexer& in) { return NaNResult{*kind, Type::f64}; } - if (in.takeSExprStart("v128.const"sv)) { - LaneResults lanes; - if (in.takeKeyword("f32x4"sv)) { - for (int i = 0; i < 4; ++i) { - if (auto f = in.takeF32()) { - lanes.push_back(Literal(*f)); - } else { - auto kind = nan(in); - CHECK_ERR(kind); - lanes.push_back(NaNResult{*kind, Type::f32}); - } - } - } else if (in.takeKeyword("f64x2"sv)) { - for (int i = 0; i < 2; ++i) { - if (auto f = in.takeF64()) { - lanes.push_back(Literal(*f)); - } else { - auto kind = nan(in); - CHECK_ERR(kind); - lanes.push_back(NaNResult{*kind, Type::f64}); - } - } - } else { - return in.err("unexpected vector shape"); - } - if (!in.takeRParen()) { - return in.err("expected end of v128.const"); - } - return lanes; - } - if (in.takeSExprStart("ref.null")) { if (!in.takeRParen()) { return in.err("expected end of ref.null"); diff --git a/src/parser/wat-parser.h b/src/parser/wat-parser.h index 8190db4e100..ad90f78a577 100644 --- a/src/parser/wat-parser.h +++ b/src/parser/wat-parser.h @@ -74,7 +74,17 @@ struct NaNResult { using LaneResult = std::variant; -using LaneResults = std::vector; +struct LaneResults { + enum class LaneType { + Int, + Float, + }; + LaneResults(LaneType type, std::vector lanes = {}) + : type(type), lanes(std::move(lanes)) {} + + LaneType type; + std::vector lanes; +}; using ExpectedResult = std::variant; diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 32c1b98ad4e..11553119b96 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -400,28 +400,43 @@ struct Shell { err << e->msg << atIndex(); return Err{err.str()}; } - } else if (auto* lanes = std::get_if(&expected)) { + } else if (auto* l = std::get_if(&expected)) { + auto* lanes = &l->lanes; + + auto check = [&](const auto& vals) -> Result<> { + for (size_t i = 0; i < vals.size(); ++i) { + auto check = checkLane(vals[i], (*lanes)[i], i); + if (auto* e = check.getErr()) { + err << e->msg << atIndex(); + return Err{err.str()}; + } + } + return Ok{}; + }; + + bool isFloat = l->type == WATParser::LaneResults::LaneType::Float; switch (lanes->size()) { + // Use unsigned values for the smaller types here to avoid sign + // extension when storing 8/16-bit values in 32-bit ints. This isn't + // needed for i32 and i64. + case 16: { + // There is no f8. + CHECK_ERR(check(val.getLanesUI8x16())); + break; + } + case 8: { + CHECK_ERR( + check(isFloat ? val.getLanesF16x8() : val.getLanesUI16x8())); + break; + } case 4: { - auto vals = val.getLanesF32x4(); - for (Index i = 0; i < 4; ++i) { - auto check = checkLane(vals[i], (*lanes)[i], i); - if (auto* e = check.getErr()) { - err << e->msg << atIndex(); - return Err{err.str()}; - } - } + CHECK_ERR( + check(isFloat ? val.getLanesF32x4() : val.getLanesI32x4())); break; } case 2: { - auto vals = val.getLanesF64x2(); - for (Index i = 0; i < 2; ++i) { - auto check = checkLane(vals[i], (*lanes)[i], i); - if (auto* e = check.getErr()) { - err << e->msg << atIndex(); - return Err{err.str()}; - } - } + CHECK_ERR( + check(isFloat ? val.getLanesF64x2() : val.getLanesI64x2())); break; } default: