-
Notifications
You must be signed in to change notification settings - Fork 839
Add support for (either ...) in wast #8421
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: lanes
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -319,31 +319,31 @@ struct Shell { | |
| switch (nan.kind) { | ||
| case NaNKind::Canonical: | ||
| if (val.type != nan.type || !val.isCanonicalNaN()) { | ||
| err << "expected canonical " << nan.type << " NaN, got " << val; | ||
| err << "canonical " << nan.type; | ||
| return Err{err.str()}; | ||
| } | ||
| break; | ||
| case NaNKind::Arithmetic: | ||
| if (val.type != nan.type || !val.isArithmeticNaN()) { | ||
| err << "expected arithmetic " << nan.type << " NaN, got " << val; | ||
| err << "arithmetic " << nan.type; | ||
| return Err{err.str()}; | ||
| } | ||
| break; | ||
| } | ||
| return Ok{}; | ||
| } | ||
|
|
||
| Result<> checkLane(Literal val, LaneResult expected, Index index) { | ||
| Result<> checkLane(Literal val, LaneResult expected) { | ||
| std::stringstream err; | ||
| if (auto* e = std::get_if<Literal>(&expected)) { | ||
| if (*e != val) { | ||
| err << "expected " << *e << ", got " << val << " at lane " << index; | ||
| err << *e; | ||
| return Err{err.str()}; | ||
| } | ||
| } else if (auto* nan = std::get_if<NaNResult>(&expected)) { | ||
| auto check = checkNaN(val, *nan); | ||
| if (auto* e = check.getErr()) { | ||
| err << e->msg << " at lane " << index; | ||
| err << e->msg; | ||
| return Err{err.str()}; | ||
| } | ||
| } else { | ||
|
|
@@ -352,6 +352,88 @@ struct Shell { | |
| return Ok{}; | ||
| } | ||
|
|
||
| struct AlternativeErr { | ||
| std::string expected; | ||
| int lane = -1; | ||
| }; | ||
|
|
||
| Result<Ok, AlternativeErr> matchAlternative(const Literal& val, | ||
| const ExpectedResult& expected) { | ||
| std::stringstream err; | ||
|
|
||
| if (auto* v = std::get_if<Literal>(&expected)) { | ||
| if (val != *v) { | ||
| err << *v; | ||
| return AlternativeErr{err.str()}; | ||
| } | ||
| } else if (auto* ref = std::get_if<RefResult>(&expected)) { | ||
| if (!val.type.isRef() || | ||
| !HeapType::isSubType(val.type.getHeapType(), ref->type)) { | ||
|
Comment on lines
+370
to
+371
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably check that the value is not null here, too.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was part of the existing code, I'll send a new PR for this with a test if that sounds good
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sent #8446 for this. |
||
| err << ref->type; | ||
| return AlternativeErr{err.str()}; | ||
| } | ||
| } else if ([[maybe_unused]] auto* nullRef = | ||
| std::get_if<NullRefResult>(&expected)) { | ||
| if (!val.isNull()) { | ||
| err << "ref.null"; | ||
| return AlternativeErr{err.str()}; | ||
| } | ||
| } else if (auto* nan = std::get_if<NaNResult>(&expected)) { | ||
| auto check = checkNaN(val, *nan); | ||
| if (auto* e = check.getErr()) { | ||
| err << e->msg; | ||
| return AlternativeErr{err.str()}; | ||
| } | ||
| } else if (auto* laneResults = std::get_if<LaneResults>(&expected)) { | ||
| auto check = [&](const auto& vals) -> Result<Ok, AlternativeErr> { | ||
| for (size_t i = 0; i < vals.size(); ++i) { | ||
| auto check = checkLane(vals[i], laneResults->lanes[i]); | ||
| if (auto* e = check.getErr()) { | ||
| err << e->msg; | ||
|
|
||
| // The number of lanes is small | ||
| assert(i <= std::numeric_limits<int>::max()); | ||
| return AlternativeErr{err.str(), static_cast<int>(i)}; | ||
| } | ||
| } | ||
| return Ok{}; | ||
| }; | ||
|
|
||
| bool isFloat = | ||
| laneResults->type == WATParser::LaneResults::LaneType::Float; | ||
| switch (laneResults->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. | ||
stevenfontanella marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert(!isFloat && "float8 does not exist"); | ||
| CHECK_ERR(check(val.getLanesUI8x16())); | ||
| break; | ||
| } | ||
| case 8: { | ||
| CHECK_ERR( | ||
| check(isFloat ? val.getLanesF16x8() : val.getLanesUI16x8())); | ||
| break; | ||
| } | ||
| case 4: { | ||
| CHECK_ERR(check(isFloat ? val.getLanesF32x4() : val.getLanesI32x4())); | ||
| break; | ||
| } | ||
| case 2: { | ||
| CHECK_ERR(check(isFloat ? val.getLanesF64x2() : val.getLanesI64x2())); | ||
| break; | ||
| } | ||
| default: | ||
| WASM_UNREACHABLE("unexpected number of lanes"); | ||
| } | ||
|
|
||
| } else { | ||
| WASM_UNREACHABLE("unexpected expectation"); | ||
| } | ||
| return Ok{}; | ||
| } | ||
|
|
||
| Result<> assertReturn(AssertReturn& assn) { | ||
| std::stringstream err; | ||
| auto result = doAction(assn.action); | ||
|
|
@@ -374,78 +456,53 @@ struct Shell { | |
| return ss.str(); | ||
| }; | ||
|
|
||
| Literal val = (*values)[i]; | ||
| auto& expected = assn.expected[i]; | ||
| if (auto* v = std::get_if<Literal>(&expected)) { | ||
| if (val != *v) { | ||
| err << "expected " << *v << ", got " << val << atIndex(); | ||
| return Err{err.str()}; | ||
| } | ||
| } else if (auto* ref = std::get_if<RefResult>(&expected)) { | ||
| if (!val.type.isRef() || | ||
| !HeapType::isSubType(val.type.getHeapType(), ref->type)) { | ||
| err << "expected " << ref->type << " reference, got " << val | ||
| << atIndex(); | ||
| return Err{err.str()}; | ||
| } | ||
| } else if ([[maybe_unused]] auto* nullRef = | ||
| std::get_if<NullRefResult>(&expected)) { | ||
| if (!val.isNull()) { | ||
| err << "expected ref.null, got " << val << atIndex(); | ||
| return Err{err.str()}; | ||
| // non-either case | ||
| if (assn.expected[i].size() == 1) { | ||
| auto result = matchAlternative((*values)[i], assn.expected[i][0]); | ||
| if (auto* e = result.getErr()) { | ||
| std::stringstream ss; | ||
| ss << "expected " << e->expected << ", got " << (*values)[i]; | ||
| if (e->lane != -1) { | ||
| ss << " at lane " << e->lane; | ||
| } | ||
| ss << atIndex(); | ||
| return Err{ss.str()}; | ||
| } | ||
| } else if (auto* nan = std::get_if<NaNResult>(&expected)) { | ||
| auto check = checkNaN(val, *nan); | ||
| if (auto* e = check.getErr()) { | ||
| err << e->msg << atIndex(); | ||
| return Err{err.str()}; | ||
| continue; | ||
| } | ||
|
|
||
| // either case | ||
| bool success = false; | ||
| std::vector<std::string> expecteds; | ||
| int failedLane = -1; | ||
| for (const auto& alternative : assn.expected[i]) { | ||
| auto result = matchAlternative((*values)[i], alternative); | ||
| if (!result.getErr()) { | ||
| success = true; | ||
| break; | ||
| } | ||
| } else if (auto* l = std::get_if<LaneResults>(&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: { | ||
| CHECK_ERR( | ||
| check(isFloat ? val.getLanesF32x4() : val.getLanesI32x4())); | ||
| break; | ||
| } | ||
| case 2: { | ||
| CHECK_ERR( | ||
| check(isFloat ? val.getLanesF64x2() : val.getLanesI64x2())); | ||
| break; | ||
| } | ||
| default: | ||
| WASM_UNREACHABLE("unexpected number of lanes"); | ||
|
|
||
| auto* e = result.getErr(); | ||
| expecteds.push_back(e->expected); | ||
| if (failedLane == -1 && e->lane != -1) { | ||
| failedLane = e->lane; | ||
| } | ||
| } else { | ||
| WASM_UNREACHABLE("unexpected expectation"); | ||
| } | ||
| if (success) { | ||
| continue; | ||
| } | ||
| std::stringstream ss; | ||
| ss << "Expected one of (" << String::join(expecteds, " | ") << ")"; | ||
| if (failedLane != -1) { | ||
| ss << " at lane " << failedLane; | ||
| } | ||
| ss << " but got " << (*values)[i]; | ||
|
|
||
| ss << atIndex(); | ||
|
|
||
| return Err{ss.str()}; | ||
| } | ||
|
|
||
| return Ok{}; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.