diff options
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) ) ) |