diff options
author | Thomas Lively <tlively@google.com> | 2023-08-09 17:18:13 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-08-09 21:18:13 +0000 |
commit | c003a01aa855bfa1377237eb2ce788b9fa96e839 (patch) | |
tree | 454d2b6de36ea56de5d3e310d81f02155aa73db1 | |
parent | d0bdf202463323a0b9f3be95fe2c64765a84a4b7 (diff) | |
download | binaryen-c003a01aa855bfa1377237eb2ce788b9fa96e839.tar.gz binaryen-c003a01aa855bfa1377237eb2ce788b9fa96e839.tar.bz2 binaryen-c003a01aa855bfa1377237eb2ce788b9fa96e839.zip |
Remove legacy WasmGC instructions (#5861)
Remove old, experimental instructions and type encodings that will not be
shipped as part of WasmGC. Updating the encodings and text format to match the
final spec is left as future work.
39 files changed, 281 insertions, 2342 deletions
diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index d9d013b9b..f82156b43 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -568,21 +568,11 @@ instructions = [ ("i31.get_s", "makeI31Get(s, true)"), ("i31.get_u", "makeI31Get(s, false)"), ("ref.test", "makeRefTest(s)"), - ("ref.test_static", "makeRefTest(s)"), ("ref.cast", "makeRefCast(s)"), - ("ref.cast_static", "makeRefCast(s)"), - ("ref.cast_nop", "makeRefCastNop(s)"), - ("ref.cast_nop_static", "makeRefCastNop(s)"), ("br_on_null", "makeBrOnNull(s)"), ("br_on_non_null", "makeBrOnNull(s, true)"), - ("br_on_cast", "makeBrOnCast(s, std::nullopt)"), - ("br_on_cast_static", "makeBrOnCast(s, std::nullopt)"), - ("br_on_cast_fail", "makeBrOnCast(s, std::nullopt, true)"), - ("br_on_cast_static_fail", "makeBrOnCast(s, std::nullopt, true)"), - ("br_on_func", "makeBrOnCast(s, Type(HeapType::func, NonNullable))"), - ("br_on_non_func", "makeBrOnCast(s, Type(HeapType::func, NonNullable), true)"), - ("br_on_i31", "makeBrOnCast(s, Type(HeapType::i31, NonNullable))"), - ("br_on_non_i31", "makeBrOnCast(s, Type(HeapType::i31, NonNullable), true)"), + ("br_on_cast", "makeBrOnCast(s)"), + ("br_on_cast_fail", "makeBrOnCast(s, true)"), ("struct.new", "makeStructNew(s, false)"), ("struct.new_default", "makeStructNew(s, true)"), ("struct.get", "makeStructGet(s)"), @@ -604,11 +594,7 @@ instructions = [ ("array.fill", "makeArrayFill(s)"), ("array.init_data", "makeArrayInitData(s)"), ("array.init_elem", "makeArrayInitElem(s)"), - ("ref.is_func", "makeRefTest(s, Type(HeapType::func, NonNullable))"), - ("ref.is_i31", "makeRefTest(s, Type(HeapType::i31, NonNullable))"), ("ref.as_non_null", "makeRefAs(s, RefAsNonNull)"), - ("ref.as_func", "makeRefCast(s, Type(HeapType::func, NonNullable))"), - ("ref.as_i31", "makeRefCast(s, Type(HeapType::i31, NonNullable))"), ("extern.internalize", "makeRefAs(s, ExternInternalize)"), ("extern.externalize", "makeRefAs(s, ExternExternalize)"), ("string.new_wtf8", "makeStringNew(s, StringNewWTF8, false)"), diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index dd2ad5c4a..0b7adf92a 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1768,8 +1768,7 @@ BinaryenExpressionRef BinaryenRefCast(BinaryenModuleRef module, BinaryenExpressionRef ref, BinaryenType type) { return static_cast<Expression*>( - Builder(*(Module*)module) - .makeRefCast((Expression*)ref, Type(type), RefCast::Safety::Safe)); + Builder(*(Module*)module).makeRefCast((Expression*)ref, Type(type))); } BinaryenExpressionRef BinaryenBrOn(BinaryenModuleRef module, BinaryenOp op, diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 772847f9b..ce7baadd5 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -117,52 +117,19 @@ switch (buf[0]) { case 'c': { switch (buf[10]) { case '\0': - if (op == "br_on_cast"sv) { return makeBrOnCast(s, std::nullopt); } + if (op == "br_on_cast"sv) { return makeBrOnCast(s); } + goto parse_error; + case '_': + if (op == "br_on_cast_fail"sv) { return makeBrOnCast(s, true); } goto parse_error; - case '_': { - switch (buf[11]) { - case 'f': - if (op == "br_on_cast_fail"sv) { return makeBrOnCast(s, std::nullopt, true); } - goto parse_error; - case 's': { - switch (buf[17]) { - case '\0': - if (op == "br_on_cast_static"sv) { return makeBrOnCast(s, std::nullopt); } - goto parse_error; - case '_': - if (op == "br_on_cast_static_fail"sv) { return makeBrOnCast(s, std::nullopt, true); } - goto parse_error; - default: goto parse_error; - } - } - default: goto parse_error; - } - } default: goto parse_error; } } - case 'f': - if (op == "br_on_func"sv) { return makeBrOnCast(s, Type(HeapType::func, NonNullable)); } - goto parse_error; - case 'i': - if (op == "br_on_i31"sv) { return makeBrOnCast(s, Type(HeapType::i31, NonNullable)); } - goto parse_error; case 'n': { switch (buf[7]) { - case 'o': { - switch (buf[10]) { - case 'f': - if (op == "br_on_non_func"sv) { return makeBrOnCast(s, Type(HeapType::func, NonNullable), true); } - goto parse_error; - case 'i': - if (op == "br_on_non_i31"sv) { return makeBrOnCast(s, Type(HeapType::i31, NonNullable), true); } - goto parse_error; - case 'n': - if (op == "br_on_non_null"sv) { return makeBrOnNull(s, true); } - goto parse_error; - default: goto parse_error; - } - } + case 'o': + if (op == "br_on_non_null"sv) { return makeBrOnNull(s, true); } + goto parse_error; case 'u': if (op == "br_on_null"sv) { return makeBrOnNull(s); } goto parse_error; @@ -3008,81 +2975,27 @@ switch (buf[0]) { switch (buf[2]) { case 'f': { switch (buf[4]) { - case 'a': { - switch (buf[7]) { - case 'f': - if (op == "ref.as_func"sv) { return makeRefCast(s, Type(HeapType::func, NonNullable)); } - goto parse_error; - case 'i': - if (op == "ref.as_i31"sv) { return makeRefCast(s, Type(HeapType::i31, NonNullable)); } - goto parse_error; - case 'n': - if (op == "ref.as_non_null"sv) { return makeRefAs(s, RefAsNonNull); } - goto parse_error; - default: goto parse_error; - } - } - case 'c': { - switch (buf[8]) { - case '\0': - if (op == "ref.cast"sv) { return makeRefCast(s); } - goto parse_error; - case '_': { - switch (buf[9]) { - case 'n': { - switch (buf[12]) { - case '\0': - if (op == "ref.cast_nop"sv) { return makeRefCastNop(s); } - goto parse_error; - case '_': - if (op == "ref.cast_nop_static"sv) { return makeRefCastNop(s); } - goto parse_error; - default: goto parse_error; - } - } - case 's': - if (op == "ref.cast_static"sv) { return makeRefCast(s); } - goto parse_error; - default: goto parse_error; - } - } - default: goto parse_error; - } - } + case 'a': + if (op == "ref.as_non_null"sv) { return makeRefAs(s, RefAsNonNull); } + goto parse_error; + case 'c': + if (op == "ref.cast"sv) { return makeRefCast(s); } + goto parse_error; case 'e': if (op == "ref.eq"sv) { return makeRefEq(s); } goto parse_error; case 'f': if (op == "ref.func"sv) { return makeRefFunc(s); } goto parse_error; - case 'i': { - switch (buf[7]) { - case 'f': - if (op == "ref.is_func"sv) { return makeRefTest(s, Type(HeapType::func, NonNullable)); } - goto parse_error; - case 'i': - if (op == "ref.is_i31"sv) { return makeRefTest(s, Type(HeapType::i31, NonNullable)); } - goto parse_error; - case 'n': - if (op == "ref.is_null"sv) { return makeRefIsNull(s); } - goto parse_error; - default: goto parse_error; - } - } + case 'i': + if (op == "ref.is_null"sv) { return makeRefIsNull(s); } + goto parse_error; case 'n': if (op == "ref.null"sv) { return makeRefNull(s); } goto parse_error; - case 't': { - switch (buf[8]) { - case '\0': - if (op == "ref.test"sv) { return makeRefTest(s); } - goto parse_error; - case '_': - if (op == "ref.test_static"sv) { return makeRefTest(s); } - goto parse_error; - default: goto parse_error; - } - } + case 't': + if (op == "ref.test"sv) { return makeRefTest(s); } + goto parse_error; default: goto parse_error; } } @@ -3795,87 +3708,30 @@ switch (buf[0]) { switch (buf[10]) { case '\0': if (op == "br_on_cast"sv) { - auto ret = makeBrOnCast(ctx, pos, std::nullopt); + auto ret = makeBrOnCast(ctx, pos); CHECK_ERR(ret); return *ret; } goto parse_error; - case '_': { - switch (buf[11]) { - case 'f': - if (op == "br_on_cast_fail"sv) { - auto ret = makeBrOnCast(ctx, pos, std::nullopt, true); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 's': { - switch (buf[17]) { - case '\0': - if (op == "br_on_cast_static"sv) { - auto ret = makeBrOnCast(ctx, pos, std::nullopt); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case '_': - if (op == "br_on_cast_static_fail"sv) { - auto ret = makeBrOnCast(ctx, pos, std::nullopt, true); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - default: goto parse_error; - } - } - default: goto parse_error; + case '_': + if (op == "br_on_cast_fail"sv) { + auto ret = makeBrOnCast(ctx, pos, true); + CHECK_ERR(ret); + return *ret; } - } + goto parse_error; default: goto parse_error; } } - case 'f': - if (op == "br_on_func"sv) { - auto ret = makeBrOnCast(ctx, pos, Type(HeapType::func, NonNullable)); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 'i': - if (op == "br_on_i31"sv) { - auto ret = makeBrOnCast(ctx, pos, Type(HeapType::i31, NonNullable)); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; case 'n': { switch (buf[7]) { - case 'o': { - switch (buf[10]) { - case 'f': - if (op == "br_on_non_func"sv) { - auto ret = makeBrOnCast(ctx, pos, Type(HeapType::func, NonNullable), true); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 'i': - if (op == "br_on_non_i31"sv) { - auto ret = makeBrOnCast(ctx, pos, Type(HeapType::i31, NonNullable), true); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 'n': - if (op == "br_on_non_null"sv) { - auto ret = makeBrOnNull(ctx, pos, true); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - default: goto parse_error; + case 'o': + if (op == "br_on_non_null"sv) { + auto ret = makeBrOnNull(ctx, pos, true); + CHECK_ERR(ret); + return *ret; } - } + goto parse_error; case 'u': if (op == "br_on_null"sv) { auto ret = makeBrOnNull(ctx, pos); @@ -8649,75 +8505,20 @@ switch (buf[0]) { switch (buf[2]) { case 'f': { switch (buf[4]) { - case 'a': { - switch (buf[7]) { - case 'f': - if (op == "ref.as_func"sv) { - auto ret = makeRefCast(ctx, pos, Type(HeapType::func, NonNullable)); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 'i': - if (op == "ref.as_i31"sv) { - auto ret = makeRefCast(ctx, pos, Type(HeapType::i31, NonNullable)); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 'n': - if (op == "ref.as_non_null"sv) { - auto ret = makeRefAs(ctx, pos, RefAsNonNull); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - default: goto parse_error; + case 'a': + if (op == "ref.as_non_null"sv) { + auto ret = makeRefAs(ctx, pos, RefAsNonNull); + CHECK_ERR(ret); + return *ret; } - } - case 'c': { - switch (buf[8]) { - case '\0': - if (op == "ref.cast"sv) { - auto ret = makeRefCast(ctx, pos); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case '_': { - switch (buf[9]) { - case 'n': { - switch (buf[12]) { - case '\0': - if (op == "ref.cast_nop"sv) { - auto ret = makeRefCastNop(ctx, pos); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case '_': - if (op == "ref.cast_nop_static"sv) { - auto ret = makeRefCastNop(ctx, pos); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - default: goto parse_error; - } - } - case 's': - if (op == "ref.cast_static"sv) { - auto ret = makeRefCast(ctx, pos); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - default: goto parse_error; - } - } - default: goto parse_error; + goto parse_error; + case 'c': + if (op == "ref.cast"sv) { + auto ret = makeRefCast(ctx, pos); + CHECK_ERR(ret); + return *ret; } - } + goto parse_error; case 'e': if (op == "ref.eq"sv) { auto ret = makeRefEq(ctx, pos); @@ -8732,32 +8533,13 @@ switch (buf[0]) { return *ret; } goto parse_error; - case 'i': { - switch (buf[7]) { - case 'f': - if (op == "ref.is_func"sv) { - auto ret = makeRefTest(ctx, pos, Type(HeapType::func, NonNullable)); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 'i': - if (op == "ref.is_i31"sv) { - auto ret = makeRefTest(ctx, pos, Type(HeapType::i31, NonNullable)); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case 'n': - if (op == "ref.is_null"sv) { - auto ret = makeRefIsNull(ctx, pos); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - default: goto parse_error; + case 'i': + if (op == "ref.is_null"sv) { + auto ret = makeRefIsNull(ctx, pos); + CHECK_ERR(ret); + return *ret; } - } + goto parse_error; case 'n': if (op == "ref.null"sv) { auto ret = makeRefNull(ctx, pos); @@ -8765,25 +8547,13 @@ switch (buf[0]) { return *ret; } goto parse_error; - case 't': { - switch (buf[8]) { - case '\0': - if (op == "ref.test"sv) { - auto ret = makeRefTest(ctx, pos); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - case '_': - if (op == "ref.test_static"sv) { - auto ret = makeRefTest(ctx, pos); - CHECK_ERR(ret); - return *ret; - } - goto parse_error; - default: goto parse_error; + case 't': + if (op == "ref.test"sv) { + auto ret = makeRefTest(ctx, pos); + CHECK_ERR(ret); + return *ret; } - } + goto parse_error; default: goto parse_error; } } diff --git a/src/ir/stack-utils.h b/src/ir/stack-utils.h index aad13f7f0..82d1f5a3d 100644 --- a/src/ir/stack-utils.h +++ b/src/ir/stack-utils.h @@ -131,13 +131,13 @@ struct StackSignature { // // As an example of the first rule, consider this instruction sequence: // - // ref.as_func + // ref.cast (ref i31) // drop // i32.add // // The most specific type you could give this sequence is [i32, i32, anyref] // -> [i32]. But it could also be used in a context that expects [i32, i32, - // funcref] -> [i32] because ref.as_func can accept funcref or any other + // structref] -> [i32] because ref.cast can accept structref or any other // subtype of anyref. That's where the contravariance comes from. This // instruction sequence could also be used anywhere that expects [f32, i32, // i32, anyref] -> [f32, i32] because the f32 simply stays on the stack @@ -145,7 +145,7 @@ struct StackSignature { // // For the second rule, consider this sequence: // - // ref.as_func + // ref.cast (ref i31) // drop // i32.add // unreachable diff --git a/src/passes/OptimizeCasts.cpp b/src/passes/OptimizeCasts.cpp index 599e403ff..7877bea9f 100644 --- a/src/passes/OptimizeCasts.cpp +++ b/src/passes/OptimizeCasts.cpp @@ -385,10 +385,8 @@ struct EarlyCastApplier : public PostWalker<EarlyCastApplier> { auto refCastIter = finder.refCastToApply.find(curr); if (refCastIter != finder.refCastToApply.end()) { - currPtr = replaceCurrent(Builder(*getModule()) - .makeRefCast(currPtr, - refCastIter->second->type, - refCastIter->second->safety)); + currPtr = replaceCurrent( + Builder(*getModule()).makeRefCast(currPtr, refCastIter->second->type)); } auto refAsIter = finder.refAsToApply.find(curr); diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 44078545b..965f8b2d8 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1406,13 +1406,13 @@ struct OptimizeInstructions // skipCast do): removing a cast is potentially dangerous, as it removes // information from the IR. For example: // - // (ref.is_func - // (ref.as_func + // (ref.test (ref i31) + // (ref.cast (ref i31) // (local.get $anyref))) // // The local has no useful type info here (it is anyref). The cast forces it - // to be a function, so we know that if we do not trap then the ref.is will - // definitely be 1. But if we removed the ref.as first (which we can do in + // to be an i31, so we know that if we do not trap then the ref.test will + // definitely be 1. But if we removed the ref.cast first (which we can do in // traps-never-happen mode) then we'd not have the type info we need to // optimize that way. // @@ -1420,12 +1420,12 @@ struct OptimizeInstructions // // * Before removing a cast we should use its type information in the best // way we can. Only after doing so should a cast be removed. In the exmaple - // above, that means first seeing that the ref.is must return 1, and only - // then possibly removing the ref.as. + // above, that means first seeing that the ref.test must return 1, and only + // then possibly removing the ref.cast. // * Do not remove a cast if removing it might remove useful information for // others. For example, // - // (ref.cast $A + // (ref.cast (ref null $A) // (ref.as_non_null ..)) // // If we remove the inner cast then the outer cast becomes nullable. That diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 6740bc8ed..dee23d67d 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2102,14 +2102,10 @@ struct PrintExpressionContents if (printUnreachableReplacement(curr)) { return; } - if (curr->safety == RefCast::Unsafe) { - printMedium(o, "ref.cast_nop "); + if (curr->type.isNullable()) { + printMedium(o, "ref.cast null "); } else { - if (curr->type.isNullable()) { - printMedium(o, "ref.cast null "); - } else { - printMedium(o, "ref.cast "); - } + printMedium(o, "ref.cast "); } printHeapType(o, curr->type.getHeapType(), wasm); } diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp index 197126f5e..dc7741c0e 100644 --- a/src/passes/RemoveUnusedBrs.cpp +++ b/src/passes/RemoveUnusedBrs.cpp @@ -714,9 +714,6 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> { // First, check for a possible null which would prevent optimizations on // null checks. - // TODO: Look into using BrOnNonNull here, to replace a br_on_func whose - // input is (ref null func) with br_on_non_null (as only the null check - // would be needed). // TODO: Use the fallthrough to determine in more cases that we // definitely have a null. auto refType = curr->ref->type; diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 8df9b9afc..2317e7d49 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -3394,8 +3394,7 @@ Expression* TranslateToFuzzReader::makeRefCast(Type type) { // This unreachable avoids a warning on refType being possibly undefined. WASM_UNREACHABLE("bad case"); } - // TODO: Fuzz unsafe casts? - return builder.makeRefCast(make(refType), type, RefCast::Safe); + return builder.makeRefCast(make(refType), type); } Expression* TranslateToFuzzReader::makeStructGet(Type type) { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index c6b3e7b6f..05cd38320 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -389,10 +389,6 @@ enum EncodedType { Array = -0x22, // 0x5e Sub = -0x30, // 0x50 SubFinal = -0x32, // 0x4e - // prototype nominal forms we still parse - FuncSubtype = -0x23, // 0x5d - StructSubtype = -0x24, // 0x5c - ArraySubtype = -0x25, // 0x5b // isorecursive recursion groups Rec = -0x31, // 0x4f // block_type @@ -1108,7 +1104,6 @@ enum ASTNodes { ArrayGetS = 0x14, ArrayGetU = 0x15, ArraySet = 0x16, - ArrayLenAnnotated = 0x17, ArrayCopy = 0x18, ArrayLen = 0x19, ArrayNewFixed = 0x1a, @@ -1120,23 +1115,10 @@ enum ASTNodes { I31GetU = 0x22, RefTest = 0x40, RefCast = 0x41, - BrOnCastLegacy = 0x42, - BrOnCastFailLegacy = 0x43, - BrOnCastNullLegacy = 0x4a, - BrOnCastFailNullLegacy = 0x4b, BrOnCast = 0x4e, BrOnCastFail = 0x4f, - RefTestStatic = 0x44, - RefCastStatic = 0x45, RefTestNull = 0x48, RefCastNull = 0x49, - RefCastNop = 0x4c, - RefAsFunc = 0x58, - RefAsI31 = 0x5a, - BrOnFunc = 0x60, - BrOnI31 = 0x62, - BrOnNonFunc = 0x63, - BrOnNonI31 = 0x65, ExternInternalize = 0x70, ExternExternalize = 0x71, ArrayFill = 0x0f, diff --git a/src/wasm-builder.h b/src/wasm-builder.h index a3bf22fdc..cb7c5e745 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -876,13 +876,10 @@ public: ret->finalize(); return ret; } - RefCast* makeRefCast(Expression* ref, - Type type, - RefCast::Safety safety = RefCast::Safe) { + RefCast* makeRefCast(Expression* ref, Type type) { auto* ret = wasm.allocator.alloc<RefCast>(); ret->ref = ref; ret->type = type; - ret->safety = safety; ret->finalize(); return ret; } diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index 1d9d6244d..cd8976f82 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -648,7 +648,6 @@ switch (DELEGATE_ID) { } case Expression::Id::RefCastId: { DELEGATE_START(RefCast); - DELEGATE_FIELD_INT(RefCast, safety); DELEGATE_FIELD_CHILD(RefCast, ref); DELEGATE_END(RefCast); break; diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index f61a5000a..84299f04b 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -287,14 +287,10 @@ private: Expression* makeCallRef(Element& s, bool isReturn); Expression* makeI31New(Element& s); Expression* makeI31Get(Element& s, bool signed_); - Expression* makeRefTest(Element& s, - std::optional<Type> castType = std::nullopt); - Expression* makeRefCast(Element& s, - std::optional<Type> castType = std::nullopt); - Expression* makeRefCastNop(Element& s); + Expression* makeRefTest(Element& s); + Expression* makeRefCast(Element& s); Expression* makeBrOnNull(Element& s, bool onFail = false); - Expression* - makeBrOnCast(Element& s, std::optional<Type> castType, bool onFail = false); + Expression* makeBrOnCast(Element& s, bool onFail = false); Expression* makeStructNew(Element& s, bool default_); Index getStructIndex(Element& type, Element& field); Expression* makeStructGet(Element& s, bool signed_ = false); diff --git a/src/wasm.h b/src/wasm.h index c059009b6..39cc9fb54 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1525,11 +1525,6 @@ public: Expression* ref; - // Support the unsafe `ref.cast_nop_static` to enable precise cast overhead - // measurements. - enum Safety { Safe, Unsafe }; - Safety safety = Safe; - void finalize(); Type& getCastType() { return type; } diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 3ceab828b..98e832225 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2256,49 +2256,15 @@ void WasmBinaryReader::readTypes() { } form = getS32LEB(); } - if (form == BinaryConsts::EncodedType::Func || - form == BinaryConsts::EncodedType::FuncSubtype) { + if (form == BinaryConsts::EncodedType::Func) { builder[i] = readSignatureDef(); - } else if (form == BinaryConsts::EncodedType::Struct || - form == BinaryConsts::EncodedType::StructSubtype) { + } else if (form == BinaryConsts::EncodedType::Struct) { builder[i] = readStructDef(); - } else if (form == BinaryConsts::EncodedType::Array || - form == BinaryConsts::EncodedType::ArraySubtype) { + } else if (form == BinaryConsts::EncodedType::Array) { builder[i] = Array(readFieldDef()); } else { throwError("Bad type form " + std::to_string(form)); } - if (form == BinaryConsts::EncodedType::FuncSubtype || - form == BinaryConsts::EncodedType::StructSubtype || - form == BinaryConsts::EncodedType::ArraySubtype) { - int64_t super = getS64LEB(); // TODO: Actually s33 - if (super >= 0) { - superIndex = (uint32_t)super; - } else { - // Validate but otherwise ignore trivial supertypes. - HeapType basicSuper; - if (!getBasicHeapType(super, basicSuper)) { - throwError("Unrecognized supertype " + std::to_string(super)); - } - if (form == BinaryConsts::EncodedType::FuncSubtype) { - if (basicSuper != HeapType::func) { - throwError( - "The only allowed trivial supertype for functions is func"); - } - } else { - // Check for "struct" here even if we are parsing an array definition. - // This is the old nonstandard "struct_subtype" or "array_subtype" - // form of type definitions that used the old "data" type as the - // supertype placeholder when there was no nontrivial supertype. - // "data" no longer exists, but "struct" has the same encoding it used - // to have. - if (basicSuper != HeapType::struct_) { - throwError("The only allowed trivial supertype for structs and " - "arrays is data"); - } - } - } - } if (superIndex) { if (*superIndex > builder.size()) { throwError("Out of bounds supertype index " + @@ -4162,12 +4128,6 @@ BinaryConsts::ASTNodes WasmBinaryReader::readExpression(Expression*& curr) { if (maybeVisitStringSliceIter(curr, opcode)) { break; } - if (opcode == BinaryConsts::RefAsFunc || - opcode == BinaryConsts::RefAsI31) { - visitRefAsCast((curr = allocator.alloc<RefCast>())->cast<RefCast>(), - opcode); - break; - } if (opcode == BinaryConsts::ExternInternalize || opcode == BinaryConsts::ExternExternalize) { visitRefAs((curr = allocator.alloc<RefAs>())->cast<RefAs>(), opcode); @@ -7011,10 +6971,8 @@ bool WasmBinaryReader::maybeVisitI31Get(Expression*& out, uint32_t code) { } bool WasmBinaryReader::maybeVisitRefTest(Expression*& out, uint32_t code) { - if (code == BinaryConsts::RefTestStatic || code == BinaryConsts::RefTest || - code == BinaryConsts::RefTestNull) { - bool legacy = code == BinaryConsts::RefTestStatic; - auto castType = legacy ? getIndexedHeapType() : getHeapType(); + if (code == BinaryConsts::RefTest || code == BinaryConsts::RefTestNull) { + auto castType = getHeapType(); auto nullability = (code == BinaryConsts::RefTestNull) ? Nullable : NonNullable; auto* ref = popNonVoidExpression(); @@ -7024,40 +6982,13 @@ bool WasmBinaryReader::maybeVisitRefTest(Expression*& out, uint32_t code) { return false; } -void WasmBinaryReader::visitRefAsCast(RefCast* curr, uint32_t code) { - // TODO: These instructions are deprecated. Remove them. - switch (code) { - case BinaryConsts::RefAsFunc: - curr->type = Type(HeapType::func, NonNullable); - break; - case BinaryConsts::RefAsI31: - curr->type = Type(HeapType::i31, NonNullable); - break; - default: - WASM_UNREACHABLE("unexpected ref.as*"); - } - curr->ref = popNonVoidExpression(); - curr->safety = RefCast::Safe; - curr->finalize(); -} - bool WasmBinaryReader::maybeVisitRefCast(Expression*& out, uint32_t code) { - if (code == BinaryConsts::RefCastStatic || code == BinaryConsts::RefCast || - code == BinaryConsts::RefCastNull || code == BinaryConsts::RefCastNop) { - bool legacy = code == BinaryConsts::RefCastStatic; - auto heapType = legacy ? getIndexedHeapType() : getHeapType(); - auto* ref = popNonVoidExpression(); - Nullability nullability; - if (legacy) { - // Legacy polymorphic behavior. - nullability = ref->type.getNullability(); - } else { - nullability = code == BinaryConsts::RefCast ? NonNullable : Nullable; - } - auto safety = - code == BinaryConsts::RefCastNop ? RefCast::Unsafe : RefCast::Safe; + if (code == BinaryConsts::RefCast || code == BinaryConsts::RefCastNull) { + auto heapType = getHeapType(); + auto nullability = code == BinaryConsts::RefCast ? NonNullable : Nullable; auto type = Type(heapType, nullability); - out = Builder(wasm).makeRefCast(ref, type, safety); + auto* ref = popNonVoidExpression(); + out = Builder(wasm).makeRefCast(ref, type); return true; } return false; @@ -7074,63 +7005,32 @@ bool WasmBinaryReader::maybeVisitBrOn(Expression*& out, uint32_t code) { op = BrOnNonNull; break; case BinaryConsts::BrOnCast: - case BinaryConsts::BrOnCastLegacy: - case BinaryConsts::BrOnCastNullLegacy: op = BrOnCast; break; case BinaryConsts::BrOnCastFail: - case BinaryConsts::BrOnCastFailLegacy: - case BinaryConsts::BrOnCastFailNullLegacy: op = BrOnCastFail; break; - case BinaryConsts::BrOnFunc: - op = BrOnCast; - castType = Type(HeapType::func, NonNullable); - break; - case BinaryConsts::BrOnNonFunc: - op = BrOnCastFail; - castType = Type(HeapType::func, NonNullable); - break; - case BinaryConsts::BrOnI31: - op = BrOnCast; - castType = Type(HeapType::i31, NonNullable); - break; - case BinaryConsts::BrOnNonI31: - op = BrOnCastFail; - castType = Type(HeapType::i31, NonNullable); - break; default: return false; } - bool hasInputAnnotation = + bool isCast = code == BinaryConsts::BrOnCast || code == BinaryConsts::BrOnCastFail; uint8_t flags = 0; - if (hasInputAnnotation) { + if (isCast) { flags = getInt8(); } auto name = getBreakTarget(getU32LEB()).name; auto* ref = popNonVoidExpression(); - if (op == BrOnCast || op == BrOnCastFail) { - Nullability inputNullability, castNullability; - HeapType inputHeapType, castHeapType; - if (hasInputAnnotation) { - inputNullability = (flags & 1) ? Nullable : NonNullable; - castNullability = (flags & 2) ? Nullable : NonNullable; - inputHeapType = getHeapType(); - } else { - castNullability = (code == BinaryConsts::BrOnCastNullLegacy || - code == BinaryConsts::BrOnCastFailNullLegacy) - ? Nullable - : NonNullable; - } - castHeapType = getHeapType(); + if (isCast) { + auto inputNullability = (flags & 1) ? Nullable : NonNullable; + auto castNullability = (flags & 2) ? Nullable : NonNullable; + auto inputHeapType = getHeapType(); + auto castHeapType = getHeapType(); castType = Type(castHeapType, castNullability); - if (hasInputAnnotation) { - auto inputType = Type(inputHeapType, inputNullability); - if (!Type::isSubType(ref->type, inputType)) { - throwError(std::string("Invalid reference type for ") + - ((op == BrOnCast) ? "br_on_cast" : "br_on_cast_fail")); - } + auto inputType = Type(inputHeapType, inputNullability); + if (!Type::isSubType(ref->type, inputType)) { + throwError(std::string("Invalid reference type for ") + + ((op == BrOnCast) ? "br_on_cast" : "br_on_cast_fail")); } } out = Builder(wasm).makeBrOn(op, name, ref, castType); @@ -7288,10 +7188,7 @@ bool WasmBinaryReader::maybeVisitArraySet(Expression*& out, uint32_t code) { } bool WasmBinaryReader::maybeVisitArrayLen(Expression*& out, uint32_t code) { - if (code == BinaryConsts::ArrayLenAnnotated) { - // Ignore the type annotation and don't bother validating it. - getU32LEB(); - } else if (code != BinaryConsts::ArrayLen) { + if (code != BinaryConsts::ArrayLen) { return false; } auto* ref = popNonVoidExpression(); diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 9b7a1a90d..0115cdac3 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2841,51 +2841,30 @@ Expression* SExpressionWasmBuilder::makeI31Get(Element& s, bool signed_) { return ret; } -Expression* SExpressionWasmBuilder::makeRefTest(Element& s, - std::optional<Type> castType) { +Expression* SExpressionWasmBuilder::makeRefTest(Element& s) { int i = 1; - if (!castType) { - auto nullability = NonNullable; - if (s[0]->str().str != "ref.test_static" && s[1]->str().str == "null") { - nullability = Nullable; - ++i; - } - auto type = parseHeapType(*s[i++]); - castType = Type(type, nullability); + auto nullability = NonNullable; + if (s[1]->str().str == "null") { + nullability = Nullable; + ++i; } + auto type = parseHeapType(*s[i++]); + auto castType = Type(type, nullability); auto* ref = parseExpression(*s[i++]); - return Builder(wasm).makeRefTest(ref, *castType); + return Builder(wasm).makeRefTest(ref, castType); } -Expression* SExpressionWasmBuilder::makeRefCast(Element& s, - std::optional<Type> castType) { +Expression* SExpressionWasmBuilder::makeRefCast(Element& s) { int i = 1; - bool legacy = false; - if (!castType) { - Nullability nullability = NonNullable; - if (s[0]->str().str == "ref.cast_static") { - legacy = true; - } else if (s[i]->str().str == "null") { - nullability = Nullable; - ++i; - } - auto type = parseHeapType(*s[i++]); - castType = Type(type, nullability); + Nullability nullability = NonNullable; + if (s[i]->str().str == "null") { + nullability = Nullable; + ++i; } + auto type = parseHeapType(*s[i++]); + auto castType = Type(type, nullability); auto* ref = parseExpression(*s[i++]); - if (legacy) { - // Legacy polymorphic behavior. - castType = Type(castType->getHeapType(), ref->type.getNullability()); - } - return Builder(wasm).makeRefCast(ref, *castType, RefCast::Safe); -} - -Expression* SExpressionWasmBuilder::makeRefCastNop(Element& s) { - auto heapType = parseHeapType(*s[1]); - auto* ref = parseExpression(*s[2]); - // Legacy polymorphic behavior. - auto type = Type(heapType, ref->type.getNullability()); - return Builder(wasm).makeRefCast(ref, type, RefCast::Unsafe); + return Builder(wasm).makeRefCast(ref, castType); } Expression* SExpressionWasmBuilder::makeBrOnNull(Element& s, bool onFail) { @@ -2896,23 +2875,18 @@ Expression* SExpressionWasmBuilder::makeBrOnNull(Element& s, bool onFail) { return Builder(wasm).makeBrOn(op, name, ref); } -Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s, - std::optional<Type> castType, - bool onFail) { +Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s, bool onFail) { int i = 1; auto name = getLabel(*s[i++]); - std::optional<Type> inputType; - if (!castType) { - inputType = elementToType(*s[i++]); - castType = elementToType(*s[i++]); - } + auto inputType = elementToType(*s[i++]); + auto castType = elementToType(*s[i++]); auto* ref = parseExpression(*s[i]); - if (inputType && !Type::isSubType(ref->type, *inputType)) { + if (!Type::isSubType(ref->type, inputType)) { throw ParseException( "br_on_cast* ref type does not match expected type", s.line, s.col); } auto op = onFail ? BrOnCastFail : BrOnCast; - return Builder(wasm).makeBrOn(op, name, ref, *castType); + return Builder(wasm).makeBrOn(op, name, ref, castType); } Expression* SExpressionWasmBuilder::makeStructNew(Element& s, bool default_) { diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index ee457da69..3b7756992 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2021,17 +2021,12 @@ void BinaryInstWriter::visitRefTest(RefTest* curr) { void BinaryInstWriter::visitRefCast(RefCast* curr) { o << int8_t(BinaryConsts::GCPrefix); - if (curr->safety == RefCast::Unsafe) { - o << U32LEB(BinaryConsts::RefCastNop); - parent.writeHeapType(curr->type.getHeapType()); + if (curr->type.isNullable()) { + o << U32LEB(BinaryConsts::RefCastNull); } else { - if (curr->type.isNullable()) { - o << U32LEB(BinaryConsts::RefCastNull); - } else { - o << U32LEB(BinaryConsts::RefCast); - } - parent.writeHeapType(curr->type.getHeapType()); + o << U32LEB(BinaryConsts::RefCast); } + parent.writeHeapType(curr->type.getHeapType()); } void BinaryInstWriter::visitBrOn(BrOn* curr) { diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index 528d0d1af..d5bda85fe 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -2374,18 +2374,12 @@ Result<typename Ctx::InstrT> makeCallRef(Ctx&, Index, bool isReturn); template<typename Ctx> Result<typename Ctx::InstrT> makeI31New(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeI31Get(Ctx&, Index, bool signed_); -template<typename Ctx> -Result<typename Ctx::InstrT> -makeRefTest(Ctx&, Index, std::optional<Type> castType = std::nullopt); -template<typename Ctx> -Result<typename Ctx::InstrT> -makeRefCast(Ctx&, Index, std::optional<Type> castType = std::nullopt); -template<typename Ctx> Result<typename Ctx::InstrT> makeRefCastNop(Ctx&, Index); +template<typename Ctx> Result<typename Ctx::InstrT> makeRefTest(Ctx&, Index); +template<typename Ctx> Result<typename Ctx::InstrT> makeRefCast(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeBrOnNull(Ctx&, Index, bool onFail = false); template<typename Ctx> -Result<typename Ctx::InstrT> -makeBrOnCast(Ctx&, Index, std::optional<Type>, bool onFail = false); +Result<typename Ctx::InstrT> makeBrOnCast(Ctx&, Index, bool onFail = false); template<typename Ctx> Result<typename Ctx::InstrT> makeStructNew(Ctx&, Index, bool default_); template<typename Ctx> @@ -3480,19 +3474,12 @@ Result<typename Ctx::InstrT> makeI31Get(Ctx& ctx, Index pos, bool signed_) { } template<typename Ctx> -Result<typename Ctx::InstrT> -makeRefTest(Ctx& ctx, Index pos, std::optional<Type> castType) { - return ctx.in.err("unimplemented instruction"); -} - -template<typename Ctx> -Result<typename Ctx::InstrT> -makeRefCast(Ctx& ctx, Index pos, std::optional<Type> castType) { +Result<typename Ctx::InstrT> makeRefTest(Ctx& ctx, Index pos) { return ctx.in.err("unimplemented instruction"); } template<typename Ctx> -Result<typename Ctx::InstrT> makeRefCastNop(Ctx& ctx, Index pos) { +Result<typename Ctx::InstrT> makeRefCast(Ctx& ctx, Index pos) { return ctx.in.err("unimplemented instruction"); } @@ -3502,8 +3489,7 @@ Result<typename Ctx::InstrT> makeBrOnNull(Ctx& ctx, Index pos, bool onFail) { } template<typename Ctx> -Result<typename Ctx::InstrT> -makeBrOnCast(Ctx& ctx, Index pos, std::optional<Type> castType, bool onFail) { +Result<typename Ctx::InstrT> makeBrOnCast(Ctx& ctx, Index pos, bool onFail) { return ctx.in.err("unimplemented instruction"); } diff --git a/test/heap-types.wast b/test/heap-types.wast deleted file mode 100644 index 1d297f82e..000000000 --- a/test/heap-types.wast +++ /dev/null @@ -1,334 +0,0 @@ -;; Test that we can roundtrip struct and array types -(module - ;; Structs - (type $struct.A (struct - i32 - (field f32) - (field $named f64) - )) - ;; identical to $struct.A, so will be canonicalized with it, but field names - ;; are different - (type $struct.A.prime (struct - i32 - (field f32) - (field $othername f64) - )) - (type $struct.B (struct - (field i8) - (field (mut i16)) - (field (ref $struct.A)) - (field (mut (ref $struct.A))) - )) - (type $struct.C (struct - (field $named-mut (mut f32)) - )) - - ;; Arrays - (type $vector (array (mut f64))) - (type $matrix (array (mut (ref null $vector)))) - (type $bytes (array (mut i8))) - (type $words (array (mut i32))) - - (type $parent (struct)) - (type $child (struct_subtype i32 $parent)) - (type $grandchild (struct_subtype i32 i64 $child)) - - (type $nested-child-struct (struct (field (mut (ref $child))))) - (type $nested-child-array (array (mut (ref $child)))) - - (global $struct.new-in-global (ref $struct.A) - (struct.new_default $struct.A) - ) - - (func $structs (param $x (ref $struct.A)) (param $struct.A.prime (ref null $struct.A.prime)) (param $grandchild (ref null $grandchild)) (param $struct.C (ref null $struct.C)) (param $nested-child-struct (ref null $nested-child-struct)) (result (ref $struct.B)) - (local $tA (ref null $struct.A)) - (local $tB (ref null $struct.B)) - (local $tc (ref null $struct.C)) - (local $tv (ref null $vector)) - (local $tm (ref null $matrix)) - (drop - (local.get $x) - ) - (drop - (struct.get $struct.A 0 (local.get $x)) - ) - (drop - (struct.get $struct.A 1 (local.get $x)) - ) - (drop - (struct.get $struct.A 2 (local.get $x)) - ) - (drop - (struct.get $struct.A $named (local.get $x)) - ) - (drop - (struct.get $struct.A.prime $othername (local.get $struct.A.prime)) - ) - (drop - (struct.get_u $struct.B 0 (local.get $tB)) - ) - (drop - (struct.get_s $struct.B 0 (local.get $tB)) - ) - ;; immutable fields allow subtyping. - (drop - (struct.get $child 0 (local.get $grandchild)) - ) - (drop - (block (result (ref null $struct.A)) - (local.get $x) - ) - ) - (drop - (if (result (ref null $struct.A)) - (i32.const 1) - (local.get $x) - (local.get $x) - ) - ) - (drop - (loop (result (ref null $struct.A)) - (local.get $x) - ) - ) - (drop - (select (result (ref null $struct.A)) - (local.get $x) - (local.get $x) - (i32.const 1) - ) - ) - (struct.set $struct.C 0 - (local.get $struct.C) - (f32.const 100) - ) - ;; values may be subtypes - (struct.set $nested-child-struct 0 - (local.get $nested-child-struct) - (ref.as_non_null - (local.get $grandchild) - ) - ) - (drop - (struct.new_default $struct.A) - ) - (drop - (struct.new $struct.A - (i32.const 1) - (f32.const 2.345) - (f64.const 3.14159) - ) - ) - (unreachable) - ) - (func $arrays (param $x (ref $vector)) (param $nested-child-array (ref null $nested-child-array)) (param $grandchild (ref null $grandchild)) (result (ref $matrix)) - (local $tv (ref null $vector)) - (local $tm (ref null $matrix)) - (local $tb (ref null $bytes)) - (local $tw (ref null $words)) - (drop - (array.new $vector - (f64.const 3.14159) - (i32.const 3) - ) - ) - (drop - (array.new_default $matrix - (i32.const 10) - ) - ) - (drop - (array.get $vector - (local.get $x) - (i32.const 2) - ) - ) - (array.set $vector - (local.get $x) - (i32.const 2) - (f64.const 2.18281828) - ) - ;; values may be subtypes - (array.set $nested-child-array - (local.get $nested-child-array) - (i32.const 3) - (ref.as_non_null - (local.get $grandchild) - ) - ) - (drop - (array.len $vector - (local.get $x) - ) - ) - (drop - (array.get $words - (local.get $tw) - (i32.const 1) - ) - ) - (drop - (array.get_u $bytes - (local.get $tb) - (i32.const 2) - ) - ) - (drop - (array.get_s $bytes - (local.get $tb) - (i32.const 3) - ) - ) - (unreachable) - ) - (func $ref.is_X (param $x anyref) - (if (ref.is_null (local.get $x)) (unreachable)) - (if (ref.is_i31 (local.get $x)) (unreachable)) - ) - (func $ref.as_X (param $x anyref) (param $f funcref) - (drop (ref.as_non_null (local.get $x))) - (drop (ref.as_func (local.get $f))) - (drop (ref.as_i31 (local.get $x))) - ) - (func $br_on_X (param $x anyref) - (local $y anyref) - (local $z (ref null any)) - (local $temp-func (ref null func)) - (local $temp-i31 (ref null i31)) - (block $null - (local.set $z - (br_on_null $null (local.get $x)) - ) - ) - (drop - (block $i31 (result (ref null i31)) - (local.set $y - (br_on_i31 $i31 (local.get $x)) - ) - (ref.null i31) - ) - ) - (drop - (block $non-null (result (ref any)) - (br_on_non_null $non-null (local.get $x)) - (unreachable) - ) - ) - (drop - (block $non-i31 (result anyref) - (local.set $temp-i31 - (br_on_non_i31 $non-i31 (local.get $x)) - ) - (ref.null any) - ) - ) - ) - (func $unreachables-1 - (drop - (struct.get $struct.C 0 (unreachable)) - ) - ) - (func $unreachables-2 (param $struct.C (ref null $struct.C)) - (struct.set $struct.C 0 (local.get $struct.C) (unreachable)) - ) - (func $unreachables-3 - (struct.set $struct.C 0 (unreachable) (unreachable)) - ) - (func $unreachables-4 - (struct.set $struct.C 0 (unreachable) (f32.const 1)) - ) - (func $unreachables-array-1 - (array.get $vector - (unreachable) - (i32.const 2) - ) - ) - (func $unreachables-array-2 (param $vector (ref null $vector)) - (array.get $vector - (local.get $vector) - (unreachable) - ) - ) - (func $unreachables-array-3 - (array.set $vector - (unreachable) - (i32.const 2) - (f64.const 2.18281828) - ) - ) - (func $unreachables-array-4 (param $vector (ref null $vector)) - (array.set $vector - (local.get $vector) - (unreachable) - (f64.const 2.18281828) - ) - ) - (func $unreachables-array-5 (param $vector (ref null $vector)) - (array.set $vector - (local.get $vector) - (i32.const 2) - (unreachable) - ) - ) - (func $unreachables-array-6 - (drop - (array.len $vector - (unreachable) - ) - ) - ) - (func $array-copy (param $x (ref $vector)) (param $y (ref null $vector)) - (array.copy $vector $vector - (local.get $x) - (i32.const 11) - (local.get $y) - (i32.const 42) - (i32.const 1337) - ) - ) - (func $array-init (result (ref $vector)) - (array.new_fixed $vector - (f64.const 1) - (f64.const 2) - (f64.const 4) - (f64.const 8) - ) - ) - (func $array-init-packed (result (ref $bytes)) - (array.new_fixed $bytes - (i32.const 4) - (i32.const 2) - (i32.const 1) - ) - ) - (func $static-operations - (local $temp.A (ref null $struct.A)) - (local $temp.B (ref null $struct.B)) - (drop - (ref.test $struct.B (ref.null $struct.A)) - ) - (drop - (ref.cast null $struct.B (ref.null $struct.A)) - ) - (drop - (block $out-B (result (ref $struct.B)) - (local.set $temp.A - (br_on_cast $out-B (ref null $struct.A) (ref $struct.B) - (ref.null $struct.A) - ) - ) - (unreachable) - ) - ) - (drop - (block $out-A (result (ref null $struct.A)) - (local.set $temp.B - (br_on_cast_fail $out-A (ref null $struct.A) (ref $struct.B) - (ref.null $struct.A) - ) - ) - (unreachable) - ) - ) - ) -) diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast deleted file mode 100644 index 2504a6f82..000000000 --- a/test/heap-types.wast.from-wast +++ /dev/null @@ -1,399 +0,0 @@ -(module - (type $struct.A (struct (field i32) (field f32) (field $named f64))) - (type $vector (array (mut f64))) - (type $struct.B (struct (field i8) (field (mut i16)) (field (ref $struct.A)) (field (mut (ref $struct.A))))) - (type $none_=>_none (func)) - (type $struct.C (struct (field $named-mut (mut f32)))) - (type $matrix (array (mut (ref null $vector)))) - (type $bytes (array (mut i8))) - (type $parent (struct )) - (type $child (sub $parent (struct (field i32)))) - (type $grandchild (sub $child (struct (field i32) (field i64)))) - (type $ref?|$vector|_=>_none (func (param (ref null $vector)))) - (type $nested-child-struct (struct (field (mut (ref $child))))) - (type $words (array (mut i32))) - (type $nested-child-array (array (mut (ref $child)))) - (type $anyref_=>_none (func (param anyref))) - (type $ref|$struct.A|_ref?|$struct.A|_ref?|$grandchild|_ref?|$struct.C|_ref?|$nested-child-struct|_=>_ref|$struct.B| (func (param (ref $struct.A) (ref null $struct.A) (ref null $grandchild) (ref null $struct.C) (ref null $nested-child-struct)) (result (ref $struct.B)))) - (type $ref|$vector|_ref?|$nested-child-array|_ref?|$grandchild|_=>_ref|$matrix| (func (param (ref $vector) (ref null $nested-child-array) (ref null $grandchild)) (result (ref $matrix)))) - (type $anyref_funcref_=>_none (func (param anyref funcref))) - (type $ref?|$struct.C|_=>_none (func (param (ref null $struct.C)))) - (type $ref|$vector|_ref?|$vector|_=>_none (func (param (ref $vector) (ref null $vector)))) - (type $none_=>_ref|$vector| (func (result (ref $vector)))) - (type $none_=>_ref|$bytes| (func (result (ref $bytes)))) - (global $struct.new-in-global (ref $struct.A) (struct.new_default $struct.A)) - (func $structs (type $ref|$struct.A|_ref?|$struct.A|_ref?|$grandchild|_ref?|$struct.C|_ref?|$nested-child-struct|_=>_ref|$struct.B|) (param $x (ref $struct.A)) (param $struct.A.prime (ref null $struct.A)) (param $grandchild (ref null $grandchild)) (param $struct.C (ref null $struct.C)) (param $nested-child-struct (ref null $nested-child-struct)) (result (ref $struct.B)) - (local $tA (ref null $struct.A)) - (local $tB (ref null $struct.B)) - (local $tc (ref null $struct.C)) - (local $tv (ref null $vector)) - (local $tm (ref null $matrix)) - (drop - (local.get $x) - ) - (drop - (struct.get $struct.A 0 - (local.get $x) - ) - ) - (drop - (struct.get $struct.A 1 - (local.get $x) - ) - ) - (drop - (struct.get $struct.A $named - (local.get $x) - ) - ) - (drop - (struct.get $struct.A $named - (local.get $x) - ) - ) - (drop - (struct.get $struct.A $named - (local.get $struct.A.prime) - ) - ) - (drop - (struct.get_u $struct.B 0 - (local.get $tB) - ) - ) - (drop - (struct.get_s $struct.B 0 - (local.get $tB) - ) - ) - (drop - (struct.get $grandchild 0 - (local.get $grandchild) - ) - ) - (drop - (block (result (ref null $struct.A)) - (local.get $x) - ) - ) - (drop - (if (result (ref null $struct.A)) - (i32.const 1) - (local.get $x) - (local.get $x) - ) - ) - (drop - (loop $loop-in (result (ref null $struct.A)) - (local.get $x) - ) - ) - (drop - (select (result (ref null $struct.A)) - (local.get $x) - (local.get $x) - (i32.const 1) - ) - ) - (struct.set $struct.C $named-mut - (local.get $struct.C) - (f32.const 100) - ) - (struct.set $nested-child-struct 0 - (local.get $nested-child-struct) - (ref.as_non_null - (local.get $grandchild) - ) - ) - (drop - (struct.new_default $struct.A) - ) - (drop - (struct.new $struct.A - (i32.const 1) - (f32.const 2.3450000286102295) - (f64.const 3.14159) - ) - ) - (unreachable) - ) - (func $arrays (type $ref|$vector|_ref?|$nested-child-array|_ref?|$grandchild|_=>_ref|$matrix|) (param $x (ref $vector)) (param $nested-child-array (ref null $nested-child-array)) (param $grandchild (ref null $grandchild)) (result (ref $matrix)) - (local $tv (ref null $vector)) - (local $tm (ref null $matrix)) - (local $tb (ref null $bytes)) - (local $tw (ref null $words)) - (drop - (array.new $vector - (f64.const 3.14159) - (i32.const 3) - ) - ) - (drop - (array.new_default $matrix - (i32.const 10) - ) - ) - (drop - (array.get $vector - (local.get $x) - (i32.const 2) - ) - ) - (array.set $vector - (local.get $x) - (i32.const 2) - (f64.const 2.18281828) - ) - (array.set $nested-child-array - (local.get $nested-child-array) - (i32.const 3) - (ref.as_non_null - (local.get $grandchild) - ) - ) - (drop - (array.len - (local.get $x) - ) - ) - (drop - (array.get $words - (local.get $tw) - (i32.const 1) - ) - ) - (drop - (array.get_u $bytes - (local.get $tb) - (i32.const 2) - ) - ) - (drop - (array.get_s $bytes - (local.get $tb) - (i32.const 3) - ) - ) - (unreachable) - ) - (func $ref.is_X (type $anyref_=>_none) (param $x anyref) - (if - (ref.is_null - (local.get $x) - ) - (unreachable) - ) - (if - (ref.test i31 - (local.get $x) - ) - (unreachable) - ) - ) - (func $ref.as_X (type $anyref_funcref_=>_none) (param $x anyref) (param $f funcref) - (drop - (ref.as_non_null - (local.get $x) - ) - ) - (drop - (ref.cast func - (local.get $f) - ) - ) - (drop - (ref.cast i31 - (local.get $x) - ) - ) - ) - (func $br_on_X (type $anyref_=>_none) (param $x anyref) - (local $y anyref) - (local $z anyref) - (local $temp-func funcref) - (local $temp-i31 i31ref) - (block $null - (local.set $z - (br_on_null $null - (local.get $x) - ) - ) - ) - (drop - (block $i31 (result i31ref) - (local.set $y - (br_on_cast $i31 anyref (ref i31) - (local.get $x) - ) - ) - (ref.null none) - ) - ) - (drop - (block $non-null (result (ref any)) - (br_on_non_null $non-null - (local.get $x) - ) - (unreachable) - ) - ) - (drop - (block $non-i31 (result anyref) - (local.set $temp-i31 - (br_on_cast_fail $non-i31 anyref (ref i31) - (local.get $x) - ) - ) - (ref.null none) - ) - ) - ) - (func $unreachables-1 (type $none_=>_none) - (drop - (block ;; (replaces something unreachable we can't emit) - (drop - (unreachable) - ) - (unreachable) - ) - ) - ) - (func $unreachables-2 (type $ref?|$struct.C|_=>_none) (param $struct.C (ref null $struct.C)) - (struct.set $struct.C $named-mut - (local.get $struct.C) - (unreachable) - ) - ) - (func $unreachables-3 (type $none_=>_none) - (block ;; (replaces something unreachable we can't emit) - (drop - (unreachable) - ) - (drop - (unreachable) - ) - (unreachable) - ) - ) - (func $unreachables-4 (type $none_=>_none) - (block ;; (replaces something unreachable we can't emit) - (drop - (unreachable) - ) - (drop - (f32.const 1) - ) - (unreachable) - ) - ) - (func $unreachables-array-1 (type $none_=>_none) - (block ;; (replaces something unreachable we can't emit) - (drop - (unreachable) - ) - (drop - (i32.const 2) - ) - (unreachable) - ) - ) - (func $unreachables-array-2 (type $ref?|$vector|_=>_none) (param $vector (ref null $vector)) - (array.get $vector - (local.get $vector) - (unreachable) - ) - ) - (func $unreachables-array-3 (type $none_=>_none) - (block ;; (replaces something unreachable we can't emit) - (drop - (unreachable) - ) - (drop - (i32.const 2) - ) - (drop - (f64.const 2.18281828) - ) - (unreachable) - ) - ) - (func $unreachables-array-4 (type $ref?|$vector|_=>_none) (param $vector (ref null $vector)) - (array.set $vector - (local.get $vector) - (unreachable) - (f64.const 2.18281828) - ) - ) - (func $unreachables-array-5 (type $ref?|$vector|_=>_none) (param $vector (ref null $vector)) - (array.set $vector - (local.get $vector) - (i32.const 2) - (unreachable) - ) - ) - (func $unreachables-array-6 (type $none_=>_none) - (drop - (array.len - (unreachable) - ) - ) - ) - (func $array-copy (type $ref|$vector|_ref?|$vector|_=>_none) (param $x (ref $vector)) (param $y (ref null $vector)) - (array.copy $vector $vector - (local.get $x) - (i32.const 11) - (local.get $y) - (i32.const 42) - (i32.const 1337) - ) - ) - (func $array-init (type $none_=>_ref|$vector|) (result (ref $vector)) - (array.new_fixed $vector - (f64.const 1) - (f64.const 2) - (f64.const 4) - (f64.const 8) - ) - ) - (func $array-init-packed (type $none_=>_ref|$bytes|) (result (ref $bytes)) - (array.new_fixed $bytes - (i32.const 4) - (i32.const 2) - (i32.const 1) - ) - ) - (func $static-operations (type $none_=>_none) - (local $temp.A (ref null $struct.A)) - (local $temp.B (ref null $struct.B)) - (drop - (ref.test $struct.B - (ref.null none) - ) - ) - (drop - (ref.cast null none - (ref.null none) - ) - ) - (drop - (block $out-B (result (ref $struct.B)) - (local.set $temp.A - (br_on_cast $out-B nullref (ref $struct.B) - (ref.null none) - ) - ) - (unreachable) - ) - ) - (drop - (block $out-A (result (ref null $struct.A)) - (local.set $temp.B - (br_on_cast_fail $out-A nullref (ref $struct.B) - (ref.null none) - ) - ) - (unreachable) - ) - ) - ) -) diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary deleted file mode 100644 index f95e1508d..000000000 --- a/test/heap-types.wast.fromBinary +++ /dev/null @@ -1,353 +0,0 @@ -(module - (type $struct.A (struct (field i32) (field f32) (field $named f64))) - (type $vector (array (mut f64))) - (type $struct.B (struct (field i8) (field (mut i16)) (field (ref $struct.A)) (field (mut (ref $struct.A))))) - (type $none_=>_none (func)) - (type $matrix (array (mut (ref null $vector)))) - (type $bytes (array (mut i8))) - (type $struct.C (struct (field $named-mut (mut f32)))) - (type $parent (struct )) - (type $child (sub $parent (struct (field i32)))) - (type $grandchild (sub $child (struct (field i32) (field i64)))) - (type $ref?|$vector|_=>_none (func (param (ref null $vector)))) - (type $nested-child-struct (struct (field (mut (ref $child))))) - (type $words (array (mut i32))) - (type $nested-child-array (array (mut (ref $child)))) - (type $anyref_=>_none (func (param anyref))) - (type $ref|$struct.A|_ref?|$struct.A|_ref?|$grandchild|_ref?|$struct.C|_ref?|$nested-child-struct|_=>_ref|$struct.B| (func (param (ref $struct.A) (ref null $struct.A) (ref null $grandchild) (ref null $struct.C) (ref null $nested-child-struct)) (result (ref $struct.B)))) - (type $ref|$vector|_ref?|$nested-child-array|_ref?|$grandchild|_=>_ref|$matrix| (func (param (ref $vector) (ref null $nested-child-array) (ref null $grandchild)) (result (ref $matrix)))) - (type $anyref_funcref_=>_none (func (param anyref funcref))) - (type $ref?|$struct.C|_=>_none (func (param (ref null $struct.C)))) - (type $ref|$vector|_ref?|$vector|_=>_none (func (param (ref $vector) (ref null $vector)))) - (type $none_=>_ref|$vector| (func (result (ref $vector)))) - (type $none_=>_ref|$bytes| (func (result (ref $bytes)))) - (global $struct.new-in-global (ref $struct.A) (struct.new_default $struct.A)) - (func $structs (type $ref|$struct.A|_ref?|$struct.A|_ref?|$grandchild|_ref?|$struct.C|_ref?|$nested-child-struct|_=>_ref|$struct.B|) (param $x (ref $struct.A)) (param $struct.A.prime (ref null $struct.A)) (param $grandchild (ref null $grandchild)) (param $struct.C (ref null $struct.C)) (param $nested-child-struct (ref null $nested-child-struct)) (result (ref $struct.B)) - (local $tA (ref null $struct.A)) - (local $tB (ref null $struct.B)) - (local $tc (ref null $struct.C)) - (local $tv (ref null $vector)) - (local $tm (ref null $matrix)) - (drop - (local.get $x) - ) - (drop - (struct.get $struct.A 0 - (local.get $x) - ) - ) - (drop - (struct.get $struct.A 1 - (local.get $x) - ) - ) - (drop - (struct.get $struct.A $named - (local.get $x) - ) - ) - (drop - (struct.get $struct.A $named - (local.get $x) - ) - ) - (drop - (struct.get $struct.A $named - (local.get $struct.A.prime) - ) - ) - (drop - (struct.get_u $struct.B 0 - (local.get $tB) - ) - ) - (drop - (struct.get_s $struct.B 0 - (local.get $tB) - ) - ) - (drop - (struct.get $grandchild 0 - (local.get $grandchild) - ) - ) - (drop - (local.get $x) - ) - (drop - (if (result (ref null $struct.A)) - (i32.const 1) - (local.get $x) - (local.get $x) - ) - ) - (drop - (loop $label$3 (result (ref null $struct.A)) - (local.get $x) - ) - ) - (drop - (select (result (ref null $struct.A)) - (local.get $x) - (local.get $x) - (i32.const 1) - ) - ) - (struct.set $struct.C $named-mut - (local.get $struct.C) - (f32.const 100) - ) - (struct.set $nested-child-struct 0 - (local.get $nested-child-struct) - (ref.as_non_null - (local.get $grandchild) - ) - ) - (drop - (struct.new_default $struct.A) - ) - (drop - (struct.new $struct.A - (i32.const 1) - (f32.const 2.3450000286102295) - (f64.const 3.14159) - ) - ) - (unreachable) - ) - (func $arrays (type $ref|$vector|_ref?|$nested-child-array|_ref?|$grandchild|_=>_ref|$matrix|) (param $x (ref $vector)) (param $nested-child-array (ref null $nested-child-array)) (param $grandchild (ref null $grandchild)) (result (ref $matrix)) - (local $tv (ref null $vector)) - (local $tm (ref null $matrix)) - (local $tb (ref null $bytes)) - (local $tw (ref null $words)) - (drop - (array.new $vector - (f64.const 3.14159) - (i32.const 3) - ) - ) - (drop - (array.new_default $matrix - (i32.const 10) - ) - ) - (drop - (array.get $vector - (local.get $x) - (i32.const 2) - ) - ) - (array.set $vector - (local.get $x) - (i32.const 2) - (f64.const 2.18281828) - ) - (array.set $nested-child-array - (local.get $nested-child-array) - (i32.const 3) - (ref.as_non_null - (local.get $grandchild) - ) - ) - (drop - (array.len - (local.get $x) - ) - ) - (drop - (array.get $words - (local.get $tw) - (i32.const 1) - ) - ) - (drop - (array.get_u $bytes - (local.get $tb) - (i32.const 2) - ) - ) - (drop - (array.get_s $bytes - (local.get $tb) - (i32.const 3) - ) - ) - (unreachable) - ) - (func $ref.is_X (type $anyref_=>_none) (param $x anyref) - (if - (ref.is_null - (local.get $x) - ) - (unreachable) - ) - (if - (ref.test i31 - (local.get $x) - ) - (unreachable) - ) - ) - (func $ref.as_X (type $anyref_funcref_=>_none) (param $x anyref) (param $f funcref) - (drop - (ref.as_non_null - (local.get $x) - ) - ) - (drop - (ref.cast func - (local.get $f) - ) - ) - (drop - (ref.cast i31 - (local.get $x) - ) - ) - ) - (func $br_on_X (type $anyref_=>_none) (param $x anyref) - (local $y anyref) - (local $z anyref) - (local $temp-func funcref) - (local $temp-i31 i31ref) - (block $label$1 - (local.set $z - (br_on_null $label$1 - (local.get $x) - ) - ) - ) - (drop - (block $label$2 (result i31ref) - (local.set $y - (br_on_cast $label$2 anyref (ref i31) - (local.get $x) - ) - ) - (ref.null none) - ) - ) - (drop - (block $label$3 (result (ref any)) - (br_on_non_null $label$3 - (local.get $x) - ) - (unreachable) - ) - ) - (drop - (block $label$4 (result anyref) - (local.set $temp-i31 - (br_on_cast_fail $label$4 anyref (ref i31) - (local.get $x) - ) - ) - (ref.null none) - ) - ) - ) - (func $unreachables-1 (type $none_=>_none) - (unreachable) - ) - (func $unreachables-2 (type $ref?|$struct.C|_=>_none) (param $struct.C (ref null $struct.C)) - (drop - (local.get $struct.C) - ) - (unreachable) - ) - (func $unreachables-3 (type $none_=>_none) - (unreachable) - ) - (func $unreachables-4 (type $none_=>_none) - (unreachable) - ) - (func $unreachables-array-1 (type $none_=>_none) - (unreachable) - ) - (func $unreachables-array-2 (type $ref?|$vector|_=>_none) (param $vector (ref null $vector)) - (drop - (local.get $vector) - ) - (unreachable) - ) - (func $unreachables-array-3 (type $none_=>_none) - (unreachable) - ) - (func $unreachables-array-4 (type $ref?|$vector|_=>_none) (param $vector (ref null $vector)) - (drop - (local.get $vector) - ) - (unreachable) - ) - (func $unreachables-array-5 (type $ref?|$vector|_=>_none) (param $vector (ref null $vector)) - (drop - (local.get $vector) - ) - (drop - (i32.const 2) - ) - (unreachable) - ) - (func $unreachables-array-6 (type $none_=>_none) - (unreachable) - ) - (func $array-copy (type $ref|$vector|_ref?|$vector|_=>_none) (param $x (ref $vector)) (param $y (ref null $vector)) - (array.copy $vector $vector - (local.get $x) - (i32.const 11) - (local.get $y) - (i32.const 42) - (i32.const 1337) - ) - ) - (func $array-init (type $none_=>_ref|$vector|) (result (ref $vector)) - (array.new_fixed $vector - (f64.const 1) - (f64.const 2) - (f64.const 4) - (f64.const 8) - ) - ) - (func $array-init-packed (type $none_=>_ref|$bytes|) (result (ref $bytes)) - (array.new_fixed $bytes - (i32.const 4) - (i32.const 2) - (i32.const 1) - ) - ) - (func $static-operations (type $none_=>_none) - (local $temp.A (ref null $struct.A)) - (local $temp.B (ref null $struct.B)) - (drop - (ref.test $struct.B - (ref.null none) - ) - ) - (drop - (ref.cast null none - (ref.null none) - ) - ) - (drop - (block $label$1 (result (ref $struct.B)) - (local.set $temp.A - (br_on_cast $label$1 nullref (ref $struct.B) - (ref.null none) - ) - ) - (unreachable) - ) - ) - (drop - (block $label$2 (result (ref null $struct.A)) - (local.set $temp.B - (br_on_cast_fail $label$2 nullref (ref $struct.B) - (ref.null none) - ) - ) - (unreachable) - ) - ) - ) -) - diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo deleted file mode 100644 index 904caa825..000000000 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ /dev/null @@ -1,353 +0,0 @@ -(module - (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64))) - (type $[mut:f64] (array (mut f64))) - (type ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} (struct (field i8) (field (mut i16)) (field (ref ${i32_f32_f64})) (field (mut (ref ${i32_f32_f64}))))) - (type $none_=>_none (func)) - (type $[mut:ref?|[mut:f64]|] (array (mut (ref null $[mut:f64])))) - (type $[mut:i8] (array (mut i8))) - (type ${mut:f32} (struct (field (mut f32)))) - (type ${} (struct )) - (type ${i32} (sub ${} (struct (field i32)))) - (type ${i32_i64} (sub ${i32} (struct (field i32) (field i64)))) - (type $ref?|[mut:f64]|_=>_none (func (param (ref null $[mut:f64])))) - (type ${mut:ref|{i32}|} (struct (field (mut (ref ${i32}))))) - (type $[mut:i32] (array (mut i32))) - (type $[mut:ref|{i32}|] (array (mut (ref ${i32})))) - (type $anyref_=>_none (func (param anyref))) - (type $ref|{i32_f32_f64}|_ref?|{i32_f32_f64}|_ref?|{i32_i64}|_ref?|{mut:f32}|_ref?|{mut:ref|{i32}|}|_=>_ref|{i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}| (func (param (ref ${i32_f32_f64}) (ref null ${i32_f32_f64}) (ref null ${i32_i64}) (ref null ${mut:f32}) (ref null ${mut:ref|{i32}|})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})))) - (type $ref|[mut:f64]|_ref?|[mut:ref|{i32}|]|_ref?|{i32_i64}|_=>_ref|[mut:ref?|[mut:f64]|]| (func (param (ref $[mut:f64]) (ref null $[mut:ref|{i32}|]) (ref null ${i32_i64})) (result (ref $[mut:ref?|[mut:f64]|])))) - (type $anyref_funcref_=>_none (func (param anyref funcref))) - (type $ref?|{mut:f32}|_=>_none (func (param (ref null ${mut:f32})))) - (type $ref|[mut:f64]|_ref?|[mut:f64]|_=>_none (func (param (ref $[mut:f64]) (ref null $[mut:f64])))) - (type $none_=>_ref|[mut:f64]| (func (result (ref $[mut:f64])))) - (type $none_=>_ref|[mut:i8]| (func (result (ref $[mut:i8])))) - (global $global$0 (ref ${i32_f32_f64}) (struct.new_default ${i32_f32_f64})) - (func $0 (type $ref|{i32_f32_f64}|_ref?|{i32_f32_f64}|_ref?|{i32_i64}|_ref?|{mut:f32}|_ref?|{mut:ref|{i32}|}|_=>_ref|{i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}|) (param $0 (ref ${i32_f32_f64})) (param $1 (ref null ${i32_f32_f64})) (param $2 (ref null ${i32_i64})) (param $3 (ref null ${mut:f32})) (param $4 (ref null ${mut:ref|{i32}|})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) - (local $5 (ref null ${i32_f32_f64})) - (local $6 (ref null ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) - (local $7 (ref null ${mut:f32})) - (local $8 (ref null $[mut:f64])) - (local $9 (ref null $[mut:ref?|[mut:f64]|])) - (drop - (local.get $0) - ) - (drop - (struct.get ${i32_f32_f64} 0 - (local.get $0) - ) - ) - (drop - (struct.get ${i32_f32_f64} 1 - (local.get $0) - ) - ) - (drop - (struct.get ${i32_f32_f64} 2 - (local.get $0) - ) - ) - (drop - (struct.get ${i32_f32_f64} 2 - (local.get $0) - ) - ) - (drop - (struct.get ${i32_f32_f64} 2 - (local.get $1) - ) - ) - (drop - (struct.get_u ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 - (local.get $6) - ) - ) - (drop - (struct.get_s ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 - (local.get $6) - ) - ) - (drop - (struct.get ${i32_i64} 0 - (local.get $2) - ) - ) - (drop - (local.get $0) - ) - (drop - (if (result (ref null ${i32_f32_f64})) - (i32.const 1) - (local.get $0) - (local.get $0) - ) - ) - (drop - (loop $label$3 (result (ref null ${i32_f32_f64})) - (local.get $0) - ) - ) - (drop - (select (result (ref null ${i32_f32_f64})) - (local.get $0) - (local.get $0) - (i32.const 1) - ) - ) - (struct.set ${mut:f32} 0 - (local.get $3) - (f32.const 100) - ) - (struct.set ${mut:ref|{i32}|} 0 - (local.get $4) - (ref.as_non_null - (local.get $2) - ) - ) - (drop - (struct.new_default ${i32_f32_f64}) - ) - (drop - (struct.new ${i32_f32_f64} - (i32.const 1) - (f32.const 2.3450000286102295) - (f64.const 3.14159) - ) - ) - (unreachable) - ) - (func $1 (type $ref|[mut:f64]|_ref?|[mut:ref|{i32}|]|_ref?|{i32_i64}|_=>_ref|[mut:ref?|[mut:f64]|]|) (param $0 (ref $[mut:f64])) (param $1 (ref null $[mut:ref|{i32}|])) (param $2 (ref null ${i32_i64})) (result (ref $[mut:ref?|[mut:f64]|])) - (local $3 (ref null $[mut:f64])) - (local $4 (ref null $[mut:ref?|[mut:f64]|])) - (local $5 (ref null $[mut:i8])) - (local $6 (ref null $[mut:i32])) - (drop - (array.new $[mut:f64] - (f64.const 3.14159) - (i32.const 3) - ) - ) - (drop - (array.new_default $[mut:ref?|[mut:f64]|] - (i32.const 10) - ) - ) - (drop - (array.get $[mut:f64] - (local.get $0) - (i32.const 2) - ) - ) - (array.set $[mut:f64] - (local.get $0) - (i32.const 2) - (f64.const 2.18281828) - ) - (array.set $[mut:ref|{i32}|] - (local.get $1) - (i32.const 3) - (ref.as_non_null - (local.get $2) - ) - ) - (drop - (array.len - (local.get $0) - ) - ) - (drop - (array.get $[mut:i32] - (local.get $6) - (i32.const 1) - ) - ) - (drop - (array.get_u $[mut:i8] - (local.get $5) - (i32.const 2) - ) - ) - (drop - (array.get_s $[mut:i8] - (local.get $5) - (i32.const 3) - ) - ) - (unreachable) - ) - (func $2 (type $anyref_=>_none) (param $0 anyref) - (if - (ref.is_null - (local.get $0) - ) - (unreachable) - ) - (if - (ref.test i31 - (local.get $0) - ) - (unreachable) - ) - ) - (func $3 (type $anyref_funcref_=>_none) (param $0 anyref) (param $1 funcref) - (drop - (ref.as_non_null - (local.get $0) - ) - ) - (drop - (ref.cast func - (local.get $1) - ) - ) - (drop - (ref.cast i31 - (local.get $0) - ) - ) - ) - (func $4 (type $anyref_=>_none) (param $0 anyref) - (local $1 anyref) - (local $2 anyref) - (local $3 funcref) - (local $4 i31ref) - (block $label$1 - (local.set $2 - (br_on_null $label$1 - (local.get $0) - ) - ) - ) - (drop - (block $label$2 (result i31ref) - (local.set $1 - (br_on_cast $label$2 anyref (ref i31) - (local.get $0) - ) - ) - (ref.null none) - ) - ) - (drop - (block $label$3 (result (ref any)) - (br_on_non_null $label$3 - (local.get $0) - ) - (unreachable) - ) - ) - (drop - (block $label$4 (result anyref) - (local.set $4 - (br_on_cast_fail $label$4 anyref (ref i31) - (local.get $0) - ) - ) - (ref.null none) - ) - ) - ) - (func $5 (type $none_=>_none) - (unreachable) - ) - (func $6 (type $ref?|{mut:f32}|_=>_none) (param $0 (ref null ${mut:f32})) - (drop - (local.get $0) - ) - (unreachable) - ) - (func $7 (type $none_=>_none) - (unreachable) - ) - (func $8 (type $none_=>_none) - (unreachable) - ) - (func $9 (type $none_=>_none) - (unreachable) - ) - (func $10 (type $ref?|[mut:f64]|_=>_none) (param $0 (ref null $[mut:f64])) - (drop - (local.get $0) - ) - (unreachable) - ) - (func $11 (type $none_=>_none) - (unreachable) - ) - (func $12 (type $ref?|[mut:f64]|_=>_none) (param $0 (ref null $[mut:f64])) - (drop - (local.get $0) - ) - (unreachable) - ) - (func $13 (type $ref?|[mut:f64]|_=>_none) (param $0 (ref null $[mut:f64])) - (drop - (local.get $0) - ) - (drop - (i32.const 2) - ) - (unreachable) - ) - (func $14 (type $none_=>_none) - (unreachable) - ) - (func $15 (type $ref|[mut:f64]|_ref?|[mut:f64]|_=>_none) (param $0 (ref $[mut:f64])) (param $1 (ref null $[mut:f64])) - (array.copy $[mut:f64] $[mut:f64] - (local.get $0) - (i32.const 11) - (local.get $1) - (i32.const 42) - (i32.const 1337) - ) - ) - (func $16 (type $none_=>_ref|[mut:f64]|) (result (ref $[mut:f64])) - (array.new_fixed $[mut:f64] - (f64.const 1) - (f64.const 2) - (f64.const 4) - (f64.const 8) - ) - ) - (func $17 (type $none_=>_ref|[mut:i8]|) (result (ref $[mut:i8])) - (array.new_fixed $[mut:i8] - (i32.const 4) - (i32.const 2) - (i32.const 1) - ) - ) - (func $18 (type $none_=>_none) - (local $0 (ref null ${i32_f32_f64})) - (local $1 (ref null ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) - (drop - (ref.test ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} - (ref.null none) - ) - ) - (drop - (ref.cast null none - (ref.null none) - ) - ) - (drop - (block $label$1 (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) - (local.set $0 - (br_on_cast $label$1 nullref (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}) - (ref.null none) - ) - ) - (unreachable) - ) - ) - (drop - (block $label$2 (result (ref null ${i32_f32_f64})) - (local.set $1 - (br_on_cast_fail $label$2 nullref (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}) - (ref.null none) - ) - ) - (unreachable) - ) - ) - ) -) - diff --git a/test/lit/binary/annotated-array-len.test b/test/lit/binary/annotated-array-len.test deleted file mode 100644 index 9cf6eecbe..000000000 --- a/test/lit/binary/annotated-array-len.test +++ /dev/null @@ -1,18 +0,0 @@ -;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. - -;; Test the we can properly parse the annotated array.len format that we no -;; longer emit. - -;; RUN: wasm-dis %s.wasm -all | filecheck %s - -;; CHECK: (type $none_=>_i32 (func (result i32))) - -;; CHECK: (type $[mut:i8] (array (mut i8))) - -;; CHECK: (func $0 (type $none_=>_i32) (result i32) -;; CHECK-NEXT: (array.len -;; CHECK-NEXT: (array.new_default $[mut:i8] -;; CHECK-NEXT: (i32.const 0) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) -;; CHECK-NEXT: ) diff --git a/test/lit/binary/annotated-array-len.test.wasm b/test/lit/binary/annotated-array-len.test.wasm Binary files differdeleted file mode 100644 index b199f58de..000000000 --- a/test/lit/binary/annotated-array-len.test.wasm +++ /dev/null diff --git a/test/lit/binary/bad-ref-as.test b/test/lit/binary/bad-ref-as.test deleted file mode 100644 index 3accdd553..000000000 --- a/test/lit/binary/bad-ref-as.test +++ /dev/null @@ -1,5 +0,0 @@ -;; Test that we error properly on a file with a ref.as of a non-ref type. - -;; RUN: not wasm-opt -all %s.wasm 2>&1 | filecheck %s - -;; CHECK: ref.cast ref must have ref type diff --git a/test/lit/binary/bad-ref-as.test.wasm b/test/lit/binary/bad-ref-as.test.wasm Binary files differdeleted file mode 100644 index 637537dd2..000000000 --- a/test/lit/binary/bad-ref-as.test.wasm +++ /dev/null diff --git a/test/lit/legacy-static-casts.wast b/test/lit/legacy-static-casts.wast deleted file mode 100644 index 893fb0a33..000000000 --- a/test/lit/legacy-static-casts.wast +++ /dev/null @@ -1,47 +0,0 @@ -;; NOTE: Assertions have been generated by update_lit_checks.py --all-items and should not be edited. - -;; Check that the deprecated *_static instruction names are still parsed correctly. - -;; RUN: wasm-opt %s -all -S -o - | filecheck %s - -(module - ;; CHECK: (type $none_=>_none (func)) - - ;; CHECK: (type $struct (struct )) - (type $struct (struct)) - - ;; CHECK: (func $test (type $none_=>_none) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.test $struct - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.cast null none - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.cast_nop none - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $test - (drop - (ref.test_static $struct - (ref.null none) - ) - ) - (drop - (ref.cast_static $struct - (ref.null none) - ) - ) - (drop - (ref.cast_nop_static $struct - (ref.null none) - ) - ) - ) -) diff --git a/test/lit/passes/abstract-type-refining.wast b/test/lit/passes/abstract-type-refining.wast index 220de9656..af2b210fd 100644 --- a/test/lit/passes/abstract-type-refining.wast +++ b/test/lit/passes/abstract-type-refining.wast @@ -217,11 +217,6 @@ ;; YESTNH-NEXT: (local.get $x) ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: ) - ;; YESTNH-NEXT: (drop - ;; YESTNH-NEXT: (ref.cast i31 - ;; YESTNH-NEXT: (local.get $x) - ;; YESTNH-NEXT: ) - ;; YESTNH-NEXT: ) ;; YESTNH-NEXT: ) ;; NO_TNH: (func $basic (type $anyref_=>_none) (param $x anyref) ;; NO_TNH-NEXT: (drop @@ -229,11 +224,6 @@ ;; NO_TNH-NEXT: (local.get $x) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (ref.cast i31 - ;; NO_TNH-NEXT: (local.get $x) - ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) (func $basic (param $x anyref) ;; Casts to basic types should not be modified. @@ -242,11 +232,6 @@ (local.get $x) ) ) - (drop - (ref.as_i31 - (local.get $x) - ) - ) ) ;; YESTNH: (func $locals (type $none_=>_none) diff --git a/test/lit/passes/code-pushing-gc.wast b/test/lit/passes/code-pushing-gc.wast index 56cfc8777..9587d5ab7 100644 --- a/test/lit/passes/code-pushing-gc.wast +++ b/test/lit/passes/code-pushing-gc.wast @@ -7,8 +7,8 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $out (result (ref func)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_on_cast $out (ref $none_=>_none) (ref func) - ;; CHECK-NEXT: (ref.func $br_on) + ;; CHECK-NEXT: (br_on_cast $out nullfuncref (ref func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $x @@ -28,8 +28,8 @@ ;; We can push the local.set past the br_on. (local.set $x (ref.func $br_on)) (drop - (br_on_func $out - (ref.func $br_on) + (br_on_cast $out funcref (ref func) + (ref.null nofunc) ) ) (drop @@ -48,8 +48,8 @@ ;; CHECK-NEXT: (ref.func $br_on_no) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_on_cast $out (ref $none_=>_none) (ref func) - ;; CHECK-NEXT: (ref.func $br_on_no) + ;; CHECK-NEXT: (br_on_cast $out nullfuncref (ref func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.func $br_on_no) @@ -61,13 +61,13 @@ ;; CHECK-NEXT: ) (func $br_on_no (local $x (ref null func)) - ;; We can't push here since the local.get is outside of the loop. + ;; We can't push here since the local.get is outside of the block. (drop (block $out (result (ref func)) (local.set $x (ref.func $br_on_no)) (drop - (br_on_func $out - (ref.func $br_on_no) + (br_on_cast $out funcref (ref func) + (ref.null nofunc) ) ) (ref.func $br_on_no) diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 7c7aa8c40..b82fbf148 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -54,7 +54,7 @@ (ref.is_null (loop $loop (result (ref func)) (nop) - (ref.as_func + (ref.cast func (ref.as_non_null (ref.null func) ) diff --git a/test/lit/passes/merge-blocks.wast b/test/lit/passes/merge-blocks.wast index 2b3afa771..02772c9b6 100644 --- a/test/lit/passes/merge-blocks.wast +++ b/test/lit/passes/merge-blocks.wast @@ -34,7 +34,7 @@ (block $label$1 (result (ref null i31)) ;; this block type must stay, we ;; cannot remove it due to the br_on (drop - (br_on_i31 $label$1 + (br_on_cast $label$1 anyref (ref i31) (ref.null any) ) ) diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast index 831d229a2..155ac82cf 100644 --- a/test/lit/passes/optimize-instructions-gc-tnh.wast +++ b/test/lit/passes/optimize-instructions-gc-tnh.wast @@ -146,7 +146,7 @@ ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) (func $ref.is_b (param $a eqref) (param $f funcref) (result i32) - ;; Here we only have a cast, and no ref.as operations that force the value + ;; Here we only have a cast, and no cast operations that force the value ;; to be non-nullable. That means we cannot remove the ref.is, but we can ;; remove the cast in TNH. (drop @@ -164,28 +164,56 @@ ) ) - ;; TNH: (func $ref.is_func (type $funcref_=>_i32) (param $a funcref) (result i32) + ;; TNH: (func $ref.test (type $eqref_=>_i32) (param $a eqref) (result i32) ;; TNH-NEXT: (drop - ;; TNH-NEXT: (ref.as_non_null - ;; TNH-NEXT: (local.get $a) + ;; TNH-NEXT: (block (result i32) + ;; TNH-NEXT: (drop + ;; TNH-NEXT: (ref.cast null i31 + ;; TNH-NEXT: (local.get $a) + ;; TNH-NEXT: ) + ;; TNH-NEXT: ) + ;; TNH-NEXT: (i32.const 1) ;; TNH-NEXT: ) ;; TNH-NEXT: ) - ;; TNH-NEXT: (i32.const 1) + ;; TNH-NEXT: (block (result i32) + ;; TNH-NEXT: (drop + ;; TNH-NEXT: (ref.as_non_null + ;; TNH-NEXT: (local.get $a) + ;; TNH-NEXT: ) + ;; TNH-NEXT: ) + ;; TNH-NEXT: (i32.const 1) + ;; TNH-NEXT: ) ;; TNH-NEXT: ) - ;; NO_TNH: (func $ref.is_func (type $funcref_=>_i32) (param $a funcref) (result i32) + ;; NO_TNH: (func $ref.test (type $eqref_=>_i32) (param $a eqref) (result i32) ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (ref.as_non_null - ;; NO_TNH-NEXT: (local.get $a) + ;; NO_TNH-NEXT: (block (result i32) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.cast null i31 + ;; NO_TNH-NEXT: (local.get $a) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.const 1) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (block (result i32) + ;; NO_TNH-NEXT: (drop + ;; NO_TNH-NEXT: (ref.as_non_null + ;; NO_TNH-NEXT: (local.get $a) + ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) + ;; NO_TNH-NEXT: (i32.const 1) ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (i32.const 1) ;; NO_TNH-NEXT: ) - (func $ref.is_func (param $a funcref) (result i32) - ;; The check must succeed. We can return 1 here, and drop the rest, with or - ;; without TNH (in particular, TNH should not just remove the cast but not - ;; return a 1). - (ref.is_func - (ref.as_func + (func $ref.test (param $a eqref) (result i32) + (drop + (ref.test null i31 + (ref.cast null i31 + (local.get $a) + ) + ) + ) + (ref.test eq + (ref.cast eq (local.get $a) ) ) diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index 34070487b..9f33c55a3 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -122,8 +122,8 @@ ) ;; ref.is_null is not needed on a non-nullable value, and if something is - ;; a func we don't need that either etc. if we know the result - ;; CHECK: (func $unneeded_is (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31)) + ;; cast to its own type, we don't need that either, etc. + ;; CHECK: (func $unneeded_test (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop @@ -149,7 +149,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unneeded_is + (func $unneeded_test (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31)) @@ -157,16 +157,16 @@ (ref.is_null (local.get $struct)) ) (drop - (ref.is_func (local.get $func)) + (ref.test func (local.get $func)) ) (drop - (ref.is_i31 (local.get $i31)) + (ref.test i31 (local.get $i31)) ) ) ;; similar to $unneeded_is, but the values are nullable. we can at least ;; leave just the null check. - ;; CHECK: (func $unneeded_is_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref) + ;; CHECK: (func $unneeded_test_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.is_null ;; CHECK-NEXT: (local.get $struct) @@ -187,7 +187,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unneeded_is_null + (func $unneeded_test_null (param $struct (ref null $struct)) (param $func (ref null func)) (param $i31 (ref null i31)) @@ -197,17 +197,17 @@ ;; This can be optimized to !is_null rather than ref.test func, since we ;; know the heap type is what we want, so the only possible issue is a null. (drop - (ref.is_func (local.get $func)) + (ref.test func (local.get $func)) ) ;; This can be optimized similarly. (drop - (ref.is_i31 (local.get $i31)) + (ref.test i31 (local.get $i31)) ) ) ;; ref.as_non_null is not needed on a non-nullable value, and if something is ;; a func we don't need that either etc., and can just return the value. - ;; CHECK: (func $unneeded_as (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31)) + ;; CHECK: (func $unneeded_cast (type $ref|$struct|_ref|func|_ref|i31|_=>_none) (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) @@ -218,7 +218,7 @@ ;; CHECK-NEXT: (local.get $i31) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unneeded_as + (func $unneeded_cast (param $struct (ref $struct)) (param $func (ref func)) (param $i31 (ref i31)) @@ -226,16 +226,16 @@ (ref.as_non_null (local.get $struct)) ) (drop - (ref.as_func (local.get $func)) + (ref.cast func (local.get $func)) ) (drop - (ref.as_i31 (local.get $i31)) + (ref.cast i31 (local.get $i31)) ) ) - ;; similar to $unneeded_as, but the values are nullable. we can turn the + ;; similar to $unneeded_cast, but the values are nullable. we can turn the ;; more specific things into ref.as_non_null. - ;; CHECK: (func $unneeded_as_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref) + ;; CHECK: (func $unneeded_cast_null (type $ref?|$struct|_funcref_i31ref_=>_none) (param $struct (ref null $struct)) (param $func funcref) (param $i31 i31ref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null ;; CHECK-NEXT: (local.get $struct) @@ -252,7 +252,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unneeded_as_null + (func $unneeded_cast_null (param $struct (ref null $struct)) (param $func (ref null func)) (param $i31 (ref null i31)) @@ -260,10 +260,10 @@ (ref.as_non_null (local.get $struct)) ) (drop - (ref.as_func (local.get $func)) + (ref.cast func (local.get $func)) ) (drop - (ref.as_i31 (local.get $i31)) + (ref.cast i31 (local.get $i31)) ) ) @@ -285,10 +285,10 @@ (func $unneeded_unreachability ;; unreachable instructions can simply be ignored (drop - (ref.is_func (unreachable)) + (ref.test func (unreachable)) ) (drop - (ref.as_func (unreachable)) + (ref.cast func (unreachable)) ) ) @@ -617,7 +617,7 @@ ;; This will trap, so we can emit an unreachable. (drop (ref.cast $struct - (ref.as_i31 + (ref.cast i31 (local.get $x) ) ) diff --git a/test/lit/passes/remove-unused-brs-gc.wast b/test/lit/passes/remove-unused-brs-gc.wast index e063fa482..50ffd9583 100644 --- a/test/lit/passes/remove-unused-brs-gc.wast +++ b/test/lit/passes/remove-unused-brs-gc.wast @@ -11,57 +11,6 @@ (type $struct2 (struct)) ) - ;; CHECK: (func $br_on_non_i31-1 (type $none_=>_none) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $any (result (ref null $struct)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br $any - ;; CHECK-NEXT: (struct.new_default $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $br_on_non_i31-1 - (drop - (block $any (result anyref) - (drop - ;; An struct is not an i31, and so we should branch. - (br_on_non_i31 $any - (struct.new $struct) - ) - ) - (ref.null any) - ) - ) - ) - ;; CHECK: (func $br_on_non_i31-2 (type $none_=>_none) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $any (result nullref) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i31.new - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $br_on_non_i31-2 - (drop - (block $any (result anyref) - (drop - ;; An i31 is provided here, and so we will not branch. - (br_on_non_i31 $any - (i31.new (i32.const 0)) - ) - ) - (ref.null any) - ) - ) - ) - ;; CHECK: (func $br_on-if (type $ref|struct|_=>_none) (param $0 (ref struct)) ;; CHECK-NEXT: (block $label ;; CHECK-NEXT: (drop @@ -93,51 +42,51 @@ ) ) - ;; CHECK: (func $nested_br_on (type $none_=>_i31ref) (result i31ref) - ;; CHECK-NEXT: (block $label$1 (result (ref i31)) + ;; CHECK: (func $br_on_cast (type $none_=>_ref|$struct|) (result (ref $struct)) + ;; CHECK-NEXT: (block $block (result (ref $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br $label$1 - ;; CHECK-NEXT: (i31.new - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br $block + ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $nested_br_on (result i31ref) - (block $label$1 (result i31ref) + (func $br_on_cast (result (ref $struct)) + (block $block (result (ref $struct)) (drop - ;; The inner br_on_i31 will become a direct br since the type proves it - ;; is in fact data. That then becomes unreachable, and the parent must - ;; handle that properly (do nothing without hitting an assertion). - (br_on_i31 $label$1 - (br_on_i31 $label$1 - (i31.new (i32.const 0)) - ) + ;; This static cast can be computed at compile time: it will definitely be + ;; taken, so we can turn it into a normal br. + (br_on_cast $block anyref (ref $struct) + (struct.new $struct) ) ) (unreachable) ) ) - ;; CHECK: (func $br_on_cast (type $none_=>_ref|$struct|) (result (ref $struct)) - ;; CHECK-NEXT: (block $block (result (ref $struct)) + ;; CHECK: (func $nested_br_on_cast (type $none_=>_i31ref) (result i31ref) + ;; CHECK-NEXT: (block $label$1 (result (ref i31)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br $block - ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: (br $label$1 + ;; CHECK-NEXT: (i31.new + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $br_on_cast (result (ref $struct)) - (block $block (result (ref $struct)) + (func $nested_br_on_cast (result i31ref) + (block $label$1 (result i31ref) (drop - ;; This static cast can be computed at compile time: it will definitely be - ;; taken, so we can turn it into a normal br. - (br_on_cast $block anyref (ref $struct) - (struct.new $struct) + ;; The inner br_on_cast will become a direct br since the type proves it + ;; is in fact i31. That then becomes unreachable, and the parent must + ;; handle that properly (do nothing without hitting an assertion). + (br_on_cast $label$1 (ref any) (ref i31) + (br_on_cast $label$1 (ref any) (ref i31) + (i31.new (i32.const 0)) + ) ) ) (unreachable) diff --git a/test/lit/passes/remove-unused-brs_all-features.wast b/test/lit/passes/remove-unused-brs_all-features.wast index 8ca632040..c93f25df2 100644 --- a/test/lit/passes/remove-unused-brs_all-features.wast +++ b/test/lit/passes/remove-unused-brs_all-features.wast @@ -8,10 +8,10 @@ (type $vector (array (mut i32))) ;; CHECK: (type $struct (struct (field (ref null $vector)))) (type $struct (struct (field (ref null $vector)))) - ;; CHECK: (type $ref|func|_=>_none (func (param (ref func)))) - ;; CHECK: (type $i32_=>_none (func (param i32))) + ;; CHECK: (type $none_=>_funcref (func (result funcref))) + ;; CHECK: (type $none_=>_ref?|$struct| (func (result (ref null $struct)))) ;; CHECK: (type $none_=>_f64 (func (result f64))) @@ -20,9 +20,11 @@ ;; CHECK: (type $i32_=>_funcref (func (param i32) (result funcref))) + ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (import "out" "log" (func $log (type $i32_=>_none) (param i32))) (import "out" "log" (func $log (param i32))) - ;; CHECK: (elem declare func $br_on-to-br $i32_=>_none $none_=>_i32) + ;; CHECK: (elem declare func $br_on_non_null $br_on_null $i32_=>_none $none_=>_i32) ;; CHECK: (func $foo (type $none_=>_ref?|$struct|) (result (ref null $struct)) ;; CHECK-NEXT: (if (result (ref null $struct)) @@ -116,110 +118,57 @@ ) ) - ;; CHECK: (func $br_on-to-br (type $ref|func|_=>_none) (param $func (ref func)) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) + ;; CHECK: (func $br_on_null (type $none_=>_none) ;; CHECK-NEXT: (block $null ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.func $br_on-to-br) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $func (result (ref $ref|func|_=>_none)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br $func - ;; CHECK-NEXT: (ref.func $br_on-to-br) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 3) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.func $br_on-to-br) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 4) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $i31 (result (ref i31)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br $i31 - ;; CHECK-NEXT: (i31.new - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 5) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i31.new - ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (br_on_null $null + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 6) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $non-null (result (ref $ref|func|_=>_none)) - ;; CHECK-NEXT: (br $non-null - ;; CHECK-NEXT: (ref.func $br_on-to-br) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call $log - ;; CHECK-NEXT: (i32.const 7) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.func $br_on-to-br) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.func $br_on_null) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $br_on-to-br (param $func (ref func)) - (call $log (i32.const 0)) + (func $br_on_null (block $null - ;; a non-null reference is not null, and the br is never taken + ;; A null reference to bottom is definitely null, and the br is always taken. + ;; TODO: Optimize this. (drop - (br_on_null $null (ref.func $br_on-to-br)) + (br_on_null $null (ref.null nofunc)) ) - (call $log (i32.const 1)) - ) - (call $log (i32.const 2)) - (drop - (block $func (result funcref) - ;; a non-null function reference means we always take the br - (drop - (br_on_func $func (ref.func $br_on-to-br)) - ) - (call $log (i32.const 3)) - (ref.func $br_on-to-br) + ;; On the other hand, if we know the input is not null, the branch will never + ;; be taken. + (drop + (br_on_null $null (ref.func $br_on_null)) ) ) - (call $log (i32.const 4)) - (drop - (block $i31 (result i31ref) - ;; a non-null i31 reference means we always take the br - (drop - (br_on_i31 $i31 - (i31.new (i32.const 42)) - ) - ) - (call $log (i32.const 5)) - (i31.new (i32.const 1337)) + ) + + ;; CHECK: (func $br_on_non_null (type $none_=>_funcref) (result funcref) + ;; CHECK-NEXT: (block $non-null (result (ref $none_=>_funcref)) + ;; CHECK-NEXT: (br $non-null + ;; CHECK-NEXT: (ref.func $br_on_non_null) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (br_on_non_null $non-null + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.func $br_on_non_null) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $br_on_non_null (result funcref) + (block $non-null (result (ref func)) + ;; A non-null reference is not null, and the br is always taken. + (br_on_non_null $non-null + (ref.func $br_on_non_null) ) - ) - (call $log (i32.const 6)) - (drop - (block $non-null (result (ref func)) - ;; a non-null reference is not null, and the br is always taken - (br_on_non_null $non-null (ref.func $br_on-to-br)) - (call $log (i32.const 7)) - (ref.func $br_on-to-br) + ;; On the other hand, if we know the input is null, the branch will never be + ;; taken. + ;; TODO: Optimize this. + (br_on_non_null $non-null + (ref.null nofunc) ) + (ref.func $br_on_non_null) ) ) ) diff --git a/test/lit/passes/vacuum-gc.wast b/test/lit/passes/vacuum-gc.wast index 69dbe0b89..fcdeb8cd2 100644 --- a/test/lit/passes/vacuum-gc.wast +++ b/test/lit/passes/vacuum-gc.wast @@ -18,13 +18,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.cast i31 + ;; CHECK-NEXT: (ref.cast null i31 ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $drop-ref-as (param $x anyref) - ;; Without -tnh, we must assume all ref_as* can have a trap effect, and so + ;; Without -tnh, we must assume all casts can have a trap effect, and so ;; we cannot remove anything here. (drop (ref.as_non_null @@ -32,7 +32,7 @@ ) ) (drop - (ref.as_i31 + (ref.cast null i31 (local.get $x) ) ) diff --git a/test/lit/passes/vacuum-tnh.wast b/test/lit/passes/vacuum-tnh.wast index f60c4c5cb..c3de8c21c 100644 --- a/test/lit/passes/vacuum-tnh.wast +++ b/test/lit/passes/vacuum-tnh.wast @@ -33,7 +33,7 @@ ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (ref.cast i31 + ;; NO_TNH-NEXT: (ref.cast null i31 ;; NO_TNH-NEXT: (local.get $y) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) @@ -55,9 +55,9 @@ ) ) - ;; Other ref.as* as well. + ;; Other casts as well. (drop - (ref.as_i31 + (ref.cast null i31 (local.get $y) ) ) diff --git a/test/lit/ref-cast-nop.wast b/test/lit/ref-cast-nop.wast deleted file mode 100644 index 3b284db04..000000000 --- a/test/lit/ref-cast-nop.wast +++ /dev/null @@ -1,29 +0,0 @@ -;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. - -;; RUN: wasm-opt -all %s -S --roundtrip -o - | filecheck %s - -(module - ;; CHECK: (type $struct (struct (field i32))) - (type $struct (struct i32)) - ;; CHECK: (func $ref.cast_nop (type $ref|any|_=>_ref|$struct|) (param $x (ref any)) (result (ref $struct)) - ;; CHECK-NEXT: (ref.cast_nop $struct - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $ref.cast_nop (param $x (ref any)) (result (ref $struct)) - (ref.cast_nop $struct - (local.get $x) - ) - ) - - ;; CHECK: (func $ref.cast_nop.null (type $ref|any|_=>_ref|none|) (param $x (ref any)) (result (ref none)) - ;; CHECK-NEXT: (ref.cast_nop none - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $ref.cast_nop.null (param $x (ref any)) (result (ref none)) - (ref.cast_nop none - (local.get $x) - ) - ) -) diff --git a/test/passes/Oz_fuzz-exec_all-features.wast b/test/passes/Oz_fuzz-exec_all-features.wast index 3155c3855..b057e0c16 100644 --- a/test/passes/Oz_fuzz-exec_all-features.wast +++ b/test/passes/Oz_fuzz-exec_all-features.wast @@ -179,7 +179,7 @@ ) (func "ref-as-func-of-func" (drop - (ref.as_func + (ref.cast func (ref.func $0) ) ) |