From 7d215a986c2853cb764a39b0b7d62dcaf31c2d93 Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Sat, 7 Mar 2026 00:29:54 +0000 Subject: [PATCH 1/2] Fix handling for SIMD lanes in tests --- src/parser/wast-parser.cpp | 98 ++++++++++++++++++++++++++------------ src/parser/wat-parser.h | 10 +++- src/tools/wasm-shell.cpp | 49 ++++++++++++------- 3 files changed, 108 insertions(+), 49 deletions(-) diff --git a/src/parser/wast-parser.cpp b/src/parser/wast-parser.cpp index a7b0cba870a..c5f5f9168c1 100644 --- a/src/parser/wast-parser.cpp +++ b/src/parser/wast-parser.cpp @@ -169,6 +169,73 @@ Result nan(Lexer& in) { } Result result(Lexer& in) { + if (in.takeSExprStart("v128.const"sv)) { + LaneResults results; + auto& lanes = results.lanes; + results.type = in.buffer[in.getPos()] == 'f' ? LaneResults::LaneType::Float + : LaneResults::LaneType::Int; + + 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 +265,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..4eac32b4942 100644 --- a/src/parser/wat-parser.h +++ b/src/parser/wat-parser.h @@ -74,7 +74,15 @@ struct NaNResult { using LaneResult = std::variant; -using LaneResults = std::vector; +struct LaneResults { + enum class LaneType { + Unknown, + Int, + Float, + }; + std::vector lanes; + LaneType type = LaneType::Unknown; +}; using ExpectedResult = std::variant; diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 32c1b98ad4e..4eb6f521fb3 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 = [&](int size, const auto& vals) -> Result<> { + for (int i = 0; i < 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(16, val.getLanesUI8x16())); + break; + } + case 8: { + CHECK_ERR( + check(8, 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(4, 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(2, isFloat ? val.getLanesF64x2() : val.getLanesI64x2())); break; } default: From 15de160057ca72b80d085e82257bccde0975599a Mon Sep 17 00:00:00 2001 From: stevenfontanella Date: Mon, 9 Mar 2026 23:23:26 +0000 Subject: [PATCH 2/2] PR updates --- src/parser/lexer.cpp | 9 +++++++++ src/parser/lexer.h | 2 ++ src/parser/wast-parser.cpp | 5 ++--- src/parser/wat-parser.h | 6 ++++-- src/tools/wasm-shell.cpp | 12 ++++++------ 5 files changed, 23 insertions(+), 11 deletions(-) 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 c5f5f9168c1..bf8b8f643d6 100644 --- a/src/parser/wast-parser.cpp +++ b/src/parser/wast-parser.cpp @@ -170,10 +170,9 @@ Result nan(Lexer& in) { Result result(Lexer& in) { if (in.takeSExprStart("v128.const"sv)) { - LaneResults results; + LaneResults results(in.peekChar() == 'f' ? LaneResults::LaneType::Float + : LaneResults::LaneType::Int); auto& lanes = results.lanes; - results.type = in.buffer[in.getPos()] == 'f' ? LaneResults::LaneType::Float - : LaneResults::LaneType::Int; if (in.takeKeyword("i8x16"sv)) { for (int i = 0; i < 16; ++i) { diff --git a/src/parser/wat-parser.h b/src/parser/wat-parser.h index 4eac32b4942..ad90f78a577 100644 --- a/src/parser/wat-parser.h +++ b/src/parser/wat-parser.h @@ -76,12 +76,14 @@ using LaneResult = std::variant; struct LaneResults { enum class LaneType { - Unknown, Int, Float, }; + LaneResults(LaneType type, std::vector lanes = {}) + : type(type), lanes(std::move(lanes)) {} + + LaneType type; std::vector lanes; - LaneType type = LaneType::Unknown; }; using ExpectedResult = diff --git a/src/tools/wasm-shell.cpp b/src/tools/wasm-shell.cpp index 4eb6f521fb3..11553119b96 100644 --- a/src/tools/wasm-shell.cpp +++ b/src/tools/wasm-shell.cpp @@ -403,8 +403,8 @@ struct Shell { } else if (auto* l = std::get_if(&expected)) { auto* lanes = &l->lanes; - auto check = [&](int size, const auto& vals) -> Result<> { - for (int i = 0; i < size; ++i) { + 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(); @@ -421,22 +421,22 @@ struct Shell { // needed for i32 and i64. case 16: { // There is no f8. - CHECK_ERR(check(16, val.getLanesUI8x16())); + CHECK_ERR(check(val.getLanesUI8x16())); break; } case 8: { CHECK_ERR( - check(8, isFloat ? val.getLanesF16x8() : val.getLanesUI16x8())); + check(isFloat ? val.getLanesF16x8() : val.getLanesUI16x8())); break; } case 4: { CHECK_ERR( - check(4, isFloat ? val.getLanesF32x4() : val.getLanesI32x4())); + check(isFloat ? val.getLanesF32x4() : val.getLanesI32x4())); break; } case 2: { CHECK_ERR( - check(2, isFloat ? val.getLanesF64x2() : val.getLanesI64x2())); + check(isFloat ? val.getLanesF64x2() : val.getLanesI64x2())); break; } default: