diff options
-rwxr-xr-x | scripts/gen-s-parser.py | 24 | ||||
-rw-r--r-- | src/binaryen-c.cpp | 6 | ||||
-rw-r--r-- | src/binaryen-c.h | 6 | ||||
-rw-r--r-- | src/gen-s-parser.inc | 48 | ||||
-rw-r--r-- | src/ir/gc-type-utils.h | 18 | ||||
-rw-r--r-- | src/js/binaryen.js-post.js | 6 | ||||
-rw-r--r-- | src/passes/Print.cpp | 68 | ||||
-rw-r--r-- | src/wasm-builder.h | 11 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 50 | ||||
-rw-r--r-- | src/wasm-s-parser.h | 4 | ||||
-rw-r--r-- | src/wasm.h | 7 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 35 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 18 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 79 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 25 | ||||
-rw-r--r-- | src/wasm/wat-parser.cpp | 13 | ||||
-rw-r--r-- | test/heap-types.wast | 16 | ||||
-rw-r--r-- | test/heap-types.wast.from-wast | 20 | ||||
-rw-r--r-- | test/heap-types.wast.fromBinary | 32 | ||||
-rw-r--r-- | test/heap-types.wast.fromBinary.noDebugInfo | 32 | ||||
-rw-r--r-- | test/lit/cast-to-basic.wast | 2 | ||||
-rw-r--r-- | test/lit/passes/gufa-refs.wast | 48 | ||||
-rw-r--r-- | test/passes/remove-unused-brs_all-features.txt | 43 | ||||
-rw-r--r-- | test/passes/remove-unused-brs_all-features.wast | 53 |
24 files changed, 200 insertions, 464 deletions
diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index 689c30ae1..46b62711a 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -573,18 +573,18 @@ instructions = [ ("ref.cast_static", "makeRefCast(s)"), ("ref.cast_nop", "makeRefCastNop(s)"), ("ref.cast_nop_static", "makeRefCastNop(s)"), - ("br_on_null", "makeBrOn(s, BrOnNull)"), - ("br_on_non_null", "makeBrOn(s, BrOnNonNull)"), - ("br_on_cast", "makeBrOn(s, BrOnCast)"), - ("br_on_cast_static", "makeBrOn(s, BrOnCast)"), - ("br_on_cast_fail", "makeBrOn(s, BrOnCastFail)"), - ("br_on_cast_static_fail", "makeBrOn(s, BrOnCastFail)"), - ("br_on_func", "makeBrOn(s, BrOnFunc)"), - ("br_on_non_func", "makeBrOn(s, BrOnNonFunc)"), - ("br_on_data", "makeBrOn(s, BrOnData)"), - ("br_on_non_data", "makeBrOn(s, BrOnNonData)"), - ("br_on_i31", "makeBrOn(s, BrOnI31)"), - ("br_on_non_i31", "makeBrOn(s, BrOnNonI31)"), + ("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_data", "makeBrOnCast(s, Type(HeapType::data, NonNullable))"), + ("br_on_non_data", "makeBrOnCast(s, Type(HeapType::data, NonNullable), true)"), + ("br_on_i31", "makeBrOnCast(s, Type(HeapType::i31, NonNullable))"), + ("br_on_non_i31", "makeBrOnCast(s, Type(HeapType::i31, NonNullable), true)"), ("struct.new", "makeStructNew(s, false)"), ("struct.new_default", "makeStructNew(s, true)"), ("struct.get", "makeStructGet(s)"), diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 34a45540d..7ff827aac 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1022,12 +1022,6 @@ BinaryenOp BinaryenBrOnNull(void) { return BrOnNull; } BinaryenOp BinaryenBrOnNonNull(void) { return BrOnNonNull; } BinaryenOp BinaryenBrOnCast(void) { return BrOnCast; } BinaryenOp BinaryenBrOnCastFail(void) { return BrOnCastFail; }; -BinaryenOp BinaryenBrOnFunc(void) { return BrOnFunc; } -BinaryenOp BinaryenBrOnNonFunc(void) { return BrOnNonFunc; } -BinaryenOp BinaryenBrOnData(void) { return BrOnData; } -BinaryenOp BinaryenBrOnNonData(void) { return BrOnNonData; } -BinaryenOp BinaryenBrOnI31(void) { return BrOnI31; } -BinaryenOp BinaryenBrOnNonI31(void) { return BrOnNonI31; } BinaryenOp BinaryenStringNewUTF8(void) { return StringNewUTF8; } BinaryenOp BinaryenStringNewWTF8(void) { return StringNewWTF8; } BinaryenOp BinaryenStringNewReplace(void) { return StringNewReplace; } diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 357e1f18d..171d1248d 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -684,12 +684,6 @@ BINARYEN_API BinaryenOp BinaryenBrOnNull(void); BINARYEN_API BinaryenOp BinaryenBrOnNonNull(void); BINARYEN_API BinaryenOp BinaryenBrOnCast(void); BINARYEN_API BinaryenOp BinaryenBrOnCastFail(void); -BINARYEN_API BinaryenOp BinaryenBrOnFunc(void); -BINARYEN_API BinaryenOp BinaryenBrOnNonFunc(void); -BINARYEN_API BinaryenOp BinaryenBrOnData(void); -BINARYEN_API BinaryenOp BinaryenBrOnNonData(void); -BINARYEN_API BinaryenOp BinaryenBrOnI31(void); -BINARYEN_API BinaryenOp BinaryenBrOnNonI31(void); BINARYEN_API BinaryenOp BinaryenStringNewUTF8(void); BINARYEN_API BinaryenOp BinaryenStringNewWTF8(void); BINARYEN_API BinaryenOp BinaryenStringNewReplace(void); diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 83a7a3121..acae3af50 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -100,20 +100,20 @@ switch (buf[0]) { case 'c': { switch (buf[10]) { case '\0': - if (op == "br_on_cast"sv) { return makeBrOn(s, BrOnCast); } + if (op == "br_on_cast"sv) { return makeBrOnCast(s, std::nullopt); } goto parse_error; case '_': { switch (buf[11]) { case 'f': - if (op == "br_on_cast_fail"sv) { return makeBrOn(s, BrOnCastFail); } + 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 makeBrOn(s, BrOnCast); } + 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 makeBrOn(s, BrOnCastFail); } + if (op == "br_on_cast_static_fail"sv) { return makeBrOnCast(s, std::nullopt, true); } goto parse_error; default: goto parse_error; } @@ -125,35 +125,35 @@ switch (buf[0]) { } } case 'd': - if (op == "br_on_data"sv) { return makeBrOn(s, BrOnData); } + if (op == "br_on_data"sv) { return makeBrOnCast(s, Type(HeapType::data, NonNullable)); } goto parse_error; case 'f': - if (op == "br_on_func"sv) { return makeBrOn(s, BrOnFunc); } + 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 makeBrOn(s, BrOnI31); } + 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 'd': - if (op == "br_on_non_data"sv) { return makeBrOn(s, BrOnNonData); } + if (op == "br_on_non_data"sv) { return makeBrOnCast(s, Type(HeapType::data, NonNullable), true); } goto parse_error; case 'f': - if (op == "br_on_non_func"sv) { return makeBrOn(s, BrOnNonFunc); } + 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 makeBrOn(s, BrOnNonI31); } + 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 makeBrOn(s, BrOnNonNull); } + if (op == "br_on_non_null"sv) { return makeBrOnNull(s, true); } goto parse_error; default: goto parse_error; } } case 'u': - if (op == "br_on_null"sv) { return makeBrOn(s, BrOnNull); } + if (op == "br_on_null"sv) { return makeBrOnNull(s); } goto parse_error; default: goto parse_error; } @@ -3727,7 +3727,7 @@ switch (buf[0]) { switch (buf[10]) { case '\0': if (op == "br_on_cast"sv) { - auto ret = makeBrOn(ctx, pos, BrOnCast); + auto ret = makeBrOnCast(ctx, pos, std::nullopt); CHECK_ERR(ret); return *ret; } @@ -3736,7 +3736,7 @@ switch (buf[0]) { switch (buf[11]) { case 'f': if (op == "br_on_cast_fail"sv) { - auto ret = makeBrOn(ctx, pos, BrOnCastFail); + auto ret = makeBrOnCast(ctx, pos, std::nullopt, true); CHECK_ERR(ret); return *ret; } @@ -3745,14 +3745,14 @@ switch (buf[0]) { switch (buf[17]) { case '\0': if (op == "br_on_cast_static"sv) { - auto ret = makeBrOn(ctx, pos, BrOnCast); + 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 = makeBrOn(ctx, pos, BrOnCastFail); + auto ret = makeBrOnCast(ctx, pos, std::nullopt, true); CHECK_ERR(ret); return *ret; } @@ -3768,21 +3768,21 @@ switch (buf[0]) { } case 'd': if (op == "br_on_data"sv) { - auto ret = makeBrOn(ctx, pos, BrOnData); + auto ret = makeBrOnCast(ctx, pos, Type(HeapType::data, NonNullable)); CHECK_ERR(ret); return *ret; } goto parse_error; case 'f': if (op == "br_on_func"sv) { - auto ret = makeBrOn(ctx, pos, BrOnFunc); + 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 = makeBrOn(ctx, pos, BrOnI31); + auto ret = makeBrOnCast(ctx, pos, Type(HeapType::i31, NonNullable)); CHECK_ERR(ret); return *ret; } @@ -3793,28 +3793,28 @@ switch (buf[0]) { switch (buf[10]) { case 'd': if (op == "br_on_non_data"sv) { - auto ret = makeBrOn(ctx, pos, BrOnNonData); + auto ret = makeBrOnCast(ctx, pos, Type(HeapType::data, NonNullable), true); CHECK_ERR(ret); return *ret; } goto parse_error; case 'f': if (op == "br_on_non_func"sv) { - auto ret = makeBrOn(ctx, pos, BrOnNonFunc); + 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 = makeBrOn(ctx, pos, BrOnNonI31); + 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 = makeBrOn(ctx, pos, BrOnNonNull); + auto ret = makeBrOnNull(ctx, pos, true); CHECK_ERR(ret); return *ret; } @@ -3824,7 +3824,7 @@ switch (buf[0]) { } case 'u': if (op == "br_on_null"sv) { - auto ret = makeBrOn(ctx, pos, BrOnNull); + auto ret = makeBrOnNull(ctx, pos); CHECK_ERR(ret); return *ret; } diff --git a/src/ir/gc-type-utils.h b/src/ir/gc-type-utils.h index 5e3de37e5..6ac604ad2 100644 --- a/src/ir/gc-type-utils.h +++ b/src/ir/gc-type-utils.h @@ -67,24 +67,6 @@ inline EvaluationResult evaluateKindCheck(Expression* curr) { return flip ? Success : Failure; } return Unknown; - case BrOnNonFunc: - flip = true; - [[fallthrough]]; - case BrOnFunc: - expected = Func; - break; - case BrOnNonData: - flip = true; - [[fallthrough]]; - case BrOnData: - expected = Data; - break; - case BrOnNonI31: - flip = true; - [[fallthrough]]; - case BrOnI31: - expected = I31; - break; default: WASM_UNREACHABLE("unhandled BrOn"); } diff --git a/src/js/binaryen.js-post.js b/src/js/binaryen.js-post.js index f252dae8e..d4395359e 100644 --- a/src/js/binaryen.js-post.js +++ b/src/js/binaryen.js-post.js @@ -563,12 +563,6 @@ function initializeConstants() { 'BrOnNonNull', 'BrOnCast', 'BrOnCastFail', - 'BrOnFunc', - 'BrOnNonFunc', - 'BrOnData', - 'BrOnNonData', - 'BrOnI31', - 'BrOnNonI31', 'StringNewUTF8', 'StringNewWTF8', 'StringNewReplace', diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index c1064b7db..988b1d251 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2135,11 +2135,33 @@ struct PrintExpressionContents switch (curr->op) { case BrOnNull: printMedium(o, "br_on_null "); - break; + printName(curr->name, o); + return; case BrOnNonNull: printMedium(o, "br_on_non_null "); - break; + printName(curr->name, o); + return; case BrOnCast: + // TODO: These instructions are deprecated, so stop emitting them. + if (auto type = curr->castType.getHeapType(); + type.isBasic() && curr->castType.isNonNullable()) { + switch (type.getBasic()) { + case HeapType::func: + printMedium(o, "br_on_func "); + printName(curr->name, o); + return; + case HeapType::data: + printMedium(o, "br_on_data "); + printName(curr->name, o); + return; + case HeapType::i31: + printMedium(o, "br_on_i31 "); + printName(curr->name, o); + return; + default: + break; + } + } printMedium(o, "br_on_cast "); printName(curr->name, o); o << ' '; @@ -2149,6 +2171,26 @@ struct PrintExpressionContents printHeapType(o, curr->castType.getHeapType(), wasm); return; case BrOnCastFail: + // TODO: These instructions are deprecated, so stop emitting them. + if (auto type = curr->castType.getHeapType(); + type.isBasic() && curr->castType.isNonNullable()) { + switch (type.getBasic()) { + case HeapType::func: + printMedium(o, "br_on_non_func "); + printName(curr->name, o); + return; + case HeapType::data: + printMedium(o, "br_on_non_data "); + printName(curr->name, o); + return; + case HeapType::i31: + printMedium(o, "br_on_non_i31 "); + printName(curr->name, o); + return; + default: + break; + } + } printMedium(o, "br_on_cast_fail "); printName(curr->name, o); o << ' '; @@ -2157,28 +2199,8 @@ struct PrintExpressionContents } printHeapType(o, curr->castType.getHeapType(), wasm); return; - case BrOnFunc: - printMedium(o, "br_on_func "); - break; - case BrOnNonFunc: - printMedium(o, "br_on_non_func "); - break; - case BrOnData: - printMedium(o, "br_on_data "); - break; - case BrOnNonData: - printMedium(o, "br_on_non_data "); - break; - case BrOnI31: - printMedium(o, "br_on_i31 "); - break; - case BrOnNonI31: - printMedium(o, "br_on_non_i31 "); - break; - default: - WASM_UNREACHABLE("invalid ref.is_*"); } - printName(curr->name, o); + WASM_UNREACHABLE("Unexpected br_on* op"); } void visitStructNew(StructNew* curr) { if (printUnreachableReplacement(curr)) { diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 49c9bb0ba..915c189ae 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -891,15 +891,8 @@ public: ret->finalize(); return ret; } - BrOn* makeBrOn(BrOnOp op, Name name, Expression* ref) { - auto* ret = wasm.allocator.alloc<BrOn>(); - ret->op = op; - ret->name = name; - ret->ref = ref; - ret->finalize(); - return ret; - } - BrOn* makeBrOn(BrOnOp op, Name name, Expression* ref, Type castType) { + BrOn* + makeBrOn(BrOnOp op, Name name, Expression* ref, Type castType = Type::none) { auto* ret = wasm.allocator.alloc<BrOn>(); ret->op = op; ret->name = name; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 17c8a6456..181114c92 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1512,7 +1512,7 @@ public: } } } - // The others do a simpler check for the type. + // Otherwise we are just checking for null. Flow flow = visit(curr->ref); if (flow.breaking()) { return flow; @@ -1520,62 +1520,20 @@ public: const auto& value = flow.getSingleValue(); NOTE_EVAL1(value); if (curr->op == BrOnNull) { - // Unlike the others, BrOnNull does not propagate the value if it takes - // the branch. + // BrOnNull does not propagate the value if it takes the branch. if (value.isNull()) { return Flow(curr->name); } // If the branch is not taken, we return the non-null value. return {value}; - } - if (curr->op == BrOnNonNull) { - // Unlike the others, BrOnNonNull does not return a value if it does not - // take the branch. + } else { + // BrOnNonNull does not return a value if it does not take the branch. if (value.isNull()) { return Flow(); } // If the branch is taken, we send the non-null value. return Flow(curr->name, value); } - // See if the input is the right kind (ignoring the flipping behavior of - // BrOn*). - bool isRightKind; - if (value.isNull()) { - // A null is never the right kind. - isRightKind = false; - } else { - switch (curr->op) { - case BrOnNonFunc: - case BrOnFunc: - isRightKind = value.type.isFunction(); - break; - case BrOnNonData: - case BrOnData: - isRightKind = value.isData(); - break; - case BrOnNonI31: - case BrOnI31: - isRightKind = value.type.getHeapType() == HeapType::i31; - break; - default: - WASM_UNREACHABLE("invalid br_on_*"); - } - } - // The Non* operations require us to flip the normal behavior. - switch (curr->op) { - case BrOnNonFunc: - case BrOnNonData: - case BrOnNonI31: - isRightKind = !isRightKind; - break; - default: { - } - } - if (isRightKind) { - // Take the branch. - return Flow(curr->name, value); - } - return {value}; } Flow visitStructNew(StructNew* curr) { NOTE_ENTER("StructNew"); diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h index 23eed7923..04c832869 100644 --- a/src/wasm-s-parser.h +++ b/src/wasm-s-parser.h @@ -286,7 +286,9 @@ private: Expression* makeRefTest(Element& s); Expression* makeRefCast(Element& s); Expression* makeRefCastNop(Element& s); - Expression* makeBrOn(Element& s, BrOnOp op); + Expression* makeBrOnNull(Element& s, bool onFail = false); + Expression* + makeBrOnCast(Element& s, std::optional<Type> castType, 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 db10fe260..ae88bc4d9 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -583,12 +583,6 @@ enum BrOnOp { BrOnNonNull, BrOnCast, BrOnCastFail, - BrOnFunc, - BrOnNonFunc, - BrOnData, - BrOnNonData, - BrOnI31, - BrOnNonI31, }; enum StringNewOp { @@ -1552,7 +1546,6 @@ public: BrOnOp op; Name name; Expression* ref; - Type castType; void finalize(); diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 61fd65eab..2639599d5 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -6930,8 +6930,8 @@ bool WasmBinaryBuilder::maybeVisitRefCast(Expression*& out, uint32_t code) { } bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) { + Type castType = Type::none; BrOnOp op; - auto nullability = NonNullable; switch (code) { case BinaryConsts::BrOnNull: op = BrOnNull; @@ -6941,44 +6941,47 @@ bool WasmBinaryBuilder::maybeVisitBrOn(Expression*& out, uint32_t code) { break; case BinaryConsts::BrOnCastStatic: case BinaryConsts::BrOnCast: + case BinaryConsts::BrOnCastNull: op = BrOnCast; break; case BinaryConsts::BrOnCastStaticFail: case BinaryConsts::BrOnCastFail: - op = BrOnCastFail; - break; - case BinaryConsts::BrOnCastNull: - op = BrOnCast; - nullability = Nullable; - break; case BinaryConsts::BrOnCastFailNull: op = BrOnCastFail; - nullability = Nullable; break; case BinaryConsts::BrOnFunc: - op = BrOnFunc; + op = BrOnCast; + castType = Type(HeapType::func, NonNullable); break; case BinaryConsts::BrOnNonFunc: - op = BrOnNonFunc; + op = BrOnCastFail; + castType = Type(HeapType::func, NonNullable); break; case BinaryConsts::BrOnData: - op = BrOnData; + op = BrOnCast; + castType = Type(HeapType::data, NonNullable); break; case BinaryConsts::BrOnNonData: - op = BrOnNonData; + op = BrOnCastFail; + castType = Type(HeapType::data, NonNullable); break; case BinaryConsts::BrOnI31: - op = BrOnI31; + op = BrOnCast; + castType = Type(HeapType::i31, NonNullable); break; case BinaryConsts::BrOnNonI31: - op = BrOnNonI31; + op = BrOnCastFail; + castType = Type(HeapType::i31, NonNullable); break; default: return false; } auto name = getBreakTarget(getU32LEB()).name; - Type castType = Type::none; - if (op == BrOnCast || op == BrOnCastFail) { + if (castType == Type::none && (op == BrOnCast || op == BrOnCastFail)) { + auto nullability = (code == BinaryConsts::BrOnCastNull || + code == BinaryConsts::BrOnCastFailNull) + ? Nullable + : NonNullable; bool legacy = code == BinaryConsts::BrOnCastStatic || code == BinaryConsts::BrOnCastStaticFail; auto type = legacy ? getIndexedHeapType() : getHeapType(); diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index fd3cbcc23..638dfbebf 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2818,11 +2818,20 @@ Expression* SExpressionWasmBuilder::makeRefCastNop(Element& s) { return Builder(wasm).makeRefCast(ref, type, RefCast::Unsafe); } -Expression* SExpressionWasmBuilder::makeBrOn(Element& s, BrOnOp op) { +Expression* SExpressionWasmBuilder::makeBrOnNull(Element& s, bool onFail) { int i = 1; auto name = getLabel(*s[i++]); - Type castType = Type::none; - if (op == BrOnCast || op == BrOnCastFail) { + auto* ref = parseExpression(*s[i]); + auto op = onFail ? BrOnNonNull : BrOnNull; + return Builder(wasm).makeBrOn(op, name, ref); +} + +Expression* SExpressionWasmBuilder::makeBrOnCast(Element& s, + std::optional<Type> castType, + bool onFail) { + int i = 1; + auto name = getLabel(*s[i++]); + if (!castType) { auto nullability = NonNullable; if (s[i]->str().str == "null") { nullability = Nullable; @@ -2832,7 +2841,8 @@ Expression* SExpressionWasmBuilder::makeBrOn(Element& s, BrOnOp op) { castType = Type(type, nullability); } auto* ref = parseExpression(*s[i]); - return Builder(wasm).makeBrOn(op, name, ref, castType); + auto op = onFail ? BrOnCastFail : BrOnCast; + 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 fbf73b7c2..24710f206 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2052,51 +2052,74 @@ void BinaryInstWriter::visitBrOn(BrOn* curr) { switch (curr->op) { case BrOnNull: o << int8_t(BinaryConsts::BrOnNull); - break; + o << U32LEB(getBreakIndex(curr->name)); + return; case BrOnNonNull: o << int8_t(BinaryConsts::BrOnNonNull); - break; + o << U32LEB(getBreakIndex(curr->name)); + return; case BrOnCast: o << int8_t(BinaryConsts::GCPrefix); + // TODO: These instructions are deprecated, so stop emitting them. + if (auto type = curr->castType.getHeapType(); + type.isBasic() && curr->castType.isNonNullable()) { + switch (type.getBasic()) { + case HeapType::func: + o << U32LEB(BinaryConsts::BrOnFunc); + o << U32LEB(getBreakIndex(curr->name)); + return; + case HeapType::data: + o << U32LEB(BinaryConsts::BrOnData); + o << U32LEB(getBreakIndex(curr->name)); + return; + case HeapType::i31: + o << U32LEB(BinaryConsts::BrOnI31); + o << U32LEB(getBreakIndex(curr->name)); + return; + default: + break; + } + } if (curr->castType.isNullable()) { o << U32LEB(BinaryConsts::BrOnCastNull); } else { o << U32LEB(BinaryConsts::BrOnCast); } - break; + o << U32LEB(getBreakIndex(curr->name)); + parent.writeHeapType(curr->castType.getHeapType()); + return; case BrOnCastFail: o << int8_t(BinaryConsts::GCPrefix); + // TODO: These instructions are deprecated, so stop emitting them. + if (auto type = curr->castType.getHeapType(); + type.isBasic() && curr->castType.isNonNullable()) { + switch (type.getBasic()) { + case HeapType::func: + o << U32LEB(BinaryConsts::BrOnNonFunc); + o << U32LEB(getBreakIndex(curr->name)); + return; + case HeapType::data: + o << U32LEB(BinaryConsts::BrOnNonData); + o << U32LEB(getBreakIndex(curr->name)); + return; + case HeapType::i31: + o << U32LEB(BinaryConsts::BrOnNonI31); + o << U32LEB(getBreakIndex(curr->name)); + return; + default: + break; + } + } if (curr->castType.isNullable()) { o << U32LEB(BinaryConsts::BrOnCastFailNull); } else { o << U32LEB(BinaryConsts::BrOnCastFail); } - break; - case BrOnFunc: - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnFunc); - break; - case BrOnNonFunc: - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnNonFunc); - break; - case BrOnData: - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnData); - break; - case BrOnNonData: - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnNonData); - break; - case BrOnI31: - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnI31); - break; - case BrOnNonI31: - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::BrOnNonI31); - break; - default: - WASM_UNREACHABLE("invalid br_on_*"); - } - o << U32LEB(getBreakIndex(curr->name)); - if (curr->op == BrOnCast || curr->op == BrOnCastFail) { - parent.writeHeapType(curr->castType.getHeapType()); + o << U32LEB(getBreakIndex(curr->name)); + parent.writeHeapType(curr->castType.getHeapType()); + return; } + WASM_UNREACHABLE("invalid br_on_*"); } void BinaryInstWriter::visitStructNew(StructNew* curr) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index de18966ff..c6779a328 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -968,21 +968,6 @@ void BrOn::finalize() { // us flow out the null, but it does not). type = Type::none; break; - case BrOnFunc: - case BrOnData: - case BrOnI31: - // If we do not branch, we return the input in this case. - type = ref->type; - break; - case BrOnNonFunc: - type = Type(HeapType::func, NonNullable); - break; - case BrOnNonData: - type = Type(HeapType::data, NonNullable); - break; - case BrOnNonI31: - type = Type(HeapType::i31, NonNullable); - break; case BrOnCast: if (castType.isNullable()) { // Nulls take the branch, so the result is non-nullable. @@ -1021,16 +1006,6 @@ Type BrOn::getSentType() { } // BrOnNonNull sends the non-nullable type on the branch. return Type(ref->type.getHeapType(), NonNullable); - case BrOnFunc: - return Type(HeapType::func, NonNullable); - case BrOnData: - return Type(HeapType::data, NonNullable); - case BrOnI31: - return Type(HeapType::i31, NonNullable); - case BrOnNonFunc: - case BrOnNonData: - case BrOnNonI31: - return ref->type; case BrOnCast: // The same as the result type of br_on_cast_fail. if (castType.isNullable()) { diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index 409d51052..14d30db1c 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -2349,9 +2349,10 @@ 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> makeRefCastNop(Ctx&, Index); template<typename Ctx> -Result<typename Ctx::InstrT> makeBrOn(Ctx&, Index, BrOnOp op); +Result<typename Ctx::InstrT> makeBrOnNull(Ctx&, Index, bool onFail = false); template<typename Ctx> -Result<typename Ctx::InstrT> makeBrOn(Ctx&, Index, BrOnOp op); +Result<typename Ctx::InstrT> +makeBrOnCast(Ctx&, Index, std::optional<Type>, bool onFail = false); template<typename Ctx> Result<typename Ctx::InstrT> makeStructNew(Ctx&, Index, bool default_); template<typename Ctx> @@ -3452,7 +3453,13 @@ Result<typename Ctx::InstrT> makeRefCastNop(Ctx& ctx, Index pos) { } template<typename Ctx> -Result<typename Ctx::InstrT> makeBrOn(Ctx& ctx, Index pos, BrOnOp op) { +Result<typename Ctx::InstrT> makeBrOnNull(Ctx& ctx, Index pos, bool onFail) { + return ctx.in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> +makeBrOnCast(Ctx& ctx, Index pos, std::optional<Type> castType, bool onFail) { return ctx.in.err("unimplemented instruction"); } diff --git a/test/heap-types.wast b/test/heap-types.wast index 9366dca01..f75622142 100644 --- a/test/heap-types.wast +++ b/test/heap-types.wast @@ -203,14 +203,6 @@ ) ) (drop - (block $func (result funcref) - (local.set $y - (br_on_func $func (local.get $x)) - ) - (ref.null func) - ) - ) - (drop (block $i31 (result (ref null i31)) (local.set $y (br_on_i31 $i31 (local.get $x)) @@ -225,14 +217,6 @@ ) ) (drop - (block $non-func (result anyref) - (local.set $temp-func - (br_on_non_func $non-func (local.get $x)) - ) - (ref.null any) - ) - ) - (drop (block $non-i31 (result anyref) (local.set $temp-i31 (br_on_non_i31 $non-i31 (local.get $x)) diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast index 9f1a28d13..9eafd633b 100644 --- a/test/heap-types.wast.from-wast +++ b/test/heap-types.wast.from-wast @@ -230,16 +230,6 @@ ) ) (drop - (block $func (result funcref) - (local.set $y - (br_on_func $func - (local.get $x) - ) - ) - (ref.null nofunc) - ) - ) - (drop (block $i31 (result i31ref) (local.set $y (br_on_i31 $i31 @@ -258,16 +248,6 @@ ) ) (drop - (block $non-func (result anyref) - (local.set $temp-func - (br_on_non_func $non-func - (local.get $x) - ) - ) - (ref.null none) - ) - ) - (drop (block $non-i31 (result anyref) (local.set $temp-i31 (br_on_non_i31 $non-i31 diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary index b217ebc2e..04e9bbe05 100644 --- a/test/heap-types.wast.fromBinary +++ b/test/heap-types.wast.fromBinary @@ -228,19 +228,9 @@ ) ) (drop - (block $label$2 (result funcref) + (block $label$2 (result i31ref) (local.set $y - (br_on_func $label$2 - (local.get $x) - ) - ) - (ref.null nofunc) - ) - ) - (drop - (block $label$3 (result i31ref) - (local.set $y - (br_on_i31 $label$3 + (br_on_i31 $label$2 (local.get $x) ) ) @@ -248,27 +238,17 @@ ) ) (drop - (block $label$4 (result (ref any)) - (br_on_non_null $label$4 + (block $label$3 (result (ref any)) + (br_on_non_null $label$3 (local.get $x) ) (unreachable) ) ) (drop - (block $label$5 (result anyref) - (local.set $temp-func - (br_on_non_func $label$5 - (local.get $x) - ) - ) - (ref.null none) - ) - ) - (drop - (block $label$6 (result anyref) + (block $label$4 (result anyref) (local.set $temp-i31 - (br_on_non_i31 $label$6 + (br_on_non_i31 $label$4 (local.get $x) ) ) diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo index 89f0c676e..472c3288f 100644 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ b/test/heap-types.wast.fromBinary.noDebugInfo @@ -228,19 +228,9 @@ ) ) (drop - (block $label$2 (result funcref) + (block $label$2 (result i31ref) (local.set $1 - (br_on_func $label$2 - (local.get $0) - ) - ) - (ref.null nofunc) - ) - ) - (drop - (block $label$3 (result i31ref) - (local.set $1 - (br_on_i31 $label$3 + (br_on_i31 $label$2 (local.get $0) ) ) @@ -248,27 +238,17 @@ ) ) (drop - (block $label$4 (result (ref any)) - (br_on_non_null $label$4 + (block $label$3 (result (ref any)) + (br_on_non_null $label$3 (local.get $0) ) (unreachable) ) ) (drop - (block $label$5 (result anyref) - (local.set $3 - (br_on_non_func $label$5 - (local.get $0) - ) - ) - (ref.null none) - ) - ) - (drop - (block $label$6 (result anyref) + (block $label$4 (result anyref) (local.set $4 - (br_on_non_i31 $label$6 + (br_on_non_i31 $label$4 (local.get $0) ) ) diff --git a/test/lit/cast-to-basic.wast b/test/lit/cast-to-basic.wast index 1aa329bf5..239fd820c 100644 --- a/test/lit/cast-to-basic.wast +++ b/test/lit/cast-to-basic.wast @@ -35,7 +35,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block $label$1 (result dataref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_on_cast $label$1 data + ;; CHECK-NEXT: (br_on_data $label$1 ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 9f45ab62a..f1ea265d7 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -14,8 +14,6 @@ ;; CHECK: (type $none_=>_ref|any| (func (result (ref any)))) - ;; CHECK: (type $none_=>_funcref (func (result funcref))) - ;; CHECK: (import "a" "b" (func $import (result i32))) (import "a" "b" (func $import (result i32))) @@ -58,7 +56,7 @@ (nop) (ref.as_func (ref.as_non_null - (ref.null any) + (ref.null func) ) ) ) @@ -360,50 +358,6 @@ (local.get $z) ) ) - - ;; CHECK: (func $nondeterminism (type $none_=>_funcref) (result funcref) - ;; CHECK-NEXT: (block $label$1 (result funcref) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br_on_func $label$1 - ;; CHECK-NEXT: (i31.new - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - (func $nondeterminism (result funcref) - ;; This block is sent an i31 and a null. The null is compatible with the - ;; type and the i31 is not. The order in which we process this matters: - ;; - ;; * If the i31 arrives first, we'll filter it out as incompatible with the - ;; type of the block. Then the null arrives and the final result is that - ;; null, which we can then optimize the block to return. - ;; * Or, if the null arrives first, then when the i31 arrives the - ;; combination of nullfunc + i31 is Many (since the types are - ;; incompatible). We then filter that to the block's type, ending up with - ;; a cone of funcref. We cannot optimize in that case, unlike before. - ;; - ;; Ideally we'd optimize here, but atm we do not since the order in - ;; practice is a less ideal one. At minimum we should be deterministic in - ;; how we handle this, which this test enforces at least. - ;; - ;; TODO: Find a way to actually optimize such cases, perhaps by filtering - ;; when sending as well and not just when receiving (the br_on_func - ;; here should not send anything, as what it sends should be first - ;; intersected with funcref). - (block $label$1 (result funcref) - (drop - (br_on_func $label$1 - (i31.new - (i32.const 1337) - ) - ) - ) - (ref.null nofunc) - ) - ) ) (module diff --git a/test/passes/remove-unused-brs_all-features.txt b/test/passes/remove-unused-brs_all-features.txt index d833e469e..253092e1c 100644 --- a/test/passes/remove-unused-brs_all-features.txt +++ b/test/passes/remove-unused-brs_all-features.txt @@ -7,9 +7,8 @@ (type $none_=>_f64 (func (result f64))) (type $none_=>_i32 (func (result i32))) (type $i32_=>_funcref (func (param i32) (result funcref))) - (type $none_=>_none (func)) (import "out" "log" (func $log (param i32))) - (elem declare func $br_on-to-br $br_on-to-flow $i32_=>_none $none_=>_i32) + (elem declare func $br_on-to-br $i32_=>_none $none_=>_i32) (func $foo (type $none_=>_ref?|$struct|) (result (ref null $struct)) (if (result (ref null $struct)) (i32.const 1) @@ -114,44 +113,4 @@ ) ) ) - (func $br_on-to-flow (type $none_=>_none) - (drop - (block $func (result nullfuncref) - (drop - (array.new_default $vector - (i32.const 2) - ) - ) - (ref.null nofunc) - ) - ) - (drop - (block $funcb (result nullfuncref) - (drop - (i31.new - (i32.const 1337) - ) - ) - (ref.null nofunc) - ) - ) - (drop - (block $i31 (result nullref) - (drop - (array.new_default $vector - (i32.const 2) - ) - ) - (ref.null none) - ) - ) - (drop - (block $i31b (result nullref) - (drop - (ref.func $br_on-to-flow) - ) - (ref.null none) - ) - ) - ) ) diff --git a/test/passes/remove-unused-brs_all-features.wast b/test/passes/remove-unused-brs_all-features.wast index 356616b7b..5960e1029 100644 --- a/test/passes/remove-unused-brs_all-features.wast +++ b/test/passes/remove-unused-brs_all-features.wast @@ -96,55 +96,4 @@ ) ) ) - - ;; a br_on of the obviously incorrect kind can just flow out the value as the - ;; break is never taken - (func $br_on-to-flow - ;; brs to func - (drop - (block $func (result (ref null func)) - (drop - (br_on_func $func - (array.new_default $vector - (i32.const 2) - ) - ) - ) - (ref.null func) - ) - ) - (drop - (block $funcb (result (ref null func)) - (drop - (br_on_func $funcb - (i31.new (i32.const 1337)) - ) - ) - (ref.null func) - ) - ) - ;; brs to i31 - (drop - (block $i31 (result (ref null i31)) - (drop - (br_on_i31 $i31 - (array.new_default $vector - (i32.const 2) - ) - ) - ) - (ref.null i31) - ) - ) - (drop - (block $i31b (result (ref null i31)) - (drop - (br_on_i31 $i31b - (ref.func $br_on-to-flow) - ) - ) - (ref.null i31) - ) - ) - ) -) +)
\ No newline at end of file |