From ab096d517c6b3834cd74f1ab0153e48102ab9d41 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 7 Sep 2022 09:59:04 -0700 Subject: [PATCH 01/18] Implement bottom heap types These types, `none`, `nofunc`, and `noextern` are uninhabited, so references to them can only possibly be null. To simplify the IR and increase type precision, introduce new invariants that all `ref.null` instructions must be typed with one of these new bottom types and that `Literals` have a bottom type iff they represent null values. These new invariants requires several additional changes. First, it is now possible that the `ref` or `target` child of a `StructGet`, `StructSet`, `ArrayGet`, `ArraySet`, or `CallRef` instruction has a bottom reference type, so it is not possible to determine what heap type annotation to emit in the binary or text formats. (The bottom types are not valid type annotations since they do not have indices in the type section.) To fix that problem, update the printer and binary emitter to emit unreachables instead of the instruction with undetermined type annotation. This is a valid transformation because the only possible value that could flow into those instructions in that case is null, and all of those instructions trap on nulls. That fix uncovered a latent bug in the binary parser in which new unreachables within unreachable code were handled incorrectly. This bug was not previously found by the fuzzer because we generally stop emitting code once we encounter an instruction with type `unreachable`. Now, however, it is possible to emit an `unreachable` for instructions that do not have type `unreachable` (but are known to trap at runtime), so we will continue emitting code. See the new test/lit/parse-double-unreachable.wast for details. Update other miscellaneous code that creates `RefNull` expressions and null `Literals` to maintain the new invariants as well. --- src/binaryen-c.cpp | 185 +++-- src/binaryen-c.h | 4 + src/ir/effects.h | 28 + src/ir/manipulation.h | 1 + src/ir/possible-contents.cpp | 3 +- src/ir/struct-utils.h | 5 +- src/literal.h | 23 +- src/passes/Inlining.cpp | 37 +- src/passes/JSPI.cpp | 6 +- src/passes/OptimizeInstructions.cpp | 33 +- src/passes/Precompute.cpp | 4 +- src/passes/Print.cpp | 55 +- src/passes/TypeRefining.cpp | 2 +- src/tools/fuzzing/fuzzing.cpp | 57 +- src/tools/fuzzing/heap-types.cpp | 37 +- src/tools/wasm-reduce.cpp | 2 +- src/wasm-binary.h | 8 + src/wasm-builder.h | 38 +- src/wasm-type.h | 13 +- src/wasm/literal.cpp | 135 ++-- src/wasm/wasm-binary.cpp | 166 ++-- src/wasm/wasm-s-parser.cpp | 30 +- src/wasm/wasm-stack.cpp | 29 +- src/wasm/wasm-type.cpp | 154 +++- src/wasm/wasm-validator.cpp | 109 ++- src/wasm/wasm.cpp | 9 +- test/ctor-eval/bad-indirect-call3.wast.out | 2 +- test/ctor-eval/gc.wast.out | 2 +- test/example/c-api-kitchen-sink.c | 35 +- test/example/c-api-kitchen-sink.txt | 34 +- test/example/cpp-unit.cpp | 26 - test/example/cpp-unit.txt | 2 - test/example/typeinfo.txt | 2 +- test/gc.wast.from-wast | 18 +- test/gc.wast.fromBinary | 18 +- test/gc.wast.fromBinary.noDebugInfo | 18 +- test/gtest/type-builder.cpp | 4 + test/heap-types.wast.from-wast | 139 ++-- test/heap-types.wast.fromBinary | 129 +--- test/heap-types.wast.fromBinary.noDebugInfo | 129 +--- test/lit/fuzz-types/isorecursive.test | 40 +- test/lit/fuzz-types/nominal.test | 40 +- test/lit/fuzz-types/structural.test | 36 +- test/lit/gc-eh.wast | 4 +- test/lit/global-only.wast | 2 +- test/lit/heap-types.wast | 10 +- test/lit/isorecursive-singleton-group.wast | 2 +- test/lit/isorecursive-whole-group.wast | 2 +- test/lit/lub-bug-3843.wast | 15 +- test/lit/nominal-chain.wast | 8 +- test/lit/parse-double-unreachable.wast | 44 ++ test/lit/parse-nominal-types-extends.wast | 30 +- test/lit/parse-nominal-types.wast | 30 +- test/lit/passes/cfp.wast | 707 ++++++++++-------- test/lit/passes/coalesce-locals-gc.wast | 31 +- test/lit/passes/dae-gc-refine-params.wast | 116 ++- test/lit/passes/dae-gc-refine-return.wast | 6 +- test/lit/passes/dae-gc.wast | 8 +- test/lit/passes/flatten_all-features.wast | 13 +- test/lit/passes/global-refining.wast | 19 +- test/lit/passes/gsi.wast | 236 +++--- test/lit/passes/gto-mutability.wast | 334 ++++++--- test/lit/passes/gto-removals.wast | 87 +-- test/lit/passes/gufa-refs.wast | 200 ++--- test/lit/passes/gufa-vs-cfp.wast | 31 +- test/lit/passes/gufa.wast | 6 +- test/lit/passes/heap2local.wast | 450 +++++------ test/lit/passes/inlining-gc.wast | 2 +- test/lit/passes/inlining-optimizing.wast | 1 + test/lit/passes/inlining_all-features.wast | 14 +- test/lit/passes/inlining_splitting.wast | 36 +- test/lit/passes/intrinsic-lowering.wast | 8 +- test/lit/passes/jspi.wast | 2 +- test/lit/passes/local-subtyping-nn.wast | 18 +- test/lit/passes/local-subtyping.wast | 17 +- test/lit/passes/merge-blocks.wast | 24 +- .../optimize-instructions-call_ref.wast | 3 + .../passes/optimize-instructions-gc-heap.wast | 7 +- .../passes/optimize-instructions-gc-tnh.wast | 20 +- test/lit/passes/optimize-instructions-gc.wast | 121 ++- test/lit/passes/precompute-gc-immutable.wast | 8 +- test/lit/passes/precompute-gc.wast | 58 +- test/lit/passes/remove-unused-brs-gc.wast | 28 +- test/lit/passes/remove-unused-brs.wast | 6 +- .../remove-unused-module-elements-refs.wast | 63 +- test/lit/passes/roundtrip.wast | 2 +- test/lit/passes/signature-pruning.wast | 4 +- test/lit/passes/signature-refining.wast | 15 +- test/lit/passes/simplify-locals-gc-nn.wast | 4 +- .../passes/simplify-locals-gc-validation.wast | 2 +- test/lit/passes/simplify-locals-gc.wast | 14 +- .../passes/type-refining-isorecursive.wast | 12 +- test/lit/passes/type-refining.wast | 122 +-- test/lit/table-operations.wast | 6 +- test/lit/types-function-references.wast | 36 +- test/lit/validation/eqref.wast | 12 +- test/multi-table.wast.from-wast | 6 +- test/multi-table.wast.fromBinary | 6 +- test/multi-table.wast.fromBinary.noDebugInfo | 6 +- test/multivalue.wast.from-wast | 4 +- test/multivalue.wast.fromBinary | 4 +- test/multivalue.wast.fromBinary.noDebugInfo | 4 +- test/passes/Oz_fuzz-exec_all-features.txt | 4 +- test/passes/precompute_all-features.txt | 12 +- .../passes/remove-unused-brs_all-features.txt | 26 +- test/passes/simplify-globals_all-features.txt | 4 +- ...implify-globals_all-features_fuzz-exec.txt | 2 +- ..._roundtrip_print-features_all-features.txt | 2 +- ...e-to-fuzz_all-features_metrics_noprint.txt | 70 +- test/reference-types.wast.from-wast | 102 +-- test/reference-types.wast.fromBinary | 94 +-- ...eference-types.wast.fromBinary.noDebugInfo | 94 +-- test/unit/input/gc_target_feature.wasm | Bin 94 -> 94 bytes 113 files changed, 2971 insertions(+), 2372 deletions(-) create mode 100644 test/lit/parse-double-unreachable.wast diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index cc7ed5b1569..21f73d7d669 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -51,96 +51,111 @@ static_assert(sizeof(BinaryenLiteral) == sizeof(Literal), BinaryenLiteral toBinaryenLiteral(Literal x) { BinaryenLiteral ret; ret.type = x.type.getID(); - if (x.type.isRef()) { - auto heapType = x.type.getHeapType(); - if (heapType.isBasic()) { - switch (heapType.getBasic()) { - case HeapType::func: - ret.func = x.isNull() ? nullptr : x.getFunc().c_str(); - break; - case HeapType::ext: - case HeapType::eq: - assert(x.isNull() && "unexpected non-null reference type literal"); - break; - case HeapType::any: - case HeapType::i31: - case HeapType::data: - case HeapType::string: - case HeapType::stringview_wtf8: - case HeapType::stringview_wtf16: - case HeapType::stringview_iter: - WASM_UNREACHABLE("TODO: reftypes"); - } - return ret; + assert(x.type.isSingle()); + if (x.type.isBasic()) { + switch (x.type.getBasic()) { + case Type::i32: + ret.i32 = x.geti32(); + return ret; + case Type::i64: + ret.i64 = x.geti64(); + return ret; + case Type::f32: + ret.i32 = x.reinterpreti32(); + return ret; + case Type::f64: + ret.i64 = x.reinterpreti64(); + return ret; + case Type::v128: + memcpy(&ret.v128, x.getv128Ptr(), 16); + return ret; + case Type::none: + case Type::unreachable: + WASM_UNREACHABLE("unexpected type"); } - WASM_UNREACHABLE("TODO: reftypes"); } - TODO_SINGLE_COMPOUND(x.type); - switch (x.type.getBasic()) { - case Type::i32: - ret.i32 = x.geti32(); - break; - case Type::i64: - ret.i64 = x.geti64(); - break; - case Type::f32: - ret.i32 = x.reinterpreti32(); - break; - case Type::f64: - ret.i64 = x.reinterpreti64(); - break; - case Type::v128: - memcpy(&ret.v128, x.getv128Ptr(), 16); - break; - case Type::none: - case Type::unreachable: - WASM_UNREACHABLE("unexpected type"); + assert(x.type.isRef()); + auto heapType = x.type.getHeapType(); + if (heapType.isBasic()) { + switch (heapType.getBasic()) { + case HeapType::i31: + WASM_UNREACHABLE("TODO: i31"); + case HeapType::ext: + case HeapType::any: + WASM_UNREACHABLE("TODO: extern literals"); + case HeapType::eq: + case HeapType::func: + case HeapType::data: + WASM_UNREACHABLE("invalid type"); + case HeapType::string: + case HeapType::stringview_wtf8: + case HeapType::stringview_wtf16: + case HeapType::stringview_iter: + WASM_UNREACHABLE("TODO: string literals"); + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + // Null. + return ret; + } } - return ret; + if (heapType.isSignature()) { + ret.func = x.getFunc().c_str(); + return ret; + } + assert(x.isData()); + WASM_UNREACHABLE("TODO: gc data"); } Literal fromBinaryenLiteral(BinaryenLiteral x) { auto type = Type(x.type); - if (type.isRef()) { - auto heapType = type.getHeapType(); - if (type.isNullable()) { - return Literal::makeNull(heapType); + if (type.isBasic()) { + switch (type.getBasic()) { + case Type::i32: + return Literal(x.i32); + case Type::i64: + return Literal(x.i64); + case Type::f32: + return Literal(x.i32).castToF32(); + case Type::f64: + return Literal(x.i64).castToF64(); + case Type::v128: + return Literal(x.v128); + case Type::none: + case Type::unreachable: + WASM_UNREACHABLE("unexpected type"); } - if (heapType.isBasic()) { - switch (heapType.getBasic()) { - case HeapType::func: - case HeapType::any: - case HeapType::eq: - case HeapType::data: - assert(false && "Literals must have concrete types"); - WASM_UNREACHABLE("no fallthrough here"); - case HeapType::ext: - case HeapType::i31: - case HeapType::string: - case HeapType::stringview_wtf8: - case HeapType::stringview_wtf16: - case HeapType::stringview_iter: - WASM_UNREACHABLE("TODO: reftypes"); - } + } + assert(type.isRef()); + auto heapType = type.getHeapType(); + if (heapType.isBasic()) { + switch (heapType.getBasic()) { + case HeapType::i31: + WASM_UNREACHABLE("TODO: i31"); + case HeapType::ext: + case HeapType::any: + WASM_UNREACHABLE("TODO: extern literals"); + case HeapType::eq: + case HeapType::func: + case HeapType::data: + WASM_UNREACHABLE("invalid type"); + case HeapType::string: + case HeapType::stringview_wtf8: + case HeapType::stringview_wtf16: + case HeapType::stringview_iter: + WASM_UNREACHABLE("TODO: string literals"); + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + assert(type.isNullable()); + return Literal::makeNull(heapType); } } - assert(type.isBasic()); - switch (type.getBasic()) { - case Type::i32: - return Literal(x.i32); - case Type::i64: - return Literal(x.i64); - case Type::f32: - return Literal(x.i32).castToF32(); - case Type::f64: - return Literal(x.i64).castToF64(); - case Type::v128: - return Literal(x.v128); - case Type::none: - case Type::unreachable: - WASM_UNREACHABLE("unexpected type"); + if (heapType.isSignature()) { + return Literal::makeFunc(Name(x.func), heapType); } - WASM_UNREACHABLE("invalid type"); + assert(heapType.isData()); + WASM_UNREACHABLE("TODO: gc data"); } // Mutexes (global for now; in theory if multiple modules @@ -197,6 +212,15 @@ BinaryenType BinaryenTypeStringviewWTF16() { BinaryenType BinaryenTypeStringviewIter() { return Type(HeapType::stringview_iter, Nullable).getID(); } +BinaryenType BinaryenTypeNullref() { + return Type(HeapType::none, Nullable).getID(); +} +BinaryenType BinaryenTypeNullExternref(void) { + return Type(HeapType::noext, Nullable).getID(); +} +BinaryenType BinaryenTypeNullFuncref(void) { + return Type(HeapType::nofunc, Nullable).getID(); +} BinaryenType BinaryenTypeUnreachable(void) { return Type::unreachable; } BinaryenType BinaryenTypeAuto(void) { return uintptr_t(-1); } @@ -1699,10 +1723,11 @@ BinaryenExpressionRef BinaryenArrayInit(BinaryenModuleRef module, BinaryenExpressionRef BinaryenArrayGet(BinaryenModuleRef module, BinaryenExpressionRef ref, BinaryenExpressionRef index, + BinaryenType type, bool signed_) { return static_cast( Builder(*(Module*)module) - .makeArrayGet((Expression*)ref, (Expression*)index, signed_)); + .makeArrayGet((Expression*)ref, (Expression*)index, Type(type), signed_)); } BinaryenExpressionRef BinaryenArraySet(BinaryenModuleRef module, BinaryenExpressionRef ref, diff --git a/src/binaryen-c.h b/src/binaryen-c.h index 5b343e8bace..9cc282721c6 100644 --- a/src/binaryen-c.h +++ b/src/binaryen-c.h @@ -109,6 +109,9 @@ BINARYEN_API BinaryenType BinaryenTypeStringref(void); BINARYEN_API BinaryenType BinaryenTypeStringviewWTF8(void); BINARYEN_API BinaryenType BinaryenTypeStringviewWTF16(void); BINARYEN_API BinaryenType BinaryenTypeStringviewIter(void); +BINARYEN_API BinaryenType BinaryenTypeNullref(void); +BINARYEN_API BinaryenType BinaryenTypeNullExternref(void); +BINARYEN_API BinaryenType BinaryenTypeNullFuncref(void); BINARYEN_API BinaryenType BinaryenTypeUnreachable(void); // Not a real type. Used as the last parameter to BinaryenBlock to let // the API figure out the type instead of providing one. @@ -1044,6 +1047,7 @@ BinaryenArrayInit(BinaryenModuleRef module, BINARYEN_API BinaryenExpressionRef BinaryenArrayGet(BinaryenModuleRef module, BinaryenExpressionRef ref, BinaryenExpressionRef index, + BinaryenType type, bool signed_); BINARYEN_API BinaryenExpressionRef BinaryenArraySet(BinaryenModuleRef module, diff --git a/src/ir/effects.h b/src/ir/effects.h index 63d9fafc59c..2dfe616f97c 100644 --- a/src/ir/effects.h +++ b/src/ir/effects.h @@ -701,6 +701,10 @@ class EffectAnalyzer { } } void visitCallRef(CallRef* curr) { + if (curr->target->type.isNull()) { + parent.trap = true; + return; + } parent.calls = true; if (parent.features.hasExceptionHandling() && parent.tryDepth == 0) { parent.throws_ = true; @@ -724,6 +728,10 @@ class EffectAnalyzer { if (curr->ref->type == Type::unreachable) { return; } + if (curr->ref->type.isNull()) { + parent.trap = true; + return; + } if (curr->ref->type.getHeapType() .getStruct() .fields[curr->index] @@ -736,6 +744,10 @@ class EffectAnalyzer { } } void visitStructSet(StructSet* curr) { + if (curr->ref->type.isNull()) { + parent.trap = true; + return; + } parent.writesStruct = true; // traps when the arg is null if (curr->ref->type.isNullable()) { @@ -745,22 +757,38 @@ class EffectAnalyzer { void visitArrayNew(ArrayNew* curr) {} void visitArrayInit(ArrayInit* curr) {} void visitArrayGet(ArrayGet* curr) { + if (curr->ref->type.isNull()) { + parent.trap = true; + return; + } parent.readsArray = true; // traps when the arg is null or the index out of bounds parent.implicitTrap = true; } void visitArraySet(ArraySet* curr) { + if (curr->ref->type.isNull()) { + parent.trap = true; + return; + } parent.writesArray = true; // traps when the arg is null or the index out of bounds parent.implicitTrap = true; } void visitArrayLen(ArrayLen* curr) { + if (curr->ref->type.isNull()) { + parent.trap = true; + return; + } // traps when the arg is null if (curr->ref->type.isNullable()) { parent.implicitTrap = true; } } void visitArrayCopy(ArrayCopy* curr) { + if (curr->destRef->type.isNull() || curr->srcRef->type.isNull()) { + parent.trap = true; + return; + } parent.readsArray = true; parent.writesArray = true; // traps when a ref is null, or when out of bounds. diff --git a/src/ir/manipulation.h b/src/ir/manipulation.h index 54822f2bd58..33c7d1bd712 100644 --- a/src/ir/manipulation.h +++ b/src/ir/manipulation.h @@ -41,6 +41,7 @@ template inline Nop* nop(InputType* target) { template inline RefNull* refNull(InputType* target, Type type) { + assert(type.isNullable() && type.getHeapType().isBottom()); auto* ret = convert(target); ret->finalize(type); return ret; diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index 1b5c5ae0df6..d01348e3f19 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -785,7 +785,8 @@ struct InfoCollector // part of the main IR, which is potentially confusing during debugging, // however, which is a downside. Builder builder(*getModule()); - auto* get = builder.makeArrayGet(curr->srcRef, curr->srcIndex); + auto* get = + builder.makeArrayGet(curr->srcRef, curr->srcIndex, curr->srcRef->type); visitArrayGet(get); auto* set = builder.makeArraySet(curr->destRef, curr->destIndex, get); visitArraySet(set); diff --git a/src/ir/struct-utils.h b/src/ir/struct-utils.h index 9d02bb779dc..9f880985ffd 100644 --- a/src/ir/struct-utils.h +++ b/src/ir/struct-utils.h @@ -50,6 +50,7 @@ struct StructValuesMap : public std::unordered_map> { // When we access an item, if it does not already exist, create it with a // vector of the right length for that type. StructValues& operator[](HeapType type) { + assert(type.isStruct()); auto inserted = this->insert({type, {}}); auto& values = inserted.first->second; if (inserted.second) { @@ -159,7 +160,7 @@ struct StructScanner void visitStructSet(StructSet* curr) { auto type = curr->ref->type; - if (type == Type::unreachable) { + if (type == Type::unreachable || type.isNull()) { return; } @@ -173,7 +174,7 @@ struct StructScanner void visitStructGet(StructGet* curr) { auto type = curr->ref->type; - if (type == Type::unreachable) { + if (type == Type::unreachable || type.isNull()) { return; } diff --git a/src/literal.h b/src/literal.h index 318ab012a70..f6865e4a914 100644 --- a/src/literal.h +++ b/src/literal.h @@ -79,7 +79,9 @@ class Literal { explicit Literal(const std::array&); explicit Literal(const std::array&); explicit Literal(Name func, HeapType type) - : func(func), type(type, NonNullable) {} + : func(func), type(type, NonNullable) { + assert(type.isSignature()); + } explicit Literal(std::shared_ptr gcData, HeapType type); Literal(const Literal& other); Literal& operator=(const Literal& other); @@ -90,21 +92,8 @@ class Literal { bool isFunction() const { return type.isFunction(); } bool isData() const { return type.isData(); } - bool isNull() const { - if (type.isNullable()) { - if (type.isFunction()) { - return func.isNull(); - } - if (isData()) { - return !gcData; - } - if (type.getHeapType() == HeapType::i31) { - return i32 == 0; - } - return true; - } - return false; - } + bool isNull() const { return type.isRef() && type.getHeapType().isBottom(); } + bool isZero() const { switch (type.getBasic()) { case Type::i32: @@ -239,7 +228,7 @@ class Literal { } } static Literal makeNull(HeapType type) { - return Literal(Type(type, Nullable)); + return Literal(Type(type.getBottom(), Nullable)); } static Literal makeFunc(Name func, HeapType type) { return Literal(func, type); diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index c03b404b073..18324a395b1 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -32,6 +32,7 @@ #include "ir/branch-utils.h" #include "ir/debug.h" +#include "ir/drop.h" #include "ir/eh-utils.h" #include "ir/element-utils.h" #include "ir/literal-utils.h" @@ -251,6 +252,10 @@ struct Updater : public PostWalker { Name returnName; bool isReturn; Builder* builder; + PassOptions& options; + + Updater(PassOptions& options) : options(options) {} + void visitReturn(Return* curr) { replaceCurrent(builder->makeBreak(returnName, curr->value)); } @@ -259,7 +264,7 @@ struct Updater : public PostWalker { // achieve this, make the call a non-return call and add a break. This does // not cause unbounded stack growth because inlining and return calling both // avoid creating a new stack frame. - template void handleReturnCall(T* curr, HeapType targetType) { + template void handleReturnCall(T* curr, Type results) { if (isReturn) { // If the inlined callsite was already a return_call, then we can keep // return_calls in the inlined function rather than downgrading them. @@ -269,7 +274,7 @@ struct Updater : public PostWalker { return; } curr->isReturn = false; - curr->type = targetType.getSignature().results; + curr->type = results; if (curr->type.isConcrete()) { replaceCurrent(builder->makeBreak(returnName, curr)); } else { @@ -278,17 +283,26 @@ struct Updater : public PostWalker { } void visitCall(Call* curr) { if (curr->isReturn) { - handleReturnCall(curr, module->getFunction(curr->target)->type); + auto* func = module->getFunction(curr->target); + handleReturnCall(curr, func->type.getSignature().results); } } void visitCallIndirect(CallIndirect* curr) { if (curr->isReturn) { - handleReturnCall(curr, curr->heapType); + handleReturnCall(curr, curr->heapType.getSignature().results); } } void visitCallRef(CallRef* curr) { + Type targetType = curr->target->type; + if (targetType.isNull()) { + // We don't know what type the call should return, but we can't leave it + // as a potentially-invalid return_call_ref, either. + replaceCurrent(getDroppedChildrenAndAppend( + curr, *module, options, Builder(*module).makeUnreachable())); + return; + } if (curr->isReturn) { - handleReturnCall(curr, curr->target->type.getHeapType()); + handleReturnCall(curr, targetType.getHeapType().getSignature().results); } } void visitLocalGet(LocalGet* curr) { @@ -301,8 +315,10 @@ struct Updater : public PostWalker { // Core inlining logic. Modifies the outside function (adding locals as // needed), and returns the inlined code. -static Expression* -doInlining(Module* module, Function* into, const InliningAction& action) { +static Expression* doInlining(Module* module, + Function* into, + const InliningAction& action, + PassOptions& options) { Function* from = action.contents; auto* call = (*action.callSite)->cast(); // Works for return_call, too @@ -337,7 +353,7 @@ doInlining(Module* module, Function* into, const InliningAction& action) { *action.callSite = block; } // Prepare to update the inlined code's locals and other things. - Updater updater; + Updater updater(options); updater.module = module; updater.returnName = block->name; updater.isReturn = call->isReturn; @@ -1002,7 +1018,7 @@ struct Inlining : public Pass { action.contents = getActuallyInlinedFunction(action.contents); // Perform the inlining and update counts. - doInlining(module, func, action); + doInlining(module, func, action, getPassOptions()); inlinedUses[inlinedName]++; inlinedInto.insert(func); assert(inlinedUses[inlinedName] <= infos[inlinedName].refs); @@ -1116,7 +1132,8 @@ struct InlineMainPass : public Pass { // No call at all. return; } - doInlining(module, main, InliningAction(callSite, originalMain)); + doInlining( + module, main, InliningAction(callSite, originalMain), getPassOptions()); } }; diff --git a/src/passes/JSPI.cpp b/src/passes/JSPI.cpp index 9660b962d29..fe24d60f7a8 100644 --- a/src/passes/JSPI.cpp +++ b/src/passes/JSPI.cpp @@ -45,8 +45,10 @@ struct JSPI : public Pass { // Create a global to store the suspender that is passed into exported // functions and will then need to be passed out to the imported functions. Name suspender = Names::getValidGlobalName(*module, "suspender"); - module->addGlobal(builder.makeGlobal( - suspender, externref, builder.makeRefNull(externref), Builder::Mutable)); + module->addGlobal(builder.makeGlobal(suspender, + externref, + builder.makeRefNull(HeapType::noext), + Builder::Mutable)); // Keep track of already wrapped functions since they can be exported // multiple times, but only one wrapper is needed. diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 4ffd6be675d..9538d954e51 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1509,6 +1509,17 @@ struct OptimizeInstructions return getDroppedChildrenAndAppend(curr, result); } + bool trapOnNull(Expression* curr, Expression* ref) { + if (ref->type.isNull()) { + replaceCurrent(getDroppedChildrenAndAppend( + curr, Builder(*getModule()).makeUnreachable())); + // Propagate the unreachability. + refinalize = true; + return true; + } + return false; + } + void visitRefEq(RefEq* curr) { // The types may prove that the same reference cannot appear on both sides. auto leftType = curr->left->type; @@ -1564,10 +1575,16 @@ struct OptimizeInstructions } } - void visitStructGet(StructGet* curr) { skipNonNullCast(curr->ref); } + void visitStructGet(StructGet* curr) { + skipNonNullCast(curr->ref); + trapOnNull(curr, curr->ref); + } void visitStructSet(StructSet* curr) { skipNonNullCast(curr->ref); + if (trapOnNull(curr, curr->ref)) { + return; + } if (curr->ref->type != Type::unreachable && curr->value->type.isInteger()) { const auto& fields = curr->ref->type.getHeapType().getStruct().fields; @@ -1715,10 +1732,16 @@ struct OptimizeInstructions return true; } - void visitArrayGet(ArrayGet* curr) { skipNonNullCast(curr->ref); } + void visitArrayGet(ArrayGet* curr) { + skipNonNullCast(curr->ref); + trapOnNull(curr, curr->ref); + } void visitArraySet(ArraySet* curr) { skipNonNullCast(curr->ref); + if (trapOnNull(curr, curr->ref)) { + return; + } if (curr->ref->type != Type::unreachable && curr->value->type.isInteger()) { auto element = curr->ref->type.getHeapType().getArray().element; @@ -1726,11 +1749,15 @@ struct OptimizeInstructions } } - void visitArrayLen(ArrayLen* curr) { skipNonNullCast(curr->ref); } + void visitArrayLen(ArrayLen* curr) { + skipNonNullCast(curr->ref); + trapOnNull(curr, curr->ref); + } void visitArrayCopy(ArrayCopy* curr) { skipNonNullCast(curr->destRef); skipNonNullCast(curr->srcRef); + trapOnNull(curr, curr->destRef) || trapOnNull(curr, curr->srcRef); } bool canBeCastTo(HeapType a, HeapType b) { diff --git a/src/passes/Precompute.cpp b/src/passes/Precompute.cpp index 466614d14e6..c90fdf167cc 100644 --- a/src/passes/Precompute.cpp +++ b/src/passes/Precompute.cpp @@ -130,7 +130,7 @@ class PrecomputingExpressionRunner } Flow visitStructSet(StructSet* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitStructGet(StructGet* curr) { - if (curr->ref->type != Type::unreachable) { + if (curr->ref->type != Type::unreachable && !curr->ref->type.isNull()) { // If this field is immutable then we may be able to precompute this, as // if we also created the data in this function (or it was created in an // immutable global) then we know the value in the field. If it is @@ -164,7 +164,7 @@ class PrecomputingExpressionRunner } Flow visitArraySet(ArraySet* curr) { return Flow(NONCONSTANT_FLOW); } Flow visitArrayGet(ArrayGet* curr) { - if (curr->ref->type != Type::unreachable) { + if (curr->ref->type != Type::unreachable && !curr->ref->type.isNull()) { // See above with struct.get auto element = curr->ref->type.getHeapType().getArray().element; if (element.mutable_ == Immutable) { diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 01b004d97d9..7ebad332229 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -115,6 +115,15 @@ bool maybePrintRefShorthand(std::ostream& o, Type type) { case HeapType::stringview_iter: o << "stringview_iter"; return true; + case HeapType::none: + o << "nullref"; + return true; + case HeapType::noext: + o << "nullexternref"; + return true; + case HeapType::nofunc: + o << "nullfuncref"; + return true; } } return false; @@ -2058,10 +2067,17 @@ struct PrintExpressionContents } return false; } + bool printUnreachableOrNullReplacement(Expression* curr) { + if (curr->type == Type::unreachable || curr->type.isNull()) { + printMedium(o, "block"); + return true; + } + return false; + } void visitCallRef(CallRef* curr) { // TODO: Workaround if target has bottom type. - if (printUnreachableReplacement(curr->target)) { + if (printUnreachableOrNullReplacement(curr->target)) { return; } printMedium(o, curr->isReturn ? "return_call_ref " : "call_ref "); @@ -2144,7 +2160,7 @@ struct PrintExpressionContents }); } void visitStructGet(StructGet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } auto heapType = curr->ref->type.getHeapType(); @@ -2163,7 +2179,7 @@ struct PrintExpressionContents printFieldName(heapType, curr->index); } void visitStructSet(StructSet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } printMedium(o, "struct.set "); @@ -2192,7 +2208,7 @@ struct PrintExpressionContents TypeNamePrinter(o, wasm).print(curr->type.getHeapType()); } void visitArrayGet(ArrayGet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } const auto& element = curr->ref->type.getHeapType().getArray().element; @@ -2208,22 +2224,22 @@ struct PrintExpressionContents TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); } void visitArraySet(ArraySet* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } printMedium(o, "array.set "); TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); } void visitArrayLen(ArrayLen* curr) { - if (printUnreachableReplacement(curr->ref)) { + if (printUnreachableOrNullReplacement(curr->ref)) { return; } printMedium(o, "array.len "); TypeNamePrinter(o, wasm).print(curr->ref->type.getHeapType()); } void visitArrayCopy(ArrayCopy* curr) { - if (printUnreachableReplacement(curr->srcRef) || - printUnreachableReplacement(curr->destRef)) { + if (printUnreachableOrNullReplacement(curr->srcRef) || + printUnreachableOrNullReplacement(curr->destRef)) { return; } printMedium(o, "array.copy "); @@ -2746,19 +2762,29 @@ struct PrintSExpression : public UnifiedExpressionVisitor { drop.value = child; printFullLine(&drop); } + Unreachable unreachable; + printFullLine(&unreachable); decIndent(); } + // This must be used for the same Expressions that use + // PrintExpressionContents::printUnreachableOrNullReplacement. + void maybePrintUnreachableOrNullReplacement(Expression* curr, Type type) { + if (type.isNull()) { + type = Type::unreachable; + } + maybePrintUnreachableReplacement(curr, type); + } void visitCallRef(CallRef* curr) { - maybePrintUnreachableReplacement(curr, curr->target->type); + maybePrintUnreachableOrNullReplacement(curr, curr->target->type); } void visitStructNew(StructNew* curr) { maybePrintUnreachableReplacement(curr, curr->type); } void visitStructSet(StructSet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } void visitStructGet(StructGet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } void visitArrayNew(ArrayNew* curr) { maybePrintUnreachableReplacement(curr, curr->type); @@ -2767,10 +2793,13 @@ struct PrintSExpression : public UnifiedExpressionVisitor { maybePrintUnreachableReplacement(curr, curr->type); } void visitArraySet(ArraySet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } void visitArrayGet(ArrayGet* curr) { - maybePrintUnreachableReplacement(curr, curr->ref->type); + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); + } + void visitArrayLen(ArrayLen* curr) { + maybePrintUnreachableOrNullReplacement(curr, curr->ref->type); } // Module-level visitors void printSupertypeOr(HeapType curr, std::string noSuper) { diff --git a/src/passes/TypeRefining.cpp b/src/passes/TypeRefining.cpp index 6ce503cc09f..e9aa07ca617 100644 --- a/src/passes/TypeRefining.cpp +++ b/src/passes/TypeRefining.cpp @@ -251,7 +251,7 @@ struct TypeRefining : public Pass { } void visitStructGet(StructGet* curr) { - if (curr->ref->type == Type::unreachable) { + if (curr->ref->type == Type::unreachable || curr->ref->type.isNull()) { return; } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 2b368a4e87d..09df9ac31ac 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -1976,7 +1976,7 @@ Expression* TranslateToFuzzReader::makeRefFuncConst(Type type) { // to add a ref.as_non_null to validate, and the code will trap when we get // here). if ((type.isNullable() && oneIn(2)) || (type.isNonNullable() && oneIn(16))) { - Expression* ret = builder.makeRefNull(Type(heapType, Nullable)); + Expression* ret = builder.makeRefNull(HeapType::nofunc); if (!type.isNullable()) { ret = builder.makeRefAs(RefAsNonNull, ret); } @@ -2000,7 +2000,7 @@ Expression* TranslateToFuzzReader::makeConst(Type type) { assert(wasm.features.hasReferenceTypes()); // With a low chance, just emit a null if that is valid. if (type.isNullable() && oneIn(8)) { - return builder.makeRefNull(type); + return builder.makeRefNull(type.getHeapType()); } if (type.getHeapType().isBasic()) { return makeConstBasicRef(type); @@ -2050,7 +2050,7 @@ Expression* TranslateToFuzzReader::makeConstBasicRef(Type type) { // a subtype of anyref, but we cannot create constants of it, except // for null. assert(type.isNullable()); - return builder.makeRefNull(type); + return builder.makeRefNull(HeapType::none); } auto nullability = getSubType(type.getNullability()); // i31.new is not allowed in initializer expressions. @@ -2065,7 +2065,7 @@ Expression* TranslateToFuzzReader::makeConstBasicRef(Type type) { case HeapType::i31: { assert(wasm.features.hasGC()); if (type.isNullable() && oneIn(4)) { - return builder.makeRefNull(type); + return builder.makeRefNull(HeapType::none); } return builder.makeI31New(makeConst(Type::i32)); } @@ -2086,10 +2086,22 @@ Expression* TranslateToFuzzReader::makeConstBasicRef(Type type) { return builder.makeArrayInit(trivialArray, {}); } } - default: { - WASM_UNREACHABLE("invalid basic ref type"); + case HeapType::string: + case HeapType::stringview_wtf8: + case HeapType::stringview_wtf16: + case HeapType::stringview_iter: + WASM_UNREACHABLE("TODO: strings"); + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: { + auto null = builder.makeRefNull(heapType); + if (!type.isNullable()) { + return builder.makeRefAs(RefAsNonNull, null); + } + return null; } } + WASM_UNREACHABLE("invalid basic ref type"); } Expression* TranslateToFuzzReader::makeConstCompoundRef(Type type) { @@ -2104,15 +2116,14 @@ Expression* TranslateToFuzzReader::makeConstCompoundRef(Type type) { // We weren't able to directly materialize a non-null constant. Try again to // create a null. if (type.isNullable()) { - return builder.makeRefNull(type); + return builder.makeRefNull(heapType); } // We have to produce a non-null value. Possibly create a null and cast it // to non-null even though that will trap at runtime. We must have a // function context for this because the cast is not allowed in globals. if (funcContext) { - return builder.makeRefAs(RefAsNonNull, - builder.makeRefNull(Type(heapType, Nullable))); + return builder.makeRefAs(RefAsNonNull, builder.makeRefNull(heapType)); } // Otherwise, we are not in a function context. This can happen if we need @@ -3138,33 +3149,49 @@ Nullability TranslateToFuzzReader::getSubType(Nullability nullability) { } HeapType TranslateToFuzzReader::getSubType(HeapType type) { + if (oneIn(2)) { + return type; + } if (type.isBasic()) { switch (type.getBasic()) { case HeapType::func: // TODO: Typed function references. - return HeapType::func; + return pick(FeatureOptions() + .add(FeatureSet::ReferenceTypes, HeapType::func) + .add(FeatureSet::GC, HeapType::nofunc)); case HeapType::ext: - return HeapType::ext; + return pick(FeatureOptions() + .add(FeatureSet::ReferenceTypes, HeapType::ext) + .add(FeatureSet::GC, HeapType::noext)); case HeapType::any: // TODO: nontrivial types as well. assert(wasm.features.hasReferenceTypes()); assert(wasm.features.hasGC()); - return pick(HeapType::any, HeapType::eq, HeapType::i31, HeapType::data); + return pick(HeapType::any, + HeapType::eq, + HeapType::i31, + HeapType::data, + HeapType::none); case HeapType::eq: // TODO: nontrivial types as well. assert(wasm.features.hasReferenceTypes()); assert(wasm.features.hasGC()); - return pick(HeapType::eq, HeapType::i31, HeapType::data); + return pick( + HeapType::eq, HeapType::i31, HeapType::data, HeapType::none); case HeapType::i31: - return HeapType::i31; + return pick(HeapType::i31, HeapType::none); case HeapType::data: // TODO: nontrivial types as well. - return HeapType::data; + return pick(HeapType::data, HeapType::none); case HeapType::string: case HeapType::stringview_wtf8: case HeapType::stringview_wtf16: case HeapType::stringview_iter: WASM_UNREACHABLE("TODO: fuzz strings"); + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + break; } } // TODO: nontrivial types as well. diff --git a/src/tools/fuzzing/heap-types.cpp b/src/tools/fuzzing/heap-types.cpp index ad87c6fabb5..351035f939f 100644 --- a/src/tools/fuzzing/heap-types.cpp +++ b/src/tools/fuzzing/heap-types.cpp @@ -69,7 +69,7 @@ struct HeapTypeGeneratorImpl { typeIndices.insert({builder[i], i}); // Everything is a subtype of itself. subtypeIndices[i].push_back(i); - if (i < numRoots) { + if (i < numRoots || rand.oneIn(2)) { // This is a root type with no supertype. Choose a kind for this type. typeKinds.emplace_back(generateHeapTypeKind()); } else { @@ -148,6 +148,11 @@ struct HeapTypeGeneratorImpl { } HeapType::BasicHeapType generateBasicHeapType() { + // Choose bottom types more rarely. + if (rand.oneIn(16)) { + return rand.pick(HeapType::noext, HeapType::nofunc, HeapType::none); + } + // TODO: strings return rand.pick(HeapType::func, HeapType::ext, HeapType::any, @@ -254,6 +259,8 @@ struct HeapTypeGeneratorImpl { HeapType pickSubFunc() { if (auto type = pickKind()) { return *type; + } else if (rand.oneIn(2)) { + return HeapType::nofunc; } else { return HeapType::func; } @@ -262,6 +269,8 @@ struct HeapTypeGeneratorImpl { HeapType pickSubData() { if (auto type = pickKind()) { return *type; + } else if (rand.oneIn(2)) { + return HeapType::none; } else { return HeapType::data; } @@ -292,7 +301,7 @@ struct HeapTypeGeneratorImpl { // can only choose those defined before the end of the current recursion // group. std::vector candidateIndices; - for (auto i : subtypeIndices[typeIndices[type]]) { + for (auto i : subtypeIndices[it->second]) { if (i < recGroupEnds[index]) { candidateIndices.push_back(i); } @@ -301,6 +310,9 @@ struct HeapTypeGeneratorImpl { } else { // This is not a constructed type, so it must be a basic type. assert(type.isBasic()); + if (rand.oneIn(8)) { + return type.getBottom(); + } switch (type.getBasic()) { case HeapType::ext: return HeapType::ext; @@ -318,7 +330,10 @@ struct HeapTypeGeneratorImpl { case HeapType::stringview_wtf8: case HeapType::stringview_wtf16: case HeapType::stringview_iter: - WASM_UNREACHABLE("TODO: fuzz strings"); + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + return type; } WASM_UNREACHABLE("unexpected kind"); } @@ -403,6 +418,17 @@ struct HeapTypeGeneratorImpl { } HeapTypeKind getSubKind(HeapTypeKind super) { + if (rand.oneIn(16)) { + // Occasionally go directly to the bottom type. + if (auto* basic = std::get_if(&super)) { + return HeapType(*basic).getBottom(); + } else if (std::get_if(&super)) { + return HeapType::nofunc; + } else if (std::get_if(&super)) { + return HeapType::none; + } + WASM_UNREACHABLE("unexpected kind"); + } if (auto* basic = std::get_if(&super)) { if (rand.oneIn(8)) { return super; @@ -441,7 +467,10 @@ struct HeapTypeGeneratorImpl { case HeapType::stringview_wtf8: case HeapType::stringview_wtf16: case HeapType::stringview_iter: - WASM_UNREACHABLE("TODO: fuzz strings"); + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + return super; } WASM_UNREACHABLE("unexpected kind"); } else { diff --git a/src/tools/wasm-reduce.cpp b/src/tools/wasm-reduce.cpp index 6febcf6b907..557e8a770a6 100644 --- a/src/tools/wasm-reduce.cpp +++ b/src/tools/wasm-reduce.cpp @@ -1142,7 +1142,7 @@ struct Reducer } // try to replace with a trivial value if (curr->type.isNullable()) { - RefNull* n = builder->makeRefNull(curr->type); + RefNull* n = builder->makeRefNull(curr->type.getHeapType()); return tryToReplaceCurrent(n); } if (curr->type.isTuple() && curr->type.isDefaultable()) { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index b308abade73..39041c95e5e 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -381,6 +381,10 @@ enum EncodedType { stringview_wtf8 = -0x1d, // 0x63 stringview_wtf16 = -0x1e, // 0x62 stringview_iter = -0x1f, // 0x61 + // bottom types + nullexternref = -0x17, // 0x69 + nullfuncref = -0x18, // 0x68 + nullref = -0x1b, // 0x65 // type forms Func = -0x20, // 0x60 Struct = -0x21, // 0x5f @@ -410,6 +414,10 @@ enum EncodedHeapType { stringview_wtf8_heap = -0x1d, // 0x63 stringview_wtf16_heap = -0x1e, // 0x62 stringview_iter_heap = -0x1f, // 0x61 + // bottom types + noext = -0x17, // 0x69 + nofunc = -0x18, // 0x68 + none = -0x1b, // 0x65 }; namespace UserSections { diff --git a/src/wasm-builder.h b/src/wasm-builder.h index cc3b991384b..3572eaf60de 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -699,10 +699,11 @@ class Builder { } RefNull* makeRefNull(HeapType type) { auto* ret = wasm.allocator.alloc(); - ret->finalize(Type(type, Nullable)); + ret->finalize(Type(type.getBottom(), Nullable)); return ret; } RefNull* makeRefNull(Type type) { + assert(type.isNullable() && type.getHeapType().isBottom()); auto* ret = wasm.allocator.alloc(); ret->finalize(type); return ret; @@ -942,11 +943,14 @@ class Builder { ret->finalize(); return ret; } - ArrayGet* - makeArrayGet(Expression* ref, Expression* index, bool signed_ = false) { + ArrayGet* makeArrayGet(Expression* ref, + Expression* index, + Type type, + bool signed_ = false) { auto* ret = wasm.allocator.alloc(); ret->ref = ref; ret->index = index; + ret->type = type; ret->signed_ = signed_; ret->finalize(); return ret; @@ -1262,7 +1266,7 @@ class Builder { if (curr->type.isTuple() && curr->type.isDefaultable()) { return makeConstantExpression(Literal::makeZeros(curr->type)); } - if (curr->type.isNullable()) { + if (curr->type.isNullable() && curr->type.getHeapType().isBottom()) { return ExpressionManipulator::refNull(curr, curr->type); } if (curr->type.isRef() && curr->type.getHeapType() == HeapType::i31) { @@ -1329,18 +1333,24 @@ class ValidatingBuilder : public Builder { Expression* validateAndMakeCallRef(Expression* target, const T& args, bool isReturn = false) { - if (!target->type.isRef()) { - if (target->type == Type::unreachable) { - // An unreachable target is not supported. Similiar to br_on_cast, just - // emit an unreachable sequence, since we don't have enough information - // to create a full call_ref. - auto* block = makeBlock(args); - block->list.push_back(target); - block->finalize(Type::unreachable); - return block; - } + if (target->type != Type::unreachable && !target->type.isRef()) { throw ParseException("Non-reference type for a call_ref", line, col); } + // TODO: This won't be necessary once type annotations are mandatory on + // call_ref. + if (target->type == Type::unreachable || + target->type.getHeapType() == HeapType::nofunc) { + // An unreachable target is not supported. Similiar to br_on_cast, just + // emit an unreachable sequence, since we don't have enough information + // to create a full call_ref. + std::vector children; + for (auto* arg : args) { + children.push_back(makeDrop(arg)); + } + children.push_back(makeDrop(target)); + children.push_back(makeUnreachable()); + return makeBlock(children, Type::unreachable); + } auto heapType = target->type.getHeapType(); if (!heapType.isSignature()) { throw ParseException("Invalid reference type for a call_ref", line, col); diff --git a/src/wasm-type.h b/src/wasm-type.h index 940009cbe20..dbdbe3d317a 100644 --- a/src/wasm-type.h +++ b/src/wasm-type.h @@ -169,6 +169,8 @@ class Type { // is irrelevant. (For that reason, this is only the negation of isNullable() // on references, but both return false on non-references.) bool isNonNullable() const; + // Whether this type is only inhabited by null values. + bool isNull() const; bool isStruct() const; bool isArray() const; bool isDefaultable() const; @@ -326,8 +328,11 @@ class HeapType { stringview_wtf8, stringview_wtf16, stringview_iter, + none, + noext, + nofunc, }; - static constexpr BasicHeapType _last_basic_type = stringview_iter; + static constexpr BasicHeapType _last_basic_type = nofunc; // BasicHeapType can be implicitly upgraded to HeapType constexpr HeapType(BasicHeapType id) : id(id) {} @@ -358,6 +363,7 @@ class HeapType { bool isSignature() const; bool isStruct() const; bool isArray() const; + bool isBottom() const; Signature getSignature() const; const Struct& getStruct() const; @@ -371,6 +377,9 @@ class HeapType { // number of supertypes in its supertype chain. size_t getDepth() const; + // Get the bottom heap type for this heap type's hierarchy. + BasicHeapType getBottom() const; + // Get the recursion group for this non-basic type. RecGroup getRecGroup() const; size_t getRecGroupIndex() const; @@ -421,6 +430,8 @@ class HeapType { std::string toString() const; }; +inline bool Type::isNull() const { return isRef() && getHeapType().isBottom(); } + // A recursion group consisting of one or more HeapTypes. HeapTypes with single // members are encoded without using any additional memory, which is why // `getHeapTypes` has to return a vector by value; it might have to create one diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 43f40752587..9271aed8d71 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -44,19 +44,25 @@ Literal::Literal(Type type) : type(type) { memset(&v128, 0, 16); return; case Type::none: - return; case Type::unreachable: - break; + WASM_UNREACHABLE("Invalid literal type"); + return; } } - if (isData()) { - assert(!type.isNonNullable()); + if (type.isNull()) { + assert(type.isNullable()); new (&gcData) std::shared_ptr(); - } else { - // For anything else, zero out all the union data. - memset(&v128, 0, 16); + return; } + + if (type.isRef() && type.getHeapType() == HeapType::i31) { + assert(type.isNonNullable()); + i32 = 0; + return; + } + + WASM_UNREACHABLE("Unexpected literal type"); } Literal::Literal(const uint8_t init[16]) : type(Type::v128) { @@ -64,9 +70,9 @@ Literal::Literal(const uint8_t init[16]) : type(Type::v128) { } Literal::Literal(std::shared_ptr gcData, HeapType type) - : gcData(gcData), type(type, gcData ? NonNullable : Nullable) { + : gcData(gcData), type(type, NonNullable) { // The type must be a proper type for GC data. - assert(isData()); + assert((isData() && gcData) || (type.isBottom() && !gcData)); } Literal::Literal(const Literal& other) : type(other.type) { @@ -89,6 +95,10 @@ Literal::Literal(const Literal& other) : type(other.type) { break; } } + if (other.isNull()) { + new (&gcData) std::shared_ptr(); + return; + } if (other.isData()) { new (&gcData) std::shared_ptr(other.gcData); return; @@ -98,23 +108,30 @@ Literal::Literal(const Literal& other) : type(other.type) { return; } if (type.isRef()) { + assert(!type.isNullable()); auto heapType = type.getHeapType(); if (heapType.isBasic()) { switch (heapType.getBasic()) { - case HeapType::ext: - case HeapType::any: - case HeapType::eq: - return; // null case HeapType::i31: i32 = other.i32; return; + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + // Null + return; + case HeapType::ext: + case HeapType::any: + WASM_UNREACHABLE("TODO: extern literals"); + case HeapType::eq: case HeapType::func: case HeapType::data: + WASM_UNREACHABLE("invalid type"); case HeapType::string: case HeapType::stringview_wtf8: case HeapType::stringview_wtf16: case HeapType::stringview_iter: - WASM_UNREACHABLE("invalid type"); + WASM_UNREACHABLE("TODO: string literals"); } } } @@ -125,7 +142,7 @@ Literal::~Literal() { if (type.isBasic()) { return; } - if (isData()) { + if (isNull() || isData()) { gcData.~shared_ptr(); } } @@ -239,7 +256,7 @@ std::array Literal::getv128() const { } std::shared_ptr Literal::getGCData() const { - assert(isData()); + assert(isNull() || isData()); return gcData; } @@ -463,52 +480,8 @@ void Literal::printVec128(std::ostream& o, const std::array& v) { std::ostream& operator<<(std::ostream& o, Literal literal) { prepareMinorColor(o); - if (literal.type.isFunction()) { - if (literal.isNull()) { - o << "funcref(null)"; - } else { - o << "funcref(" << literal.getFunc() << ")"; - } - } else if (literal.type.isRef()) { - if (literal.isData()) { - auto data = literal.getGCData(); - if (data) { - o << "[ref " << data->type << ' ' << data->values << ']'; - } else { - o << "[ref null " << literal.type << ']'; - } - } else { - switch (literal.type.getHeapType().getBasic()) { - case HeapType::ext: - assert(literal.isNull() && "unexpected non-null externref literal"); - o << "externref(null)"; - break; - case HeapType::any: - assert(literal.isNull() && "unexpected non-null anyref literal"); - o << "anyref(null)"; - break; - case HeapType::eq: - assert(literal.isNull() && "unexpected non-null eqref literal"); - o << "eqref(null)"; - break; - case HeapType::i31: - if (literal.isNull()) { - o << "i31ref(null)"; - } else { - o << "i31ref(" << literal.geti31() << ")"; - } - break; - case HeapType::func: - case HeapType::data: - case HeapType::string: - case HeapType::stringview_wtf8: - case HeapType::stringview_wtf16: - case HeapType::stringview_iter: - WASM_UNREACHABLE("type should have been handled above"); - } - } - } else { - TODO_SINGLE_COMPOUND(literal.type); + assert(literal.type.isSingle()); + if (literal.type.isBasic()) { switch (literal.type.getBasic()) { case Type::none: o << "?"; @@ -532,6 +505,44 @@ std::ostream& operator<<(std::ostream& o, Literal literal) { case Type::unreachable: WASM_UNREACHABLE("unexpected type"); } + } else { + assert(literal.type.isRef()); + auto heapType = literal.type.getHeapType(); + if (heapType.isBasic()) { + switch (heapType.getBasic()) { + case HeapType::i31: + o << "i31ref(" << literal.geti31() << ")"; + break; + case HeapType::none: + o << "nullref"; + break; + case HeapType::noext: + o << "nullexternref"; + break; + case HeapType::nofunc: + o << "nullfuncref"; + break; + case HeapType::ext: + case HeapType::any: + WASM_UNREACHABLE("TODO: extern literals"); + case HeapType::eq: + case HeapType::func: + case HeapType::data: + WASM_UNREACHABLE("invalid type"); + case HeapType::string: + case HeapType::stringview_wtf8: + case HeapType::stringview_wtf16: + case HeapType::stringview_iter: + WASM_UNREACHABLE("TODO: string literals"); + } + } else if (heapType.isSignature()) { + o << "funcref(" << literal.getFunc() << ")"; + } else { + assert(literal.isData()); + auto data = literal.getGCData(); + assert(data); + o << "[ref " << data->type << ' ' << data->values << ']'; + } } restoreNormalColor(o); return o; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 4e5db69b17c..0334d43847c 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1424,6 +1424,25 @@ void WasmBinaryWriter::writeType(Type type) { case HeapType::stringview_iter: o << S32LEB(BinaryConsts::EncodedType::stringview_iter); return; + case HeapType::none: + o << S32LEB(BinaryConsts::EncodedType::nullref); + return; + case HeapType::noext: + // See comment on writeHeapType. + if (!wasm->features.hasGC()) { + o << S32LEB(BinaryConsts::EncodedType::externref); + } else { + o << S32LEB(BinaryConsts::EncodedType::nullexternref); + } + return; + case HeapType::nofunc: + // See comment on writeHeapType. + if (!wasm->features.hasGC()) { + o << S32LEB(BinaryConsts::EncodedType::funcref); + } else { + o << S32LEB(BinaryConsts::EncodedType::nullfuncref); + } + return; } } if (type.isNullable()) { @@ -1463,46 +1482,63 @@ void WasmBinaryWriter::writeType(Type type) { } void WasmBinaryWriter::writeHeapType(HeapType type) { + // ref.null always has a bottom heap type in Binaryen IR, but those types are + // only actually valid with GC enabled. When GC is not enabled, emit the + // corresponding valid top types instead. + if (!wasm->features.hasGC()) { + if (type == HeapType::nofunc || type.isSignature()) { + type = HeapType::func; + } else if (type == HeapType::noext) { + type = HeapType::ext; + } + } + if (type.isSignature() || type.isStruct() || type.isArray()) { o << S64LEB(getTypeIndex(type)); // TODO: Actually s33 return; } int ret = 0; - if (type.isBasic()) { - switch (type.getBasic()) { - case HeapType::ext: - ret = BinaryConsts::EncodedHeapType::ext; - break; - case HeapType::func: - ret = BinaryConsts::EncodedHeapType::func; - break; - case HeapType::any: - ret = BinaryConsts::EncodedHeapType::any; - break; - case HeapType::eq: - ret = BinaryConsts::EncodedHeapType::eq; - break; - case HeapType::i31: - ret = BinaryConsts::EncodedHeapType::i31; - break; - case HeapType::data: - ret = BinaryConsts::EncodedHeapType::data; - break; - case HeapType::string: - ret = BinaryConsts::EncodedHeapType::string; - break; - case HeapType::stringview_wtf8: - ret = BinaryConsts::EncodedHeapType::stringview_wtf8_heap; - break; - case HeapType::stringview_wtf16: - ret = BinaryConsts::EncodedHeapType::stringview_wtf16_heap; - break; - case HeapType::stringview_iter: - ret = BinaryConsts::EncodedHeapType::stringview_iter_heap; - break; - } - } else { - WASM_UNREACHABLE("TODO: compound GC types"); + assert(type.isBasic()); + switch (type.getBasic()) { + case HeapType::ext: + ret = BinaryConsts::EncodedHeapType::ext; + break; + case HeapType::func: + ret = BinaryConsts::EncodedHeapType::func; + break; + case HeapType::any: + ret = BinaryConsts::EncodedHeapType::any; + break; + case HeapType::eq: + ret = BinaryConsts::EncodedHeapType::eq; + break; + case HeapType::i31: + ret = BinaryConsts::EncodedHeapType::i31; + break; + case HeapType::data: + ret = BinaryConsts::EncodedHeapType::data; + break; + case HeapType::string: + ret = BinaryConsts::EncodedHeapType::string; + break; + case HeapType::stringview_wtf8: + ret = BinaryConsts::EncodedHeapType::stringview_wtf8_heap; + break; + case HeapType::stringview_wtf16: + ret = BinaryConsts::EncodedHeapType::stringview_wtf16_heap; + break; + case HeapType::stringview_iter: + ret = BinaryConsts::EncodedHeapType::stringview_iter_heap; + break; + case HeapType::none: + ret = BinaryConsts::EncodedHeapType::none; + break; + case HeapType::noext: + ret = BinaryConsts::EncodedHeapType::noext; + break; + case HeapType::nofunc: + ret = BinaryConsts::EncodedHeapType::nofunc; + break; } o << S64LEB(ret); // TODO: Actually s33 } @@ -1862,6 +1898,15 @@ bool WasmBinaryBuilder::getBasicType(int32_t code, Type& out) { case BinaryConsts::EncodedType::stringview_iter: out = Type(HeapType::stringview_iter, Nullable); return true; + case BinaryConsts::EncodedType::nullref: + out = Type(HeapType::none, Nullable); + return true; + case BinaryConsts::EncodedType::nullexternref: + out = Type(HeapType::noext, Nullable); + return true; + case BinaryConsts::EncodedType::nullfuncref: + out = Type(HeapType::nofunc, Nullable); + return true; default: return false; } @@ -1899,6 +1944,15 @@ bool WasmBinaryBuilder::getBasicHeapType(int64_t code, HeapType& out) { case BinaryConsts::EncodedHeapType::stringview_iter_heap: out = HeapType::stringview_iter; return true; + case BinaryConsts::EncodedHeapType::none: + out = HeapType::none; + return true; + case BinaryConsts::EncodedHeapType::noext: + out = HeapType::noext; + return true; + case BinaryConsts::EncodedHeapType::nofunc: + out = HeapType::nofunc; + return true; default: return false; } @@ -2844,7 +2898,12 @@ void WasmBinaryBuilder::skipUnreachableCode() { expressionStack = savedStack; return; } - pushExpression(curr); + if (curr->type == Type::unreachable) { + // Don't want to pop back past the unreachable. + expressionStack.clear(); + } else { + pushExpression(curr); + } } } @@ -6525,7 +6584,7 @@ void WasmBinaryBuilder::visitDrop(Drop* curr) { void WasmBinaryBuilder::visitRefNull(RefNull* curr) { BYN_TRACE("zz node: RefNull\n"); - curr->finalize(getHeapType()); + curr->finalize(getHeapType().getBottom()); } void WasmBinaryBuilder::visitRefIs(RefIs* curr, uint8_t code) { @@ -6936,28 +6995,29 @@ bool WasmBinaryBuilder::maybeVisitStructNew(Expression*& out, uint32_t code) { } bool WasmBinaryBuilder::maybeVisitStructGet(Expression*& out, uint32_t code) { - StructGet* curr; + bool signed_ = false; switch (code) { case BinaryConsts::StructGet: - curr = allocator.alloc(); + case BinaryConsts::StructGetU: break; case BinaryConsts::StructGetS: - curr = allocator.alloc(); - curr->signed_ = true; - break; - case BinaryConsts::StructGetU: - curr = allocator.alloc(); - curr->signed_ = false; + signed_ = true; break; default: return false; } auto heapType = getIndexedHeapType(); - curr->index = getU32LEB(); - curr->ref = popNonVoidExpression(); - validateHeapTypeUsingChild(curr->ref, heapType); - curr->finalize(); - out = curr; + if (!heapType.isStruct()) { + throwError("Expected struct heaptype"); + } + auto index = getU32LEB(); + if (index >= heapType.getStruct().fields.size()) { + throwError("Struct field index out of bounds"); + } + auto type = heapType.getStruct().fields[index].type; + auto ref = popNonVoidExpression(); + validateHeapTypeUsingChild(ref, heapType); + out = Builder(wasm).makeStructGet(index, ref, type, signed_); return true; } @@ -7017,10 +7077,14 @@ bool WasmBinaryBuilder::maybeVisitArrayGet(Expression*& out, uint32_t code) { return false; } auto heapType = getIndexedHeapType(); + if (!heapType.isArray()) { + throwError("Expected array heaptype"); + } + auto type = heapType.getArray().element.type; auto* index = popNonVoidExpression(); auto* ref = popNonVoidExpression(); validateHeapTypeUsingChild(ref, heapType); - out = Builder(wasm).makeArrayGet(ref, index, signed_); + out = Builder(wasm).makeArrayGet(ref, index, type, signed_); return true; } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 6de8744a678..b2341907172 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -1196,6 +1196,15 @@ Type SExpressionWasmBuilder::stringToType(const char* str, if (strncmp(str, "stringview_iter", 15) == 0 && (prefix || str[15] == 0)) { return Type(HeapType::stringview_iter, Nullable); } + if (strncmp(str, "nullref", 7) == 0 && (prefix || str[7] == 0)) { + return Type(HeapType::none, Nullable); + } + if (strncmp(str, "nullexternref", 13) == 0 && (prefix || str[13] == 0)) { + return Type(HeapType::noext, Nullable); + } + if (strncmp(str, "nullfuncref", 11) == 0 && (prefix || str[11] == 0)) { + return Type(HeapType::nofunc, Nullable); + } if (allowError) { return Type::none; } @@ -1249,6 +1258,17 @@ HeapType SExpressionWasmBuilder::stringToHeapType(const char* str, return HeapType::stringview_iter; } } + if (str[0] == 'n') { + if (strncmp(str, "none", 4) == 0 && (prefix || str[4] == 0)) { + return HeapType::none; + } + if (strncmp(str, "noextern", 8) == 0 && (prefix || str[8] == 0)) { + return HeapType::noext; + } + if (strncmp(str, "nofunc", 6) == 0 && (prefix || str[6] == 0)) { + return HeapType::nofunc; + } + } throw ParseException(std::string("invalid wasm heap type: ") + str); } @@ -2615,9 +2635,9 @@ Expression* SExpressionWasmBuilder::makeRefNull(Element& s) { // (ref.null func), or it may be the name of a defined type, such as // (ref.null $struct.FOO) if (s[1]->dollared()) { - ret->finalize(parseHeapType(*s[1])); + ret->finalize(parseHeapType(*s[1]).getBottom()); } else { - ret->finalize(stringToHeapType(s[1]->str())); + ret->finalize(stringToHeapType(s[1]->str()).getBottom()); } return ret; } @@ -2990,10 +3010,14 @@ Expression* SExpressionWasmBuilder::makeArrayInitStatic(Element& s) { Expression* SExpressionWasmBuilder::makeArrayGet(Element& s, bool signed_) { auto heapType = parseHeapType(*s[1]); + if (!heapType.isArray()) { + throw ParseException("bad array heap type", s.line, s.col); + } auto ref = parseExpression(*s[2]); + auto type = heapType.getArray().element.type; validateHeapTypeUsingChild(ref, heapType, s); auto index = parseExpression(*s[3]); - return Builder(wasm).makeArrayGet(ref, index, signed_); + return Builder(wasm).makeArrayGet(ref, index, type, signed_); } Expression* SExpressionWasmBuilder::makeArraySet(Element& s) { diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 71bc989289b..13d85d33845 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2014,7 +2014,10 @@ void BinaryInstWriter::visitI31Get(I31Get* curr) { void BinaryInstWriter::visitCallRef(CallRef* curr) { assert(curr->target->type != Type::unreachable); - // TODO: `emitUnreachable` if target has bottom type. + if (curr->target->type.isNull()) { + emitUnreachable(); + return; + } o << int8_t(curr->isReturn ? BinaryConsts::RetCallRef : BinaryConsts::CallRef); parent.writeIndexedHeapType(curr->target->type.getHeapType()); @@ -2090,6 +2093,10 @@ void BinaryInstWriter::visitStructNew(StructNew* curr) { } void BinaryInstWriter::visitStructGet(StructGet* curr) { + if (curr->ref->type.isNull()) { + emitUnreachable(); + return; + } const auto& heapType = curr->ref->type.getHeapType(); const auto& field = heapType.getStruct().fields[curr->index]; int8_t op; @@ -2106,6 +2113,10 @@ void BinaryInstWriter::visitStructGet(StructGet* curr) { } void BinaryInstWriter::visitStructSet(StructSet* curr) { + if (curr->ref->type.isNull()) { + emitUnreachable(); + return; + } o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::StructSet); parent.writeIndexedHeapType(curr->ref->type.getHeapType()); o << U32LEB(curr->index); @@ -2129,6 +2140,10 @@ void BinaryInstWriter::visitArrayInit(ArrayInit* curr) { } void BinaryInstWriter::visitArrayGet(ArrayGet* curr) { + if (curr->ref->type.isNull()) { + emitUnreachable(); + return; + } auto heapType = curr->ref->type.getHeapType(); const auto& field = heapType.getArray().element; int8_t op; @@ -2144,16 +2159,28 @@ void BinaryInstWriter::visitArrayGet(ArrayGet* curr) { } void BinaryInstWriter::visitArraySet(ArraySet* curr) { + if (curr->ref->type.isNull()) { + emitUnreachable(); + return; + } o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArraySet); parent.writeIndexedHeapType(curr->ref->type.getHeapType()); } void BinaryInstWriter::visitArrayLen(ArrayLen* curr) { + if (curr->ref->type.isNull()) { + emitUnreachable(); + return; + } o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArrayLen); parent.writeIndexedHeapType(curr->ref->type.getHeapType()); } void BinaryInstWriter::visitArrayCopy(ArrayCopy* curr) { + if (curr->srcRef->type.isNull() || curr->destRef->type.isNull()) { + emitUnreachable(); + return; + } o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArrayCopy); parent.writeIndexedHeapType(curr->destRef->type.getHeapType()); parent.writeIndexedHeapType(curr->srcRef->type.getHeapType()); diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index d24e42acb45..a6a89323254 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -578,6 +578,15 @@ std::optional getBasicHeapTypeLUB(HeapType::BasicHeapType a, if (a == b) { return a; } + if (HeapType(a).getBottom() != HeapType(b).getBottom()) { + return {}; + } + if (HeapType(a).isBottom()) { + return b; + } + if (HeapType(b).isBottom()) { + return a; + } // Canonicalize to have `a` be the lesser type. if (unsigned(a) > unsigned(b)) { std::swap(a, b); @@ -604,6 +613,11 @@ std::optional getBasicHeapTypeLUB(HeapType::BasicHeapType a, case HeapType::stringview_wtf16: case HeapType::stringview_iter: return {HeapType::any}; + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + // Bottom types already handled. + break; } WASM_UNREACHABLE("unexpected basic type"); } @@ -1085,6 +1099,12 @@ FeatureSet Type::getFeatures() const { case HeapType::stringview_wtf16: case HeapType::stringview_iter: return FeatureSet::ReferenceTypes | FeatureSet::Strings; + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: + // Technically introduced in GC, but used internally as part of + // ref.null with just reference types. + return FeatureSet::ReferenceTypes; } } // Note: Technically typed function references also require the typed @@ -1360,6 +1380,29 @@ bool HeapType::isArray() const { } } +bool HeapType::isBottom() const { + if (isBasic()) { + switch (getBasic()) { + case ext: + case func: + case any: + case eq: + case i31: + case data: + case string: + case stringview_wtf8: + case stringview_wtf16: + case stringview_iter: + return false; + case none: + case noext: + case nofunc: + return true; + } + } + return false; +} + Signature HeapType::getSignature() const { assert(isSignature()); return getHeapTypeInfo(*this)->signature; @@ -1420,11 +1463,52 @@ size_t HeapType::getDepth() const { case HeapType::stringview_iter: depth += 2; break; + case HeapType::none: + case HeapType::nofunc: + case HeapType::noext: + // Bottom types are infinitely deep. + depth = size_t(-1l); } } return depth; } +HeapType::BasicHeapType HeapType::getBottom() const { + if (isBasic()) { + switch (getBasic()) { + case ext: + return noext; + case func: + return nofunc; + case any: + case eq: + case i31: + case data: + case string: + case stringview_wtf8: + case stringview_wtf16: + case stringview_iter: + case none: + return none; + case noext: + return noext; + case nofunc: + return nofunc; + } + } + auto* info = getHeapTypeInfo(*this); + switch (info->kind) { + case HeapTypeInfo::BasicKind: + return HeapType(info->basic).getBottom(); + case HeapTypeInfo::SignatureKind: + return nofunc; + case HeapTypeInfo::StructKind: + case HeapTypeInfo::ArrayKind: + return none; + } + WASM_UNREACHABLE("unexpected kind"); +} + bool HeapType::isSubType(HeapType left, HeapType right) { // As an optimization, in the common case do not even construct a SubTyper. if (left == right) { @@ -1451,6 +1535,15 @@ std::optional HeapType::getLeastUpperBound(HeapType a, HeapType b) { if (a == b) { return a; } + if (a.getBottom() != b.getBottom()) { + return {}; + } + if (a.isBottom()) { + return b; + } + if (b.isBottom()) { + return a; + } if (getTypeSystem() == TypeSystem::Equirecursive) { return TypeBounder().getLeastUpperBound(a, b); } @@ -1653,27 +1746,34 @@ bool SubTyper::isSubType(HeapType a, HeapType b) { if (b.isBasic()) { switch (b.getBasic()) { case HeapType::ext: - return a == HeapType::ext; + return a == HeapType::noext; case HeapType::func: - return a.isSignature(); + return a == HeapType::nofunc || a.isSignature(); case HeapType::any: - return a != HeapType::ext && !a.isFunction(); + return a == HeapType::eq || a == HeapType::i31 || a == HeapType::data || + a == HeapType::none || a.isData(); case HeapType::eq: - return a == HeapType::i31 || a.isData(); + return a == HeapType::i31 || a == HeapType::data || + a == HeapType::none || a.isData(); case HeapType::i31: - return false; + return a == HeapType::none; case HeapType::data: - return a.isData(); + return a == HeapType::none || a.isData(); case HeapType::string: case HeapType::stringview_wtf8: case HeapType::stringview_wtf16: case HeapType::stringview_iter: + return a == HeapType::none; + case HeapType::none: + case HeapType::noext: + case HeapType::nofunc: return false; } } if (a.isBasic()) { - // Basic HeapTypes are never subtypes of compound HeapTypes. - return false; + // Basic HeapTypes are only subtypes of compound HeapTypes if they are + // bottom types. + return a == b.getBottom(); } if (typeSystem == TypeSystem::Nominal || typeSystem == TypeSystem::Isorecursive) { @@ -1823,6 +1923,15 @@ std::optional TypeBounder::lub(HeapType a, HeapType b) { if (a == b) { return a; } + if (a.getBottom() != b.getBottom()) { + return {}; + } + if (a.isBottom()) { + return b; + } + if (b.isBottom()) { + return a; + } if (a.isBasic() || b.isBasic()) { return getBasicHeapTypeLUB(getBasicHeapSupertype(a), @@ -2000,12 +2109,18 @@ std::ostream& TypePrinter::print(Type type) { // Print shorthands for certain basic heap types. if (type.isNullable()) { switch (heapType.getBasic()) { + case HeapType::ext: + return os << "externref"; case HeapType::func: return os << "funcref"; case HeapType::any: return os << "anyref"; case HeapType::eq: return os << "eqref"; + case HeapType::i31: + return os << "i31ref"; + case HeapType::data: + return os << "dataref"; case HeapType::string: return os << "stringref"; case HeapType::stringview_wtf8: @@ -2014,17 +2129,12 @@ std::ostream& TypePrinter::print(Type type) { return os << "stringview_wtf16"; case HeapType::stringview_iter: return os << "stringview_iter"; - default: - break; - } - } else { - switch (heapType.getBasic()) { - case HeapType::i31: - return os << "i31ref"; - case HeapType::data: - return os << "dataref"; - default: - break; + case HeapType::none: + return os << "nullref"; + case HeapType::noext: + return os << "nullexternref"; + case HeapType::nofunc: + return os << "nullfuncref"; } } } @@ -2063,6 +2173,12 @@ std::ostream& TypePrinter::print(HeapType type) { return os << "stringview_wtf16"; case HeapType::stringview_iter: return os << "stringview_iter"; + case HeapType::none: + return os << "none"; + case HeapType::noext: + return os << "noextern"; + case HeapType::nofunc: + return os << "nofunc"; } } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 5e3fdc6e724..b7afed1e71e 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2079,6 +2079,10 @@ void FunctionValidator::visitSelect(Select* curr) { } void FunctionValidator::visitDrop(Drop* curr) { + if (!curr->value->type.isConcrete() && + curr->value->type != Type::unreachable) { + assert(false); + } shouldBeTrue(curr->value->type.isConcrete() || curr->value->type == Type::unreachable, curr, @@ -2110,13 +2114,13 @@ void FunctionValidator::visitRefNull(RefNull* curr) { shouldBeTrue(!getFunction() || getModule()->features.hasReferenceTypes(), curr, "ref.null requires reference-types to be enabled"); - shouldBeTrue( - curr->type.isNullable(), curr, "ref.null types must be nullable"); - - // The type of the null must also be valid for the features. - shouldBeTrue(curr->type.getFeatures() <= getModule()->features, - curr->type, - "ref.null type should be allowed"); + if (!shouldBeTrue( + curr->type.isNullable(), curr, "ref.null types must be nullable")) { + return; + } + shouldBeTrue(curr->type.getHeapType().isBottom(), + curr, + "ref.null must have a bottom heap type"); } void FunctionValidator::visitRefIs(RefIs* curr) { @@ -2454,12 +2458,15 @@ void FunctionValidator::visitCallRef(CallRef* curr) { validateReturnCall(curr); shouldBeTrue( getModule()->features.hasGC(), curr, "call_ref requires gc to be enabled"); - if (curr->target->type != Type::unreachable) { - if (shouldBeTrue(curr->target->type.isFunction(), - curr, - "call_ref target must be a function reference")) { - validateCallParamsAndResult(curr, curr->target->type.getHeapType()); - } + if (curr->target->type == Type::unreachable || + (curr->target->type.isRef() && + curr->target->type.getHeapType() == HeapType::nofunc)) { + return; + } + if (shouldBeTrue(curr->target->type.isFunction(), + curr, + "call_ref target must be a function reference")) { + validateCallParamsAndResult(curr, curr->target->type.getHeapType()); } } @@ -2580,7 +2587,7 @@ void FunctionValidator::visitStructGet(StructGet* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, "struct.get requires gc to be enabled"); - if (curr->ref->type == Type::unreachable) { + if (curr->type == Type::unreachable || curr->ref->type.isNull()) { return; } if (!shouldBeTrue(curr->ref->type.isStruct(), @@ -2610,22 +2617,28 @@ void FunctionValidator::visitStructSet(StructSet* curr) { if (curr->ref->type == Type::unreachable) { return; } - if (!shouldBeTrue(curr->ref->type.isStruct(), + if (!shouldBeTrue(curr->ref->type.isRef(), curr->ref, - "struct.set ref must be a struct")) { + "struct.set ref must be a reference type")) { return; } - if (curr->ref->type != Type::unreachable) { - const auto& fields = curr->ref->type.getHeapType().getStruct().fields; - shouldBeTrue(curr->index < fields.size(), curr, "bad struct.get field"); - auto& field = fields[curr->index]; - shouldBeSubType(curr->value->type, - field.type, - curr, - "struct.set must have the proper type"); - shouldBeEqual( - field.mutable_, Mutable, curr, "struct.set field must be mutable"); + auto type = curr->ref->type.getHeapType(); + if (type == HeapType::none) { + return; } + if (!shouldBeTrue( + type.isStruct(), curr->ref, "struct.set ref must be a struct")) { + return; + } + const auto& fields = type.getStruct().fields; + shouldBeTrue(curr->index < fields.size(), curr, "bad struct.get field"); + auto& field = fields[curr->index]; + shouldBeSubType(curr->value->type, + field.type, + curr, + "struct.set must have the proper type"); + shouldBeEqual( + field.mutable_, Mutable, curr, "struct.set field must be mutable"); } void FunctionValidator::visitArrayNew(ArrayNew* curr) { @@ -2688,7 +2701,18 @@ void FunctionValidator::visitArrayGet(ArrayGet* curr) { if (curr->type == Type::unreachable) { return; } - const auto& element = curr->ref->type.getHeapType().getArray().element; + // TODO: array rather than data once we've implemented that. + if (!shouldBeSubType(curr->ref->type, + Type(HeapType::data, Nullable), + curr, + "array.get target should be an array reference")) { + return; + } + auto heapType = curr->ref->type.getHeapType(); + if (heapType == HeapType::none) { + return; + } + const auto& element = heapType.getArray().element; // If the type is not packed, it must be marked internally as unsigned, by // convention. if (element.type != Type::i32 || element.packedType == Field::not_packed) { @@ -2706,6 +2730,17 @@ void FunctionValidator::visitArraySet(ArraySet* curr) { if (curr->type == Type::unreachable) { return; } + // TODO: array rather than data once we've implemented that. + if (!shouldBeSubType(curr->ref->type, + Type(HeapType::data, Nullable), + curr, + "array.set target should be an array reference")) { + return; + } + auto heapType = curr->ref->type.getHeapType(); + if (heapType == HeapType::none) { + return; + } const auto& element = curr->ref->type.getHeapType().getArray().element; shouldBeSubType(curr->value->type, element.type, @@ -2736,9 +2771,23 @@ void FunctionValidator::visitArrayCopy(ArrayCopy* curr) { if (curr->type == Type::unreachable) { return; } - const auto& srcElement = curr->srcRef->type.getHeapType().getArray().element; - const auto& destElement = - curr->destRef->type.getHeapType().getArray().element; + if (!shouldBeSubType(curr->srcRef->type, + Type(HeapType::data, Nullable), + curr, + "array.copy source should be an array reference") || + !shouldBeSubType(curr->destRef->type, + Type(HeapType::data, Nullable), + curr, + "array.copy destination should be an array reference")) { + return; + } + auto srcHeapType = curr->srcRef->type.getHeapType(); + auto destHeapType = curr->destRef->type.getHeapType(); + if (srcHeapType == HeapType::none || destHeapType == HeapType::none) { + return; + } + const auto& srcElement = srcHeapType.getArray().element; + const auto& destElement = destHeapType.getArray().element; shouldBeSubType(srcElement.type, destElement.type, curr, diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 724fc12e2a0..27690f43ecc 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -796,7 +796,10 @@ void MemoryGrow::finalize() { } } -void RefNull::finalize(HeapType heapType) { type = Type(heapType, Nullable); } +void RefNull::finalize(HeapType heapType) { + assert(heapType.isBottom()); + type = Type(heapType, Nullable); +} void RefNull::finalize(Type type_) { type = type_; } @@ -1033,7 +1036,7 @@ void StructNew::finalize() { void StructGet::finalize() { if (ref->type == Type::unreachable) { type = Type::unreachable; - } else { + } else if (!ref->type.isNull()) { type = ref->type.getHeapType().getStruct().fields[index].type; } } @@ -1066,7 +1069,7 @@ void ArrayInit::finalize() { void ArrayGet::finalize() { if (ref->type == Type::unreachable || index->type == Type::unreachable) { type = Type::unreachable; - } else { + } else if (!ref->type.isNull()) { type = ref->type.getHeapType().getArray().element.type; } } diff --git a/test/ctor-eval/bad-indirect-call3.wast.out b/test/ctor-eval/bad-indirect-call3.wast.out index 4b470e10a94..2f3cd9709df 100644 --- a/test/ctor-eval/bad-indirect-call3.wast.out +++ b/test/ctor-eval/bad-indirect-call3.wast.out @@ -15,7 +15,7 @@ ) (func $sig_mismatch (call_indirect $0 (type $funcref_=>_none) - (ref.null func) + (ref.null nofunc) (i32.const 0) ) ) diff --git a/test/ctor-eval/gc.wast.out b/test/ctor-eval/gc.wast.out index e1520f12b11..45e5ff5ca54 100644 --- a/test/ctor-eval/gc.wast.out +++ b/test/ctor-eval/gc.wast.out @@ -32,7 +32,7 @@ (global.get $ctor-eval$global_0) ) (call $import - (ref.null $struct) + (ref.null none) ) (call $import (local.get $0) diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c index bc6b4b873a8..251aa3b90cb 100644 --- a/test/example/c-api-kitchen-sink.c +++ b/test/example/c-api-kitchen-sink.c @@ -431,9 +431,9 @@ void test_core() { temp15 = makeInt32(module, 110), temp16 = makeInt64(module, 111); BinaryenExpressionRef externrefExpr = - BinaryenRefNull(module, BinaryenTypeExternref()); + BinaryenRefNull(module, BinaryenTypeNullExternref()); BinaryenExpressionRef funcrefExpr = - BinaryenRefNull(module, BinaryenTypeFuncref()); + BinaryenRefNull(module, BinaryenTypeNullFuncref()); funcrefExpr = BinaryenRefFunc(module, "kitchen()sinker", BinaryenTypeFuncref()); BinaryenExpressionRef i31refExpr = @@ -973,40 +973,40 @@ void test_core() { BinaryenSelect( module, temp10, - BinaryenRefNull(module, BinaryenTypeFuncref()), + BinaryenRefNull(module, BinaryenTypeNullFuncref()), BinaryenRefFunc(module, "kitchen()sinker", BinaryenTypeFuncref()), BinaryenTypeFuncref()), // GC BinaryenRefEq(module, - BinaryenRefNull(module, BinaryenTypeEqref()), - BinaryenRefNull(module, BinaryenTypeEqref())), + BinaryenRefNull(module, BinaryenTypeNullref()), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefIs(module, BinaryenRefIsFunc(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefIs(module, BinaryenRefIsData(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefIs(module, BinaryenRefIsI31(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefAs(module, BinaryenRefAsNonNull(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefAs(module, BinaryenRefAsFunc(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefAs(module, BinaryenRefAsData(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefAs(module, BinaryenRefAsI31(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), BinaryenRefAs(module, BinaryenRefAsExternInternalize(), - BinaryenRefNull(module, BinaryenTypeExternref())), + BinaryenRefNull(module, BinaryenTypeNullExternref())), BinaryenRefAs(module, BinaryenRefAsExternExternalize(), - BinaryenRefNull(module, BinaryenTypeAnyref())), + BinaryenRefNull(module, BinaryenTypeNullref())), // Exception handling BinaryenTry(module, NULL, tryBody, catchTags, 1, catchBodies, 2, NULL), // (try $try_outer @@ -1103,11 +1103,8 @@ void test_core() { BinaryenArrayGet(module, BinaryenGlobalGet(module, "i8Array-global", i8Array), makeInt32(module, 0), + BinaryenTypeInt32(), true), - BinaryenArrayGet(module, - BinaryenGlobalGet(module, "i8Array-global", i8Array), - makeInt32(module, 0), - false), BinaryenArraySet(module, BinaryenGlobalGet(module, "i8Array-global", i8Array), makeInt32(module, 0), @@ -1420,7 +1417,7 @@ void test_core() { BinaryenTableSizeSetTable(tablesize, table); BinaryenExpressionRef valueExpr = - BinaryenRefNull(module, BinaryenTypeFuncref()); + BinaryenRefNull(module, BinaryenTypeNullFuncref()); BinaryenExpressionRef sizeExpr = makeInt32(module, 0); BinaryenExpressionRef growExpr = BinaryenTableGrow(module, "0", valueExpr, sizeExpr); diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt index a8e4d200b17..3d2b749384e 100644 --- a/test/example/c-api-kitchen-sink.txt +++ b/test/example/c-api-kitchen-sink.txt @@ -58,7 +58,7 @@ BinaryenFeatureAll: 126975 ) (table.size $0) (table.grow $0 - (ref.null func) + (ref.null nofunc) (i32.const 0) ) (module @@ -1974,7 +1974,7 @@ BinaryenFeatureAll: 126975 ) (drop (ref.is_null - (ref.null extern) + (ref.null noextern) ) ) (drop @@ -1984,60 +1984,60 @@ BinaryenFeatureAll: 126975 ) (drop (select (result funcref) - (ref.null func) + (ref.null nofunc) (ref.func "$kitchen()sinker") (i32.const 1) ) ) (drop (ref.eq - (ref.null eq) - (ref.null eq) + (ref.null none) + (ref.null none) ) ) (drop (ref.is_func - (ref.null any) + (ref.null none) ) ) (drop (ref.is_data - (ref.null any) + (ref.null none) ) ) (drop (ref.is_i31 - (ref.null any) + (ref.null none) ) ) (drop (ref.as_non_null - (ref.null any) + (ref.null none) ) ) (drop (ref.as_func - (ref.null any) + (ref.null none) ) ) (drop (ref.as_data - (ref.null any) + (ref.null none) ) ) (drop (ref.as_i31 - (ref.null any) + (ref.null none) ) ) (drop (extern.internalize - (ref.null extern) + (ref.null noextern) ) ) (drop (extern.externalize - (ref.null any) + (ref.null none) ) ) (try @@ -2207,12 +2207,6 @@ BinaryenFeatureAll: 126975 (i32.const 0) ) ) - (drop - (array.get_u $[mut:i8] - (global.get $i8Array-global) - (i32.const 0) - ) - ) (array.set $[mut:i8] (global.get $i8Array-global) (i32.const 0) diff --git a/test/example/cpp-unit.cpp b/test/example/cpp-unit.cpp index b9453040136..df0902f7793 100644 --- a/test/example/cpp-unit.cpp +++ b/test/example/cpp-unit.cpp @@ -602,31 +602,6 @@ void test_effects() { // Nops... do not. Nop nop; assert_equal(EffectAnalyzer(options, module, &nop).trap, false); - - // ArrayCopy can trap, reads arrays, and writes arrays (but not structs). - { - ArrayCopy arrayCopy(module.allocator); - EffectAnalyzer effects(options, module); - effects.visit(&arrayCopy); - assert_equal(effects.trap, true); - assert_equal(effects.readsArray, true); - assert_equal(effects.writesArray, true); - assert_equal(effects.readsMutableStruct, false); - assert_equal(effects.writesStruct, false); - } -} - -void test_literals() { - // The i31 heap type may or may not be basic, depending on if it is nullable. - // Verify we handle both code paths. - { - Literal x(Type(HeapType::i31, Nullable)); - std::cout << x << '\n'; - } - { - Literal x(Type(HeapType::i31, NonNullable)); - std::cout << x << '\n'; - } } void test_field() { @@ -681,7 +656,6 @@ int main() { test_bits(); test_cost(); test_effects(); - test_literals(); test_field(); test_queue(); diff --git a/test/example/cpp-unit.txt b/test/example/cpp-unit.txt index d1f1fc1fb2d..35821117c87 100644 --- a/test/example/cpp-unit.txt +++ b/test/example/cpp-unit.txt @@ -1,3 +1 @@ -i31ref(null) -i31ref(0) Success diff --git a/test/example/typeinfo.txt b/test/example/typeinfo.txt index 2fbd8ec520c..7015e6cfc25 100644 --- a/test/example/typeinfo.txt +++ b/test/example/typeinfo.txt @@ -9,8 +9,8 @@ eq eqref (ref eq) i31 -(ref null i31) i31ref +(ref i31) (func) (struct) (array i32) diff --git a/test/gc.wast.from-wast b/test/gc.wast.from-wast index 19936135ca8..a518ceffaa1 100644 --- a/test/gc.wast.from-wast +++ b/test/gc.wast.from-wast @@ -1,12 +1,12 @@ (module (type $i31ref_dataref_=>_none (func (param i31ref dataref))) (type $i31ref_ref|i31|_dataref_ref|data|_=>_none (func (param i31ref (ref i31) dataref (ref data)))) - (global $global_anyref (mut anyref) (ref.null any)) - (global $global_eqref (mut eqref) (ref.null eq)) + (global $global_anyref (mut anyref) (ref.null none)) + (global $global_eqref (mut eqref) (ref.null none)) (global $global_i31ref (mut i31ref) (i31.new (i32.const 0) )) - (global $global_anyref2 (mut anyref) (ref.null eq)) + (global $global_anyref2 (mut anyref) (ref.null none)) (global $global_anyref3 (mut anyref) (i31.new (i32.const 0) )) @@ -24,7 +24,7 @@ (global.get $global_anyref) ) (local.set $local_anyref - (ref.null any) + (ref.null none) ) (local.set $local_eqref (local.get $local_eqref) @@ -33,7 +33,7 @@ (global.get $global_eqref) ) (local.set $local_eqref - (ref.null eq) + (ref.null none) ) (local.set $local_i31ref (local.get $local_i31ref) @@ -53,7 +53,7 @@ (global.get $global_eqref) ) (local.set $local_anyref - (ref.null eq) + (ref.null none) ) (local.set $local_anyref (local.get $local_i31ref) @@ -84,7 +84,7 @@ (global.get $global_anyref) ) (global.set $global_anyref - (ref.null any) + (ref.null none) ) (global.set $global_eqref (local.get $local_eqref) @@ -93,7 +93,7 @@ (global.get $global_eqref) ) (global.set $global_eqref - (ref.null eq) + (ref.null none) ) (global.set $global_i31ref (local.get $local_i31ref) @@ -113,7 +113,7 @@ (global.get $global_eqref) ) (global.set $global_anyref - (ref.null eq) + (ref.null none) ) (global.set $global_anyref (local.get $local_i31ref) diff --git a/test/gc.wast.fromBinary b/test/gc.wast.fromBinary index 80d12cf1dd9..72c1508e7a2 100644 --- a/test/gc.wast.fromBinary +++ b/test/gc.wast.fromBinary @@ -1,12 +1,12 @@ (module (type $i31ref_dataref_=>_none (func (param i31ref dataref))) (type $i31ref_ref|i31|_dataref_ref|data|_=>_none (func (param i31ref (ref i31) dataref (ref data)))) - (global $global_anyref (mut anyref) (ref.null any)) - (global $global_eqref (mut eqref) (ref.null eq)) + (global $global_anyref (mut anyref) (ref.null none)) + (global $global_eqref (mut eqref) (ref.null none)) (global $global_i31ref (mut i31ref) (i31.new (i32.const 0) )) - (global $global_anyref2 (mut anyref) (ref.null eq)) + (global $global_anyref2 (mut anyref) (ref.null none)) (global $global_anyref3 (mut anyref) (i31.new (i32.const 0) )) @@ -24,7 +24,7 @@ (global.get $global_anyref) ) (local.set $local_anyref - (ref.null any) + (ref.null none) ) (local.set $local_eqref (local.get $local_eqref) @@ -33,7 +33,7 @@ (global.get $global_eqref) ) (local.set $local_eqref - (ref.null eq) + (ref.null none) ) (local.set $local_i31ref (local.get $local_i31ref) @@ -53,7 +53,7 @@ (global.get $global_eqref) ) (local.set $local_anyref - (ref.null eq) + (ref.null none) ) (local.set $local_anyref (local.get $local_i31ref) @@ -84,7 +84,7 @@ (global.get $global_anyref) ) (global.set $global_anyref - (ref.null any) + (ref.null none) ) (global.set $global_eqref (local.get $local_eqref) @@ -93,7 +93,7 @@ (global.get $global_eqref) ) (global.set $global_eqref - (ref.null eq) + (ref.null none) ) (global.set $global_i31ref (local.get $local_i31ref) @@ -113,7 +113,7 @@ (global.get $global_eqref) ) (global.set $global_anyref - (ref.null eq) + (ref.null none) ) (global.set $global_anyref (local.get $local_i31ref) diff --git a/test/gc.wast.fromBinary.noDebugInfo b/test/gc.wast.fromBinary.noDebugInfo index 0ab9159aa68..61437688102 100644 --- a/test/gc.wast.fromBinary.noDebugInfo +++ b/test/gc.wast.fromBinary.noDebugInfo @@ -1,12 +1,12 @@ (module (type $i31ref_dataref_=>_none (func (param i31ref dataref))) (type $i31ref_ref|i31|_dataref_ref|data|_=>_none (func (param i31ref (ref i31) dataref (ref data)))) - (global $global$0 (mut anyref) (ref.null any)) - (global $global$1 (mut eqref) (ref.null eq)) + (global $global$0 (mut anyref) (ref.null none)) + (global $global$1 (mut eqref) (ref.null none)) (global $global$2 (mut i31ref) (i31.new (i32.const 0) )) - (global $global$3 (mut anyref) (ref.null eq)) + (global $global$3 (mut anyref) (ref.null none)) (global $global$4 (mut anyref) (i31.new (i32.const 0) )) @@ -24,7 +24,7 @@ (global.get $global$0) ) (local.set $3 - (ref.null any) + (ref.null none) ) (local.set $4 (local.get $4) @@ -33,7 +33,7 @@ (global.get $global$1) ) (local.set $4 - (ref.null eq) + (ref.null none) ) (local.set $0 (local.get $0) @@ -53,7 +53,7 @@ (global.get $global$1) ) (local.set $3 - (ref.null eq) + (ref.null none) ) (local.set $3 (local.get $0) @@ -84,7 +84,7 @@ (global.get $global$0) ) (global.set $global$0 - (ref.null any) + (ref.null none) ) (global.set $global$1 (local.get $4) @@ -93,7 +93,7 @@ (global.get $global$1) ) (global.set $global$1 - (ref.null eq) + (ref.null none) ) (global.set $global$2 (local.get $0) @@ -113,7 +113,7 @@ (global.get $global$1) ) (global.set $global$0 - (ref.null eq) + (ref.null none) ) (global.set $global$0 (local.get $0) diff --git a/test/gtest/type-builder.cpp b/test/gtest/type-builder.cpp index 94a2a1f80d6..d642893c3fd 100644 --- a/test/gtest/type-builder.cpp +++ b/test/gtest/type-builder.cpp @@ -656,4 +656,8 @@ TEST_F(NominalTest, TestDepth) { EXPECT_EQ(HeapType(HeapType::stringview_wtf8).getDepth(), 2U); EXPECT_EQ(HeapType(HeapType::stringview_wtf16).getDepth(), 2U); EXPECT_EQ(HeapType(HeapType::stringview_iter).getDepth(), 2U); + + EXPECT_EQ(HeapType(HeapType::none).getDepth(), size_t(-1)); + EXPECT_EQ(HeapType(HeapType::nofunc).getDepth(), size_t(-1)); + EXPECT_EQ(HeapType(HeapType::noext).getDepth(), size_t(-1)); } diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast index 09a12833f2b..ebe01c76ac5 100644 --- a/test/heap-types.wast.from-wast +++ b/test/heap-types.wast.from-wast @@ -1,18 +1,14 @@ (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 $vector (array (mut f64))) (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 $grandchild (struct (field i32) (field i64))) (type $anyref_=>_none (func (param anyref))) - (type $nested-child-struct (struct (field (mut (ref $child))))) (type $words (array (mut i32))) - (type $nested-child-array (array (mut (ref $child)))) - (type $child (struct (field i32))) (type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B)))) + (type $struct.C (struct (field $named-mut (mut f32)))) (type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) (type $ref|$vector|_ref?|$vector|_=>_none (func (param (ref $vector) (ref null $vector)))) (type $none_=>_ref|$vector| (func (result (ref $vector)))) @@ -48,8 +44,11 @@ ) ) (drop - (struct.get $struct.A $named - (ref.null $struct.A) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (unreachable) ) ) (drop @@ -63,12 +62,15 @@ ) ) (drop - (struct.get $grandchild 0 - (ref.null $grandchild) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (unreachable) ) ) (drop - (ref.null $struct.A) + (ref.null none) ) (drop (block (result (ref null $struct.A)) @@ -94,15 +96,25 @@ (i32.const 1) ) ) - (struct.set $struct.C $named-mut - (ref.null $struct.C) - (f32.const 100) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (drop + (f32.const 100) + ) + (unreachable) ) - (struct.set $nested-child-struct 0 - (ref.null $nested-child-struct) - (ref.as_non_null - (ref.null $grandchild) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (drop + (ref.as_non_null + (ref.null none) + ) ) + (unreachable) ) (drop (struct.new_default $struct.A) @@ -143,12 +155,19 @@ (i32.const 2) (f64.const 2.18281828) ) - (array.set $nested-child-array - (ref.null $nested-child-array) - (i32.const 3) - (ref.as_non_null - (ref.null $grandchild) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (drop + (i32.const 3) + ) + (drop + (ref.as_non_null + (ref.null none) + ) ) + (unreachable) ) (drop (array.len $vector @@ -237,7 +256,7 @@ (local.get $x) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -247,7 +266,7 @@ (local.get $x) ) ) - (ref.null data) + (ref.null none) ) ) (drop @@ -257,7 +276,7 @@ (local.get $x) ) ) - (ref.null i31) + (ref.null none) ) ) (drop @@ -275,7 +294,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -285,7 +304,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -295,7 +314,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) ) @@ -305,12 +324,18 @@ (drop (unreachable) ) + (unreachable) ) ) ) (func $unreachables-2 - (struct.set $struct.C $named-mut - (ref.null $struct.C) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (drop + (unreachable) + ) (unreachable) ) ) @@ -322,6 +347,7 @@ (drop (unreachable) ) + (unreachable) ) ) (func $unreachables-4 @@ -332,6 +358,7 @@ (drop (f32.const 1) ) + (unreachable) ) ) (func $unreachables-array-1 @@ -342,11 +369,17 @@ (drop (i32.const 2) ) + (unreachable) ) ) (func $unreachables-array-2 - (array.get $vector - (ref.null $vector) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (drop + (unreachable) + ) (unreachable) ) ) @@ -361,25 +394,43 @@ (drop (f64.const 2.18281828) ) + (unreachable) ) ) (func $unreachables-array-4 - (array.set $vector - (ref.null $vector) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (drop + (unreachable) + ) + (drop + (f64.const 2.18281828) + ) (unreachable) - (f64.const 2.18281828) ) ) (func $unreachables-array-5 - (array.set $vector - (ref.null $vector) - (i32.const 2) + (block ;; (replaces something unreachable we can't emit) + (drop + (ref.null none) + ) + (drop + (i32.const 2) + ) + (drop + (unreachable) + ) (unreachable) ) ) (func $unreachables-array-6 (drop - (block + (block ;; (replaces something unreachable we can't emit) + (drop + (unreachable) + ) (unreachable) ) ) @@ -413,19 +464,19 @@ (local $temp.B (ref null $struct.B)) (drop (ref.test_static $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (drop (ref.cast_static $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (drop (block $out-B (result (ref $struct.B)) (local.set $temp.A (br_on_cast_static $out-B $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (unreachable) @@ -435,7 +486,7 @@ (block $out-A (result (ref null $struct.A)) (local.set $temp.B (br_on_cast_static_fail $out-A $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (unreachable) diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary index 266d04f93ee..1cb09864370 100644 --- a/test/heap-types.wast.fromBinary +++ b/test/heap-types.wast.fromBinary @@ -1,19 +1,15 @@ (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.B (struct (field i8) (field (mut i16)) (field (ref $struct.A)) (field (mut (ref $struct.A))))) (type $matrix (array (mut (ref null $vector)))) (type $bytes (array (mut i8))) - (type $struct.C (struct (field $named-mut (mut f32)))) - (type $grandchild (struct (field i32) (field i64))) (type $anyref_=>_none (func (param anyref))) - (type $nested-child-struct (struct (field (mut (ref $child))))) - (type $words (array (mut i32))) - (type $nested-child-array (array (mut (ref $child)))) - (type $child (struct (field i32))) (type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B)))) + (type $struct.C (struct (field $named-mut (mut f32)))) (type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) + (type $words (array (mut i32))) (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)))) @@ -48,69 +44,7 @@ ) ) (drop - (struct.get $struct.A $named - (ref.null $struct.A) - ) - ) - (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 - (ref.null $grandchild) - ) - ) - (drop - (ref.null $struct.A) - ) - (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 - (ref.null $struct.C) - (f32.const 100) - ) - (struct.set $nested-child-struct 0 - (ref.null $nested-child-struct) - (ref.as_non_null - (ref.null $grandchild) - ) - ) - (drop - (struct.new_default $struct.A) - ) - (drop - (struct.new $struct.A - (i32.const 1) - (f32.const 2.3450000286102295) - (f64.const 3.14159) - ) + (ref.null none) ) (unreachable) ) @@ -141,34 +75,15 @@ (i32.const 2) (f64.const 2.18281828) ) - (array.set $nested-child-array - (ref.null $nested-child-array) - (i32.const 3) - (ref.as_non_null - (ref.null $grandchild) - ) - ) (drop - (array.len $vector - (local.get $x) - ) + (ref.null none) ) (drop - (array.get $words - (local.get $tw) - (i32.const 1) - ) - ) - (drop - (array.get_u $bytes - (local.get $tb) - (i32.const 2) - ) + (i32.const 3) ) (drop - (array.get_s $bytes - (local.get $tb) - (i32.const 3) + (ref.as_non_null + (ref.null none) ) ) (unreachable) @@ -235,7 +150,7 @@ (local.get $x) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -245,7 +160,7 @@ (local.get $x) ) ) - (ref.null data) + (ref.null none) ) ) (drop @@ -255,7 +170,7 @@ (local.get $x) ) ) - (ref.null i31) + (ref.null none) ) ) (drop @@ -273,7 +188,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -283,7 +198,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -293,7 +208,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) ) @@ -302,7 +217,7 @@ ) (func $unreachables-2 (drop - (ref.null $struct.C) + (ref.null none) ) (unreachable) ) @@ -317,7 +232,7 @@ ) (func $unreachables-array-2 (drop - (ref.null $vector) + (ref.null none) ) (unreachable) ) @@ -326,13 +241,13 @@ ) (func $unreachables-array-4 (drop - (ref.null $vector) + (ref.null none) ) (unreachable) ) (func $unreachables-array-5 (drop - (ref.null $vector) + (ref.null none) ) (drop (i32.const 2) @@ -371,19 +286,19 @@ (local $temp.B (ref null $struct.B)) (drop (ref.test_static $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (drop (ref.cast_static $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (drop (block $label$1 (result (ref $struct.B)) (local.set $temp.A (br_on_cast_static $label$1 $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (unreachable) @@ -393,7 +308,7 @@ (block $label$2 (result (ref null $struct.A)) (local.set $temp.B (br_on_cast_static_fail $label$2 $struct.B - (ref.null $struct.A) + (ref.null none) ) ) (unreachable) diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo index 03970672f34..9b34b58290b 100644 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ b/test/heap-types.wast.fromBinary.noDebugInfo @@ -1,19 +1,15 @@ (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 ${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 $[mut:ref?|[mut:f64]|] (array (mut (ref null $[mut:f64])))) (type $[mut:i8] (array (mut i8))) - (type ${mut:f32} (struct (field (mut f32)))) - (type ${i32_i64} (struct (field i32) (field i64))) (type $anyref_=>_none (func (param anyref))) - (type ${mut:ref|{i32}|} (struct (field (mut (ref ${i32}))))) - (type $[mut:i32] (array (mut i32))) - (type $[mut:ref|{i32}|] (array (mut (ref ${i32})))) - (type ${i32} (struct (field i32))) (type $ref|{i32_f32_f64}|_=>_ref|{i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}| (func (param (ref ${i32_f32_f64})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})))) + (type ${mut:f32} (struct (field (mut f32)))) (type $ref|[mut:f64]|_=>_ref|[mut:ref?|[mut:f64]|]| (func (param (ref $[mut:f64])) (result (ref $[mut:ref?|[mut:f64]|])))) + (type $[mut:i32] (array (mut i32))) (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])))) @@ -48,69 +44,7 @@ ) ) (drop - (struct.get ${i32_f32_f64} 2 - (ref.null ${i32_f32_f64}) - ) - ) - (drop - (struct.get_u ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 - (local.get $2) - ) - ) - (drop - (struct.get_s ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 - (local.get $2) - ) - ) - (drop - (struct.get ${i32_i64} 0 - (ref.null ${i32_i64}) - ) - ) - (drop - (ref.null ${i32_f32_f64}) - ) - (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 - (ref.null ${mut:f32}) - (f32.const 100) - ) - (struct.set ${mut:ref|{i32}|} 0 - (ref.null ${mut:ref|{i32}|}) - (ref.as_non_null - (ref.null ${i32_i64}) - ) - ) - (drop - (struct.new_default ${i32_f32_f64}) - ) - (drop - (struct.new ${i32_f32_f64} - (i32.const 1) - (f32.const 2.3450000286102295) - (f64.const 3.14159) - ) + (ref.null none) ) (unreachable) ) @@ -141,34 +75,15 @@ (i32.const 2) (f64.const 2.18281828) ) - (array.set $[mut:ref|{i32}|] - (ref.null $[mut:ref|{i32}|]) - (i32.const 3) - (ref.as_non_null - (ref.null ${i32_i64}) - ) - ) (drop - (array.len $[mut:f64] - (local.get $0) - ) + (ref.null none) ) (drop - (array.get $[mut:i32] - (local.get $4) - (i32.const 1) - ) - ) - (drop - (array.get_u $[mut:i8] - (local.get $3) - (i32.const 2) - ) + (i32.const 3) ) (drop - (array.get_s $[mut:i8] - (local.get $3) - (i32.const 3) + (ref.as_non_null + (ref.null none) ) ) (unreachable) @@ -235,7 +150,7 @@ (local.get $0) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -245,7 +160,7 @@ (local.get $0) ) ) - (ref.null data) + (ref.null none) ) ) (drop @@ -255,7 +170,7 @@ (local.get $0) ) ) - (ref.null i31) + (ref.null none) ) ) (drop @@ -273,7 +188,7 @@ (local.get $0) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -283,7 +198,7 @@ (local.get $0) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -293,7 +208,7 @@ (local.get $0) ) ) - (ref.null any) + (ref.null none) ) ) ) @@ -302,7 +217,7 @@ ) (func $6 (drop - (ref.null ${mut:f32}) + (ref.null none) ) (unreachable) ) @@ -317,7 +232,7 @@ ) (func $10 (drop - (ref.null $[mut:f64]) + (ref.null none) ) (unreachable) ) @@ -326,13 +241,13 @@ ) (func $12 (drop - (ref.null $[mut:f64]) + (ref.null none) ) (unreachable) ) (func $13 (drop - (ref.null $[mut:f64]) + (ref.null none) ) (drop (i32.const 2) @@ -371,19 +286,19 @@ (local $1 (ref null ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) (drop (ref.test_static ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} - (ref.null ${i32_f32_f64}) + (ref.null none) ) ) (drop (ref.cast_static ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} - (ref.null ${i32_f32_f64}) + (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_static $label$1 ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} - (ref.null ${i32_f32_f64}) + (ref.null none) ) ) (unreachable) @@ -393,7 +308,7 @@ (block $label$2 (result (ref null ${i32_f32_f64})) (local.set $1 (br_on_cast_static_fail $label$2 ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} - (ref.null ${i32_f32_f64}) + (ref.null none) ) ) (unreachable) diff --git a/test/lit/fuzz-types/isorecursive.test b/test/lit/fuzz-types/isorecursive.test index 18fade75bd8..ccbb63d5ef6 100644 --- a/test/lit/fuzz-types/isorecursive.test +++ b/test/lit/fuzz-types/isorecursive.test @@ -1,26 +1,26 @@ ;; RUN: wasm-fuzz-types --hybrid -v --seed=0 | filecheck %s ;; CHECK: (rec -;; CHECK-NEXT: (type $0 (struct_subtype data)) -;; CHECK-NEXT: (type $1 (func_subtype (param (ref $0)) func)) -;; CHECK-NEXT: (type $2 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32) data)) -;; CHECK-NEXT: (type $3 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32) $2)) -;; CHECK-NEXT: (type $4 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32) $2)) -;; CHECK-NEXT: (type $5 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32) $3)) -;; CHECK-NEXT: (type $6 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32 v128) $3)) -;; CHECK-NEXT: (type $7 (struct_subtype $0)) -;; CHECK-NEXT: (type $8 (struct_subtype $0)) -;; CHECK-NEXT: (type $9 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32 v128) $6)) -;; CHECK-NEXT: (type $10 (struct_subtype (field (mut i64)) $0)) -;; CHECK-NEXT: (type $11 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32) $2)) -;; CHECK-NEXT: (type $12 (struct_subtype $0)) -;; CHECK-NEXT: (type $13 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32 v128) $6)) +;; CHECK-NEXT: (type $0 (array_subtype (mut i64) data)) +;; CHECK-NEXT: (type $1 (func_subtype (param i32 (ref eq) (ref null $3)) (result v128) func)) +;; CHECK-NEXT: (type $2 (array_subtype (mut v128) data)) +;; CHECK-NEXT: (type $3 (array_subtype (mut i64) $0)) +;; CHECK-NEXT: (type $4 (array_subtype i32 data)) +;; CHECK-NEXT: (type $5 none) +;; CHECK-NEXT: (type $6 extern) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (rec -;; CHECK-NEXT: (type $14 (struct_subtype (field (mut i64) (ref null $11) v128) $10)) -;; CHECK-NEXT: (type $15 (func_subtype (param (ref $0)) $1)) -;; CHECK-NEXT: (type $16 (struct_subtype (field (mut (ref null $2)) v128 i8 (mut i8) f32 (mut i64)) $2)) -;; CHECK-NEXT: (type $17 (struct_subtype (field (mut i64) (ref $11) v128 i16 i8) $14)) -;; CHECK-NEXT: (type $18 (struct_subtype (field (mut f64)) $12)) -;; CHECK-NEXT: (type $19 (func_subtype (param (ref $0)) $15)) +;; CHECK-NEXT: (type $7 (array_subtype (mut i64) $3)) +;; CHECK-NEXT: (type $8 (func_subtype (result v128) func)) +;; CHECK-NEXT: (type $9 (array_subtype (mut v128) $2)) +;; CHECK-NEXT: (type $10 none) +;; CHECK-NEXT: (type $11 none) +;; CHECK-NEXT: (type $12 (array_subtype (mut v128) $2)) +;; CHECK-NEXT: (type $13 (func_subtype (param f32 (ref none) (ref null $3)) (result eqref) func)) +;; CHECK-NEXT: (type $14 (array_subtype (mut i64) $7)) +;; CHECK-NEXT: (type $15 (func_subtype (param (ref null $17) v128 (ref i31)) func)) +;; CHECK-NEXT: (type $16 (array_subtype i32 data)) +;; CHECK-NEXT: (type $17 (func_subtype (param (ref i31)) (result v128) func)) +;; CHECK-NEXT: (type $18 (func_subtype (param f32) func)) +;; CHECK-NEXT: (type $19 (array_subtype (mut i64) $3)) ;; CHECK-NEXT: ) diff --git a/test/lit/fuzz-types/nominal.test b/test/lit/fuzz-types/nominal.test index 7ef381bfea7..bb84f6991b2 100644 --- a/test/lit/fuzz-types/nominal.test +++ b/test/lit/fuzz-types/nominal.test @@ -1,22 +1,22 @@ ;; RUN: wasm-fuzz-types --nominal -v --seed=0 | filecheck %s -;; CHECK: (type $0 (struct_subtype (field v128 (ref null $4)) data)) -;; CHECK-NEXT: (type $1 (func_subtype (param (ref $3)) (result i32) func)) -;; CHECK-NEXT: (type $2 (struct_subtype (field (mut i64) f64) data)) -;; CHECK-NEXT: (type $3 (struct_subtype (field (mut i64) f64 (mut (ref $12)) i64) $2)) -;; CHECK-NEXT: (type $4 (struct_subtype (field (mut i64) f64) $2)) -;; CHECK-NEXT: (type $5 (struct_subtype (field (mut i64) f64 (mut (ref $12)) i64) $3)) -;; CHECK-NEXT: (type $6 (struct_subtype (field (mut i64) f64 (mut (ref $12)) i64) $3)) -;; CHECK-NEXT: (type $7 (struct_subtype (field v128 (ref null $4)) $0)) -;; CHECK-NEXT: (type $8 (struct_subtype (field v128 (ref $4) (ref null $3) v128) $0)) -;; CHECK-NEXT: (type $9 (struct_subtype (field (mut i64) f64 (mut (ref $12)) i64) $6)) -;; CHECK-NEXT: (type $10 (struct_subtype (field v128 (ref null $4)) $0)) -;; CHECK-NEXT: (type $11 (struct_subtype (field (mut i64) f64) $2)) -;; CHECK-NEXT: (type $12 (struct_subtype (field v128 (ref null $4) (mut (ref null $3))) $0)) -;; CHECK-NEXT: (type $13 (struct_subtype (field (mut i64) f64 (mut (ref $12)) i64) $6)) -;; CHECK-NEXT: (type $14 (struct_subtype (field v128 (ref null $4)) $10)) -;; CHECK-NEXT: (type $15 (func_subtype (param (ref $3)) (result i32) $1)) -;; CHECK-NEXT: (type $16 (struct_subtype (field (mut i64) f64) $2)) -;; CHECK-NEXT: (type $17 (struct_subtype (field v128 (ref null $4) i32) $14)) -;; CHECK-NEXT: (type $18 (struct_subtype (field v128 (ref null $4) (mut (ref null $3)) i16 f64) $12)) -;; CHECK-NEXT: (type $19 (func_subtype (param (ref $3)) (result i32) $15)) +;; CHECK: (type $0 (array_subtype (mut (ref null $8)) data)) +;; CHECK-NEXT: (type $1 (func_subtype (param nullref) (result v128) func)) +;; CHECK-NEXT: (type $2 (struct_subtype (field (mut i64) (mut i8) (mut (ref $12)) (mut f32)) data)) +;; CHECK-NEXT: (type $3 (array_subtype (mut (ref null $8)) $0)) +;; CHECK-NEXT: (type $4 (array_subtype (mut i64) data)) +;; CHECK-NEXT: (type $5 none) +;; CHECK-NEXT: (type $6 extern) +;; CHECK-NEXT: (type $7 (array_subtype (mut (ref null $8)) $3)) +;; CHECK-NEXT: (type $8 (func_subtype (result (ref $9)) func)) +;; CHECK-NEXT: (type $9 (struct_subtype (field (mut i64) (mut i8) (mut (ref $12)) (mut f32) i16) $2)) +;; CHECK-NEXT: (type $10 none) +;; CHECK-NEXT: (type $11 none) +;; CHECK-NEXT: (type $12 (struct_subtype (field (mut i64) (mut i8) (mut (ref $12)) (mut f32) (mut f32) (mut (ref $4))) $2)) +;; CHECK-NEXT: (type $13 (func_subtype (param dataref) func)) +;; CHECK-NEXT: (type $14 (array_subtype (mut (ref null $8)) $7)) +;; CHECK-NEXT: (type $15 (func_subtype (param externref) func)) +;; CHECK-NEXT: (type $16 (array_subtype v128 data)) +;; CHECK-NEXT: (type $17 (func_subtype (result (ref extern)) func)) +;; CHECK-NEXT: (type $18 (func_subtype (param v128 i64) func)) +;; CHECK-NEXT: (type $19 (array_subtype (mut (ref null $8)) $3)) diff --git a/test/lit/fuzz-types/structural.test b/test/lit/fuzz-types/structural.test index 345590e2b03..3dcec3179a4 100644 --- a/test/lit/fuzz-types/structural.test +++ b/test/lit/fuzz-types/structural.test @@ -1,22 +1,22 @@ ;; RUN: wasm-fuzz-types --structural -v --seed=0 | filecheck %s -;; CHECK: (type $0 (struct (field v128 (ref null $2)))) -;; CHECK-NEXT: (type $1 (func (param (ref $3)) (result i32))) -;; CHECK-NEXT: (type $2 (struct (field (mut i64) f64))) -;; CHECK-NEXT: (type $3 (struct (field (mut i64) f64 (mut (ref $12)) i64))) -;; CHECK-NEXT: (type $4 identical to $2) -;; CHECK-NEXT: (type $5 identical to $3) -;; CHECK-NEXT: (type $6 identical to $3) +;; CHECK: (type $0 (array (mut (ref null $8)))) +;; CHECK-NEXT: (type $1 (func (param nullref) (result v128))) +;; CHECK-NEXT: (type $2 (struct (field (mut i64) (mut i8) (mut (ref $12)) (mut f32)))) +;; CHECK-NEXT: (type $3 identical to $0) +;; CHECK-NEXT: (type $4 (array (mut i64))) +;; CHECK-NEXT: (type $5 none) +;; CHECK-NEXT: (type $6 extern) ;; CHECK-NEXT: (type $7 identical to $0) -;; CHECK-NEXT: (type $8 (struct (field v128 (ref $2) (ref null $3) v128))) -;; CHECK-NEXT: (type $9 identical to $3) -;; CHECK-NEXT: (type $10 identical to $0) -;; CHECK-NEXT: (type $11 identical to $2) -;; CHECK-NEXT: (type $12 (struct (field v128 (ref null $2) (mut (ref null $3))))) -;; CHECK-NEXT: (type $13 identical to $3) +;; CHECK-NEXT: (type $8 (func (result (ref $9)))) +;; CHECK-NEXT: (type $9 (struct (field (mut i64) (mut i8) (mut (ref $12)) (mut f32) i16))) +;; CHECK-NEXT: (type $10 none) +;; CHECK-NEXT: (type $11 none) +;; CHECK-NEXT: (type $12 (struct (field (mut i64) (mut i8) (mut (ref $12)) (mut f32) (mut f32) (mut (ref $4))))) +;; CHECK-NEXT: (type $13 (func (param dataref))) ;; CHECK-NEXT: (type $14 identical to $0) -;; CHECK-NEXT: (type $15 identical to $1) -;; CHECK-NEXT: (type $16 identical to $2) -;; CHECK-NEXT: (type $17 (struct (field v128 (ref null $2) i32))) -;; CHECK-NEXT: (type $18 (struct (field v128 (ref null $2) (mut (ref null $3)) i16 f64))) -;; CHECK-NEXT: (type $19 identical to $1) +;; CHECK-NEXT: (type $15 (func (param externref))) +;; CHECK-NEXT: (type $16 (array v128)) +;; CHECK-NEXT: (type $17 (func (result (ref extern)))) +;; CHECK-NEXT: (type $18 (func (param v128 i64))) +;; CHECK-NEXT: (type $19 identical to $0) diff --git a/test/lit/gc-eh.wast b/test/lit/gc-eh.wast index 41897d0b31b..335bad52578 100644 --- a/test/lit/gc-eh.wast +++ b/test/lit/gc-eh.wast @@ -27,7 +27,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; NOMNL: (func $foo (type $none_=>_ref?|$A|) (result (ref null $A)) ;; NOMNL-NEXT: (try $try @@ -40,7 +40,7 @@ ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) (func $foo (result (ref null $A)) (try diff --git a/test/lit/global-only.wast b/test/lit/global-only.wast index 6dce13d6d59..ac3e1ee8f4d 100644 --- a/test/lit/global-only.wast +++ b/test/lit/global-only.wast @@ -8,6 +8,6 @@ (module $parse ;; CHECK: (type $t (struct )) (type $t (struct)) - ;; CHECK: (global $g (ref null $t) (ref.null $t)) + ;; CHECK: (global $g (ref null $t) (ref.null none)) (global $g (ref null $t) (ref.null $t)) ) diff --git a/test/lit/heap-types.wast b/test/lit/heap-types.wast index ff9e59290bf..13d37217e54 100644 --- a/test/lit/heap-types.wast +++ b/test/lit/heap-types.wast @@ -10,21 +10,20 @@ (module ;; CHECK: (type $struct.A (struct (field i32))) - ;; NOMNL: (type $struct.A (struct_subtype (field i32) data)) (type $struct.A (struct i32)) ;; NOMNL: (type $struct.B (struct_subtype (field i32) data)) (type $struct.B (struct i32)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.test_static $struct.A - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $test (type $none_=>_none) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (ref.test_static $struct.B - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -37,21 +36,20 @@ (module ;; CHECK: (type $struct.A (struct (field i32))) - ;; NOMNL: (type $struct.A (struct_subtype (field i32) data)) (type $struct.A (struct i32)) ;; NOMNL: (type $struct.B (struct_subtype (field i32) data)) (type $struct.B (struct i32)) ;; CHECK: (func $test ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.cast_static $struct.A - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $test (type $none_=>_none) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (ref.cast_static $struct.B - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) diff --git a/test/lit/isorecursive-singleton-group.wast b/test/lit/isorecursive-singleton-group.wast index c36717376a9..bde2848bf29 100644 --- a/test/lit/isorecursive-singleton-group.wast +++ b/test/lit/isorecursive-singleton-group.wast @@ -15,6 +15,6 @@ ) ;; Use the type so it appears in the output. - ;; CHECK: (global $g (ref null $singleton) (ref.null $singleton)) + ;; CHECK: (global $g (ref null $singleton) (ref.null none)) (global $g (ref null $singleton) (ref.null $singleton)) ) diff --git a/test/lit/isorecursive-whole-group.wast b/test/lit/isorecursive-whole-group.wast index 6f12eeb7a9b..70f2f1e4e7e 100644 --- a/test/lit/isorecursive-whole-group.wast +++ b/test/lit/isorecursive-whole-group.wast @@ -17,6 +17,6 @@ (type $unused (struct_subtype data)) ) - ;; CHECK: (global $g (ref null $used) (ref.null $used)) + ;; CHECK: (global $g (ref null $used) (ref.null none)) (global $g (ref null $used) (ref.null $used)) ) diff --git a/test/lit/lub-bug-3843.wast b/test/lit/lub-bug-3843.wast index f5bb439f29d..768d47fdcb4 100644 --- a/test/lit/lub-bug-3843.wast +++ b/test/lit/lub-bug-3843.wast @@ -15,37 +15,38 @@ ;; NOMNL: (type $B (struct_subtype (field (ref null $D)) $A)) (type $B (struct_subtype (field (ref null $D)) $A)) + ;; CHECK: (type $C (struct (field (mut (ref $A))))) + ;; CHECK: (type $D (struct (field (mut (ref $A))) (field (mut (ref $A))))) ;; NOMNL: (type $C (struct_subtype (field (mut (ref $A))) data)) ;; NOMNL: (type $D (struct_subtype (field (mut (ref $A))) (field (mut (ref $A))) $C)) (type $D (struct_subtype (field (mut (ref $A))) (field (mut (ref $A))) $C)) - ;; CHECK: (type $C (struct (field (mut (ref $A))))) (type $C (struct (field (mut (ref $A))))) - ;; CHECK: (func $foo (param $a (ref null $A)) (result (ref null $A)) + ;; CHECK: (func $foo (param $a (ref null $A)) (param $b (ref null $B)) (result (ref null $A)) ;; CHECK-NEXT: (select (result (ref null $A)) ;; CHECK-NEXT: (local.get $a) - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (local.get $b) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $foo (type $ref?|$A|_=>_ref?|$A|) (param $a (ref null $A)) (result (ref null $A)) + ;; NOMNL: (func $foo (type $ref?|$A|_ref?|$B|_=>_ref?|$A|) (param $a (ref null $A)) (param $b (ref null $B)) (result (ref null $A)) ;; NOMNL-NEXT: (select (result (ref null $A)) ;; NOMNL-NEXT: (local.get $a) - ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (local.get $b) ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - (func $foo (param $a (ref null $A)) (result (ref null $A)) + (func $foo (param $a (ref null $A)) (param $b (ref null $B)) (result (ref null $A)) ;; the select should have type $A (select (result (ref null $A)) ;; one arm has type $A (local.get $a) ;; one arm has type $B (a subtype of $A) - (ref.null $B) + (local.get $b) (i32.const 0) ) ) diff --git a/test/lit/nominal-chain.wast b/test/lit/nominal-chain.wast index dda04b32c62..1403fbea48c 100644 --- a/test/lit/nominal-chain.wast +++ b/test/lit/nominal-chain.wast @@ -26,10 +26,10 @@ (type $root (struct)) - ;; CHECK: (func $make-root (type $none_=>_ref?|$root|) (result (ref null $root)) - ;; CHECK-NEXT: (ref.null $leaf) + ;; CHECK: (func $make-root (type $ref|$leaf|_=>_ref?|$root|) (param $leaf (ref $leaf)) (result (ref null $root)) + ;; CHECK-NEXT: (local.get $leaf) ;; CHECK-NEXT: ) - (func $make-root (result (ref null $root)) - (ref.null $leaf) + (func $make-root (param $leaf (ref $leaf)) (result (ref null $root)) + (local.get $leaf) ) ) diff --git a/test/lit/parse-double-unreachable.wast b/test/lit/parse-double-unreachable.wast new file mode 100644 index 00000000000..c647df330d3 --- /dev/null +++ b/test/lit/parse-double-unreachable.wast @@ -0,0 +1,44 @@ +;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited. + +;; RUN: wasm-opt %s -all --nominal --roundtrip -S -o - | filecheck %s + +;; Regression test for a bug in which we could pop the expression stack past an +;; unreachable if we were already in unreachable parsing mode. + +(module + + ;; CHECK: (type $array (array_subtype i8 data)) + (type $array (array i8)) + (type $func (func (result i32))) + + ;; CHECK: (func $double-unreachable (type $ref|$array|_=>_i32) (param $x (ref $array)) (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + (func $double-unreachable (param $x (ref $array)) (result i32) + + (drop + ;; This gets emitted as an unreachable, but it doesn't have type + ;; unreachable, so we continue emitting instructions afterward. When + ;; parsing, this will put us into unreachable mode. + (call_ref $func + (ref.null nofunc) + ) + ) + + ;; Now we are in unreachable parsing mode. Due to the bug, we would have + (array.get_u $array + (local.get $x) + + ;; Since this call_ref will be emitted as an unreachable, it does not consume + ;; the ref.null when parsing. Due to the bug, the ref.null would remain on + ;; the stack and would be incorrectly consumed as the index to the + ;; array.get_u, producing a type error. + (call_ref $func + (ref.null nofunc) + ) + ) + ) +) diff --git a/test/lit/parse-nominal-types-extends.wast b/test/lit/parse-nominal-types-extends.wast index ea9461e6716..9dbf6a0de0f 100644 --- a/test/lit/parse-nominal-types-extends.wast +++ b/test/lit/parse-nominal-types-extends.wast @@ -8,65 +8,55 @@ ;; void function type (module - ;; CHECK: (type $super (func_subtype func)) - - ;; CHECK: (type $sub (func_subtype $super)) (type $sub (func) (extends $super)) + ;; CHECK: (type $super (func_subtype func)) (type $super (func)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null nofunc)) (global $g (ref null $super) (ref.null $sub)) ) ;; function type with params and results (module - ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) - - ;; CHECK: (type $sub (func_subtype (param i32) (result i32) $super)) (type $sub (func (param i32) (result i32)) (extends $super)) + ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) (type $super (func (param i32) (result i32))) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null nofunc)) (global $g (ref null $super) (ref.null $sub)) ) ;; empty struct type (module - ;; CHECK: (type $super (struct_subtype data)) - - ;; CHECK: (type $sub (struct_subtype $super)) (type $sub (struct) (extends $super)) + ;; CHECK: (type $super (struct_subtype data)) (type $super (struct)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null none)) (global $g (ref null $super) (ref.null $sub)) ) ;; struct type with fields (module - ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) - - ;; CHECK: (type $sub (struct_subtype (field i32) (field i64) $super)) (type $sub (struct i32 (field i64)) (extends $super)) + ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) (type $super (struct (field i32) i64)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null none)) (global $g (ref null $super) (ref.null $sub)) ) ;; array type (module - ;; CHECK: (type $super (array_subtype i8 data)) - - ;; CHECK: (type $sub (array_subtype i8 $super)) (type $sub (array i8) (extends $super)) + ;; CHECK: (type $super (array_subtype i8 data)) (type $super (array i8)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null none)) (global $g (ref null $super) (ref.null $sub)) ) diff --git a/test/lit/parse-nominal-types.wast b/test/lit/parse-nominal-types.wast index db681ead96e..6bb0c8383f5 100644 --- a/test/lit/parse-nominal-types.wast +++ b/test/lit/parse-nominal-types.wast @@ -8,65 +8,55 @@ ;; void function type (module - ;; CHECK: (type $super (func_subtype func)) - - ;; CHECK: (type $sub (func_subtype $super)) (type $sub (func_subtype $super)) + ;; CHECK: (type $super (func_subtype func)) (type $super (func_subtype func)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null nofunc)) (global $g (ref null $super) (ref.null $sub)) ) ;; function type with params and results (module - ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) - - ;; CHECK: (type $sub (func_subtype (param i32) (result i32) $super)) (type $sub (func_subtype (param i32) (result i32) $super)) + ;; CHECK: (type $super (func_subtype (param i32) (result i32) func)) (type $super (func_subtype (param i32) (result i32) func)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null nofunc)) (global $g (ref null $super) (ref.null $sub)) ) ;; empty struct type (module - ;; CHECK: (type $super (struct_subtype data)) - - ;; CHECK: (type $sub (struct_subtype $super)) (type $sub (struct_subtype $super)) + ;; CHECK: (type $super (struct_subtype data)) (type $super (struct_subtype data)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null none)) (global $g (ref null $super) (ref.null $sub)) ) ;; struct type with fields (module - ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) - - ;; CHECK: (type $sub (struct_subtype (field i32) (field i64) $super)) (type $sub (struct_subtype i32 (field i64) $super)) + ;; CHECK: (type $super (struct_subtype (field i32) (field i64) data)) (type $super (struct_subtype (field i32) i64 data)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null none)) (global $g (ref null $super) (ref.null $sub)) ) ;; array type (module - ;; CHECK: (type $super (array_subtype i8 data)) - - ;; CHECK: (type $sub (array_subtype i8 $super)) (type $sub (array_subtype i8 $super)) + ;; CHECK: (type $super (array_subtype i8 data)) (type $super (array_subtype i8 data)) - ;; CHECK: (global $g (ref null $super) (ref.null $sub)) + ;; CHECK: (global $g (ref null $super) (ref.null none)) (global $g (ref null $super) (ref.null $sub)) ) diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index 437ace80398..d75c1a2f2cb 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -4,15 +4,14 @@ ;; name getting in the way) (module + (type $struct (struct i32)) ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) - (type $struct (struct i32)) ;; CHECK: (func $impossible-get (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -31,22 +30,20 @@ ) (module - ;; CHECK: (type $struct (struct_subtype (field i64) data)) - (type $struct (struct i64)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i64) data)) + (type $struct (struct i64)) ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i64.const 0) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -70,10 +67,10 @@ ) (module - ;; CHECK: (type $struct (struct_subtype (field f32) data)) - (type $struct (struct f32)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field f32) data)) + (type $struct (struct f32)) ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -81,13 +78,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f32.const 42) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -108,10 +103,10 @@ ) (module - ;; CHECK: (type $struct (struct_subtype (field f32) data)) - (type $struct (struct f32)) ;; CHECK: (type $f32_=>_none (func_subtype (param f32) func)) + ;; CHECK: (type $struct (struct_subtype (field f32) data)) + (type $struct (struct f32)) ;; CHECK: (func $test (type $f32_=>_none) (param $f f32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -119,8 +114,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -162,13 +160,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -191,13 +187,11 @@ ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -244,8 +238,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -270,10 +267,10 @@ ;; Different values assigned in different functions, and one is a struct.set. (module - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) - (type $struct (struct (mut f32))) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) + (type $struct (struct (mut f32))) ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -289,9 +286,14 @@ ) ) ;; CHECK: (func $set (type $none_=>_none) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (f32.const 1337) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $set @@ -302,8 +304,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -319,10 +324,10 @@ ;; As the last testcase, but the values happen to coincide, so we can optimize ;; the get into a constant. (module - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) - (type $struct (struct (mut f32))) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) + (type $struct (struct (mut f32))) ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -338,9 +343,14 @@ ) ) ;; CHECK: (func $set (type $none_=>_none) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (f32.const 42) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $set @@ -351,13 +361,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f32.const 42) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -372,10 +380,10 @@ ;; Check that we look into the fallthrough value that is assigned. (module - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) - (type $struct (struct (mut f32))) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) + (type $struct (struct (mut f32))) ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) ;; CHECK: (func $create (type $none_=>_none) @@ -400,13 +408,18 @@ ) ) ;; CHECK: (func $set (type $i32_=>_none) (param $x i32) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (if (result f32) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (f32.const 42) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (if (result f32) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $set (param $x i32) @@ -422,13 +435,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f32.const 42) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -456,13 +467,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref $none_=>_none)) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.func $test) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -491,6 +500,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -498,6 +508,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) @@ -507,6 +518,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $test @@ -535,7 +547,6 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $substruct (struct_subtype (field i32) $struct)) (type $substruct (struct_subtype i32 $struct)) ;; CHECK: (func $create (type $none_=>_none) @@ -556,7 +567,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $substruct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -576,11 +587,10 @@ ;; will optimize the result to the only possible value. (In practice, though, ;; it will trap anyhow.) (module - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) - (type $struct (struct (mut i32))) ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) $struct)) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) + (type $struct (struct (mut i32))) (type $substruct (struct_subtype (mut i32) $struct)) ;; CHECK: (func $create (type $none_=>_none) @@ -589,9 +599,14 @@ ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $create @@ -607,13 +622,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $substruct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -657,13 +670,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -714,13 +725,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -737,10 +746,10 @@ ;; for the shared field, preventing optimization, as a get of the ;; supertype may receive an instance of the subtype. (module - ;; CHECK: (type $struct (struct_subtype (field i32) data)) - (type $struct (struct i32)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) + (type $struct (struct i32)) ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) (type $substruct (struct_subtype i32 f64 $struct)) @@ -772,8 +781,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -828,13 +840,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $substruct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -849,23 +859,28 @@ ;; As above, but add a set of $struct. The set prevents the optimization. (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) (field f64) $struct)) (type $substruct (struct_subtype (mut i32) f64 $struct)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $substruct @@ -893,8 +908,11 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $substruct 0 - ;; CHECK-NEXT: (ref.null $substruct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -910,6 +928,8 @@ ;; Multi-level subtyping, check that we propagate not just to the immediate ;; supertype but all the way as needed. (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct1 (struct_subtype (field i32) data)) ;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $struct1)) @@ -921,14 +941,12 @@ (type $struct1 (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct3 ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: (f64.const 3.14159) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -943,63 +961,51 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1045,6 +1051,8 @@ ;; different values in the sub-most type. Create the top and bottom types, but ;; not the middle one. (module + ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) + ;; CHECK: (type $struct1 (struct_subtype (field i32) (field i32) data)) ;; CHECK: (type $struct2 (struct_subtype (field i32) (field i32) (field f64) (field f64) $struct1)) @@ -1056,8 +1064,6 @@ (type $struct2 (struct_subtype i32 i32 f64 f64 $struct1)) - ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $create (type $anyref_=>_none) (param $any anyref) @@ -1073,7 +1079,7 @@ ;; CHECK-NEXT: (i32.const 999) ;; CHECK-NEXT: (f64.const 2.71828) ;; CHECK-NEXT: (f64.const 9.9999999) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $any) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1099,113 +1105,99 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct1 1 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 999) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f64.const 2.71828) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f64.const 9.9999999) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 999) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f64.const 2.71828) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f64.const 9.9999999) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct3 5 - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1277,12 +1269,12 @@ ;; Multi-level subtyping with a different value in the middle of the chain. We ;; can only optimize $struct3. (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) (type $struct1 (struct (mut i32))) ;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1)) (type $struct2 (struct_subtype (mut i32) f64 $struct1)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) (type $struct3 (struct_subtype (mut i32) f64 anyref $struct2)) @@ -1302,7 +1294,7 @@ ;; CHECK-NEXT: (struct.new $struct3 ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: (f64.const 0) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1328,23 +1320,27 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct1 0 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 10) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1371,6 +1367,8 @@ ;; As above, but add not just a new of the middle class with a different value ;; but also a set. That prevents all optimizations. (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) ;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1)) @@ -1381,8 +1379,6 @@ ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) (type $struct3 (struct_subtype (mut i32) f64 anyref $struct2)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct1 @@ -1395,15 +1391,20 @@ ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: (i32.const 9999) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 9999) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct3 ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: (f64.const 0) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1434,18 +1435,27 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct1 0 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct3 0 - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1472,11 +1482,11 @@ ;; Test for a struct with multiple fields, some of which are constant and hence ;; optimizable, and some not. Also test that some have the same type. (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i32) (field f64) (field i32) (field f64) (field i32) data)) (type $struct (struct i32 f64 i32 f64 i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -1505,53 +1515,51 @@ ) ;; CHECK: (func $get (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result f64) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 3 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 30) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 30) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1656,34 +1664,35 @@ ;; Copies of a field to itself can be ignored. As a result, we can optimize both ;; of the gets here. (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1710,29 +1719,36 @@ ;; Test of a near-copy, of a similar looking field (same index, and same field ;; type) but in a different struct. (module - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) (field (mut i32)) data)) - (type $struct (struct (mut f32) (mut i32))) ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $other (struct_subtype (field (mut f64)) (field (mut i32)) data)) + ;; CHECK: (type $struct (struct_subtype (field (mut f32)) (field (mut i32)) data)) + (type $struct (struct (mut f32) (mut i32))) (type $other (struct (mut f64) (mut i32))) ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 1 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $other) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 1 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1757,29 +1773,35 @@ ;; Test of a near-copy, of a different index. (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) (field (mut i32)) data)) (type $struct (struct (mut i32) (mut i32))) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (block (result i32) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1803,11 +1825,11 @@ ) (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) @@ -1818,13 +1840,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1845,11 +1865,11 @@ ) (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (global $global (mut i32) (i32.const 42)) (global $global (mut i32) (i32.const 42)) @@ -1860,8 +1880,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1881,11 +1904,11 @@ ) (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) @@ -1895,18 +1918,21 @@ ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1932,11 +1958,11 @@ ) (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) ;; CHECK: (global $global-2 i32 (i32.const 1337)) @@ -1948,13 +1974,21 @@ ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (global.get $global-2) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (global.get $global-2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1978,11 +2012,11 @@ ) (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) ;; CHECK: (global $global-2 i32 (i32.const 1337)) @@ -1994,13 +2028,21 @@ ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2028,21 +2070,20 @@ ;; Test a global type other than i32. Arrays of structs are a realistic case ;; as they are used to implement itables. - ;; CHECK: (type $itable (array_subtype (ref $vtable) data)) - ;; CHECK: (type $vtable (struct_subtype (field funcref) data)) (type $vtable (struct funcref)) + ;; CHECK: (type $itable (array_subtype (ref $vtable) data)) (type $itable (array (ref $vtable))) + ;; CHECK: (type $none_=>_funcref (func_subtype (result funcref) func)) + ;; CHECK: (type $object (struct_subtype (field $itable (ref $itable)) data)) (type $object (struct (field $itable (ref $itable)))) - ;; CHECK: (type $none_=>_funcref (func_subtype (result funcref) func)) - ;; CHECK: (global $global (ref $itable) (array.init_static $itable ;; CHECK-NEXT: (struct.new $vtable - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.new $vtable ;; CHECK-NEXT: (ref.func $test) @@ -2063,18 +2104,24 @@ ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.get $vtable 0 - ;; CHECK-NEXT: (array.get $itable - ;; CHECK-NEXT: (block (result (ref $itable)) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $object) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $test (result funcref) diff --git a/test/lit/passes/coalesce-locals-gc.wast b/test/lit/passes/coalesce-locals-gc.wast index 0113af23cb4..5947aae1128 100644 --- a/test/lit/passes/coalesce-locals-gc.wast +++ b/test/lit/passes/coalesce-locals-gc.wast @@ -10,7 +10,7 @@ (module ;; CHECK: (type $array (array (mut i8))) (type $array (array (mut i8))) - ;; CHECK: (global $global (ref null $array) (ref.null $array)) + ;; CHECK: (global $global (ref null $array) (ref.null none)) (global $global (ref null $array) (ref.null $array)) ;; CHECK: (func $test-dead-get-non-nullable (param $0 (ref data)) @@ -136,4 +136,33 @@ (local.get $x) ) ) + + ;; CHECK: (func $unreachable-get-null + ;; CHECK-NEXT: (local $0 anyref) + ;; CHECK-NEXT: (local $1 i31ref) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i31.new + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $unreachable-get-null + ;; Check that we don't replace the local.get $null with a ref.null, which + ;; would have a more precise type. + (local $null-any anyref) + (local $null-i31 i31ref) + (unreachable) + (drop + (local.get $null-any) + ) + (drop + (local.get $null-i31) + ) + ) ) diff --git a/test/lit/passes/dae-gc-refine-params.wast b/test/lit/passes/dae-gc-refine-params.wast index 3b104bdcc7e..12165b6401b 100644 --- a/test/lit/passes/dae-gc-refine-params.wast +++ b/test/lit/passes/dae-gc-refine-params.wast @@ -12,18 +12,18 @@ ;; CHECK: (type ${} (struct )) (type ${} (struct)) + ;; CHECK: (type ${f64} (struct (field f64))) + ;; CHECK: (type ${i32_i64} (struct (field i32) (field i64))) + ;; NOMNL: (type ${f64} (struct_subtype (field f64) ${})) + ;; NOMNL: (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32})) (type ${i32_i64} (struct_subtype (field i32) (field i64) ${i32})) - ;; CHECK: (type ${i32_f32} (struct (field i32) (field f32))) - - ;; CHECK: (type ${f64} (struct (field f64))) - ;; NOMNL: (type ${i32_f32} (struct_subtype (field i32) (field f32) ${i32})) - - ;; NOMNL: (type ${f64} (struct_subtype (field f64) ${})) (type ${f64} (struct_subtype (field f64) ${})) + ;; CHECK: (type ${i32_f32} (struct (field i32) (field f32))) + ;; NOMNL: (type ${i32_f32} (struct_subtype (field i32) (field f32) ${i32})) (type ${i32_f32} (struct_subtype (field i32) (field f32) ${i32})) ;; CHECK: (func $call-various-params-no @@ -218,55 +218,43 @@ ;; its parameters (see last function), however, we reuse the parameters by ;; writing to them, which causes problems in one case. ;; CHECK: (func $various-params-set (param $x (ref null ${i32})) (param $y (ref null ${i32})) - ;; CHECK-NEXT: (local $2 (ref null ${})) - ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (ref.null ${}) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $y - ;; CHECK-NEXT: (call $get_null_{i32_i64}) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $x + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (call $get_null_{i32_i64}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $various-params-set (type $ref?|${i32}|_ref?|${i32}|_=>_none) (param $x (ref null ${i32})) (param $y (ref null ${i32})) - ;; NOMNL-NEXT: (local $2 (ref null ${})) - ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (local.get $x) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (block - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.get $2) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.get $y) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (local.set $2 - ;; NOMNL-NEXT: (ref.null ${}) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.get $2) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (local.set $y - ;; NOMNL-NEXT: (call $get_null_{i32_i64}) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.get $y) - ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $y) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $x + ;; NOMNL-NEXT: (ref.null none) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $y + ;; NOMNL-NEXT: (call $get_null_{i32_i64}) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $y) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) (func $various-params-set (param $x (ref null ${})) (param $y (ref null ${})) @@ -345,32 +333,32 @@ ;; CHECK: (func $call-various-params-null ;; CHECK-NEXT: (call $various-params-null ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $get_null_{i32}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $various-params-null ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $call-various-params-null (type $none_=>_none) ;; NOMNL-NEXT: (call $various-params-null ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null ${i32}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (call $get_null_{i32}) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (call $various-params-null ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null ${i32}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null ${i32}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -388,7 +376,7 @@ ) ;; This function is called in ways that allow us to make the first parameter ;; non-nullable. - ;; CHECK: (func $various-params-null (param $x (ref ${i32})) (param $y (ref null ${i32})) + ;; CHECK: (func $various-params-null (param $x (ref none)) (param $y (ref null ${i32})) ;; CHECK-NEXT: (local $temp i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $x) @@ -400,7 +388,7 @@ ;; CHECK-NEXT: (local.get $temp) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $various-params-null (type $ref|${i32}|_ref?|${i32}|_=>_none) (param $x (ref ${i32})) (param $y (ref null ${i32})) + ;; NOMNL: (func $various-params-null (type $ref|none|_ref?|${i32}|_=>_none) (param $x (ref none)) (param $y (ref null ${i32})) ;; NOMNL-NEXT: (local $temp i32) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (local.get $x) @@ -542,7 +530,7 @@ ;; CHECK: (func $call-update-null ;; CHECK-NEXT: (call $update-null - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $update-null ;; CHECK-NEXT: (struct.new_default ${}) @@ -550,7 +538,7 @@ ;; CHECK-NEXT: ) ;; NOMNL: (func $call-update-null (type $none_=>_none) ;; NOMNL-NEXT: (call $update-null - ;; NOMNL-NEXT: (ref.null ${}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (call $update-null ;; NOMNL-NEXT: (struct.new_default ${}) @@ -585,10 +573,10 @@ ) ;; CHECK: (func $get_null_{i32} (result (ref null ${i32})) - ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; NOMNL: (func $get_null_{i32} (type $none_=>_ref?|${i32}|) (result (ref null ${i32})) - ;; NOMNL-NEXT: (ref.null ${i32}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) (func $get_null_{i32} (result (ref null ${i32})) ;; Helper function that returns a null value of ${i32}. We use this instead of @@ -597,20 +585,20 @@ ) ;; CHECK: (func $get_null_{i32_i64} (result (ref null ${i32_i64})) - ;; CHECK-NEXT: (ref.null ${i32_i64}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; NOMNL: (func $get_null_{i32_i64} (type $none_=>_ref?|${i32_i64}|) (result (ref null ${i32_i64})) - ;; NOMNL-NEXT: (ref.null ${i32_i64}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) (func $get_null_{i32_i64} (result (ref null ${i32_i64})) (ref.null ${i32_i64}) ) ;; CHECK: (func $get_null_{i32_f32} (result (ref null ${i32_f32})) - ;; CHECK-NEXT: (ref.null ${i32_f32}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; NOMNL: (func $get_null_{i32_f32} (type $none_=>_ref?|${i32_f32}|) (result (ref null ${i32_f32})) - ;; NOMNL-NEXT: (ref.null ${i32_f32}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) (func $get_null_{i32_f32} (result (ref null ${i32_f32})) (ref.null ${i32_f32}) diff --git a/test/lit/passes/dae-gc-refine-return.wast b/test/lit/passes/dae-gc-refine-return.wast index 84e16165169..90084b95798 100644 --- a/test/lit/passes/dae-gc-refine-return.wast +++ b/test/lit/passes/dae-gc-refine-return.wast @@ -641,6 +641,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $tail-caller-call_ref-unreachable (type $none_=>_anyref) (result anyref) @@ -648,6 +649,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) (func $tail-caller-call_ref-unreachable (result anyref) @@ -698,7 +700,7 @@ ;; CHECK-NEXT: (struct.new_default ${i32_f32}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return @@ -715,7 +717,7 @@ ;; NOMNL-NEXT: (struct.new_default ${i32_f32}) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (return - ;; NOMNL-NEXT: (ref.null ${i32}) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (return diff --git a/test/lit/passes/dae-gc.wast b/test/lit/passes/dae-gc.wast index e6c83f0d02f..d985035c47e 100644 --- a/test/lit/passes/dae-gc.wast +++ b/test/lit/passes/dae-gc.wast @@ -159,7 +159,7 @@ ;; CHECK: (func $bar (param $0 i31ref) ;; CHECK-NEXT: (local $1 anyref) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop @@ -173,7 +173,7 @@ ;; NOMNL: (func $bar (type $i31ref_=>_none) (param $0 i31ref) ;; NOMNL-NEXT: (local $1 anyref) ;; NOMNL-NEXT: (local.set $1 - ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block ;; NOMNL-NEXT: (drop @@ -192,7 +192,7 @@ ;; CHECK: (func $call-bar ;; CHECK-NEXT: (call $bar - ;; CHECK-NEXT: (ref.null i31) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $bar ;; CHECK-NEXT: (i31.new @@ -202,7 +202,7 @@ ;; CHECK-NEXT: ) ;; NOMNL: (func $call-bar (type $none_=>_none) ;; NOMNL-NEXT: (call $bar - ;; NOMNL-NEXT: (ref.null i31) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (call $bar ;; NOMNL-NEXT: (i31.new diff --git a/test/lit/passes/flatten_all-features.wast b/test/lit/passes/flatten_all-features.wast index 934706419c8..7daf00914ea 100644 --- a/test/lit/passes/flatten_all-features.wast +++ b/test/lit/passes/flatten_all-features.wast @@ -3418,8 +3418,8 @@ ;; CHECK: (func $subtype (result anyref) ;; CHECK-NEXT: (local $0 eqref) ;; CHECK-NEXT: (local $1 anyref) - ;; CHECK-NEXT: (local $2 eqref) - ;; CHECK-NEXT: (local $3 eqref) + ;; CHECK-NEXT: (local $2 nullref) + ;; CHECK-NEXT: (local $3 nullref) ;; CHECK-NEXT: (local $4 eqref) ;; CHECK-NEXT: (local $5 eqref) ;; CHECK-NEXT: (local $6 eqref) @@ -3427,10 +3427,10 @@ ;; CHECK-NEXT: (block $label0 ;; CHECK-NEXT: (block ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br_if $label0 ;; CHECK-NEXT: (i32.const 0) @@ -3513,15 +3513,14 @@ ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (module - ;; CHECK: (type $none_=>_none (func)) (type $none_=>_none (func)) ;; CHECK: (type $none_=>_funcref (func (result funcref))) ;; CHECK: (func $0 (result funcref) - ;; CHECK-NEXT: (local $0 (ref $none_=>_none)) + ;; CHECK-NEXT: (local $0 (ref nofunc)) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $none_=>_none) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (return diff --git a/test/lit/passes/global-refining.wast b/test/lit/passes/global-refining.wast index 4e92880b309..645b170d4e5 100644 --- a/test/lit/passes/global-refining.wast +++ b/test/lit/passes/global-refining.wast @@ -9,7 +9,7 @@ ;; CHECK: (type $foo_t (func_subtype func)) (type $foo_t (func)) - ;; CHECK: (global $func-null-init (mut funcref) (ref.null $foo_t)) + ;; CHECK: (global $func-null-init (mut funcref) (ref.null nofunc)) (global $func-null-init (mut funcref) (ref.null $foo_t)) ;; CHECK: (global $func-func-init (mut (ref $foo_t)) (ref.func $foo)) (global $func-func-init (mut funcref) (ref.func $foo)) @@ -26,17 +26,17 @@ ;; CHECK: (type $foo_t (func_subtype func)) (type $foo_t (func)) - ;; CHECK: (global $func-null-init (mut funcref) (ref.null $foo_t)) + ;; CHECK: (global $func-null-init (mut funcref) (ref.null nofunc)) (global $func-null-init (mut funcref) (ref.null $foo_t)) ;; CHECK: (global $func-func-init (mut (ref null $foo_t)) (ref.func $foo)) (global $func-func-init (mut funcref) (ref.func $foo)) ;; CHECK: (func $foo (type $foo_t) ;; CHECK-NEXT: (global.set $func-null-init - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $func-func-init - ;; CHECK-NEXT: (ref.null $foo_t) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $foo (type $foo_t) @@ -51,7 +51,7 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (global $func-null-init (mut (ref null $none_=>_none)) (ref.null $none_=>_none)) + ;; CHECK: (global $func-null-init (mut (ref null $none_=>_none)) (ref.null nofunc)) (global $func-null-init (mut funcref) (ref.null func)) ;; CHECK: (global $func-func-init (mut (ref $none_=>_none)) (ref.func $foo)) (global $func-func-init (mut funcref) (ref.func $foo)) @@ -80,10 +80,9 @@ ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct)) - ;; CHECK: (type $array (array_subtype i8 data)) (type $array (array i8)) - ;; CHECK: (global $global (mut eqref) (ref.null eq)) + ;; CHECK: (global $global (mut eqref) (ref.null none)) (global $global (mut anyref) (ref.null any)) ;; CHECK: (func $foo (type $none_=>_none) @@ -96,13 +95,13 @@ ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $global - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $global - ;; CHECK-NEXT: (ref.null i31) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $global - ;; CHECK-NEXT: (ref.null $array) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $foo diff --git a/test/lit/passes/gsi.wast b/test/lit/passes/gsi.wast index e378fa26281..b3e7a669995 100644 --- a/test/lit/passes/gsi.wast +++ b/test/lit/passes/gsi.wast @@ -27,15 +27,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -74,8 +70,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -104,8 +103,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -148,8 +150,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -193,15 +198,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -244,15 +245,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global2) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -295,15 +292,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global3) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -353,8 +346,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -405,15 +401,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global3) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -454,8 +446,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -500,15 +495,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -550,7 +541,7 @@ ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (i32.const 999999) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: )) (global $global-tuple (ref $tuple) (struct.new $tuple (struct.new $struct @@ -561,8 +552,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -601,8 +595,8 @@ )) ;; CHECK: (global $global-tuple (ref $tuple) (struct.new $tuple - ;; CHECK-NEXT: (ref.null any) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: )) (global $global-tuple (ref $tuple) (struct.new $tuple (ref.null any) @@ -611,15 +605,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -655,8 +645,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -700,8 +693,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -751,15 +747,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -804,20 +796,19 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 42) - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $super-struct) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -867,8 +858,11 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -923,18 +917,27 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $super-struct 0 - ;; CHECK-NEXT: (ref.null $super-struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct1 0 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1019,32 +1022,27 @@ ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $super-struct 0 - ;; CHECK-NEXT: (ref.null $super-struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: (i32.const 1338) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (select - ;; CHECK-NEXT: (i32.const 99999) - ;; CHECK-NEXT: (i32.const 99998) - ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (global.get $global2) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast index 4ecab4f8c82..bbf7c60b11a 100644 --- a/test/lit/passes/gto-mutability.wast +++ b/test/lit/passes/gto-mutability.wast @@ -7,7 +7,7 @@ ;; The struct here has three fields, and the second of them has no struct.set ;; which means we can make it immutable. - ;; CHECK: (type $struct (struct_subtype (field (mut funcref)) (field funcref) (field (mut funcref)) data)) + ;; CHECK: (type $struct (struct_subtype (field (mut funcref)) (field funcref) data)) (type $struct (struct (field (mut funcref)) (field (mut funcref)) (field (mut funcref)))) ;; CHECK: (type $two-params (func_subtype (param (ref $struct) (ref $struct)) func)) @@ -33,18 +33,23 @@ ;; CHECK-NEXT: (local $temp (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (ref.null func) - ;; CHECK-NEXT: (ref.null func) - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $struct 2 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (local.get $x) @@ -108,7 +113,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) (func $foo (result (ref null $struct)) ;; Use a tag so that we test proper updating of its type after making @@ -155,8 +160,11 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 2 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -171,9 +179,8 @@ ;; Test recursion between structs where we only modify one. Specifically $B ;; has no writes to either of its fields. - ;; CHECK: (type $A (struct_subtype (field (mut (ref null $B))) (field (mut i32)) data)) + ;; CHECK: (type $A (struct_subtype data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) - ;; CHECK: (type $B (struct_subtype (field (ref null $A)) (field f64) data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) @@ -181,13 +188,25 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $func (type $ref|$A|_=>_none) (param $x (ref $A)) - ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $A)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $A 1 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $A)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 20) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $A)) @@ -203,23 +222,35 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -234,10 +265,9 @@ (module ;; As before, but flipped so that $A's fields can become immutable. - ;; CHECK: (type $B (struct_subtype (field (mut (ref null $A))) (field (mut f64)) data)) + ;; CHECK: (type $B (struct_subtype data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) - ;; CHECK: (type $A (struct_subtype (field (ref null $B)) (field i32) data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) ;; CHECK: (type $ref|$B|_=>_none (func_subtype (param (ref $B)) func)) @@ -245,13 +275,25 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $func (type $ref|$B|_=>_none) (param $x (ref $B)) - ;; CHECK-NEXT: (struct.set $B 0 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $B)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $B 1 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $B)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $B)) @@ -267,23 +309,35 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -298,10 +352,11 @@ (module ;; As before, but now one field in each can become immutable. - ;; CHECK: (type $B (struct_subtype (field (ref null $A)) (field (mut f64)) data)) + ;; CHECK: (type $A (struct_subtype data)) + + ;; CHECK: (type $B (struct_subtype data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) - ;; CHECK: (type $A (struct_subtype (field (mut (ref null $B))) (field i32) data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) ;; CHECK: (type $ref|$A|_ref|$B|_=>_none (func_subtype (param (ref $A) (ref $B)) func)) @@ -309,13 +364,25 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $func (type $ref|$A|_ref|$B|_=>_none) (param $x (ref $A)) (param $y (ref $B)) - ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $A)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $B 1 - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $B)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (f64.const 3.14159) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $A)) (param $y (ref $B)) @@ -331,23 +398,35 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -364,7 +443,7 @@ ;; Field #1 is mutable and can become so. ;; Field #2 is mutable and must remain so. - ;; CHECK: (type $struct (struct_subtype (field i32) (field i32) (field (mut i32)) data)) + ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct (field i32) (field (mut i32)) (field (mut i32)))) ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func)) @@ -372,9 +451,15 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $func (type $ref|$struct|_=>_none) (param $x (ref $struct)) - ;; CHECK-NEXT: (struct.set $struct 2 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $struct)) @@ -386,18 +471,27 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 1 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 2 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -412,23 +506,19 @@ ;; Subtyping. Without a write in either supertype or subtype, we can ;; optimize the field to be immutable. - ;; CHECK: (type $super (struct_subtype (field i32) data)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $super (struct_subtype data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $sub (struct_subtype (field i32) $super)) + ;; CHECK: (type $sub (struct_subtype $super)) (type $sub (struct_subtype (field (mut i32)) $super)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $func (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new $super - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new $sub - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $sub) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func @@ -447,13 +537,19 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $super 0 - ;; CHECK-NEXT: (ref.null $super) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $sub 0 - ;; CHECK-NEXT: (ref.null $sub) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -466,29 +562,31 @@ (module ;; As above, but add a write in the super, which prevents optimization. - ;; CHECK: (type $super (struct_subtype (field (mut i32)) data)) + ;; CHECK: (type $super (struct_subtype data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) - (type $sub (struct_subtype (field (mut i32)) $super)) - ;; CHECK: (type $ref|$super|_=>_none (func_subtype (param (ref $super)) func)) + ;; CHECK: (type $sub (struct_subtype $super)) + (type $sub (struct_subtype (field (mut i32)) $super)) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $func (type $ref|$super|_=>_none) (param $x (ref $super)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new $super - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new $sub - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $sub) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $super 0 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $super)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $super)) @@ -511,13 +609,19 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $super 0 - ;; CHECK-NEXT: (ref.null $super) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $sub 0 - ;; CHECK-NEXT: (ref.null $sub) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -531,9 +635,9 @@ ;; As above, but add a write in the sub, which prevents optimization. - ;; CHECK: (type $super (struct_subtype (field (mut i32)) data)) + ;; CHECK: (type $super (struct_subtype data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) + ;; CHECK: (type $sub (struct_subtype $super)) (type $sub (struct_subtype (field (mut i32)) $super)) ;; CHECK: (type $ref|$sub|_=>_none (func_subtype (param (ref $sub)) func)) @@ -541,9 +645,15 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (func $func (type $ref|$sub|_=>_none) (param $x (ref $sub)) - ;; CHECK-NEXT: (struct.set $sub 0 - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref $sub)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $sub)) @@ -555,13 +665,19 @@ ;; CHECK: (func $field-keepalive (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $super 0 - ;; CHECK-NEXT: (ref.null $super) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $sub 0 - ;; CHECK-NEXT: (ref.null $sub) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast index 5dd6ab4d19b..c125e0579c7 100644 --- a/test/lit/passes/gto-removals.wast +++ b/test/lit/passes/gto-removals.wast @@ -32,7 +32,7 @@ ;; CHECK-NEXT: (ref.as_non_null ;; CHECK-NEXT: (block (result (ref $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) @@ -399,7 +399,7 @@ (module ;; A new with side effects - ;; CHECK: (type $struct (struct_subtype (field i32) data)) + ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct i32 f64 (ref any))) @@ -421,8 +421,11 @@ ;; CHECK: (func $gets (type $ref|any|_=>_none) (param $x (ref any)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -456,9 +459,7 @@ ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -491,9 +492,7 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (global.get $imm-i32) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -530,9 +529,7 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (local.get $0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -562,6 +559,7 @@ ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -578,11 +576,15 @@ ) ;; CHECK: (func $new-side-effect-in-kept (type $ref|any|_=>_none) (param $any (ref any)) + ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (call $helper0 - ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (block (result (ref $struct)) + ;; CHECK-NEXT: (local.set $1 + ;; CHECK-NEXT: (call $helper0 + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -778,25 +780,24 @@ ) (module + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type ${mut:i8} (struct_subtype data)) (type ${mut:i8} (struct_subtype (field (mut i8)) data)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $none_=>_i32 (func_subtype (result i32) func)) ;; CHECK: (type $none_=>_ref|${mut:i8}| (func_subtype (result (ref ${mut:i8})) func)) ;; CHECK: (func $unreachable-set (type $none_=>_none) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref null ${mut:i8})) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (call $helper-i32) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null ${mut:i8}) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $helper-i32) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $unreachable-set @@ -813,17 +814,14 @@ ;; CHECK: (func $unreachable-set-2 (type $none_=>_none) ;; CHECK-NEXT: (block $block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null ${mut:i8}) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br $block) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br $block) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -840,17 +838,14 @@ ;; CHECK: (func $unreachable-set-2b (type $none_=>_none) ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null ${mut:i8}) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $unreachable-set-2b diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 905ce0a80ef..0c410c3d003 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -322,10 +322,10 @@ ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $z) @@ -369,19 +369,19 @@ ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (global $null anyref (ref.null any)) + ;; CHECK: (global $null anyref (ref.null none)) (global $null (ref null any) (ref.null any)) ;; CHECK: (global $something anyref (struct.new_default $struct)) (global $something (ref null any) (struct.new $struct)) - ;; CHECK: (global $mut-null (mut anyref) (ref.null any)) + ;; CHECK: (global $mut-null (mut anyref) (ref.null none)) (global $mut-null (mut (ref null any)) (ref.null any)) - ;; CHECK: (global $mut-something (mut anyref) (ref.null any)) + ;; CHECK: (global $mut-something (mut anyref) (ref.null none)) (global $mut-something (mut (ref null any)) (ref.null any)) ;; CHECK: (func $read-globals (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) @@ -439,7 +439,7 @@ ;; CHECK: (func $write-globals (type $none_=>_none) ;; CHECK-NEXT: (global.set $mut-null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $mut-something ;; CHECK-NEXT: (struct.new_default $struct) @@ -465,19 +465,19 @@ ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct)) - ;; CHECK: (global $A-null anyref (ref.null any)) + ;; CHECK: (global $A-null anyref (ref.null none)) (global $A-null (ref null any) (ref.null any)) ;; CHECK: (global $A-something anyref (struct.new_default $struct)) (global $A-something (ref null any) (struct.new $struct)) - ;; CHECK: (global $B-null (mut anyref) (ref.null any)) + ;; CHECK: (global $B-null (mut anyref) (ref.null none)) (global $B-null (mut (ref null any)) (ref.null any)) - ;; CHECK: (global $B-something (mut anyref) (ref.null any)) + ;; CHECK: (global $B-something (mut anyref) (ref.null none)) (global $B-something (mut (ref null any)) (ref.null any)) - ;; CHECK: (global $C-null (mut anyref) (ref.null any)) + ;; CHECK: (global $C-null (mut anyref) (ref.null none)) (global $C-null (mut (ref null any)) (ref.null any)) - ;; CHECK: (global $C-something (mut anyref) (ref.null any)) + ;; CHECK: (global $C-something (mut anyref) (ref.null none)) (global $C-something (mut (ref null any)) (ref.null any)) ;; CHECK: (func $read-globals (type $none_=>_none) @@ -541,10 +541,10 @@ ;; CHECK: (func $write-globals (type $none_=>_none) ;; CHECK-NEXT: (global.set $B-null - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $C-null - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $B-something ;; CHECK-NEXT: (global.get $A-something) @@ -946,7 +946,7 @@ ;; CHECK-NEXT: (local.set $child ;; CHECK-NEXT: (struct.new $child ;; CHECK-NEXT: (struct.new_default $struct) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -955,28 +955,28 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $child 1 ;; CHECK-NEXT: (local.get $child) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $parent ;; CHECK-NEXT: (struct.new $parent - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $parent 0 ;; CHECK-NEXT: (local.get $parent) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -1071,55 +1071,55 @@ ;; CHECK: (func $nulls (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $parent) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $block (result anyref) + ;; CHECK-NEXT: (block $block (result nullref) ;; CHECK-NEXT: (br $block - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $child)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $block0 (result (ref null $child)) + ;; CHECK-NEXT: (block $block0 (result nullref) ;; CHECK-NEXT: (br $block0 - ;; CHECK-NEXT: (ref.null $child) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $child) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $child)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $block1 (result (ref null $child)) + ;; CHECK-NEXT: (block $block1 (result nullref) ;; CHECK-NEXT: (br $block1 - ;; CHECK-NEXT: (block (result (ref null $child)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.cast_static $child - ;; CHECK-NEXT: (ref.null $parent) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $child) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $child) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1207,11 +1207,13 @@ ;; Exact types: Writes to the parent class do not confuse us. (module + ;; CHECK: (type $parent (struct_subtype (field (mut (ref null $struct))) data)) + + ;; CHECK: (type $child (struct_subtype (field (mut (ref null $struct))) (field i32) $parent)) + ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct_subtype data)) - ;; CHECK: (type $parent (struct_subtype (field (mut (ref null $struct))) data)) (type $parent (struct_subtype (field (mut (ref null $struct))) data)) - ;; CHECK: (type $child (struct_subtype (field (mut (ref null $struct))) (field i32) $parent)) (type $child (struct_subtype (field (mut (ref null $struct))) (field i32) $parent)) ;; CHECK: (type $none_=>_none (func_subtype func)) @@ -1233,20 +1235,20 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $child ;; CHECK-NEXT: (struct.new $child - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $child 0 ;; CHECK-NEXT: (local.get $child) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) @@ -1558,12 +1560,12 @@ ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (array.get $null ;; CHECK-NEXT: (array.new_default $null @@ -1572,7 +1574,7 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) @@ -1683,7 +1685,7 @@ ;; CHECK: (type $anyref_=>_anyref (func_subtype (param anyref) (result anyref) func)) - ;; CHECK: (global $x (mut anyref) (ref.null any)) + ;; CHECK: (global $x (mut anyref) (ref.null none)) (global $x (mut (ref null any)) (ref.null any)) ;; CHECK: (func $foo (type $none_=>_none) @@ -1752,29 +1754,29 @@ ;; CHECK: (type $anyref_=>_anyref (func_subtype (param anyref) (result anyref) func)) - ;; CHECK: (global $x (mut anyref) (ref.null any)) + ;; CHECK: (global $x (mut anyref) (ref.null none)) (global $x (mut (ref null any)) (ref.null any)) ;; CHECK: (func $foo (type $none_=>_none) ;; CHECK-NEXT: (local $x anyref) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.set $x - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $storage - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $pass-through - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -1806,7 +1808,7 @@ ) ;; CHECK: (func $pass-through (type $anyref_=>_anyref) (param $x anyref) (result anyref) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) (func $pass-through (param $x (ref null any)) (result (ref null any)) (local.get $x) @@ -1827,7 +1829,7 @@ ;; CHECK: (type $anyref_=>_anyref (func_subtype (param anyref) (result anyref) func)) - ;; CHECK: (global $x (mut anyref) (ref.null any)) + ;; CHECK: (global $x (mut anyref) (ref.null none)) (global $x (mut (ref null any)) (ref.null any)) ;; CHECK: (func $foo (type $none_=>_none) @@ -1885,11 +1887,11 @@ (module ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) + ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct)) - ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) - ;; CHECK: (tag $nothing (param anyref)) (tag $nothing (param (ref null any))) @@ -1902,7 +1904,7 @@ ;; CHECK: (func $func (type $none_=>_none) ;; CHECK-NEXT: (local $0 anyref) ;; CHECK-NEXT: (throw $nothing - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (try $try ;; CHECK-NEXT: (do @@ -1915,11 +1917,11 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) @@ -2117,20 +2119,20 @@ ;; Exceptions with a tuple (module - ;; CHECK: (type $struct (struct_subtype data)) - (type $struct (struct)) - ;; CHECK: (type $anyref_anyref_=>_none (func_subtype (param anyref anyref) func)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype data)) + (type $struct (struct)) + ;; CHECK: (tag $tag (param anyref anyref)) (tag $tag (param (ref null any)) (param (ref null any))) ;; CHECK: (func $func (type $none_=>_none) ;; CHECK-NEXT: (local $0 (anyref anyref)) ;; CHECK-NEXT: (throw $tag - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (try $try @@ -2142,11 +2144,11 @@ ;; CHECK-NEXT: (pop anyref anyref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2196,16 +2198,16 @@ ) (module + ;; CHECK: (type $none_=>_ref|${}| (func_subtype (result (ref ${})) func)) + ;; CHECK: (type ${} (struct_subtype data)) (type ${} (struct_subtype data)) - ;; CHECK: (type $none_=>_ref|${}| (func_subtype (result (ref ${})) func)) - ;; CHECK: (func $func (type $none_=>_ref|${}|) (result (ref ${})) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $block (result (ref ${})) + ;; CHECK-NEXT: (block $block (result (ref none)) ;; CHECK-NEXT: (br_on_non_null $block - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -2312,7 +2314,7 @@ ;; CHECK: (global $global-A (ref $vtable-A) (struct.new $vtable-A ;; CHECK-NEXT: (ref.func $foo) - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: (ref.func $foo) ;; CHECK-NEXT: )) (global $global-A (ref $vtable-A) @@ -2330,7 +2332,7 @@ ;; CHECK-NEXT: (ref.func $foo) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $vtable-A 2 @@ -2366,7 +2368,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $vtable-A ;; CHECK-NEXT: (ref.func $foo) - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: (ref.func $test) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2526,24 +2528,24 @@ ;; CHECK: (func $test-nulls (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.cast_static $struct - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.cast_static $struct - ;; CHECK-NEXT: (select (result eqref) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (select (result i31ref) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i31.new ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) @@ -2554,7 +2556,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.cast_static $struct ;; CHECK-NEXT: (select (result (ref null $struct)) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (i32.const 6) ;; CHECK-NEXT: ) @@ -2646,11 +2648,11 @@ ;; CHECK: (func $ref.test-inexact (type $i32_=>_none) (param $x i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.test_static $struct - ;; CHECK-NEXT: (select (result anyref) + ;; CHECK-NEXT: (select (result (ref null $struct)) ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2819,8 +2821,8 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.null $struct) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -2874,7 +2876,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -3002,19 +3004,19 @@ ;; CHECK-NEXT: (local $x eqref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (ref.null eq) - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.eq - ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -3448,7 +3450,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $chars ;; CHECK-NEXT: (array.init_static $chars - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (array.copy $chars $bytes @@ -3533,7 +3535,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $chars ;; CHECK-NEXT: (array.init_static $chars - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (array.copy $bytes $chars @@ -3550,14 +3552,14 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (array.get $chars ;; CHECK-NEXT: (local.get $chars) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -3603,13 +3605,12 @@ (module (type $A (struct_subtype data)) + (type $B (array (mut anyref))) + ;; CHECK: (type $none_=>_none (func_subtype func)) ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) - ;; CHECK: (type $B (array_subtype (mut anyref) data)) - (type $B (array (mut anyref))) - ;; CHECK: (memory $0 10) ;; CHECK: (table $t 0 externref) @@ -3861,7 +3862,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (table.grow $t - ;; CHECK-NEXT: (ref.null extern) + ;; CHECK-NEXT: (ref.null noextern) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -3904,8 +3905,11 @@ ;; CHECK: (func $arrays (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (array.len $B - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/gufa-vs-cfp.wast b/test/lit/passes/gufa-vs-cfp.wast index 9cb74fbe736..623d256797d 100644 --- a/test/lit/passes/gufa-vs-cfp.wast +++ b/test/lit/passes/gufa-vs-cfp.wast @@ -456,6 +456,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) @@ -464,11 +465,13 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $test @@ -599,11 +602,11 @@ (module ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) $struct)) (type $substruct (struct_subtype (mut i32) $struct)) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (func $test (type $none_=>_none) ;; CHECK-NEXT: (local $ref (ref null $struct)) ;; CHECK-NEXT: (local.set $ref @@ -618,13 +621,13 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $substruct)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.cast_static $substruct ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $substruct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) @@ -1015,7 +1018,7 @@ ;; CHECK-NEXT: (struct.new $struct3 ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: (f64.const 3.14159) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $create (result (ref $struct3)) @@ -1081,13 +1084,13 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct3 2 ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1178,7 +1181,7 @@ ;; CHECK-NEXT: (i32.const 999) ;; CHECK-NEXT: (f64.const 2.71828) ;; CHECK-NEXT: (f64.const 9.9999999) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (call $import) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1323,11 +1326,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $create3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -1421,7 +1424,7 @@ ;; CHECK-NEXT: (struct.new $struct3 ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: (f64.const 0) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $create3 (result (ref $struct3)) @@ -1726,7 +1729,7 @@ ;; CHECK-NEXT: (struct.new $struct3 ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: (f64.const 0) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $create3 (result (ref $struct3)) @@ -1842,7 +1845,7 @@ ;; CHECK-NEXT: (struct.new $struct3 ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: (f64.const 0) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $create3 (result (ref $struct3)) @@ -2629,7 +2632,7 @@ ;; CHECK: (global $global (ref $itable) (array.init_static $itable ;; CHECK-NEXT: (struct.new $vtable - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.new $vtable ;; CHECK-NEXT: (ref.func $test) diff --git a/test/lit/passes/gufa.wast b/test/lit/passes/gufa.wast index ae86e3b84ce..dfff06e4fcb 100644 --- a/test/lit/passes/gufa.wast +++ b/test/lit/passes/gufa.wast @@ -1018,7 +1018,7 @@ ;; CHECK: (func $foo ;; CHECK-NEXT: (call $call-without-effects ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-keep) @@ -1046,7 +1046,7 @@ ;; CHECK: (func $target-keep (param $x i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $target-keep (type $A) (param $x i32) @@ -1057,7 +1057,7 @@ ;; CHECK: (func $target-keep-2 (param $x i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $target-keep-2 (type $A) (param $x i32) diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast index 6fd7442789b..9d63faa171c 100644 --- a/test/lit/passes/heap2local.wast +++ b/test/lit/passes/heap2local.wast @@ -11,34 +11,30 @@ ;; CHECK: (type $struct.recursive (struct (field (mut (ref null $struct.recursive))))) - ;; CHECK: (type $struct.nondefaultable (struct (field (ref $struct.A)))) - ;; CHECK: (type $struct.packed (struct (field (mut i8)))) ;; NOMNL: (type $struct.recursive (struct_subtype (field (mut (ref null $struct.recursive))) data)) ;; NOMNL: (type $struct.packed (struct_subtype (field (mut i8)) data)) (type $struct.packed (struct (field (mut i8)))) - ;; NOMNL: (type $struct.nondefaultable (struct_subtype (field (ref $struct.A)) data)) (type $struct.nondefaultable (struct (field (ref $struct.A)))) (type $struct.recursive (struct (field (mut (ref null $struct.recursive))))) - ;; NOMNL: (type $struct.nonnullable (struct_subtype (field (ref $struct.A)) data)) (type $struct.nonnullable (struct (field (ref $struct.A)))) ;; CHECK: (func $simple ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -46,14 +42,14 @@ ;; NOMNL-NEXT: (local $0 i32) ;; NOMNL-NEXT: (local $1 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $0 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -70,14 +66,14 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -86,14 +82,14 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -114,14 +110,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) @@ -134,14 +130,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $0 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $0) @@ -167,14 +163,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) @@ -187,14 +183,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $0 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $1) @@ -214,14 +210,14 @@ ;; CHECK-NEXT: (local $0 i32) ;; CHECK-NEXT: (local $1 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 @@ -232,14 +228,14 @@ ;; NOMNL-NEXT: (local $0 i32) ;; NOMNL-NEXT: (local $1 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $0 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $0 @@ -285,7 +281,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) @@ -298,7 +294,7 @@ ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) @@ -313,7 +309,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (i32.const 2) ;; NOMNL-NEXT: ) @@ -326,7 +322,7 @@ ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (local.get $3) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $0) @@ -357,8 +353,10 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -373,8 +371,10 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -397,14 +397,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref $struct.A)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.nondefaultable)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (struct.new_default $struct.A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.nondefaultable) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) @@ -417,14 +417,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result (ref $struct.A)) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.nondefaultable)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (struct.new_default $struct.A) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $0 ;; NOMNL-NEXT: (local.get $1) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.nondefaultable) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $0) @@ -447,19 +447,19 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) @@ -471,19 +471,19 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 1) @@ -509,19 +509,19 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -531,19 +531,19 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -573,22 +573,22 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -598,22 +598,22 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -675,26 +675,26 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref null $struct.A)) ;; CHECK-NEXT: (block (result (ref null $struct.A)) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -704,26 +704,26 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result (ref null $struct.A)) ;; NOMNL-NEXT: (block (result (ref null $struct.A)) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -847,22 +847,22 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -872,22 +872,22 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -912,23 +912,23 @@ ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (local $3 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -936,7 +936,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) @@ -948,23 +948,23 @@ ;; NOMNL-NEXT: (local $2 i32) ;; NOMNL-NEXT: (local $3 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -972,7 +972,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $3) ;; NOMNL-NEXT: ) @@ -1006,25 +1006,25 @@ ;; CHECK-NEXT: (local $2 i32) ;; CHECK-NEXT: (local $3 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) @@ -1034,25 +1034,25 @@ ;; NOMNL-NEXT: (local $2 i32) ;; NOMNL-NEXT: (local $3 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (if ;; NOMNL-NEXT: (local.get $x) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $3) ;; NOMNL-NEXT: ) @@ -1080,23 +1080,23 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref null $struct.A)) ;; CHECK-NEXT: (call $send-ref - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) @@ -1107,23 +1107,23 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result (ref null $struct.A)) ;; NOMNL-NEXT: (call $send-ref - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) @@ -1154,7 +1154,7 @@ ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (local.set $ref - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.get $struct.A 1 @@ -1169,7 +1169,7 @@ ;; NOMNL-NEXT: (if ;; NOMNL-NEXT: (local.get $x) ;; NOMNL-NEXT: (local.set $ref - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (struct.get $struct.A 1 @@ -1198,14 +1198,14 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) @@ -1215,14 +1215,14 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $1) @@ -1241,30 +1241,30 @@ ;; CHECK-NEXT: (local $ref (ref null $struct.recursive)) ;; CHECK-NEXT: (local $1 (ref null $struct.recursive)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.recursive)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null $struct.recursive) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.recursive) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null $struct.recursive) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $tee-set (type $none_=>_none) ;; NOMNL-NEXT: (local $ref (ref null $struct.recursive)) ;; NOMNL-NEXT: (local $1 (ref null $struct.recursive)) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.recursive)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 - ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 - ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) (func $tee-set @@ -1280,20 +1280,30 @@ ;; CHECK: (func $set-value ;; CHECK-NEXT: (local $ref (ref null $struct.recursive)) - ;; CHECK-NEXT: (struct.set $struct.recursive 0 - ;; CHECK-NEXT: (ref.null $struct.recursive) - ;; CHECK-NEXT: (local.tee $ref - ;; CHECK-NEXT: (struct.new_default $struct.recursive) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $ref + ;; CHECK-NEXT: (struct.new_default $struct.recursive) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $set-value (type $none_=>_none) ;; NOMNL-NEXT: (local $ref (ref null $struct.recursive)) - ;; NOMNL-NEXT: (struct.set $struct.recursive 0 - ;; NOMNL-NEXT: (ref.null $struct.recursive) - ;; NOMNL-NEXT: (local.tee $ref - ;; NOMNL-NEXT: (struct.new_default $struct.recursive) + ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null none) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.tee $ref + ;; NOMNL-NEXT: (struct.new_default $struct.recursive) + ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) (func $set-value @@ -1313,20 +1323,20 @@ ;; CHECK-NEXT: (local $1 (ref null $struct.recursive)) ;; CHECK-NEXT: (local $2 (ref null $struct.recursive)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.recursive)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (struct.new_default $struct.recursive) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.recursive) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref null $struct.recursive)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.recursive) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) @@ -1337,20 +1347,20 @@ ;; NOMNL-NEXT: (local $1 (ref null $struct.recursive)) ;; NOMNL-NEXT: (local $2 (ref null $struct.recursive)) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.recursive)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (struct.new_default $struct.recursive) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result (ref null $struct.recursive)) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $1) ;; NOMNL-NEXT: ) @@ -1454,14 +1464,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result (ref $struct.A)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.nondefaultable)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (local.get $a) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.nondefaultable) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) @@ -1474,14 +1484,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result (ref $struct.A)) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.nonnullable)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (local.get $a) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.nonnullable) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $1) @@ -1508,7 +1518,7 @@ ;; CHECK-NEXT: (local $5 f64) ;; CHECK-NEXT: (loop $outer ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $4 ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) @@ -1521,13 +1531,13 @@ ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (local.get $5) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -1537,14 +1547,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (f64.const 42) @@ -1554,13 +1564,13 @@ ;; CHECK-NEXT: (loop $inner ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.add ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -1577,7 +1587,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -1585,7 +1595,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) @@ -1602,7 +1612,7 @@ ;; NOMNL-NEXT: (local $5 f64) ;; NOMNL-NEXT: (loop $outer ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $4 ;; NOMNL-NEXT: (i32.const 2) ;; NOMNL-NEXT: ) @@ -1615,13 +1625,13 @@ ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (local.get $5) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -1631,14 +1641,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $3) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (f64.const 42) @@ -1648,13 +1658,13 @@ ;; NOMNL-NEXT: (loop $inner ;; NOMNL-NEXT: (block ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (i32.add ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -1671,7 +1681,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -1679,7 +1689,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $3) ;; NOMNL-NEXT: ) @@ -1755,14 +1765,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $0) @@ -1771,14 +1781,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) @@ -1787,14 +1797,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $4 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $5) @@ -1811,14 +1821,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $0 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $0) @@ -1827,14 +1837,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) @@ -1843,14 +1853,14 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $4 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $5 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $5) @@ -1883,39 +1893,39 @@ ;; CHECK-NEXT: (local $3 i32) ;; CHECK-NEXT: (local $4 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $4 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $3) ;; CHECK-NEXT: ) @@ -1928,39 +1938,39 @@ ;; NOMNL-NEXT: (local $3 i32) ;; NOMNL-NEXT: (local $4 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $1) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $4 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $3) ;; NOMNL-NEXT: ) @@ -1996,31 +2006,31 @@ ;; CHECK-NEXT: (local $4 i32) ;; CHECK-NEXT: (local $5 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $4 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $5 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $2) ;; CHECK-NEXT: ) @@ -2028,7 +2038,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $4) ;; CHECK-NEXT: ) @@ -2042,31 +2052,31 @@ ;; NOMNL-NEXT: (local $4 i32) ;; NOMNL-NEXT: (local $5 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $4 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $5 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $2) ;; NOMNL-NEXT: ) @@ -2074,7 +2084,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $4) ;; NOMNL-NEXT: ) @@ -2112,7 +2122,7 @@ ;; CHECK-NEXT: (block $block (result (ref null $struct.A)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_if $block - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2129,7 +2139,7 @@ ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (br_if $block - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -2172,7 +2182,7 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2189,7 +2199,7 @@ ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -2218,14 +2228,14 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result f64) @@ -2233,7 +2243,7 @@ ;; CHECK-NEXT: (block $block (result (ref null $struct.A)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_if $block - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2250,14 +2260,14 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result f64) @@ -2265,7 +2275,7 @@ ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (br_if $block - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -2313,7 +2323,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_if $block - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2338,7 +2348,7 @@ ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (br_if $block - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -2515,19 +2525,19 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 1) @@ -2535,7 +2545,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2544,19 +2554,19 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 1) @@ -2564,7 +2574,7 @@ ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -2595,22 +2605,22 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.get $1) ;; CHECK-NEXT: ) @@ -2620,22 +2630,22 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (block (result i32) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.get $1) ;; NOMNL-NEXT: ) @@ -2671,7 +2681,7 @@ ;; CHECK-NEXT: (block $block (result (ref null $struct.A)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_if $block - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $3 ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) @@ -2684,7 +2694,7 @@ ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (local.get $4) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) @@ -2706,7 +2716,7 @@ ;; NOMNL-NEXT: (block $block (result (ref null $struct.A)) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (br_if $block - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $3 ;; NOMNL-NEXT: (i32.const 42) ;; NOMNL-NEXT: ) @@ -2719,7 +2729,7 @@ ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (local.get $4) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) @@ -2760,14 +2770,14 @@ ;; CHECK-NEXT: (br_if $loop ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -2781,14 +2791,14 @@ ;; NOMNL-NEXT: (br_if $loop ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -2814,14 +2824,14 @@ ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (local $2 f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $struct.A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (local.set $1 ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $struct.A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) @@ -2834,14 +2844,14 @@ ;; NOMNL-NEXT: (local $1 i32) ;; NOMNL-NEXT: (local $2 f64) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $struct.A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (local.set $1 ;; NOMNL-NEXT: (i32.const 0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (f64.const 0) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $struct.A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (unreachable) diff --git a/test/lit/passes/inlining-gc.wast b/test/lit/passes/inlining-gc.wast index 11ac125b20b..cebdbd052d9 100644 --- a/test/lit/passes/inlining-gc.wast +++ b/test/lit/passes/inlining-gc.wast @@ -6,7 +6,7 @@ ;; CHECK-NEXT: (local $0 funcref) ;; CHECK-NEXT: (block $__inlined_func$target-nullable ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/inlining-optimizing.wast b/test/lit/passes/inlining-optimizing.wast index 7da2efb72cc..65384330a7a 100644 --- a/test/lit/passes/inlining-optimizing.wast +++ b/test/lit/passes/inlining-optimizing.wast @@ -17,6 +17,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/inlining_all-features.wast b/test/lit/passes/inlining_all-features.wast index 5ce964ceb17..9b3a426d50a 100644 --- a/test/lit/passes/inlining_all-features.wast +++ b/test/lit/passes/inlining_all-features.wast @@ -141,23 +141,13 @@ ) ;; CHECK: (func $1 ;; CHECK-NEXT: (block $__inlined_func$0 - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (call_ref $none_=>_none - ;; CHECK-NEXT: (ref.null $none_=>_none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (br $__inlined_func$0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: (br $__inlined_func$0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $1 (type $none_=>_none) ;; NOMNL-NEXT: (block $__inlined_func$0 - ;; NOMNL-NEXT: (block - ;; NOMNL-NEXT: (call_ref $none_=>_none - ;; NOMNL-NEXT: (ref.null $none_=>_none) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (br $__inlined_func$0) - ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: (br $__inlined_func$0) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) diff --git a/test/lit/passes/inlining_splitting.wast b/test/lit/passes/inlining_splitting.wast index aca20f8e8f5..c114d455109 100644 --- a/test/lit/passes/inlining_splitting.wast +++ b/test/lit/passes/inlining_splitting.wast @@ -432,7 +432,7 @@ ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-ref.is ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz @@ -449,7 +449,7 @@ ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-A$condition-ref.is0 ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.eqz @@ -833,7 +833,7 @@ ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$error-if-null (result anyref) ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if @@ -855,7 +855,7 @@ ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$error-if-null0 (result anyref) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if @@ -909,12 +909,12 @@ ;; CHECK: (func $call-too-many ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -951,12 +951,12 @@ ;; CHECK: (func $call-tail-not-simple ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $tail-not-simple - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $tail-not-simple - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -987,7 +987,7 @@ ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$reachable-if-body (result anyref) ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if @@ -1010,7 +1010,7 @@ ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$reachable-if-body0 (result anyref) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if @@ -1087,12 +1087,12 @@ ;; CHECK: (func $call-reachable-if-body-return ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $reachable-if-body-return - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $reachable-if-body-return - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1121,7 +1121,7 @@ ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$unreachable-if-body-no-result ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null @@ -1136,7 +1136,7 @@ ;; CHECK-NEXT: (block ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$unreachable-if-body-no-result0 ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (ref.is_null @@ -1185,7 +1185,7 @@ ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$multi-if (result anyref) ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if @@ -1216,7 +1216,7 @@ ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (block $__inlined_func$byn-split-inlineable-B$multi-if0 (result anyref) ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (ref.null data) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result anyref) ;; CHECK-NEXT: (if @@ -1320,12 +1320,12 @@ ;; CHECK: (func $call-too-many-ifs ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many-ifs - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $too-many-ifs - ;; CHECK-NEXT: (ref.null data) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/intrinsic-lowering.wast b/test/lit/passes/intrinsic-lowering.wast index de1c981bc59..c6965c3992b 100644 --- a/test/lit/passes/intrinsic-lowering.wast +++ b/test/lit/passes/intrinsic-lowering.wast @@ -2,7 +2,6 @@ ;; RUN: wasm-opt %s --intrinsic-lowering -all -S -o - | filecheck %s (module - ;; CHECK: (type $none (func)) (type $none (func)) ;; call.without.effects with no params. @@ -27,8 +26,11 @@ ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call_ref $none - ;; CHECK-NEXT: (ref.null $none) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/jspi.wast b/test/lit/passes/jspi.wast index 104dc25220b..5b8669be122 100644 --- a/test/lit/passes/jspi.wast +++ b/test/lit/passes/jspi.wast @@ -24,7 +24,7 @@ (import "js" "import_and_export" (func $import_and_export (param i32) (result i32))) ;; CHECK: (import "js" "import_void_return" (func $import$import_void_return (param externref i32))) (import "js" "import_void_return" (func $import_void_return (param i32))) - ;; CHECK: (global $suspender (mut externref) (ref.null extern)) + ;; CHECK: (global $suspender (mut externref) (ref.null noextern)) ;; CHECK: (export "update_state_void" (func $export$update_state_void)) (export "update_state_void" (func $update_state_void)) diff --git a/test/lit/passes/local-subtyping-nn.wast b/test/lit/passes/local-subtyping-nn.wast index 24517fb0815..a3430052554 100644 --- a/test/lit/passes/local-subtyping-nn.wast +++ b/test/lit/passes/local-subtyping-nn.wast @@ -5,8 +5,6 @@ ;; RUN: | filecheck %s --check-prefix=NOMNL (module - ;; CHECK: (type $struct (struct )) - ;; NOMNL: (type $struct (struct_subtype data)) (type $struct (struct)) ;; CHECK: (import "out" "i32" (func $i32 (result i32))) @@ -14,11 +12,11 @@ (import "out" "i32" (func $i32 (result i32))) ;; CHECK: (func $non-nullable - ;; CHECK-NEXT: (local $x (ref $struct)) + ;; CHECK-NEXT: (local $x (ref none)) ;; CHECK-NEXT: (local $y (ref $none_=>_i32)) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $y @@ -29,11 +27,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $non-nullable (type $none_=>_none) - ;; NOMNL-NEXT: (local $x (ref $struct)) + ;; NOMNL-NEXT: (local $x (ref none)) ;; NOMNL-NEXT: (local $y (ref $none_=>_i32)) ;; NOMNL-NEXT: (local.set $x ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $y @@ -62,12 +60,12 @@ ) ;; CHECK: (func $uses-default (param $i i32) - ;; CHECK-NEXT: (local $x (ref null $struct)) + ;; CHECK-NEXT: (local $x nullref) ;; CHECK-NEXT: (if ;; CHECK-NEXT: (local.get $i) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -76,12 +74,12 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $uses-default (type $i32_=>_none) (param $i i32) - ;; NOMNL-NEXT: (local $x (ref null $struct)) + ;; NOMNL-NEXT: (local $x nullref) ;; NOMNL-NEXT: (if ;; NOMNL-NEXT: (local.get $i) ;; NOMNL-NEXT: (local.set $x ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) diff --git a/test/lit/passes/local-subtyping.wast b/test/lit/passes/local-subtyping.wast index a2a5780da72..e281d5cf21f 100644 --- a/test/lit/passes/local-subtyping.wast +++ b/test/lit/passes/local-subtyping.wast @@ -11,7 +11,6 @@ ;; CHECK: (type ${} (struct )) (type ${} (struct_subtype data)) - ;; CHECK: (type ${i32} (struct (field i32))) (type ${i32} (struct_subtype (field i32) data)) (type $array (array_subtype i8 data)) @@ -323,7 +322,7 @@ ;; CHECK-NEXT: (local.tee $temp ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -332,7 +331,7 @@ ;; CHECK-NEXT: (local.tee $temp ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -365,25 +364,25 @@ ;; CHECK: (func $update-nulls ;; CHECK-NEXT: (local $x (ref null ${})) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $x ;; CHECK-NEXT: (struct.new_default ${}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null ${i32}) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $update-nulls diff --git a/test/lit/passes/merge-blocks.wast b/test/lit/passes/merge-blocks.wast index f858b0dc8d8..cf920d7565f 100644 --- a/test/lit/passes/merge-blocks.wast +++ b/test/lit/passes/merge-blocks.wast @@ -21,10 +21,10 @@ ;; CHECK-NEXT: (block $label$1 (result i31ref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_on_i31 $label$1 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null i31) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -45,11 +45,13 @@ ;; CHECK: (func $struct.set ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1234) - ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1234) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 5) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) @@ -71,11 +73,13 @@ ;; CHECK: (func $struct.get ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1234) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (block (result (ref null $struct)) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1234) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) diff --git a/test/lit/passes/optimize-instructions-call_ref.wast b/test/lit/passes/optimize-instructions-call_ref.wast index 4f5d484cf60..a82b1554258 100644 --- a/test/lit/passes/optimize-instructions-call_ref.wast +++ b/test/lit/passes/optimize-instructions-call_ref.wast @@ -210,6 +210,9 @@ ) ;; CHECK: (func $ignore-unreachable + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $ignore-unreachable diff --git a/test/lit/passes/optimize-instructions-gc-heap.wast b/test/lit/passes/optimize-instructions-gc-heap.wast index fc44e11de42..e448e57fd82 100644 --- a/test/lit/passes/optimize-instructions-gc-heap.wast +++ b/test/lit/passes/optimize-instructions-gc-heap.wast @@ -308,7 +308,7 @@ ;; CHECK-NEXT: (local.get $ref) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $ref - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) @@ -343,7 +343,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $ref - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) @@ -374,7 +374,7 @@ ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (local.set $other - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) @@ -717,6 +717,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast index b1fc9a42bcb..f01be393fdf 100644 --- a/test/lit/passes/optimize-instructions-gc-tnh.wast +++ b/test/lit/passes/optimize-instructions-gc-tnh.wast @@ -53,17 +53,7 @@ ;; TNH-NEXT: (i32.const 1) ;; TNH-NEXT: ) ;; TNH-NEXT: (drop - ;; TNH-NEXT: (ref.eq - ;; TNH-NEXT: (block (result (ref null $struct)) - ;; TNH-NEXT: (drop - ;; TNH-NEXT: (ref.null any) - ;; TNH-NEXT: ) - ;; TNH-NEXT: (ref.null $struct) - ;; TNH-NEXT: ) - ;; TNH-NEXT: (ref.as_data - ;; TNH-NEXT: (ref.null any) - ;; TNH-NEXT: ) - ;; TNH-NEXT: ) + ;; TNH-NEXT: (i32.const 1) ;; TNH-NEXT: ) ;; TNH-NEXT: ) ;; NO_TNH: (func $ref.eq-no (type $eqref_eqref_=>_none) (param $a eqref) (param $b eqref) @@ -85,14 +75,14 @@ ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (drop ;; NO_TNH-NEXT: (ref.eq - ;; NO_TNH-NEXT: (block (result (ref null $struct)) + ;; NO_TNH-NEXT: (block (result nullref) ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (ref.null any) + ;; NO_TNH-NEXT: (ref.null none) ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (ref.null $struct) + ;; NO_TNH-NEXT: (ref.null none) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: (ref.as_data - ;; NO_TNH-NEXT: (ref.null any) + ;; NO_TNH-NEXT: (ref.null none) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index da2411eedf0..ae12dca7ae9 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -14,12 +14,14 @@ (field $i64 (mut i64)) )) + ;; CHECK: (type $array (array (mut i8))) + ;; CHECK: (type $A (struct (field i32))) + ;; NOMNL: (type $array (array_subtype (mut i8) data)) + ;; NOMNL: (type $A (struct_subtype (field i32) data)) (type $A (struct (field i32))) - ;; CHECK: (type $array (array (mut i8))) - ;; NOMNL: (type $array (array_subtype (mut i8) data)) (type $array (array (mut i8))) ;; CHECK: (type $B (struct (field i32) (field i32) (field f32))) @@ -30,12 +32,9 @@ ;; NOMNL: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B)) (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B)) - ;; NOMNL: (type $C (struct_subtype (field i32) (field i32) (field f64) $A)) - ;; NOMNL: (type $empty (struct_subtype data)) (type $empty (struct)) - ;; CHECK: (type $C (struct (field i32) (field i32) (field f64))) (type $C (struct_subtype (field i32) (field i32) (field f64) $A)) ;; CHECK: (import "env" "get-i32" (func $get-i32 (result i32))) @@ -45,10 +44,10 @@ ;; These functions test if an `if` with subtyped arms is correctly folded ;; 1. if its `ifTrue` and `ifFalse` arms are identical (can fold) ;; CHECK: (func $if-arms-subtype-fold (result anyref) - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; NOMNL: (func $if-arms-subtype-fold (type $none_=>_anyref) (result anyref) - ;; NOMNL-NEXT: (ref.null eq) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) (func $if-arms-subtype-fold (result anyref) (if (result anyref) @@ -59,18 +58,10 @@ ) ;; 2. if its `ifTrue` and `ifFalse` arms are not identical (cannot fold) ;; CHECK: (func $if-arms-subtype-nofold (result anyref) - ;; CHECK-NEXT: (if (result anyref) - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: (ref.null data) - ;; CHECK-NEXT: (ref.null i31) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; NOMNL: (func $if-arms-subtype-nofold (type $none_=>_anyref) (result anyref) - ;; NOMNL-NEXT: (if (result anyref) - ;; NOMNL-NEXT: (i32.const 0) - ;; NOMNL-NEXT: (ref.null data) - ;; NOMNL-NEXT: (ref.null i31) - ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) (func $if-arms-subtype-nofold (result anyref) (if (result anyref) @@ -1254,7 +1245,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.tee $x ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1263,7 +1254,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (local.tee $x ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -1881,26 +1872,10 @@ ) ;; CHECK: (func $hoist-LUB-danger (param $x i32) (result i32) - ;; CHECK-NEXT: (if (result i32) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (ref.null $B) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.get $C 1 - ;; CHECK-NEXT: (ref.null $C) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; NOMNL: (func $hoist-LUB-danger (type $i32_=>_i32) (param $x i32) (result i32) - ;; NOMNL-NEXT: (if (result i32) - ;; NOMNL-NEXT: (local.get $x) - ;; NOMNL-NEXT: (struct.get $B 1 - ;; NOMNL-NEXT: (ref.null $B) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (struct.get $C 1 - ;; NOMNL-NEXT: (ref.null $C) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) (func $hoist-LUB-danger (param $x i32) (result i32) ;; In nominal typing, if we hoist the struct.get out of the if, then the if @@ -1952,44 +1927,44 @@ ;; CHECK: (func $incompatible-cast-of-null ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $array)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $array) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref null $array)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $array) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $incompatible-cast-of-null (type $none_=>_none) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $array)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $array) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (block (result (ref null $array)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (ref.as_non_null - ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $array) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -2171,74 +2146,74 @@ ;; CHECK: (func $ref-cast-static-null ;; CHECK-NEXT: (local $a (ref null $A)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $B)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref null $A)) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.tee $a - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $ref-cast-static-null (type $none_=>_none) ;; NOMNL-NEXT: (local $a (ref null $A)) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $B)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (block (result (ref null $A)) + ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (local.tee $a - ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null $A) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) diff --git a/test/lit/passes/precompute-gc-immutable.wast b/test/lit/passes/precompute-gc-immutable.wast index bb627dfa1cf..ebb26bfb52d 100644 --- a/test/lit/passes/precompute-gc-immutable.wast +++ b/test/lit/passes/precompute-gc-immutable.wast @@ -94,6 +94,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $helper @@ -136,8 +137,11 @@ ;; CHECK: (func $local-null (type $none_=>_none) ;; CHECK-NEXT: (local $ref-imm (ref null $struct-imm)) ;; CHECK-NEXT: (call $helper - ;; CHECK-NEXT: (struct.get $struct-imm 0 - ;; CHECK-NEXT: (ref.null $struct-imm) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/precompute-gc.wast b/test/lit/passes/precompute-gc.wast index a3fa63bb5fa..78e91d74944 100644 --- a/test/lit/passes/precompute-gc.wast +++ b/test/lit/passes/precompute-gc.wast @@ -32,11 +32,11 @@ ;; CHECK: (func $test-fallthrough (result i32) ;; CHECK-NEXT: (local $x funcref) ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (block (result funcref) + ;; CHECK-NEXT: (block (result nullfuncref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $test-fallthrough) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 1) @@ -44,11 +44,11 @@ ;; NOMNL: (func $test-fallthrough (type $func-return-i32) (result i32) ;; NOMNL-NEXT: (local $x funcref) ;; NOMNL-NEXT: (local.set $x - ;; NOMNL-NEXT: (block (result funcref) + ;; NOMNL-NEXT: (block (result nullfuncref) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (call $test-fallthrough) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (ref.null func) + ;; NOMNL-NEXT: (ref.null nofunc) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (i32.const 1) @@ -342,13 +342,13 @@ ;; CHECK-NEXT: (call $log ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $log ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $log @@ -367,13 +367,13 @@ ;; NOMNL-NEXT: (call $log ;; NOMNL-NEXT: (ref.eq ;; NOMNL-NEXT: (local.get $x) - ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (call $log ;; NOMNL-NEXT: (ref.eq ;; NOMNL-NEXT: (local.get $x) - ;; NOMNL-NEXT: (ref.null $struct) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (call $log @@ -1055,22 +1055,28 @@ ;; CHECK: (func $odd-cast-and-get ;; CHECK-NEXT: (local $temp (ref null $B)) ;; CHECK-NEXT: (local.set $temp - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $odd-cast-and-get (type $none_=>_none) ;; NOMNL-NEXT: (local $temp (ref null $B)) ;; NOMNL-NEXT: (local.set $temp - ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (struct.get $B 0 - ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null none) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -1098,13 +1104,16 @@ ;; CHECK-NEXT: (local $temp ((ref null $B) i32)) ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (tuple.make - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -1112,13 +1121,16 @@ ;; NOMNL-NEXT: (local $temp ((ref null $B) i32)) ;; NOMNL-NEXT: (local.set $temp ;; NOMNL-NEXT: (tuple.make - ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: (i32.const 10) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (struct.get $B 0 - ;; NOMNL-NEXT: (ref.null $B) + ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (ref.null none) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) @@ -1199,6 +1211,7 @@ ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $new_block_unreachable (type $none_=>_anyref) (result anyref) @@ -1208,6 +1221,7 @@ ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) (func $new_block_unreachable (result anyref) @@ -1263,7 +1277,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $ref - ;; CHECK-NEXT: (ref.null $empty) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $helper @@ -1295,7 +1309,7 @@ ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $ref - ;; NOMNL-NEXT: (ref.null $empty) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (call $helper diff --git a/test/lit/passes/remove-unused-brs-gc.wast b/test/lit/passes/remove-unused-brs-gc.wast index 3b7346e3fe3..9473b062757 100644 --- a/test/lit/passes/remove-unused-brs-gc.wast +++ b/test/lit/passes/remove-unused-brs-gc.wast @@ -8,7 +8,7 @@ ;; CHECK: (func $br_on_non_data-1 ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $any (result anyref) + ;; CHECK-NEXT: (block $any (result i31ref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br $any ;; CHECK-NEXT: (i31.new @@ -16,7 +16,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -35,11 +35,11 @@ ) ;; CHECK: (func $br_on_non_data-2 (param $data (ref data)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block $any (result anyref) + ;; CHECK-NEXT: (block $any (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $data) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -144,7 +144,7 @@ ;; CHECK-NEXT: (block $block (result (ref $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_on_cast_static $block $struct - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) @@ -191,7 +191,7 @@ ;; CHECK-NEXT: (if (result i32) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (ref.test_static $struct - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) @@ -199,9 +199,9 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (if (result anyref) ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (ref.cast_static $struct - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -211,12 +211,12 @@ ;; CHECK-NEXT: (block $something (result anyref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_on_cast_static $something $struct - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -225,13 +225,13 @@ ;; CHECK-NEXT: (block $nothing ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_on_null $nothing - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/remove-unused-brs.wast b/test/lit/passes/remove-unused-brs.wast index ddfbabe844d..7db4bdcd597 100644 --- a/test/lit/passes/remove-unused-brs.wast +++ b/test/lit/passes/remove-unused-brs.wast @@ -6,9 +6,9 @@ (module ;; Regression test in which we need to calculate a proper LUB. ;; CHECK: (func $selectify-fresh-lub (param $x i32) (result anyref) - ;; CHECK-NEXT: (select (result eqref) - ;; CHECK-NEXT: (ref.null i31) - ;; CHECK-NEXT: (ref.null data) + ;; CHECK-NEXT: (select (result nullref) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/remove-unused-module-elements-refs.wast b/test/lit/passes/remove-unused-module-elements-refs.wast index 2a976cf8ad0..698b0186753 100644 --- a/test/lit/passes/remove-unused-module-elements-refs.wast +++ b/test/lit/passes/remove-unused-module-elements-refs.wast @@ -18,10 +18,16 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-B) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -44,7 +50,7 @@ ) ;; CHECK: (func $target-A (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-A (type $A) ;; This function is reachable from the export "foo": there is a RefFunc and @@ -80,8 +86,11 @@ ;; CHECK: (export "foo" (func $foo)) ;; CHECK: (func $foo (type $A) - ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A) @@ -97,7 +106,7 @@ ) ;; CHECK: (func $target-A (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-A (type $A) ;; This function is reachable. @@ -119,14 +128,20 @@ ;; CHECK: (export "foo" (func $foo)) ;; CHECK: (func $foo (type $A) - ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-2) @@ -148,14 +163,14 @@ ) ;; CHECK: (func $target-A-1 (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-A-1 (type $A) ;; This function is reachable. ) ;; CHECK: (func $target-A-2 (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-A-2 (type $A) ;; This function is reachable. @@ -181,14 +196,20 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $foo (export "foo") @@ -207,14 +228,14 @@ ) ;; CHECK: (func $target-A-1 (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-A-1 (type $A) ;; This function is reachable. ) ;; CHECK: (func $target-A-2 (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-A-2 (type $A) ;; This function is reachable. @@ -300,7 +321,7 @@ ;; CHECK: (func $foo (type $A) ;; CHECK-NEXT: (call $call-without-effects - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-keep) @@ -325,13 +346,13 @@ ) ;; CHECK: (func $target-keep (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-keep (type $A) ) ;; CHECK: (func $target-keep-2 (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-keep-2 (type $A) ) diff --git a/test/lit/passes/roundtrip.wast b/test/lit/passes/roundtrip.wast index a61e7e71022..b23819b7b3f 100644 --- a/test/lit/passes/roundtrip.wast +++ b/test/lit/passes/roundtrip.wast @@ -10,7 +10,7 @@ ;; CHECK-NEXT: (local.set $0 ;; CHECK-NEXT: (block $label$1 (result funcref (ref $none)) ;; CHECK-NEXT: (tuple.make - ;; CHECK-NEXT: (ref.null func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: (ref.func $foo) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/signature-pruning.wast b/test/lit/passes/signature-pruning.wast index ec47700efdc..26ecadfc900 100644 --- a/test/lit/passes/signature-pruning.wast +++ b/test/lit/passes/signature-pruning.wast @@ -750,7 +750,7 @@ ;; CHECK: (func $foo (type $sig-foo) ;; CHECK-NEXT: (local $0 anyref) ;; CHECK-NEXT: (local.set $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop @@ -776,7 +776,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $bar - ;; CHECK-NEXT: (ref.null data) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $bar (type $sig-bar) (param $anyref anyref) diff --git a/test/lit/passes/signature-refining.wast b/test/lit/passes/signature-refining.wast index e5f42ffa0e4..3d2f7b1a408 100644 --- a/test/lit/passes/signature-refining.wast +++ b/test/lit/passes/signature-refining.wast @@ -485,7 +485,7 @@ ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call $func - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $caller @@ -527,7 +527,7 @@ ) ;; CHECK: (func $func-cannot-refine (type $sig-cannot-refine) (result anyref) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) (func $func-cannot-refine (type $sig-cannot-refine) (result anyref) (ref.null any) @@ -583,12 +583,13 @@ ) (module + ;; CHECK: (type $sig (func_subtype (result (ref null $struct)) func)) + ;; CHECK: (type $struct (struct_subtype data)) (type $struct (struct_subtype data)) ;; This signature has multiple functions using it, and some of them have nulls ;; which should be updated when we refine. - ;; CHECK: (type $sig (func_subtype (result (ref null $struct)) func)) (type $sig (func_subtype (result anyref) func)) ;; CHECK: (func $func-1 (type $sig) (result (ref null $struct)) @@ -599,14 +600,14 @@ ) ;; CHECK: (func $func-2 (type $sig) (result (ref null $struct)) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) (func $func-2 (type $sig) (result anyref) (ref.null any) ) ;; CHECK: (func $func-3 (type $sig) (result (ref null $struct)) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) (func $func-3 (type $sig) (result anyref) (ref.null eq) @@ -616,7 +617,7 @@ ;; CHECK-NEXT: (if ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (return - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) @@ -700,7 +701,7 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/simplify-locals-gc-nn.wast b/test/lit/passes/simplify-locals-gc-nn.wast index e5941cc0eeb..c7e4b6373ea 100644 --- a/test/lit/passes/simplify-locals-gc-nn.wast +++ b/test/lit/passes/simplify-locals-gc-nn.wast @@ -9,7 +9,7 @@ ;; CHECK-NEXT: (do ;; CHECK-NEXT: (local.set $nn ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -56,7 +56,7 @@ ;; CHECK-NEXT: (do ;; CHECK-NEXT: (local.set $nullable ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/simplify-locals-gc-validation.wast b/test/lit/passes/simplify-locals-gc-validation.wast index bda59882b80..0587303c2ff 100644 --- a/test/lit/passes/simplify-locals-gc-validation.wast +++ b/test/lit/passes/simplify-locals-gc-validation.wast @@ -13,7 +13,7 @@ ;; CHECK-NEXT: (ref.as_non_null ;; CHECK-NEXT: (local.tee $nn ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/simplify-locals-gc.wast b/test/lit/passes/simplify-locals-gc.wast index ba9e144c6d5..75be02cf268 100644 --- a/test/lit/passes/simplify-locals-gc.wast +++ b/test/lit/passes/simplify-locals-gc.wast @@ -108,6 +108,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 @@ -123,6 +124,7 @@ ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (struct.set $struct 0 @@ -154,15 +156,15 @@ ;; CHECK-NEXT: (block $block ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br_on_null $block - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $temp - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (br $block) ;; CHECK-NEXT: (local.set $temp - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -176,15 +178,15 @@ ;; NOMNL-NEXT: (block $block ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (br_on_null $block - ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $temp - ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (br $block) ;; NOMNL-NEXT: (local.set $temp - ;; NOMNL-NEXT: (ref.null any) + ;; NOMNL-NEXT: (ref.null none) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop diff --git a/test/lit/passes/type-refining-isorecursive.wast b/test/lit/passes/type-refining-isorecursive.wast index 45d85a094a8..9df68615448 100644 --- a/test/lit/passes/type-refining-isorecursive.wast +++ b/test/lit/passes/type-refining-isorecursive.wast @@ -17,19 +17,19 @@ ;; CHECK: (func $foo (type $ref|$0|_ref|$1|_ref|$2|_=>_none) (param $x (ref $0)) (param $y (ref $1)) (param $z (ref $2)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $1 - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $z) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $2 - ;; CHECK-NEXT: (ref.null i31) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -86,21 +86,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $0 - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $all) ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $1 - ;; CHECK-NEXT: (ref.null eq) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $all) ;; CHECK-NEXT: (local.get $z) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $2 - ;; CHECK-NEXT: (ref.null i31) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $all) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast index 6b56e56e9f8..71a4cb4257b 100644 --- a/test/lit/passes/type-refining.wast +++ b/test/lit/passes/type-refining.wast @@ -13,7 +13,7 @@ ;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct)) ;; CHECK-NEXT: (struct.set $struct 1 ;; CHECK-NEXT: (local.get $struct) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 2 ;; CHECK-NEXT: (local.get $struct) @@ -571,7 +571,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 ;; CHECK-NEXT: (local.get $struct) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $update-null (param $struct (ref $struct)) @@ -607,7 +607,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $child 0 ;; CHECK-NEXT: (local.get $child) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $update-null (param $struct (ref $struct)) (param $child (ref $child)) @@ -635,7 +635,7 @@ ;; CHECK: (func $update-null (type $ref|$struct|_ref|$child|_=>_none) (param $struct (ref $struct)) (param $child (ref $child)) ;; CHECK-NEXT: (struct.set $struct 0 ;; CHECK-NEXT: (local.get $struct) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $child 0 ;; CHECK-NEXT: (local.get $child) @@ -711,7 +711,7 @@ ;; CHECK: (func $work (type $ref|$struct|_=>_none) (param $struct (ref $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 @@ -747,12 +747,12 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (local.get $child) - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct - ;; CHECK-NEXT: (ref.null $child) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -795,12 +795,13 @@ ;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner)) (type $Leaf2-Inner (struct_subtype $Root-Inner)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + (type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer)) - ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data)) + ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $Leaf1-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) - (type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer)) + ;; CHECK: (type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner)) + + ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data)) ;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) @@ -813,14 +814,12 @@ ;; CHECK: (func $func (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $Leaf1-Outer) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $Leaf1-Inner 0 + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -872,23 +871,39 @@ ;; CHECK: (func $non-nullability (type $ref|$A|_=>_none) (param $nn (ref $A)) ;; CHECK-NEXT: (local $temp (ref null $A)) - ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (ref.null $A) - ;; CHECK-NEXT: (local.get $nn) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $nn) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (ref.null $A) - ;; CHECK-NEXT: (local.tee $temp - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $A ;; CHECK-NEXT: (local.tee $temp - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -945,8 +960,11 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $A ;; CHECK-NEXT: (local.tee $a - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -978,32 +996,48 @@ ) (module - ;; CHECK: (type $A (struct_subtype (field (mut (ref $A))) data)) + ;; CHECK: (type $A (struct_subtype (field (mut (ref null $A))) data)) (type $A (struct_subtype (field (mut (ref null $A))) data)) ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) ;; CHECK: (func $non-nullability-block (type $ref|$A|_=>_none) (param $nn (ref $A)) - ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (ref.null $A) - ;; CHECK-NEXT: (local.get $nn) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $nn) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (ref.null $A) - ;; CHECK-NEXT: (if (result (ref $A)) - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (if (result (ref null $A)) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $A - ;; CHECK-NEXT: (if (result (ref $A)) + ;; CHECK-NEXT: (if (result (ref null $A)) ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) diff --git a/test/lit/table-operations.wast b/test/lit/table-operations.wast index ace31a9c734..842270561c9 100644 --- a/test/lit/table-operations.wast +++ b/test/lit/table-operations.wast @@ -134,13 +134,13 @@ ;; CHECK-BINARY: (func $table-grow (param $sz i32) (result i32) ;; CHECK-BINARY-NEXT: (table.grow $table-1 - ;; CHECK-BINARY-NEXT: (ref.null func) + ;; CHECK-BINARY-NEXT: (ref.null nofunc) ;; CHECK-BINARY-NEXT: (local.get $sz) ;; CHECK-BINARY-NEXT: ) ;; CHECK-BINARY-NEXT: ) ;; CHECK-TEXT: (func $table-grow (param $sz i32) (result i32) ;; CHECK-TEXT-NEXT: (table.grow $table-1 - ;; CHECK-TEXT-NEXT: (ref.null func) + ;; CHECK-TEXT-NEXT: (ref.null nofunc) ;; CHECK-TEXT-NEXT: (local.get $sz) ;; CHECK-TEXT-NEXT: ) ;; CHECK-TEXT-NEXT: ) @@ -197,7 +197,7 @@ ;; CHECK-NODEBUG: (func $4 (param $0 i32) (result i32) ;; CHECK-NODEBUG-NEXT: (table.grow $0 -;; CHECK-NODEBUG-NEXT: (ref.null func) +;; CHECK-NODEBUG-NEXT: (ref.null nofunc) ;; CHECK-NODEBUG-NEXT: (local.get $0) ;; CHECK-NODEBUG-NEXT: ) ;; CHECK-NODEBUG-NEXT: ) diff --git a/test/lit/types-function-references.wast b/test/lit/types-function-references.wast index f4b244c50c9..8722ff3fd9b 100644 --- a/test/lit/types-function-references.wast +++ b/test/lit/types-function-references.wast @@ -22,8 +22,6 @@ (type $_=>_eqref (func (result eqref))) ;; CHECK-BINARY: (type $i32-i32 (func (param i32) (result i32))) - ;; CHECK-BINARY: (type $=>eqref (func (result eqref))) - ;; CHECK-BINARY: (type $ref|$i32-i32|_=>_i32 (func (param (ref $i32-i32)) (result i32))) ;; CHECK-BINARY: (type $ref?|$i32-i32|_=>_i32 (func (param (ref null $i32-i32)) (result i32))) @@ -33,8 +31,6 @@ ;; CHECK-BINARY: (type $f64_=>_ref_null<_->_eqref> (func (param f64) (result (ref null $=>eqref)))) ;; CHECK-TEXT: (type $i32-i32 (func (param i32) (result i32))) - ;; CHECK-TEXT: (type $=>eqref (func (result eqref))) - ;; CHECK-TEXT: (type $ref|$i32-i32|_=>_i32 (func (param (ref $i32-i32)) (result i32))) ;; CHECK-TEXT: (type $ref?|$i32-i32|_=>_i32 (func (param (ref null $i32-i32)) (result i32))) @@ -43,18 +39,26 @@ ;; CHECK-TEXT: (type $f64_=>_ref_null<_->_eqref> (func (param f64) (result (ref null $=>eqref)))) (type $f64_=>_ref_null<_->_eqref> (func (param f64) (result (ref null $_=>_eqref)))) - (type $=>eqref (func (result eqref))) ;; CHECK-BINARY: (type $=>anyref (func (result anyref))) + + ;; CHECK-BINARY: (type $none_=>_i32_ref?|$mixed_results|_f64 (func (result i32 (ref null $mixed_results) f64))) + + ;; CHECK-BINARY: (type $ref?|$mixed_results|_=>_none (func (param (ref null $mixed_results)))) + + ;; CHECK-BINARY: (type $=>eqref (func (result eqref))) ;; CHECK-TEXT: (type $=>anyref (func (result anyref))) + + ;; CHECK-TEXT: (type $none_=>_i32_ref?|$mixed_results|_f64 (func (result i32 (ref null $mixed_results) f64))) + + ;; CHECK-TEXT: (type $ref?|$mixed_results|_=>_none (func (param (ref null $mixed_results)))) + + ;; CHECK-TEXT: (type $=>eqref (func (result eqref))) + (type $=>eqref (func (result eqref))) (type $=>anyref (func (result anyref))) (type $mixed_results (func (result anyref f32 anyref f32))) (type $i32-i32 (func (param i32) (result i32))) - ;; CHECK-BINARY: (type $none_=>_i32_ref?|$mixed_results|_f64 (func (result i32 (ref null $mixed_results) f64))) - - ;; CHECK-BINARY: (type $ref?|$mixed_results|_=>_none (func (param (ref null $mixed_results)))) - ;; CHECK-BINARY: (elem declare func $call-ref $call-ref-more) ;; CHECK-BINARY: (func $call-ref @@ -62,10 +66,6 @@ ;; CHECK-BINARY-NEXT: (ref.func $call-ref) ;; CHECK-BINARY-NEXT: ) ;; CHECK-BINARY-NEXT: ) - ;; CHECK-TEXT: (type $none_=>_i32_ref?|$mixed_results|_f64 (func (result i32 (ref null $mixed_results) f64))) - - ;; CHECK-TEXT: (type $ref?|$mixed_results|_=>_none (func (param (ref null $mixed_results)))) - ;; CHECK-TEXT: (elem declare func $call-ref $call-ref-more) ;; CHECK-TEXT: (func $call-ref @@ -160,10 +160,10 @@ (call_ref (i32.const 42) (local.get $f)) ) ;; CHECK-BINARY: (func $ref-in-sig (param $0 f64) (result (ref null $=>eqref)) - ;; CHECK-BINARY-NEXT: (ref.null $=>eqref) + ;; CHECK-BINARY-NEXT: (ref.null nofunc) ;; CHECK-BINARY-NEXT: ) ;; CHECK-TEXT: (func $ref-in-sig (param $0 f64) (result (ref null $=>eqref)) - ;; CHECK-TEXT-NEXT: (ref.null $=>eqref) + ;; CHECK-TEXT-NEXT: (ref.null nofunc) ;; CHECK-TEXT-NEXT: ) (func $ref-in-sig (param $0 f64) (result (ref null $=>eqref)) (ref.null $=>eqref) @@ -380,8 +380,6 @@ ;; CHECK-NODEBUG: (type $i32_=>_i32 (func (param i32) (result i32))) -;; CHECK-NODEBUG: (type $none_=>_eqref (func (result eqref))) - ;; CHECK-NODEBUG: (type $ref|i32_->_i32|_=>_i32 (func (param (ref $i32_=>_i32)) (result i32))) ;; CHECK-NODEBUG: (type $ref?|i32_->_i32|_=>_i32 (func (param (ref null $i32_=>_i32)) (result i32))) @@ -396,6 +394,8 @@ ;; CHECK-NODEBUG: (type $ref?|none_->_anyref_f32_anyref_f32|_=>_none (func (param (ref null $none_=>_anyref_f32_anyref_f32)))) +;; CHECK-NODEBUG: (type $none_=>_eqref (func (result eqref))) + ;; CHECK-NODEBUG: (elem declare func $0 $2) ;; CHECK-NODEBUG: (func $0 @@ -443,7 +443,7 @@ ;; CHECK-NODEBUG-NEXT: ) ;; CHECK-NODEBUG: (func $6 (param $0 f64) (result (ref null $none_=>_eqref)) -;; CHECK-NODEBUG-NEXT: (ref.null $none_=>_eqref) +;; CHECK-NODEBUG-NEXT: (ref.null nofunc) ;; CHECK-NODEBUG-NEXT: ) ;; CHECK-NODEBUG: (func $7 diff --git a/test/lit/validation/eqref.wast b/test/lit/validation/eqref.wast index 78b6e75d2b2..4c97ad39b5e 100644 --- a/test/lit/validation/eqref.wast +++ b/test/lit/validation/eqref.wast @@ -4,16 +4,12 @@ ;; RUN: not wasm-opt --enable-reference-types %s 2>&1 | filecheck %s --check-prefix NO-GC ;; RUN: wasm-opt --enable-reference-types --enable-gc %s -o - -S | filecheck %s --check-prefix GC -;; NO-GC: ref.null type should be allowed +;; NO-GC: all used types should be allowed -;; GC: (drop -;; GC: (ref.null eq) -;; GC: ) +;; GC: (func $foo (param $x eqref) (module - (func $foo - (drop - (ref.null eq) - ) + (func $foo (param $x eqref) + (nop) ) ) diff --git a/test/multi-table.wast.from-wast b/test/multi-table.wast.from-wast index 73a9abea331..ece92124c24 100644 --- a/test/multi-table.wast.from-wast +++ b/test/multi-table.wast.from-wast @@ -10,11 +10,11 @@ (elem $0 (table $t1) (i32.const 0) func $f) (elem $1 (table $t2) (i32.const 0) func $f) (elem $activeNonZeroOffset (table $t2) (i32.const 1) func $f $g) - (elem $e3-1 (table $t3) (global.get $g2) funcref (ref.func $f) (ref.null func)) + (elem $e3-1 (table $t3) (global.get $g2) funcref (ref.func $f) (ref.null nofunc)) (elem $e3-2 (table $t3) (i32.const 2) func $f $g) (elem $passive-1 func $f $g) - (elem $passive-2 funcref (ref.func $f) (ref.func $g) (ref.null func)) - (elem $passive-3 (ref null $none_=>_none) (ref.func $f) (ref.func $g) (ref.null $none_=>_none) (global.get $g1)) + (elem $passive-2 funcref (ref.func $f) (ref.func $g) (ref.null nofunc)) + (elem $passive-3 (ref null $none_=>_none) (ref.func $f) (ref.func $g) (ref.null nofunc) (global.get $g1)) (elem $empty func) (elem $especial (table $tspecial) (i32.const 0) (ref null $none_=>_none) (ref.func $f) (ref.func $h)) (func $f diff --git a/test/multi-table.wast.fromBinary b/test/multi-table.wast.fromBinary index 427fb44f3df..b70e78a2f10 100644 --- a/test/multi-table.wast.fromBinary +++ b/test/multi-table.wast.fromBinary @@ -10,11 +10,11 @@ (elem $0 (table $t1) (i32.const 0) func $f) (elem $1 (table $t2) (i32.const 0) func $f) (elem $activeNonZeroOffset (table $t2) (i32.const 1) func $f $g) - (elem $e3-1 (table $t3) (global.get $g2) funcref (ref.func $f) (ref.null func)) + (elem $e3-1 (table $t3) (global.get $g2) funcref (ref.func $f) (ref.null nofunc)) (elem $e3-2 (table $t3) (i32.const 2) func $f $g) (elem $passive-1 func $f $g) - (elem $passive-2 funcref (ref.func $f) (ref.func $g) (ref.null func)) - (elem $passive-3 (ref null $none_=>_none) (ref.func $f) (ref.func $g) (ref.null $none_=>_none) (global.get $g1)) + (elem $passive-2 funcref (ref.func $f) (ref.func $g) (ref.null nofunc)) + (elem $passive-3 (ref null $none_=>_none) (ref.func $f) (ref.func $g) (ref.null nofunc) (global.get $g1)) (elem $empty func) (elem $especial (table $tspecial) (i32.const 0) (ref null $none_=>_none) (ref.func $f) (ref.func $h)) (func $f diff --git a/test/multi-table.wast.fromBinary.noDebugInfo b/test/multi-table.wast.fromBinary.noDebugInfo index 7fc6670872c..cf938054a5a 100644 --- a/test/multi-table.wast.fromBinary.noDebugInfo +++ b/test/multi-table.wast.fromBinary.noDebugInfo @@ -10,11 +10,11 @@ (elem $0 (table $timport$0) (i32.const 0) func $0) (elem $1 (table $0) (i32.const 0) func $0) (elem $2 (table $0) (i32.const 1) func $0 $1) - (elem $3 (table $1) (global.get $global$1) funcref (ref.func $0) (ref.null func)) + (elem $3 (table $1) (global.get $global$1) funcref (ref.func $0) (ref.null nofunc)) (elem $4 (table $1) (i32.const 2) func $0 $1) (elem $5 func $0 $1) - (elem $6 funcref (ref.func $0) (ref.func $1) (ref.null func)) - (elem $7 (ref null $none_=>_none) (ref.func $0) (ref.func $1) (ref.null $none_=>_none) (global.get $global$0)) + (elem $6 funcref (ref.func $0) (ref.func $1) (ref.null nofunc)) + (elem $7 (ref null $none_=>_none) (ref.func $0) (ref.func $1) (ref.null nofunc) (global.get $global$0)) (elem $8 func) (elem $9 (table $3) (i32.const 0) (ref null $none_=>_none) (ref.func $0) (ref.func $2)) (func $0 diff --git a/test/multivalue.wast.from-wast b/test/multivalue.wast.from-wast index bdeb80cd46f..a09eb88ce4c 100644 --- a/test/multivalue.wast.from-wast +++ b/test/multivalue.wast.from-wast @@ -139,12 +139,12 @@ (tuple.make (i32.const 42) (i64.const 42) - (ref.null extern) + (ref.null noextern) ) (tuple.make (i32.const 42) (i64.const 42) - (ref.null extern) + (ref.null noextern) ) ) ) diff --git a/test/multivalue.wast.fromBinary b/test/multivalue.wast.fromBinary index dd39d4b34f0..28e24a2f4d6 100644 --- a/test/multivalue.wast.fromBinary +++ b/test/multivalue.wast.fromBinary @@ -397,12 +397,12 @@ (tuple.make (i32.const 42) (i64.const 42) - (ref.null extern) + (ref.null noextern) ) (tuple.make (i32.const 42) (i64.const 42) - (ref.null extern) + (ref.null noextern) ) ) ) diff --git a/test/multivalue.wast.fromBinary.noDebugInfo b/test/multivalue.wast.fromBinary.noDebugInfo index 66c0f52c5eb..192902759e3 100644 --- a/test/multivalue.wast.fromBinary.noDebugInfo +++ b/test/multivalue.wast.fromBinary.noDebugInfo @@ -397,12 +397,12 @@ (tuple.make (i32.const 42) (i64.const 42) - (ref.null extern) + (ref.null noextern) ) (tuple.make (i32.const 42) (i64.const 42) - (ref.null extern) + (ref.null noextern) ) ) ) diff --git a/test/passes/Oz_fuzz-exec_all-features.txt b/test/passes/Oz_fuzz-exec_all-features.txt index b3c8b936a5e..e19110848ed 100644 --- a/test/passes/Oz_fuzz-exec_all-features.txt +++ b/test/passes/Oz_fuzz-exec_all-features.txt @@ -173,7 +173,7 @@ (struct.new_default $struct) ) (drop - (block $any (result anyref) + (block $any (result (ref null $struct)) (call $log (i32.const 1) ) @@ -185,7 +185,7 @@ (call $log (i32.const 999) ) - (ref.null any) + (ref.null none) ) ) ) diff --git a/test/passes/precompute_all-features.txt b/test/passes/precompute_all-features.txt index 1fbea9d64d1..ea582d8d469 100644 --- a/test/passes/precompute_all-features.txt +++ b/test/passes/precompute_all-features.txt @@ -254,7 +254,7 @@ (i32.const 1) ) (func $reftype-test (result externref) - (ref.null extern) + (ref.null noextern) ) (func $dummy (nop) @@ -276,22 +276,22 @@ ) ) (drop - (block $l2 (result externref) + (block $l2 (result nullexternref) (drop (block $l3 (global.set $global-mut (i32.const 1) ) (br $l2 - (ref.null extern) + (ref.null noextern) ) ) ) - (ref.null extern) + (ref.null noextern) ) ) (drop - (block $l4 (result funcref) + (block $l4 (result (ref null $none_=>_none)) (drop (block $l5 (global.set $global-mut @@ -302,7 +302,7 @@ ) ) ) - (ref.null func) + (ref.null nofunc) ) ) ) diff --git a/test/passes/remove-unused-brs_all-features.txt b/test/passes/remove-unused-brs_all-features.txt index c340519f814..ab3ead0f432 100644 --- a/test/passes/remove-unused-brs_all-features.txt +++ b/test/passes/remove-unused-brs_all-features.txt @@ -18,7 +18,7 @@ (i32.const 1) ) ) - (ref.null $struct) + (ref.null none) ) ) (func $test-prefinalize (result f64) @@ -136,59 +136,59 @@ ) (func $br_on-to-flow (drop - (block $data (result dataref) + (block $data (result nullref) (drop (ref.func $br_on-to-flow) ) - (ref.null data) + (ref.null none) ) ) (drop - (block $datab (result dataref) + (block $datab (result nullref) (drop (i31.new (i32.const 1337) ) ) - (ref.null data) + (ref.null none) ) ) (drop - (block $func (result funcref) + (block $func (result nullfuncref) (drop (array.new_default $vector (i32.const 2) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop - (block $funcb (result funcref) + (block $funcb (result nullfuncref) (drop (i31.new (i32.const 1337) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop - (block $i31 (result i31ref) + (block $i31 (result nullref) (drop (array.new_default $vector (i32.const 2) ) ) - (ref.null i31) + (ref.null none) ) ) (drop - (block $i31b (result i31ref) + (block $i31b (result nullref) (drop (ref.func $br_on-to-flow) ) - (ref.null i31) + (ref.null none) ) ) ) diff --git a/test/passes/simplify-globals_all-features.txt b/test/passes/simplify-globals_all-features.txt index ace056aac2e..d94ac55d365 100644 --- a/test/passes/simplify-globals_all-features.txt +++ b/test/passes/simplify-globals_all-features.txt @@ -215,7 +215,7 @@ (type $none_=>_none (func)) (import "env" "global-1" (global $g1 externref)) (global $g2 externref (global.get $g1)) - (global $g3 externref (ref.null extern)) + (global $g3 externref (ref.null noextern)) (func $test1 (drop (global.get $g1) @@ -226,7 +226,7 @@ ) (func $test2 (drop - (ref.null extern) + (ref.null noextern) ) ) ) diff --git a/test/passes/simplify-globals_all-features_fuzz-exec.txt b/test/passes/simplify-globals_all-features_fuzz-exec.txt index d38d067044f..f4e2df478cc 100644 --- a/test/passes/simplify-globals_all-features_fuzz-exec.txt +++ b/test/passes/simplify-globals_all-features_fuzz-exec.txt @@ -3,7 +3,7 @@ (module (type $f32_i31ref_i64_f64_funcref_=>_none (func (param f32 i31ref i64 f64 funcref))) (type $none_=>_funcref (func (result funcref))) - (global $global$0 (mut funcref) (ref.null func)) + (global $global$0 (mut funcref) (ref.null nofunc)) (elem declare func $0) (export "export" (func $1)) (func $0 (param $0 f32) (param $1 i31ref) (param $2 i64) (param $3 f64) (param $4 funcref) diff --git a/test/passes/strip-target-features_roundtrip_print-features_all-features.txt b/test/passes/strip-target-features_roundtrip_print-features_all-features.txt index b460f880180..8e2d7300161 100644 --- a/test/passes/strip-target-features_roundtrip_print-features_all-features.txt +++ b/test/passes/strip-target-features_roundtrip_print-features_all-features.txt @@ -19,7 +19,7 @@ (func $foo (result v128 externref) (tuple.make (v128.const i32x4 0x00000000 0x00000000 0x00000000 0x00000000) - (ref.null extern) + (ref.null noextern) ) ) (func $bar (result v128 externref) diff --git a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt index 927c07bcac4..e984e8be5c9 100644 --- a/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt +++ b/test/passes/translate-to-fuzz_all-features_metrics_noprint.txt @@ -1,45 +1,45 @@ total - [exports] : 14 - [funcs] : 19 + [exports] : 7 + [funcs] : 7 [globals] : 6 [imports] : 5 [memories] : 1 [memory-data] : 22 - [table-data] : 12 + [table-data] : 8 [tables] : 1 [tags] : 2 - [total] : 771 - [vars] : 27 - ArrayInit : 1 - AtomicCmpxchg : 1 - AtomicFence : 1 + [total] : 433 + [vars] : 6 AtomicRMW : 1 - Binary : 82 - Block : 105 - Break : 19 - Call : 23 - CallIndirect : 3 - CallRef : 2 - Const : 145 - DataDrop : 1 - Drop : 7 - GlobalGet : 65 - GlobalSet : 31 - I31New : 3 - If : 35 - Load : 21 - LocalGet : 48 - LocalSet : 26 - Loop : 12 - Nop : 16 - RefEq : 1 - RefFunc : 17 - RefNull : 4 - Return : 35 + Binary : 56 + Block : 36 + Break : 4 + Call : 22 + CallRef : 8 + Const : 113 + Drop : 5 + GlobalGet : 24 + GlobalSet : 11 + I31Get : 2 + I31New : 7 + If : 14 + Load : 17 + LocalGet : 24 + LocalSet : 17 + Loop : 4 + MemoryFill : 1 + Nop : 1 + RefEq : 2 + RefFunc : 18 + RefIs : 1 + RefNull : 2 + Return : 12 SIMDExtract : 1 - Select : 1 - Store : 6 + SIMDLoad : 1 + Select : 7 + Store : 2 StructNew : 1 - TupleExtract : 2 - TupleMake : 8 - Unary : 47 + Switch : 1 + TupleMake : 2 + Unary : 13 + Unreachable : 3 diff --git a/test/reference-types.wast.from-wast b/test/reference-types.wast.from-wast index 121f3c6f448..e3a04c760c6 100644 --- a/test/reference-types.wast.from-wast +++ b/test/reference-types.wast.from-wast @@ -10,11 +10,11 @@ (type $eqref_=>_funcref (func (param eqref) (result funcref))) (import "env" "import_global" (global $import_global eqref)) (import "env" "import_func" (func $import_func (param eqref) (result funcref))) - (global $global_eqref (mut eqref) (ref.null eq)) - (global $global_funcref (mut funcref) (ref.null func)) + (global $global_eqref (mut eqref) (ref.null none)) + (global $global_funcref (mut funcref) (ref.null nofunc)) (global $global_funcref_func (mut funcref) (ref.func $foo)) - (global $global_anyref (mut anyref) (ref.null any)) - (global $global_anyref2 (mut anyref) (ref.null eq)) + (global $global_anyref (mut anyref) (ref.null none)) + (global $global_anyref2 (mut anyref) (ref.null none)) (table $0 3 3 funcref) (elem (i32.const 0) $take_eqref $take_funcref $take_anyref) (elem declare func $foo $ref-taken-but-not-in-table) @@ -44,7 +44,7 @@ (global.get $global_eqref) ) (local.set $local_eqref - (ref.null eq) + (ref.null none) ) (local.set $local_funcref (local.get $local_funcref) @@ -53,7 +53,7 @@ (global.get $global_funcref) ) (local.set $local_funcref - (ref.null func) + (ref.null nofunc) ) (local.set $local_funcref (ref.func $foo) @@ -65,7 +65,7 @@ (global.get $global_anyref) ) (local.set $local_anyref - (ref.null any) + (ref.null none) ) (local.set $local_anyref (local.get $local_eqref) @@ -74,7 +74,7 @@ (global.get $global_eqref) ) (local.set $local_anyref - (ref.null eq) + (ref.null none) ) (global.set $global_eqref (global.get $global_eqref) @@ -83,7 +83,7 @@ (local.get $local_eqref) ) (global.set $global_eqref - (ref.null eq) + (ref.null none) ) (global.set $global_funcref (global.get $global_funcref) @@ -92,7 +92,7 @@ (local.get $local_funcref) ) (global.set $global_funcref - (ref.null func) + (ref.null nofunc) ) (global.set $global_funcref (ref.func $foo) @@ -104,7 +104,7 @@ (local.get $local_anyref) ) (global.set $global_anyref - (ref.null any) + (ref.null none) ) (global.set $global_anyref (global.get $global_eqref) @@ -113,7 +113,7 @@ (local.get $local_eqref) ) (global.set $global_anyref - (ref.null eq) + (ref.null none) ) (call $take_eqref (local.get $local_eqref) @@ -122,7 +122,7 @@ (global.get $global_eqref) ) (call $take_eqref - (ref.null eq) + (ref.null none) ) (call $take_funcref (local.get $local_funcref) @@ -131,7 +131,7 @@ (global.get $global_funcref) ) (call $take_funcref - (ref.null func) + (ref.null nofunc) ) (call $take_funcref (ref.func $foo) @@ -143,7 +143,7 @@ (global.get $global_anyref) ) (call $take_anyref - (ref.null any) + (ref.null none) ) (call $take_anyref (local.get $local_eqref) @@ -152,7 +152,7 @@ (global.get $global_eqref) ) (call $take_anyref - (ref.null eq) + (ref.null none) ) (call_indirect $0 (type $sig_eqref) (local.get $local_eqref) @@ -163,7 +163,7 @@ (i32.const 0) ) (call_indirect $0 (type $sig_eqref) - (ref.null eq) + (ref.null none) (i32.const 0) ) (call_indirect $0 (type $sig_funcref) @@ -175,7 +175,7 @@ (i32.const 1) ) (call_indirect $0 (type $sig_funcref) - (ref.null func) + (ref.null nofunc) (i32.const 1) ) (call_indirect $0 (type $sig_funcref) @@ -191,7 +191,7 @@ (i32.const 3) ) (call_indirect $0 (type $sig_anyref) - (ref.null any) + (ref.null none) (i32.const 3) ) (call_indirect $0 (type $sig_anyref) @@ -203,7 +203,7 @@ (i32.const 3) ) (call_indirect $0 (type $sig_anyref) - (ref.null eq) + (ref.null none) (i32.const 3) ) (drop @@ -225,7 +225,7 @@ (drop (block $block1 (result eqref) (br_if $block1 - (ref.null eq) + (ref.null none) (i32.const 1) ) ) @@ -249,7 +249,7 @@ (drop (block $block4 (result funcref) (br_if $block4 - (ref.null func) + (ref.null nofunc) (i32.const 1) ) ) @@ -281,7 +281,7 @@ (drop (block $block8 (result anyref) (br_if $block8 - (ref.null any) + (ref.null none) (i32.const 1) ) ) @@ -297,7 +297,7 @@ (drop (block $block10 (result anyref) (br_if $block10 - (ref.null eq) + (ref.null none) (i32.const 1) ) ) @@ -314,7 +314,7 @@ ) (drop (loop $loop-in12 (result eqref) - (ref.null eq) + (ref.null none) ) ) (drop @@ -329,7 +329,7 @@ ) (drop (loop $loop-in15 (result funcref) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -349,7 +349,7 @@ ) (drop (loop $loop-in19 (result anyref) - (ref.null any) + (ref.null none) ) ) (drop @@ -364,28 +364,28 @@ ) (drop (loop $loop-in22 (result anyref) - (ref.null eq) + (ref.null none) ) ) (drop (if (result eqref) (i32.const 1) (local.get $local_eqref) - (ref.null eq) + (ref.null none) ) ) (drop (if (result funcref) (i32.const 1) (local.get $local_funcref) - (ref.null func) + (ref.null nofunc) ) ) (drop (if (result anyref) (i32.const 1) (local.get $local_anyref) - (ref.null any) + (ref.null none) ) ) (drop @@ -398,8 +398,8 @@ (drop (if (result anyref) (i32.const 1) - (ref.null eq) - (ref.null i31) + (ref.null none) + (ref.null none) ) ) (drop @@ -408,7 +408,7 @@ (i31.new (i32.const 0) ) - (ref.null eq) + (ref.null none) ) ) (drop @@ -420,7 +420,7 @@ (drop (pop i32) ) - (ref.null eq) + (ref.null none) ) ) ) @@ -433,7 +433,7 @@ (drop (pop i32) ) - (ref.null func) + (ref.null nofunc) ) ) ) @@ -446,14 +446,14 @@ (drop (pop i32) ) - (ref.null any) + (ref.null none) ) ) ) (drop (try $try30 (result anyref) (do - (ref.null eq) + (ref.null none) ) (catch $e-i32 (drop @@ -466,14 +466,14 @@ (drop (select (result eqref) (local.get $local_eqref) - (ref.null eq) + (ref.null none) (i32.const 1) ) ) (drop (select (result funcref) (local.get $local_funcref) - (ref.null func) + (ref.null nofunc) (i32.const 1) ) ) @@ -505,7 +505,7 @@ ) (drop (ref.is_null - (ref.null eq) + (ref.null none) ) ) (drop @@ -520,7 +520,7 @@ ) (drop (ref.is_null - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -540,7 +540,7 @@ ) (drop (ref.is_null - (ref.null any) + (ref.null none) ) ) ) @@ -552,7 +552,7 @@ (global.get $global_eqref) ) (func $return_eqref_null (result eqref) - (ref.null eq) + (ref.null none) ) (func $return_funcref_local (result funcref) (local $local_funcref funcref) @@ -562,7 +562,7 @@ (global.get $global_funcref) ) (func $return_funcref_null (result funcref) - (ref.null func) + (ref.null nofunc) ) (func $return_funcref_func (result funcref) (ref.func $foo) @@ -575,7 +575,7 @@ (global.get $global_anyref) ) (func $return_anyref_null (result anyref) - (ref.null any) + (ref.null none) ) (func $return_anyref2 (result anyref) (local $local_eqref eqref) @@ -585,7 +585,7 @@ (global.get $global_eqref) ) (func $return_anyref4 (result anyref) - (ref.null eq) + (ref.null none) ) (func $returns_eqref (result eqref) (local $local_eqref eqref) @@ -596,7 +596,7 @@ (global.get $global_eqref) ) (return - (ref.null eq) + (ref.null none) ) ) (func $returns_funcref (result funcref) @@ -611,7 +611,7 @@ (ref.func $foo) ) (return - (ref.null func) + (ref.null nofunc) ) ) (func $returns_anyref (result anyref) @@ -623,7 +623,7 @@ (global.get $global_anyref) ) (return - (ref.null any) + (ref.null none) ) ) (func $returns_anyref2 (result anyref) @@ -636,7 +636,7 @@ (global.get $global_eqref) ) (return - (ref.null eq) + (ref.null none) ) ) (func $ref-user diff --git a/test/reference-types.wast.fromBinary b/test/reference-types.wast.fromBinary index 80d85fd2613..670645cf2ad 100644 --- a/test/reference-types.wast.fromBinary +++ b/test/reference-types.wast.fromBinary @@ -10,11 +10,11 @@ (type $eqref_=>_funcref (func (param eqref) (result funcref))) (import "env" "import_global" (global $import_global eqref)) (import "env" "import_func" (func $import_func (param eqref) (result funcref))) - (global $global_eqref (mut eqref) (ref.null eq)) - (global $global_funcref (mut funcref) (ref.null func)) + (global $global_eqref (mut eqref) (ref.null none)) + (global $global_funcref (mut funcref) (ref.null nofunc)) (global $global_funcref_func (mut funcref) (ref.func $foo)) - (global $global_anyref (mut anyref) (ref.null any)) - (global $global_anyref2 (mut anyref) (ref.null eq)) + (global $global_anyref (mut anyref) (ref.null none)) + (global $global_anyref2 (mut anyref) (ref.null none)) (table $0 3 3 funcref) (elem (i32.const 0) $take_eqref $take_funcref $take_anyref) (elem declare func $foo $ref-taken-but-not-in-table) @@ -44,7 +44,7 @@ (global.get $global_eqref) ) (local.set $local_eqref - (ref.null eq) + (ref.null none) ) (local.set $local_funcref (local.get $local_funcref) @@ -53,7 +53,7 @@ (global.get $global_funcref) ) (local.set $local_funcref - (ref.null func) + (ref.null nofunc) ) (local.set $local_funcref (ref.func $foo) @@ -65,7 +65,7 @@ (global.get $global_anyref) ) (local.set $local_anyref - (ref.null any) + (ref.null none) ) (local.set $local_anyref (local.get $local_eqref) @@ -74,7 +74,7 @@ (global.get $global_eqref) ) (local.set $local_anyref - (ref.null eq) + (ref.null none) ) (global.set $global_eqref (global.get $global_eqref) @@ -83,7 +83,7 @@ (local.get $local_eqref) ) (global.set $global_eqref - (ref.null eq) + (ref.null none) ) (global.set $global_funcref (global.get $global_funcref) @@ -92,7 +92,7 @@ (local.get $local_funcref) ) (global.set $global_funcref - (ref.null func) + (ref.null nofunc) ) (global.set $global_funcref (ref.func $foo) @@ -104,7 +104,7 @@ (local.get $local_anyref) ) (global.set $global_anyref - (ref.null any) + (ref.null none) ) (global.set $global_anyref (global.get $global_eqref) @@ -113,7 +113,7 @@ (local.get $local_eqref) ) (global.set $global_anyref - (ref.null eq) + (ref.null none) ) (call $take_eqref (local.get $local_eqref) @@ -122,7 +122,7 @@ (global.get $global_eqref) ) (call $take_eqref - (ref.null eq) + (ref.null none) ) (call $take_funcref (local.get $local_funcref) @@ -131,7 +131,7 @@ (global.get $global_funcref) ) (call $take_funcref - (ref.null func) + (ref.null nofunc) ) (call $take_funcref (ref.func $foo) @@ -143,7 +143,7 @@ (global.get $global_anyref) ) (call $take_anyref - (ref.null any) + (ref.null none) ) (call $take_anyref (local.get $local_eqref) @@ -152,7 +152,7 @@ (global.get $global_eqref) ) (call $take_anyref - (ref.null eq) + (ref.null none) ) (call_indirect $0 (type $sig_eqref) (local.get $local_eqref) @@ -163,7 +163,7 @@ (i32.const 0) ) (call_indirect $0 (type $sig_eqref) - (ref.null eq) + (ref.null none) (i32.const 0) ) (call_indirect $0 (type $sig_funcref) @@ -175,7 +175,7 @@ (i32.const 1) ) (call_indirect $0 (type $sig_funcref) - (ref.null func) + (ref.null nofunc) (i32.const 1) ) (call_indirect $0 (type $sig_funcref) @@ -191,7 +191,7 @@ (i32.const 3) ) (call_indirect $0 (type $sig_anyref) - (ref.null any) + (ref.null none) (i32.const 3) ) (call_indirect $0 (type $sig_anyref) @@ -203,7 +203,7 @@ (i32.const 3) ) (call_indirect $0 (type $sig_anyref) - (ref.null eq) + (ref.null none) (i32.const 3) ) (drop @@ -225,7 +225,7 @@ (drop (block $label$3 (result eqref) (br_if $label$3 - (ref.null eq) + (ref.null none) (i32.const 1) ) ) @@ -249,7 +249,7 @@ (drop (block $label$6 (result funcref) (br_if $label$6 - (ref.null func) + (ref.null nofunc) (i32.const 1) ) ) @@ -281,7 +281,7 @@ (drop (block $label$10 (result anyref) (br_if $label$10 - (ref.null any) + (ref.null none) (i32.const 1) ) ) @@ -297,7 +297,7 @@ (drop (block $label$12 (result anyref) (br_if $label$12 - (ref.null eq) + (ref.null none) (i32.const 1) ) ) @@ -314,7 +314,7 @@ ) (drop (loop $label$15 (result eqref) - (ref.null eq) + (ref.null none) ) ) (drop @@ -329,7 +329,7 @@ ) (drop (loop $label$18 (result funcref) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -349,7 +349,7 @@ ) (drop (loop $label$22 (result anyref) - (ref.null any) + (ref.null none) ) ) (drop @@ -364,28 +364,28 @@ ) (drop (loop $label$25 (result anyref) - (ref.null eq) + (ref.null none) ) ) (drop (if (result eqref) (i32.const 1) (local.get $local_eqref) - (ref.null eq) + (ref.null none) ) ) (drop (if (result funcref) (i32.const 1) (local.get $local_funcref) - (ref.null func) + (ref.null nofunc) ) ) (drop (if (result anyref) (i32.const 1) (local.get $local_anyref) - (ref.null any) + (ref.null none) ) ) (drop @@ -398,8 +398,8 @@ (drop (if (result anyref) (i32.const 1) - (ref.null eq) - (ref.null i31) + (ref.null none) + (ref.null none) ) ) (drop @@ -408,7 +408,7 @@ (i31.new (i32.const 0) ) - (ref.null eq) + (ref.null none) ) ) (drop @@ -420,7 +420,7 @@ (drop (pop i32) ) - (ref.null eq) + (ref.null none) ) ) ) @@ -433,7 +433,7 @@ (drop (pop i32) ) - (ref.null func) + (ref.null nofunc) ) ) ) @@ -446,14 +446,14 @@ (drop (pop i32) ) - (ref.null any) + (ref.null none) ) ) ) (drop (try $label$49 (result anyref) (do - (ref.null eq) + (ref.null none) ) (catch $e-i32 (drop @@ -466,14 +466,14 @@ (drop (select (result eqref) (local.get $local_eqref) - (ref.null eq) + (ref.null none) (i32.const 1) ) ) (drop (select (result funcref) (local.get $local_funcref) - (ref.null func) + (ref.null nofunc) (i32.const 1) ) ) @@ -505,7 +505,7 @@ ) (drop (ref.is_null - (ref.null eq) + (ref.null none) ) ) (drop @@ -520,7 +520,7 @@ ) (drop (ref.is_null - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -540,7 +540,7 @@ ) (drop (ref.is_null - (ref.null any) + (ref.null none) ) ) ) @@ -552,7 +552,7 @@ (global.get $global_eqref) ) (func $return_eqref_null (result eqref) - (ref.null eq) + (ref.null none) ) (func $return_funcref_local (result funcref) (local $local_funcref funcref) @@ -562,7 +562,7 @@ (global.get $global_funcref) ) (func $return_funcref_null (result funcref) - (ref.null func) + (ref.null nofunc) ) (func $return_funcref_func (result funcref) (ref.func $foo) @@ -575,7 +575,7 @@ (global.get $global_anyref) ) (func $return_anyref_null (result anyref) - (ref.null any) + (ref.null none) ) (func $return_anyref2 (result anyref) (local $local_eqref eqref) @@ -585,7 +585,7 @@ (global.get $global_eqref) ) (func $return_anyref4 (result anyref) - (ref.null eq) + (ref.null none) ) (func $returns_eqref (result eqref) (local $local_eqref eqref) diff --git a/test/reference-types.wast.fromBinary.noDebugInfo b/test/reference-types.wast.fromBinary.noDebugInfo index cc05523b228..85ebc9e9ec9 100644 --- a/test/reference-types.wast.fromBinary.noDebugInfo +++ b/test/reference-types.wast.fromBinary.noDebugInfo @@ -10,11 +10,11 @@ (type $eqref_=>_funcref (func (param eqref) (result funcref))) (import "env" "import_global" (global $gimport$0 eqref)) (import "env" "import_func" (func $fimport$0 (param eqref) (result funcref))) - (global $global$0 (mut eqref) (ref.null eq)) - (global $global$1 (mut funcref) (ref.null func)) + (global $global$0 (mut eqref) (ref.null none)) + (global $global$1 (mut funcref) (ref.null nofunc)) (global $global$2 (mut funcref) (ref.func $3)) - (global $global$3 (mut anyref) (ref.null any)) - (global $global$4 (mut anyref) (ref.null eq)) + (global $global$3 (mut anyref) (ref.null none)) + (global $global$4 (mut anyref) (ref.null none)) (table $0 3 3 funcref) (elem (i32.const 0) $0 $1 $2) (elem declare func $23 $3) @@ -44,7 +44,7 @@ (global.get $global$0) ) (local.set $0 - (ref.null eq) + (ref.null none) ) (local.set $1 (local.get $1) @@ -53,7 +53,7 @@ (global.get $global$1) ) (local.set $1 - (ref.null func) + (ref.null nofunc) ) (local.set $1 (ref.func $3) @@ -65,7 +65,7 @@ (global.get $global$3) ) (local.set $2 - (ref.null any) + (ref.null none) ) (local.set $2 (local.get $0) @@ -74,7 +74,7 @@ (global.get $global$0) ) (local.set $2 - (ref.null eq) + (ref.null none) ) (global.set $global$0 (global.get $global$0) @@ -83,7 +83,7 @@ (local.get $0) ) (global.set $global$0 - (ref.null eq) + (ref.null none) ) (global.set $global$1 (global.get $global$1) @@ -92,7 +92,7 @@ (local.get $1) ) (global.set $global$1 - (ref.null func) + (ref.null nofunc) ) (global.set $global$1 (ref.func $3) @@ -104,7 +104,7 @@ (local.get $2) ) (global.set $global$3 - (ref.null any) + (ref.null none) ) (global.set $global$3 (global.get $global$0) @@ -113,7 +113,7 @@ (local.get $0) ) (global.set $global$3 - (ref.null eq) + (ref.null none) ) (call $0 (local.get $0) @@ -122,7 +122,7 @@ (global.get $global$0) ) (call $0 - (ref.null eq) + (ref.null none) ) (call $1 (local.get $1) @@ -131,7 +131,7 @@ (global.get $global$1) ) (call $1 - (ref.null func) + (ref.null nofunc) ) (call $1 (ref.func $3) @@ -143,7 +143,7 @@ (global.get $global$3) ) (call $2 - (ref.null any) + (ref.null none) ) (call $2 (local.get $0) @@ -152,7 +152,7 @@ (global.get $global$0) ) (call $2 - (ref.null eq) + (ref.null none) ) (call_indirect $0 (type $eqref_=>_none) (local.get $0) @@ -163,7 +163,7 @@ (i32.const 0) ) (call_indirect $0 (type $eqref_=>_none) - (ref.null eq) + (ref.null none) (i32.const 0) ) (call_indirect $0 (type $funcref_=>_none) @@ -175,7 +175,7 @@ (i32.const 1) ) (call_indirect $0 (type $funcref_=>_none) - (ref.null func) + (ref.null nofunc) (i32.const 1) ) (call_indirect $0 (type $funcref_=>_none) @@ -191,7 +191,7 @@ (i32.const 3) ) (call_indirect $0 (type $anyref_=>_none) - (ref.null any) + (ref.null none) (i32.const 3) ) (call_indirect $0 (type $anyref_=>_none) @@ -203,7 +203,7 @@ (i32.const 3) ) (call_indirect $0 (type $anyref_=>_none) - (ref.null eq) + (ref.null none) (i32.const 3) ) (drop @@ -225,7 +225,7 @@ (drop (block $label$3 (result eqref) (br_if $label$3 - (ref.null eq) + (ref.null none) (i32.const 1) ) ) @@ -249,7 +249,7 @@ (drop (block $label$6 (result funcref) (br_if $label$6 - (ref.null func) + (ref.null nofunc) (i32.const 1) ) ) @@ -281,7 +281,7 @@ (drop (block $label$10 (result anyref) (br_if $label$10 - (ref.null any) + (ref.null none) (i32.const 1) ) ) @@ -297,7 +297,7 @@ (drop (block $label$12 (result anyref) (br_if $label$12 - (ref.null eq) + (ref.null none) (i32.const 1) ) ) @@ -314,7 +314,7 @@ ) (drop (loop $label$15 (result eqref) - (ref.null eq) + (ref.null none) ) ) (drop @@ -329,7 +329,7 @@ ) (drop (loop $label$18 (result funcref) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -349,7 +349,7 @@ ) (drop (loop $label$22 (result anyref) - (ref.null any) + (ref.null none) ) ) (drop @@ -364,28 +364,28 @@ ) (drop (loop $label$25 (result anyref) - (ref.null eq) + (ref.null none) ) ) (drop (if (result eqref) (i32.const 1) (local.get $0) - (ref.null eq) + (ref.null none) ) ) (drop (if (result funcref) (i32.const 1) (local.get $1) - (ref.null func) + (ref.null nofunc) ) ) (drop (if (result anyref) (i32.const 1) (local.get $2) - (ref.null any) + (ref.null none) ) ) (drop @@ -398,8 +398,8 @@ (drop (if (result anyref) (i32.const 1) - (ref.null eq) - (ref.null i31) + (ref.null none) + (ref.null none) ) ) (drop @@ -408,7 +408,7 @@ (i31.new (i32.const 0) ) - (ref.null eq) + (ref.null none) ) ) (drop @@ -420,7 +420,7 @@ (drop (pop i32) ) - (ref.null eq) + (ref.null none) ) ) ) @@ -433,7 +433,7 @@ (drop (pop i32) ) - (ref.null func) + (ref.null nofunc) ) ) ) @@ -446,14 +446,14 @@ (drop (pop i32) ) - (ref.null any) + (ref.null none) ) ) ) (drop (try $label$49 (result anyref) (do - (ref.null eq) + (ref.null none) ) (catch $tag$0 (drop @@ -466,14 +466,14 @@ (drop (select (result eqref) (local.get $0) - (ref.null eq) + (ref.null none) (i32.const 1) ) ) (drop (select (result funcref) (local.get $1) - (ref.null func) + (ref.null nofunc) (i32.const 1) ) ) @@ -505,7 +505,7 @@ ) (drop (ref.is_null - (ref.null eq) + (ref.null none) ) ) (drop @@ -520,7 +520,7 @@ ) (drop (ref.is_null - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -540,7 +540,7 @@ ) (drop (ref.is_null - (ref.null any) + (ref.null none) ) ) ) @@ -552,7 +552,7 @@ (global.get $global$0) ) (func $7 (result eqref) - (ref.null eq) + (ref.null none) ) (func $8 (result funcref) (local $0 funcref) @@ -562,7 +562,7 @@ (global.get $global$1) ) (func $10 (result funcref) - (ref.null func) + (ref.null nofunc) ) (func $11 (result funcref) (ref.func $3) @@ -575,7 +575,7 @@ (global.get $global$3) ) (func $14 (result anyref) - (ref.null any) + (ref.null none) ) (func $15 (result anyref) (local $0 eqref) @@ -585,7 +585,7 @@ (global.get $global$0) ) (func $17 (result anyref) - (ref.null eq) + (ref.null none) ) (func $18 (result eqref) (local $0 eqref) diff --git a/test/unit/input/gc_target_feature.wasm b/test/unit/input/gc_target_feature.wasm index df5ab9cc0c7946e7d0b20c7f6a345f018c8b603f..30b1b21b66efb8a61368bf470160ccbf94d2c92b 100644 GIT binary patch delta 26 hcma!x6Jba!&Shj^U|{2B%4fWg$(_r1A$6jN7XVC925bNT delta 26 hcma!x6Jba!&Shj^U|{2B%4fWg&z;M7A$OvP7XVDA26_Mh From b5b453ac9d1a93a8fd46b3180c00614319821b65 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 5 Oct 2022 08:49:44 -0700 Subject: [PATCH 02/18] nullopt --- src/wasm/wasm-type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wasm/wasm-type.cpp b/src/wasm/wasm-type.cpp index a6a89323254..43b381a1b9f 100644 --- a/src/wasm/wasm-type.cpp +++ b/src/wasm/wasm-type.cpp @@ -594,7 +594,7 @@ std::optional getBasicHeapTypeLUB(HeapType::BasicHeapType a, switch (a) { case HeapType::ext: case HeapType::func: - return {}; + return std::nullopt; case HeapType::any: return {HeapType::any}; case HeapType::eq: From d6c1a6239efe1335cf0a7b35340f479375c52d55 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 5 Oct 2022 09:31:12 -0700 Subject: [PATCH 03/18] binaryen.js tests --- src/binaryen-c.cpp | 2 +- test/binaryen.js/kitchen-sink.js.txt | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 21f73d7d669..0b86eeccc70 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1508,7 +1508,7 @@ BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module, BinaryenType type) { Type type_(type); assert(type_.isNullable()); - return static_cast(Builder(*(Module*)module).makeRefNull(type_)); + return static_cast(Builder(*(Module*)module).makeRefNull(type_.getHeapType())); } BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module, diff --git a/test/binaryen.js/kitchen-sink.js.txt b/test/binaryen.js/kitchen-sink.js.txt index 076e0bedd13..104405c8a49 100644 --- a/test/binaryen.js/kitchen-sink.js.txt +++ b/test/binaryen.js/kitchen-sink.js.txt @@ -2072,12 +2072,12 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} ) (drop (ref.is_null - (ref.null extern) + (ref.null noextern) ) ) (drop (ref.is_null - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -2087,15 +2087,15 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} ) (drop (select (result funcref) - (ref.null func) + (ref.null nofunc) (ref.func "$kitchen()sinker") (i32.const 1) ) ) (drop (ref.eq - (ref.null eq) - (ref.null eq) + (ref.null none) + (ref.null none) ) ) (try @@ -4176,12 +4176,12 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} ) (drop (ref.is_null - (ref.null extern) + (ref.null noextern) ) ) (drop (ref.is_null - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -4191,15 +4191,15 @@ getExpressionInfo(tuple[3])={"id":14,"type":5,"value":3.7} ) (drop (select (result funcref) - (ref.null func) + (ref.null nofunc) (ref.func "$kitchen()sinker") (i32.const 1) ) ) (drop (ref.eq - (ref.null eq) - (ref.null eq) + (ref.null none) + (ref.null none) ) ) (try From 05ecd5f8c8261d8a1955244353f5708fa6e1302b Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 5 Oct 2022 11:14:49 -0700 Subject: [PATCH 04/18] Address feedback --- src/binaryen-c.cpp | 3 ++- src/literal.h | 2 +- src/passes/Inlining.cpp | 3 +-- src/wasm-builder.h | 4 ++-- src/wasm/wasm-binary.cpp | 4 +++- src/wasm/wasm-validator.cpp | 9 ++------- 6 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index 0b86eeccc70..f2908920c5c 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1508,7 +1508,8 @@ BinaryenExpressionRef BinaryenRefNull(BinaryenModuleRef module, BinaryenType type) { Type type_(type); assert(type_.isNullable()); - return static_cast(Builder(*(Module*)module).makeRefNull(type_.getHeapType())); + return static_cast( + Builder(*(Module*)module).makeRefNull(type_.getHeapType())); } BinaryenExpressionRef BinaryenRefIs(BinaryenModuleRef module, diff --git a/src/literal.h b/src/literal.h index f6865e4a914..7d7c778bcbf 100644 --- a/src/literal.h +++ b/src/literal.h @@ -92,7 +92,7 @@ class Literal { bool isFunction() const { return type.isFunction(); } bool isData() const { return type.isData(); } - bool isNull() const { return type.isRef() && type.getHeapType().isBottom(); } + bool isNull() const { return type.isNull(); } bool isZero() const { switch (type.getBasic()) { diff --git a/src/passes/Inlining.cpp b/src/passes/Inlining.cpp index 18324a395b1..f325f70c649 100644 --- a/src/passes/Inlining.cpp +++ b/src/passes/Inlining.cpp @@ -283,8 +283,7 @@ struct Updater : public PostWalker { } void visitCall(Call* curr) { if (curr->isReturn) { - auto* func = module->getFunction(curr->target); - handleReturnCall(curr, func->type.getSignature().results); + handleReturnCall(curr, module->getFunction(curr->target)->getResults()); } } void visitCallIndirect(CallIndirect* curr) { diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 3572eaf60de..b07af462751 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -703,7 +703,7 @@ class Builder { return ret; } RefNull* makeRefNull(Type type) { - assert(type.isNullable() && type.getHeapType().isBottom()); + assert(type.isNullable() && type.isNull()); auto* ret = wasm.allocator.alloc(); ret->finalize(type); return ret; @@ -1266,7 +1266,7 @@ class Builder { if (curr->type.isTuple() && curr->type.isDefaultable()) { return makeConstantExpression(Literal::makeZeros(curr->type)); } - if (curr->type.isNullable() && curr->type.getHeapType().isBottom()) { + if (curr->type.isNullable() && curr->type.isNull()) { return ExpressionManipulator::refNull(curr, curr->type); } if (curr->type.isRef() && curr->type.getHeapType() == HeapType::i31) { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 0334d43847c..b5bfabb039a 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2899,7 +2899,9 @@ void WasmBinaryBuilder::skipUnreachableCode() { return; } if (curr->type == Type::unreachable) { - // Don't want to pop back past the unreachable. + // Nothing before this unreachable should be available to future + // expressions. They will get `(unreachable)`s if they try to pop past + // this point. expressionStack.clear(); } else { pushExpression(curr); diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index b7afed1e71e..ba309ddeacc 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2079,10 +2079,6 @@ void FunctionValidator::visitSelect(Select* curr) { } void FunctionValidator::visitDrop(Drop* curr) { - if (!curr->value->type.isConcrete() && - curr->value->type != Type::unreachable) { - assert(false); - } shouldBeTrue(curr->value->type.isConcrete() || curr->value->type == Type::unreachable, curr, @@ -2118,9 +2114,8 @@ void FunctionValidator::visitRefNull(RefNull* curr) { curr->type.isNullable(), curr, "ref.null types must be nullable")) { return; } - shouldBeTrue(curr->type.getHeapType().isBottom(), - curr, - "ref.null must have a bottom heap type"); + shouldBeTrue( + curr->type.isNull(), curr, "ref.null must have a bottom heap type"); } void FunctionValidator::visitRefIs(RefIs* curr) { From 09d42f1c8445c4c251e0a22e08a62df23030ddbd Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 5 Oct 2022 13:10:44 -0700 Subject: [PATCH 05/18] simplify some code --- src/tools/wasm-ctor-eval.cpp | 5 +---- src/wasm-interpreter.h | 7 +++---- src/wasm/literal.cpp | 11 +++-------- 3 files changed, 7 insertions(+), 16 deletions(-) diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 5e9874cccfb..45cc63c373f 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -553,10 +553,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { // This is GC data, which we must handle in a more careful way. auto* data = value.getGCData().get(); - if (!data) { - // This is a null, so simply emit one. - return builder.makeRefNull(value.type); - } + assert(data); // There was actual GC data allocated here. auto type = value.type; diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 69434a29718..10b84a82f1d 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -1350,12 +1350,11 @@ class ExpressionRunner : public OverriddenVisitor { case RefIsNull: return Literal(value.isNull()); case RefIsFunc: - return Literal(!value.isNull() && value.type.isFunction()); + return Literal(value.type.isFunction()); case RefIsData: - return Literal(!value.isNull() && value.isData()); + return Literal(value.isData()); case RefIsI31: - return Literal(!value.isNull() && - value.type.getHeapType() == HeapType::i31); + return Literal(value.type.getHeapType() == HeapType::i31); default: WASM_UNREACHABLE("unimplemented ref.is_*"); } diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 9271aed8d71..09022eea098 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -342,11 +342,6 @@ void Literal::getBits(uint8_t (&buf)[16]) const { } bool Literal::operator==(const Literal& other) const { - // The types must be identical, unless both are references - in that case, - // nulls of different types *do* compare equal. - if (type.isRef() && other.type.isRef() && (isNull() || other.isNull())) { - return isNull() && other.isNull(); - } if (type != other.type) { return false; } @@ -367,7 +362,9 @@ bool Literal::operator==(const Literal& other) const { } } else if (type.isRef()) { assert(type.isRef()); - // Note that we've already handled nulls earlier. + if (type.isNull()) { + return true; + } if (type.isFunction()) { assert(func.is() && other.func.is()); return func == other.func; @@ -378,8 +375,6 @@ bool Literal::operator==(const Literal& other) const { if (type.getHeapType() == HeapType::i31) { return i32 == other.i32; } - // other non-null reference type literals cannot represent concrete values, - // i.e. there is no concrete anyref or eqref other than null. WASM_UNREACHABLE("unexpected type"); } WASM_UNREACHABLE("unexpected type"); From 328a068fd76de24644557801298e4382178f0764 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 5 Oct 2022 14:38:59 -0700 Subject: [PATCH 06/18] Add tests --- src/passes/OptimizeInstructions.cpp | 4 + test/lit/passes/optimize-instructions-gc.wast | 161 +++++++++++++++--- 2 files changed, 141 insertions(+), 24 deletions(-) diff --git a/src/passes/OptimizeInstructions.cpp b/src/passes/OptimizeInstructions.cpp index 9538d954e51..059ef28fb5a 100644 --- a/src/passes/OptimizeInstructions.cpp +++ b/src/passes/OptimizeInstructions.cpp @@ -1267,6 +1267,10 @@ struct OptimizeInstructions } void visitCallRef(CallRef* curr) { + skipNonNullCast(curr->target); + if (trapOnNull(curr, curr->target)) { + return; + } if (curr->target->type == Type::unreachable) { // The call_ref is not reached; leave this for DCE. return; diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index ae12dca7ae9..c0d106250a4 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -14,29 +14,39 @@ (field $i64 (mut i64)) )) + ;; CHECK: (type $B (struct (field i32) (field i32) (field f32))) + ;; CHECK: (type $array (array (mut i8))) ;; CHECK: (type $A (struct (field i32))) - ;; NOMNL: (type $array (array_subtype (mut i8) data)) - ;; NOMNL: (type $A (struct_subtype (field i32) data)) (type $A (struct (field i32))) + ;; NOMNL: (type $B (struct_subtype (field i32) (field i32) (field f32) $A)) + + ;; NOMNL: (type $array (array_subtype (mut i8) data)) (type $array (array (mut i8))) - ;; CHECK: (type $B (struct (field i32) (field i32) (field f32))) - ;; NOMNL: (type $B (struct_subtype (field i32) (field i32) (field f32) $A)) (type $B (struct_subtype (field i32) (field i32) (field f32) $A)) ;; CHECK: (type $B-child (struct (field i32) (field i32) (field f32) (field i64))) ;; NOMNL: (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B)) (type $B-child (struct_subtype (field i32) (field i32) (field f32) (field i64) $B)) + ;; NOMNL: (type $void (func_subtype func)) + + ;; NOMNL: (type $C (struct_subtype (field i32) (field i32) (field f64) $A)) + ;; NOMNL: (type $empty (struct_subtype data)) (type $empty (struct)) + ;; CHECK: (type $void (func)) + + ;; CHECK: (type $C (struct (field i32) (field i32) (field f64))) (type $C (struct_subtype (field i32) (field i32) (field f64) $A)) + (type $void (func)) + ;; CHECK: (import "env" "get-i32" (func $get-i32 (result i32))) ;; NOMNL: (import "env" "get-i32" (func $get-i32 (result i32))) (import "env" "get-i32" (func $get-i32 (result i32))) @@ -57,17 +67,25 @@ ) ) ;; 2. if its `ifTrue` and `ifFalse` arms are not identical (cannot fold) - ;; CHECK: (func $if-arms-subtype-nofold (result anyref) - ;; CHECK-NEXT: (ref.null none) + ;; CHECK: (func $if-arms-subtype-nofold (param $i31ref i31ref) (result anyref) + ;; CHECK-NEXT: (if (result anyref) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (local.get $i31ref) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $if-arms-subtype-nofold (type $none_=>_anyref) (result anyref) - ;; NOMNL-NEXT: (ref.null none) + ;; NOMNL: (func $if-arms-subtype-nofold (type $i31ref_=>_anyref) (param $i31ref i31ref) (result anyref) + ;; NOMNL-NEXT: (if (result anyref) + ;; NOMNL-NEXT: (i32.const 0) + ;; NOMNL-NEXT: (ref.null none) + ;; NOMNL-NEXT: (local.get $i31ref) + ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - (func $if-arms-subtype-nofold (result anyref) + (func $if-arms-subtype-nofold (param $i31ref i31ref) (result anyref) (if (result anyref) (i32.const 0) (ref.null data) - (ref.null i31) + (local.get $i31ref) ) ) @@ -699,7 +717,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $unneeded_unreachability (type $none_=>_none) + ;; NOMNL: (func $unneeded_unreachability (type $void) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (ref.is_func ;; NOMNL-NEXT: (unreachable) @@ -721,7 +739,7 @@ ) ) - ;; CHECK: (func $redundant-non-null-casts (param $x (ref null $struct)) (param $y (ref null $array)) + ;; CHECK: (func $redundant-non-null-casts (param $x (ref null $struct)) (param $y (ref null $array)) (param $f (ref null $void)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null ;; CHECK-NEXT: (local.get $x) @@ -752,8 +770,11 @@ ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (call_ref $void + ;; CHECK-NEXT: (local.get $f) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $redundant-non-null-casts (type $ref?|$struct|_ref?|$array|_=>_none) (param $x (ref null $struct)) (param $y (ref null $array)) + ;; NOMNL: (func $redundant-non-null-casts (type $ref?|$struct|_ref?|$array|_ref?|$void|_=>_none) (param $x (ref null $struct)) (param $y (ref null $array)) (param $f (ref null $void)) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (ref.as_non_null ;; NOMNL-NEXT: (local.get $x) @@ -784,8 +805,11 @@ ;; NOMNL-NEXT: (local.get $y) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (call_ref $void + ;; NOMNL-NEXT: (local.get $f) + ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - (func $redundant-non-null-casts (param $x (ref null $struct)) (param $y (ref null $array)) + (func $redundant-non-null-casts (param $x (ref null $struct)) (param $y (ref null $array)) (param $f (ref null $void)) (drop (ref.as_non_null (ref.as_non_null @@ -830,6 +854,11 @@ ) ) ) + (call_ref $void + (ref.as_non_null + (local.get $f) + ) + ) ) ;; CHECK: (func $get-eqref (result eqref) @@ -936,7 +965,7 @@ ;; CHECK: (func $nothing ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) - ;; NOMNL: (func $nothing (type $none_=>_none) + ;; NOMNL: (func $nothing (type $void) ;; NOMNL-NEXT: (nop) ;; NOMNL-NEXT: ) (func $nothing) @@ -1871,13 +1900,29 @@ ) ) - ;; CHECK: (func $hoist-LUB-danger (param $x i32) (result i32) - ;; CHECK-NEXT: (unreachable) + ;; CHECK: (func $hoist-LUB-danger (param $x i32) (param $b (ref $B)) (param $c (ref $C)) (result i32) + ;; CHECK-NEXT: (if (result i32) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (struct.get $B 1 + ;; CHECK-NEXT: (local.get $b) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.get $C 1 + ;; CHECK-NEXT: (local.get $c) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $hoist-LUB-danger (type $i32_=>_i32) (param $x i32) (result i32) - ;; NOMNL-NEXT: (unreachable) + ;; NOMNL: (func $hoist-LUB-danger (type $i32_ref|$B|_ref|$C|_=>_i32) (param $x i32) (param $b (ref $B)) (param $c (ref $C)) (result i32) + ;; NOMNL-NEXT: (if (result i32) + ;; NOMNL-NEXT: (local.get $x) + ;; NOMNL-NEXT: (struct.get $B 1 + ;; NOMNL-NEXT: (local.get $b) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.get $C 1 + ;; NOMNL-NEXT: (local.get $c) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - (func $hoist-LUB-danger (param $x i32) (result i32) + (func $hoist-LUB-danger (param $x i32) (param $b (ref $B)) (param $c (ref $C)) (result i32) ;; In nominal typing, if we hoist the struct.get out of the if, then the if ;; will have a new type, $A, but $A does not have field "1" which would be an ;; error. We disallow subtyping for this reason. @@ -1889,10 +1934,10 @@ (if (result i32) (local.get $x) (struct.get $B 1 - (ref.null $B) + (local.get $b) ) (struct.get $C 1 - (ref.null $C) + (local.get $c) ) ) ) @@ -1947,7 +1992,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $incompatible-cast-of-null (type $none_=>_none) + ;; NOMNL: (func $incompatible-cast-of-null (type $void) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result nullref) ;; NOMNL-NEXT: (drop @@ -2180,7 +2225,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $ref-cast-static-null (type $none_=>_none) + ;; NOMNL: (func $ref-cast-static-null (type $void) ;; NOMNL-NEXT: (local $a (ref null $A)) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (block (result nullref) @@ -3064,4 +3109,72 @@ ) ) ) + + ;; CHECK: (func $impossible (result (ref none)) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $impossible (type $none_=>_ref|none|) (result (ref none)) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + (func $impossible (result (ref none)) + (unreachable) + ) + + ;; CHECK: (func $bottom-type-accessors (param $bot (ref none)) (param $null nullref) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $impossible) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; NOMNL: (func $bottom-type-accessors (type $ref|none|_nullref_=>_none) (param $bot (ref none)) (param $null nullref) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (call $impossible) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (unreachable) + ;; NOMNL-NEXT: ) + (func $bottom-type-accessors (param $bot (ref none)) (param $null nullref) + (drop + (struct.get $A 0 + (local.get $bot) + ) + ) + (drop + (array.get $array + (local.get $null) + (i32.const 0) + ) + ) + (struct.set $A 0 + (ref.null none) + (i32.const 42) + ) + (array.set $array + (call $impossible) + (i32.const 1) + (i32.const 2) + ) + (call_ref $void + (ref.null nofunc) + ) + ) ) From ddfebfa9b9014b80072ca77232181bd8e22c28ee Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 5 Oct 2022 14:40:58 -0700 Subject: [PATCH 07/18] Changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2298928bbb3..d79c1c0f808 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ Current Trunk - If `THROW_ON_FATAL` is defined at compile-time, then fatal errors will throw a `std::runtime_error` instead of terminating the process. This may be used by embedders of Binaryen to recover from errors. +- Implemented bottom heap types: `none`, `nofunc`, and `noextern`. RefNull + expressions and null `Literal`s must now have type `nullref`, `nullfuncref`, + or `nullexternref`. v110 ---- From 5b556ca122d682c82aa1b892511290d4756216c3 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 5 Oct 2022 16:32:15 -0700 Subject: [PATCH 08/18] Replace ref.nulls with locals to avoid unreachable replacements in tests --- test/lit/passes/cfp.wast | 431 +++++++++++------------- test/lit/passes/gsi.wast | 400 +++++++++++----------- test/lit/passes/gto-mutability.wast | 417 +++++++++-------------- test/lit/passes/gto-removals.wast | 112 +++--- test/lit/passes/gufa-refs.wast | 22 +- test/lit/passes/heap2local.wast | 34 +- test/lit/passes/intrinsic-lowering.wast | 27 +- test/lit/passes/type-refining.wast | 152 ++++----- 8 files changed, 702 insertions(+), 893 deletions(-) diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index d75c1a2f2cb..cf11b2e66d5 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -4,26 +4,28 @@ ;; name getting in the way) (module - (type $struct (struct i32)) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) + (type $struct (struct i32)) ;; CHECK: (func $impossible-get (type $none_=>_none) + ;; CHECK-NEXT: (local $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $impossible-get + (func $impossible-get (local $struct (ref null $struct)) (drop ;; This type is never created, so a get is impossible, and we will trap ;; anyhow. So we can turn this into an unreachable (plus a drop of the ;; reference). (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -267,10 +269,12 @@ ;; Different values assigned in different functions, and one is a struct.set. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) (type $struct (struct (mut f32))) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -285,37 +289,29 @@ ) ) ) - ;; CHECK: (func $set (type $none_=>_none) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (f32.const 1337) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK: (func $set (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (f32.const 1337) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $set + (func $set (param $struct (ref null $struct)) (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (f32.const 1337) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -324,10 +320,12 @@ ;; As the last testcase, but the values happen to coincide, so we can optimize ;; the get into a constant. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) (type $struct (struct (mut f32))) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -342,20 +340,15 @@ ) ) ) - ;; CHECK: (func $set (type $none_=>_none) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (f32.const 42) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK: (func $set (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (f32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $set + (func $set (param $struct (ref null $struct)) (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (f32.const 42) ;; The last testcase had 1337 here. ) ) @@ -380,11 +373,13 @@ ;; Check that we look into the fallthrough value that is assigned. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) (type $struct (struct (mut f32))) - ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $i32_ref?|$struct|_=>_none (func_subtype (param i32 (ref null $struct)) func)) + + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop @@ -407,24 +402,19 @@ ) ) ) - ;; CHECK: (func $set (type $i32_=>_none) (param $x i32) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result f32) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: (f32.const 42) - ;; CHECK-NEXT: ) + ;; CHECK: (func $set (type $i32_ref?|$struct|_=>_none) (param $x i32) (param $struct (ref null $struct)) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (if (result f32) + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f32.const 42) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $set (param $x i32) + (func $set (param $x i32) (param $struct (ref null $struct)) (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) ;; Fall though a 42 via an if. (if (result f32) (local.get $x) @@ -433,20 +423,22 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -587,36 +579,33 @@ ;; will optimize the result to the only possible value. (In practice, though, ;; it will trap anyhow.) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) (type $substruct (struct_subtype (mut i32) $struct)) - ;; CHECK: (func $create (type $none_=>_none) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (func $create (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 10) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $create + (func $create (param $struct (ref null $struct)) (drop (struct.new $struct (i32.const 10) ) ) (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (i32.const 10) ) ) @@ -859,28 +848,25 @@ ;; As above, but add a set of $struct. The set prevents the optimization. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) (field f64) $struct)) (type $substruct (struct_subtype (mut i32) f64 $struct)) - ;; CHECK: (func $create (type $none_=>_none) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (func $create (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 10) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $substruct @@ -889,14 +875,14 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $create + (func $create (param $struct (ref null $struct)) (drop (struct.new $struct (i32.const 10) ) ) (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (i32.const 10) ) (drop @@ -1367,8 +1353,6 @@ ;; As above, but add not just a new of the middle class with a different value ;; but also a set. That prevents all optimizations. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) ;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1)) @@ -1376,10 +1360,14 @@ (type $struct1 (struct (mut i32))) + ;; CHECK: (type $ref?|$struct2|_=>_none (func_subtype (param (ref null $struct2)) func)) + ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) (type $struct3 (struct_subtype (mut i32) f64 anyref $struct2)) - ;; CHECK: (func $create (type $none_=>_none) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (func $create (type $ref?|$struct2|_=>_none) (param $struct2 (ref null $struct2)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct1 ;; CHECK-NEXT: (i32.const 10) @@ -1391,14 +1379,9 @@ ;; CHECK-NEXT: (f64.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 9999) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $struct2 0 + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: (i32.const 9999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct3 @@ -1408,7 +1391,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $create + (func $create (param $struct2 (ref null $struct2)) (drop (struct.new $struct1 (i32.const 10) @@ -1421,7 +1404,7 @@ ) ) (struct.set $struct2 0 - (ref.null $struct2) + (local.get $struct2) (i32.const 9999) ;; use a different value here (f64.const 0) ) @@ -1664,28 +1647,25 @@ ;; Copies of a field to itself can be ignored. As a result, we can optimize both ;; of the gets here. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block @@ -1696,16 +1676,16 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new_default $struct) ) ;; This copy does not actually introduce any new possible values, and so it ;; remains true that the only possible value is the default. (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) (drop @@ -1719,53 +1699,46 @@ ;; Test of a near-copy, of a similar looking field (same index, and same field ;; type) but in a different struct. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut f32)) (field (mut i32)) data)) (type $struct (struct (mut f32) (mut i32))) + ;; CHECK: (type $ref?|$struct|_ref?|$other|_=>_none (func_subtype (param (ref null $struct) (ref null $other)) func)) + + ;; CHECK: (type $other (struct_subtype (field (mut f64)) (field (mut i32)) data)) (type $other (struct (mut f64) (mut i32))) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_ref?|$other|_=>_none) (param $struct (ref null $struct)) (param $other (ref null $other)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.set $struct 1 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (local.get $other) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (struct.get $struct 1 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (param $other (ref null $other)) (drop (struct.new_default $struct) ) ;; As this is not a copy, we cannot optimize struct.1's get lower down. (struct.set $struct 1 - (ref.null $struct) + (local.get $struct) (struct.get $other 1 - (ref.null $other) + (local.get $other) ) ) (drop (struct.get $struct 1 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -1773,82 +1746,78 @@ ;; Test of a near-copy, of a different index. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) (field (mut i32)) data)) (type $struct (struct (mut i32) (mut i32))) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (block (result i32) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new_default $struct) ) ;; As this is not a copy, we cannot optimize struct.0's get lower down. (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (struct.get $struct 1 - (ref.null $struct) + (local.get $struct) ) ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) ;; An immutable global is the only thing written to this field, so we can ;; propagate the value to the struct.get and replace it with a global.get. (drop @@ -1858,7 +1827,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -1904,39 +1873,36 @@ ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (global.get $global) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $struct (global.get $global) @@ -1946,53 +1912,45 @@ ;; so that is fine. Also, the struct's field is now mutable as well to allow ;; that, and that also does not prevent optimization. (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (global.get $global) ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) ;; CHECK: (global $global-2 i32 (i32.const 1337)) (global $global-2 i32 (i32.const 1337)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (global.get $global-2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (global.get $global-2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $struct (global.get $global) @@ -2000,53 +1958,45 @@ ) ;; As above, but set a different global, which prevents optimization. (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (global.get $global-2) ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (global $global i32 (i32.const 42)) (global $global i32 (i32.const 42)) ;; CHECK: (global $global-2 i32 (i32.const 1337)) (global $global-2 i32 (i32.const 1337)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1337) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $struct 0 + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $struct (global.get $global) @@ -2055,12 +2005,12 @@ ;; As above, but set a constant, which means we are mixing constants with ;; globals, which prevents the optimization. (struct.set $struct 0 - (ref.null $struct) + (local.get $struct) (i32.const 1337) ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -2070,17 +2020,18 @@ ;; Test a global type other than i32. Arrays of structs are a realistic case ;; as they are used to implement itables. + ;; CHECK: (type $itable (array_subtype (ref $vtable) data)) + ;; CHECK: (type $vtable (struct_subtype (field funcref) data)) (type $vtable (struct funcref)) - ;; CHECK: (type $itable (array_subtype (ref $vtable) data)) (type $itable (array (ref $vtable))) - ;; CHECK: (type $none_=>_funcref (func_subtype (result funcref) func)) - ;; CHECK: (type $object (struct_subtype (field $itable (ref $itable)) data)) (type $object (struct (field $itable (ref $itable)))) + ;; CHECK: (type $ref?|$object|_=>_funcref (func_subtype (param (ref null $object)) (result funcref) func)) + ;; CHECK: (global $global (ref $itable) (array.init_static $itable ;; CHECK-NEXT: (struct.new $vtable ;; CHECK-NEXT: (ref.null nofunc) @@ -2098,33 +2049,27 @@ ) )) - ;; CHECK: (func $test (type $none_=>_funcref) (result funcref) + ;; CHECK: (func $test (type $ref?|$object|_=>_funcref) (param $object (ref null $object)) (result funcref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $object ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (struct.get $vtable 0 + ;; CHECK-NEXT: (array.get $itable + ;; CHECK-NEXT: (block (result (ref $itable)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $object) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test (result funcref) + (func $test (param $object (ref null $object)) (result funcref) (drop (struct.new $object (global.get $global) @@ -2139,7 +2084,7 @@ (struct.get $vtable 0 (array.get $itable (struct.get $object $itable - (ref.null $object) + (local.get $object) ) (i32.const 1) ) diff --git a/test/lit/passes/gsi.wast b/test/lit/passes/gsi.wast index b3e7a669995..9b0315df33d 100644 --- a/test/lit/passes/gsi.wast +++ b/test/lit/passes/gsi.wast @@ -5,7 +5,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -25,23 +25,27 @@ ;; CHECK: (global $global-other i32 (i32.const 123456)) (global $global-other i32 (i32.const 123456)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) ;; We can infer that this get can reference either $global1 or $global2, ;; and nothing else (aside from a null), and can emit a select between ;; those values. (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -52,7 +56,7 @@ ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -68,20 +72,17 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -92,7 +93,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -101,20 +102,17 @@ (i32.const 42) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -125,7 +123,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -148,20 +146,17 @@ (i32.const 99999) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -173,7 +168,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -196,20 +191,24 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -220,7 +219,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 1337) @@ -243,20 +242,24 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -267,7 +270,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 1337) @@ -290,20 +293,24 @@ (i32.const 42) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -314,7 +321,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -344,20 +351,17 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -369,7 +373,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -399,20 +403,24 @@ (i32.const 42) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global3) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -423,7 +431,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -439,22 +447,19 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $struct (i32.const 1) @@ -462,7 +467,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -474,7 +479,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (import "a" "b" (global $global-import (ref $struct))) (import "a" "b" (global $global-import (ref $struct))) @@ -493,20 +498,24 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -521,7 +530,7 @@ ;; CHECK: (type $tuple (struct_subtype (field anyref) (field anyref) data)) (type $tuple (struct anyref anyref)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -550,20 +559,17 @@ (ref.null any) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -578,7 +584,7 @@ ;; CHECK: (type $tuple (struct_subtype (field anyref) (field anyref) data)) (type $tuple (struct anyref anyref)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -603,20 +609,24 @@ (ref.null any) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -627,7 +637,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -643,20 +653,17 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -667,7 +674,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct_subtype i32 data)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (type $sub-struct (struct_subtype (field i32) $struct)) (type $sub-struct (struct_subtype i32 $struct)) @@ -686,22 +693,19 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $sub-struct ;; CHECK-NEXT: (i32.const 999999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $sub-struct (i32.const 999999) @@ -709,7 +713,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -724,7 +728,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) $super-struct)) (type $struct (struct_subtype i32 $super-struct)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.const 42) @@ -740,22 +744,26 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $super-struct ;; CHECK-NEXT: (i32.const 999999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $super-struct (i32.const 999999) @@ -763,7 +771,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -778,7 +786,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) $super-struct)) (type $struct (struct_subtype i32 $super-struct)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_ref?|$super-struct|_=>_none (func_subtype (param (ref null $struct) (ref null $super-struct)) func)) ;; CHECK: (global $global1 (ref $super-struct) (struct.new $super-struct ;; CHECK-NEXT: (i32.const 42) @@ -794,36 +802,37 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_ref?|$super-struct|_=>_none) (param $struct (ref null $struct)) (param $super-struct (ref null $super-struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $super-struct) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (param $super-struct (ref null $super-struct)) ;; We cannot optimize the first - it has just one global - but the second ;; will consider the struct and sub-struct, find 2 possible values, and ;; optimize. (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) (drop (struct.get $super-struct 0 - (ref.null $super-struct) + (local.get $super-struct) ) ) ) @@ -834,7 +843,7 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (global $global1 (ref $struct) (struct.new $struct ;; CHECK-NEXT: (i32.add @@ -856,20 +865,17 @@ (i32.const 1337) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -888,7 +894,7 @@ (type $struct2 (struct_subtype i32 f64 $super-struct)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$super-struct|_ref?|$struct1|_ref?|$struct2|_=>_none (func_subtype (param (ref null $super-struct) (ref null $struct1) (ref null $struct2)) func)) ;; CHECK: (global $global0 (ref $super-struct) (struct.new $super-struct ;; CHECK-NEXT: (i32.const 42) @@ -915,49 +921,40 @@ (f64.const 2.71828) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$super-struct|_ref?|$struct1|_ref?|$struct2|_=>_none) (param $super-struct (ref null $super-struct)) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $super-struct 0 + ;; CHECK-NEXT: (local.get $super-struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct1 0 + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct2 0 + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $super-struct (ref null $super-struct)) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) ;; This has three possible values due to the two children, so we do not ;; optimize. (drop (struct.get $super-struct 0 - (ref.null $super-struct) + (local.get $super-struct) ) ) ;; These each have one possible value, so we also do not optimize. (drop (struct.get $struct1 0 - (ref.null $struct1) + (local.get $struct1) ) ) (drop (struct.get $struct2 0 - (ref.null $struct2) + (local.get $struct2) ) ) ) @@ -975,7 +972,7 @@ (type $struct2 (struct_subtype i32 f64 $super-struct)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$super-struct|_ref?|$struct1|_ref?|$struct2|_=>_none (func_subtype (param (ref null $super-struct) (ref null $struct1) (ref null $struct2)) func)) ;; CHECK: (global $global0 (ref $super-struct) (struct.new $super-struct ;; CHECK-NEXT: (i32.const 42) @@ -1020,48 +1017,53 @@ (f64.const 2.71828) )) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$super-struct|_ref?|$struct1|_ref?|$struct2|_=>_none) (param $super-struct (ref null $super-struct)) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $super-struct 0 + ;; CHECK-NEXT: (local.get $super-struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: (i32.const 1338) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct1) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (select + ;; CHECK-NEXT: (i32.const 99999) + ;; CHECK-NEXT: (i32.const 99998) + ;; CHECK-NEXT: (ref.eq + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (global.get $global2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $super-struct (ref null $super-struct)) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) ;; This still cannot be optimized. (drop (struct.get $super-struct 0 - (ref.null $super-struct) + (local.get $super-struct) ) ) ;; These can be optimized, and will be different from one another. (drop (struct.get $struct1 0 - (ref.null $struct1) + (local.get $struct1) ) ) (drop (struct.get $struct2 0 - (ref.null $struct2) + (local.get $struct2) ) ) ) diff --git a/test/lit/passes/gto-mutability.wast b/test/lit/passes/gto-mutability.wast index bbf7c60b11a..edcf43bb2fc 100644 --- a/test/lit/passes/gto-mutability.wast +++ b/test/lit/passes/gto-mutability.wast @@ -7,7 +7,7 @@ ;; The struct here has three fields, and the second of them has no struct.set ;; which means we can make it immutable. - ;; CHECK: (type $struct (struct_subtype (field (mut funcref)) (field funcref) data)) + ;; CHECK: (type $struct (struct_subtype (field (mut funcref)) (field funcref) (field (mut funcref)) data)) (type $struct (struct (field (mut funcref)) (field (mut funcref)) (field (mut funcref)))) ;; CHECK: (type $two-params (func_subtype (param (ref $struct) (ref $struct)) func)) @@ -20,7 +20,7 @@ ;; CHECK: (type $none_=>_ref?|$struct| (func_subtype (result (ref null $struct)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (table $0 0 funcref) @@ -35,21 +35,16 @@ ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $struct)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 2 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (local.get $x) @@ -158,20 +153,17 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 2 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive + (func $field-keepalive (param $struct (ref null $struct)) ;; --gto will remove fields that are not read from, so add reads to any ;; that don't already have them. - (drop (struct.get $struct 2 (ref.null $struct))) + (drop (struct.get $struct 2 (local.get $struct))) ) ) @@ -179,34 +171,23 @@ ;; Test recursion between structs where we only modify one. Specifically $B ;; has no writes to either of its fields. - ;; CHECK: (type $A (struct_subtype data)) + ;; CHECK: (type $A (struct_subtype (field (mut (ref null $B))) (field (mut i32)) data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) + ;; CHECK: (type $B (struct_subtype (field (ref null $A)) (field f64) data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$A|_ref?|$B|_=>_none (func_subtype (param (ref null $A) (ref null $B)) func)) ;; CHECK: (func $func (type $ref|$A|_=>_none) (param $x (ref $A)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $A)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $A)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 20) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $A 1 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $A)) @@ -220,80 +201,57 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$A|_ref?|$B|_=>_none) (param $A (ref null $A)) (param $B (ref null $B)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $B 0 + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $B 1 + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive - (drop (struct.get $A 0 (ref.null $A))) - (drop (struct.get $A 1 (ref.null $A))) - (drop (struct.get $B 0 (ref.null $B))) - (drop (struct.get $B 1 (ref.null $B))) + (func $field-keepalive (param $A (ref null $A)) (param $B (ref null $B)) + (drop (struct.get $A 0 (local.get $A))) + (drop (struct.get $A 1 (local.get $A))) + (drop (struct.get $B 0 (local.get $B))) + (drop (struct.get $B 1 (local.get $B))) ) ) (module ;; As before, but flipped so that $A's fields can become immutable. - ;; CHECK: (type $B (struct_subtype data)) + ;; CHECK: (type $B (struct_subtype (field (mut (ref null $A))) (field (mut f64)) data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) + ;; CHECK: (type $A (struct_subtype (field (ref null $B)) (field i32) data)) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) ;; CHECK: (type $ref|$B|_=>_none (func_subtype (param (ref $B)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$A|_ref?|$B|_=>_none (func_subtype (param (ref null $A) (ref null $B)) func)) ;; CHECK: (func $func (type $ref|$B|_=>_none) (param $x (ref $B)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $B)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $B 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $B)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (f64.const 3.14159) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $B 1 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (f64.const 3.14159) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $B)) @@ -307,82 +265,58 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$A|_ref?|$B|_=>_none) (param $A (ref null $A)) (param $B (ref null $B)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $B 0 + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $B 1 + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive - (drop (struct.get $A 0 (ref.null $A))) - (drop (struct.get $A 1 (ref.null $A))) - (drop (struct.get $B 0 (ref.null $B))) - (drop (struct.get $B 1 (ref.null $B))) + (func $field-keepalive (param $A (ref null $A)) (param $B (ref null $B)) + (drop (struct.get $A 0 (local.get $A))) + (drop (struct.get $A 1 (local.get $A))) + (drop (struct.get $B 0 (local.get $B))) + (drop (struct.get $B 1 (local.get $B))) ) ) (module ;; As before, but now one field in each can become immutable. - ;; CHECK: (type $A (struct_subtype data)) + ;; CHECK: (type $A (struct_subtype (field (mut (ref null $B))) (field i32) data)) - ;; CHECK: (type $B (struct_subtype data)) + ;; CHECK: (type $B (struct_subtype (field (ref null $A)) (field (mut f64)) data)) (type $B (struct (field (mut (ref null $A))) (field (mut f64)) )) (type $A (struct (field (mut (ref null $B))) (field (mut i32)) )) ;; CHECK: (type $ref|$A|_ref|$B|_=>_none (func_subtype (param (ref $A) (ref $B)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$A|_ref?|$B|_=>_none (func_subtype (param (ref null $A) (ref null $B)) func)) ;; CHECK: (func $func (type $ref|$A|_ref|$B|_=>_none) (param $x (ref $A)) (param $y (ref $B)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $A)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $B)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (f64.const 3.14159) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $B 1 + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (f64.const 3.14159) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $A)) (param $y (ref $B)) @@ -396,45 +330,33 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$A|_ref?|$B|_=>_none) (param $A (ref null $A)) (param $B (ref null $B)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 1 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $B 0 + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $B 1 + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive - (drop (struct.get $A 0 (ref.null $A))) - (drop (struct.get $A 1 (ref.null $A))) - (drop (struct.get $B 0 (ref.null $B))) - (drop (struct.get $B 1 (ref.null $B))) + (func $field-keepalive (param $A (ref null $A)) (param $B (ref null $B)) + (drop (struct.get $A 0 (local.get $A))) + (drop (struct.get $A 1 (local.get $A))) + (drop (struct.get $B 0 (local.get $B))) + (drop (struct.get $B 1 (local.get $B))) ) ) @@ -443,23 +365,17 @@ ;; Field #1 is mutable and can become so. ;; Field #2 is mutable and must remain so. - ;; CHECK: (type $struct (struct_subtype data)) + ;; CHECK: (type $struct (struct_subtype (field i32) (field i32) (field (mut i32)) data)) (type $struct (struct (field i32) (field (mut i32)) (field (mut i32)))) ;; CHECK: (type $ref|$struct|_=>_none (func_subtype (param (ref $struct)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (func $func (type $ref|$struct|_=>_none) (param $x (ref $struct)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $struct)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct 2 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $struct)) @@ -469,36 +385,27 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 1 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 2 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive - (drop (struct.get $struct 0 (ref.null $struct))) - (drop (struct.get $struct 1 (ref.null $struct))) - (drop (struct.get $struct 2 (ref.null $struct))) + (func $field-keepalive (param $struct (ref null $struct)) + (drop (struct.get $struct 0 (local.get $struct))) + (drop (struct.get $struct 1 (local.get $struct))) + (drop (struct.get $struct 2 (local.get $struct))) ) ) @@ -506,19 +413,25 @@ ;; Subtyping. Without a write in either supertype or subtype, we can ;; optimize the field to be immutable. - ;; CHECK: (type $none_=>_none (func_subtype func)) - - ;; CHECK: (type $super (struct_subtype data)) + ;; CHECK: (type $super (struct_subtype (field i32) data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $sub (struct_subtype $super)) + ;; CHECK: (type $sub (struct_subtype (field i32) $super)) (type $sub (struct_subtype (field (mut i32)) $super)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $ref?|$super|_ref?|$sub|_=>_none (func_subtype (param (ref null $super) (ref null $sub)) func)) + ;; CHECK: (func $func (type $none_=>_none) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new_default $super) + ;; CHECK-NEXT: (struct.new $super + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new_default $sub) + ;; CHECK-NEXT: (struct.new $sub + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func @@ -535,59 +448,51 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$super|_ref?|$sub|_=>_none) (param $super (ref null $super)) (param $sub (ref null $sub)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $super 0 + ;; CHECK-NEXT: (local.get $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $sub 0 + ;; CHECK-NEXT: (local.get $sub) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive - (drop (struct.get $super 0 (ref.null $super))) - (drop (struct.get $sub 0 (ref.null $sub))) + (func $field-keepalive (param $super (ref null $super)) (param $sub (ref null $sub)) + (drop (struct.get $super 0 (local.get $super))) + (drop (struct.get $sub 0 (local.get $sub))) ) ) (module ;; As above, but add a write in the super, which prevents optimization. - ;; CHECK: (type $super (struct_subtype data)) + ;; CHECK: (type $super (struct_subtype (field (mut i32)) data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $ref|$super|_=>_none (func_subtype (param (ref $super)) func)) - - ;; CHECK: (type $sub (struct_subtype $super)) + ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) (type $sub (struct_subtype (field (mut i32)) $super)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref|$super|_=>_none (func_subtype (param (ref $super)) func)) + + ;; CHECK: (type $ref?|$super|_ref?|$sub|_=>_none (func_subtype (param (ref null $super) (ref null $sub)) func)) ;; CHECK: (func $func (type $ref|$super|_=>_none) (param $x (ref $super)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new_default $super) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.new_default $sub) + ;; CHECK-NEXT: (struct.new $super + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $super)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $sub + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $super 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $super)) ;; The presence of struct.new do not prevent us optimizing @@ -607,27 +512,21 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$super|_ref?|$sub|_=>_none) (param $super (ref null $super)) (param $sub (ref null $sub)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $super 0 + ;; CHECK-NEXT: (local.get $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $sub 0 + ;; CHECK-NEXT: (local.get $sub) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive - (drop (struct.get $super 0 (ref.null $super))) - (drop (struct.get $sub 0 (ref.null $sub))) + (func $field-keepalive (param $super (ref null $super)) (param $sub (ref null $sub)) + (drop (struct.get $super 0 (local.get $super))) + (drop (struct.get $sub 0 (local.get $sub))) ) ) @@ -635,25 +534,19 @@ ;; As above, but add a write in the sub, which prevents optimization. - ;; CHECK: (type $super (struct_subtype data)) + ;; CHECK: (type $super (struct_subtype (field (mut i32)) data)) (type $super (struct (field (mut i32)))) - ;; CHECK: (type $sub (struct_subtype $super)) + ;; CHECK: (type $sub (struct_subtype (field (mut i32)) $super)) (type $sub (struct_subtype (field (mut i32)) $super)) ;; CHECK: (type $ref|$sub|_=>_none (func_subtype (param (ref $sub)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$super|_ref?|$sub|_=>_none (func_subtype (param (ref null $super) (ref null $sub)) func)) ;; CHECK: (func $func (type $ref|$sub|_=>_none) (param $x (ref $sub)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (block (result (ref $sub)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 2) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $sub 0 + ;; CHECK-NEXT: (local.get $x) + ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $func (param $x (ref $sub)) @@ -663,26 +556,20 @@ ) ) - ;; CHECK: (func $field-keepalive (type $none_=>_none) + ;; CHECK: (func $field-keepalive (type $ref?|$super|_ref?|$sub|_=>_none) (param $super (ref null $super)) (param $sub (ref null $sub)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $super 0 + ;; CHECK-NEXT: (local.get $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $sub 0 + ;; CHECK-NEXT: (local.get $sub) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $field-keepalive - (drop (struct.get $super 0 (ref.null $super))) - (drop (struct.get $sub 0 (ref.null $sub))) + (func $field-keepalive (param $super (ref null $super)) (param $sub (ref null $sub)) + (drop (struct.get $super 0 (local.get $super))) + (drop (struct.get $sub 0 (local.get $sub))) ) ) diff --git a/test/lit/passes/gto-removals.wast b/test/lit/passes/gto-removals.wast index c125e0579c7..184359f49ba 100644 --- a/test/lit/passes/gto-removals.wast +++ b/test/lit/passes/gto-removals.wast @@ -399,12 +399,14 @@ (module ;; A new with side effects - ;; CHECK: (type $struct (struct_subtype data)) + ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32 f64 (ref any))) ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref|any|_ref?|$struct|_=>_none (func_subtype (param (ref any) (ref null $struct)) func)) + ;; CHECK: (type $ref|any|_=>_none (func_subtype (param (ref any)) func)) ;; CHECK: (type $i32_=>_i32 (func_subtype (param i32) (result i32) func)) @@ -419,21 +421,18 @@ ;; CHECK: (global $mut-i32 (mut i32) (i32.const 5678)) (global $mut-i32 (mut i32) (i32.const 5678)) - ;; CHECK: (func $gets (type $ref|any|_=>_none) (param $x (ref any)) + ;; CHECK: (func $gets (type $ref|any|_ref?|$struct|_=>_none) (param $x (ref any)) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $gets (param $x (ref any)) + (func $gets (param $x (ref any)) (param $struct (ref null $struct)) ;; Gets to keep certain fields alive. (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -459,7 +458,9 @@ ;; CHECK-NEXT: (i32.const 2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -492,7 +493,9 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (global.get $imm-i32) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -529,7 +532,9 @@ ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new_default $struct) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -576,15 +581,11 @@ ) ;; CHECK: (func $new-side-effect-in-kept (type $ref|any|_=>_none) (param $any (ref any)) - ;; CHECK-NEXT: (local $1 i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result (ref $struct)) - ;; CHECK-NEXT: (local.set $1 - ;; CHECK-NEXT: (call $helper0 - ;; CHECK-NEXT: (i32.const 0) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.new $struct + ;; CHECK-NEXT: (call $helper0 + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -780,82 +781,91 @@ ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type ${mut:i8} (struct_subtype data)) (type ${mut:i8} (struct_subtype (field (mut i8)) data)) + ;; CHECK: (type $ref?|${mut:i8}|_=>_none (func_subtype (param (ref null ${mut:i8})) func)) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $none_=>_i32 (func_subtype (result i32) func)) ;; CHECK: (type $none_=>_ref|${mut:i8}| (func_subtype (result (ref ${mut:i8})) func)) - ;; CHECK: (func $unreachable-set (type $none_=>_none) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (call $helper-i32) + ;; CHECK: (func $unreachable-set (type $ref?|${mut:i8}|_=>_none) (param ${mut:i8} (ref null ${mut:i8})) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block (result (ref null ${mut:i8})) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (call $helper-i32) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get ${mut:i8}) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unreachable-set + (func $unreachable-set (param ${mut:i8} (ref null ${mut:i8})) ;; The struct type has no reads, so we want to remove all of the sets of it. ;; This struct.set will trap on null, but first the call must run. When we ;; optimize here we should be careful to not emit something with different ;; ordering (naively emitting ref.as_non_null on the reference would trap ;; before the call, so we must reorder). (struct.set ${mut:i8} 0 - (ref.null ${mut:i8}) + (local.get ${mut:i8}) (call $helper-i32) ) ) - ;; CHECK: (func $unreachable-set-2 (type $none_=>_none) + ;; CHECK: (func $unreachable-set-2 (type $ref?|${mut:i8}|_=>_none) (param ${mut:i8} (ref null ${mut:i8})) ;; CHECK-NEXT: (block $block - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (br $block) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get ${mut:i8}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (br $block) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unreachable-set-2 + (func $unreachable-set-2 (param ${mut:i8} (ref null ${mut:i8})) ;; As above, but the side effects now are a br. Again, the br must happen ;; before the trap (in fact, the br will skip the trap here). (block (struct.set ${mut:i8} 0 - (ref.null ${mut:i8}) + (local.get ${mut:i8}) (br $block) ) ) ) - ;; CHECK: (func $unreachable-set-2b (type $none_=>_none) + ;; CHECK: (func $unreachable-set-2b (type $ref?|${mut:i8}|_=>_none) (param ${mut:i8} (ref null ${mut:i8})) ;; CHECK-NEXT: (nop) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get ${mut:i8}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $unreachable-set-2b + (func $unreachable-set-2b (param ${mut:i8} (ref null ${mut:i8})) ;; As above, but with an unreachable instead of a br. We add a nop here so ;; that we are inside of a block, and then validation would fail if we do ;; not keep the type of the replacement for the struct.set identical to the ;; struct.set. That is, the type must remain unreachable. (nop) (struct.set ${mut:i8} 0 - (ref.null ${mut:i8}) + (local.get ${mut:i8}) (unreachable) ) ) diff --git a/test/lit/passes/gufa-refs.wast b/test/lit/passes/gufa-refs.wast index 0c410c3d003..f75b0dd9661 100644 --- a/test/lit/passes/gufa-refs.wast +++ b/test/lit/passes/gufa-refs.wast @@ -3605,12 +3605,15 @@ (module (type $A (struct_subtype data)) - (type $B (array (mut anyref))) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $B (array_subtype (mut anyref) data)) + (type $B (array (mut anyref))) + ;; CHECK: (type $i32_=>_none (func_subtype (param i32) func)) + ;; CHECK: (type $ref|$B|_=>_none (func_subtype (param (ref $B)) func)) + ;; CHECK: (memory $0 10) ;; CHECK: (table $t 0 externref) @@ -3903,20 +3906,23 @@ ) ) - ;; CHECK: (func $arrays (type $none_=>_none) + ;; CHECK: (func $arrays (type $ref|$B|_=>_none) (param $B (ref $B)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (array.len $B + ;; CHECK-NEXT: (array.init_static $B + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $arrays + (func $arrays (param $B (ref $B)) (drop (array.len $B - (ref.null $B) + (array.init_static $B + (ref.null none) + (ref.null none) + ) ) ) ) diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast index 9d63faa171c..aace567f722 100644 --- a/test/lit/passes/heap2local.wast +++ b/test/lit/passes/heap2local.wast @@ -1278,38 +1278,28 @@ ) ) - ;; CHECK: (func $set-value + ;; CHECK: (func $set-value (param $struct.recursive (ref null $struct.recursive)) ;; CHECK-NEXT: (local $ref (ref null $struct.recursive)) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $ref - ;; CHECK-NEXT: (struct.new_default $struct.recursive) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $struct.recursive 0 + ;; CHECK-NEXT: (local.get $struct.recursive) + ;; CHECK-NEXT: (local.tee $ref + ;; CHECK-NEXT: (struct.new_default $struct.recursive) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; NOMNL: (func $set-value (type $none_=>_none) + ;; NOMNL: (func $set-value (type $ref?|$struct.recursive|_=>_none) (param $struct.recursive (ref null $struct.recursive)) ;; NOMNL-NEXT: (local $ref (ref null $struct.recursive)) - ;; NOMNL-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (ref.null none) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.tee $ref - ;; NOMNL-NEXT: (struct.new_default $struct.recursive) - ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (struct.set $struct.recursive 0 + ;; NOMNL-NEXT: (local.get $struct.recursive) + ;; NOMNL-NEXT: (local.tee $ref + ;; NOMNL-NEXT: (struct.new_default $struct.recursive) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (unreachable) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) - (func $set-value + (func $set-value (param $struct.recursive (ref null $struct.recursive)) (local $ref (ref null $struct.recursive)) (struct.set $struct.recursive 0 - (ref.null $struct.recursive) + (local.get $struct.recursive) ;; As above, but operands reversed: the allocation is now the value, not ;; the reference, and so it escapes. (local.tee $ref diff --git a/test/lit/passes/intrinsic-lowering.wast b/test/lit/passes/intrinsic-lowering.wast index c6965c3992b..34e994f7f89 100644 --- a/test/lit/passes/intrinsic-lowering.wast +++ b/test/lit/passes/intrinsic-lowering.wast @@ -2,6 +2,7 @@ ;; RUN: wasm-opt %s --intrinsic-lowering -all -S -o - | filecheck %s (module + ;; CHECK: (type $none (func)) (type $none (func)) ;; call.without.effects with no params. @@ -16,9 +17,9 @@ ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $cwe-n (param funcref))) (import "binaryen-intrinsics" "call.without.effects" (func $cwe-n (param funcref))) - ;; CHECK: (func $test (result i32) + ;; CHECK: (func $test (param $none (ref null $none)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (call $test) + ;; CHECK-NEXT: (call $make-i32) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (call $dif @@ -26,22 +27,22 @@ ;; CHECK-NEXT: (i32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (call_ref $none + ;; CHECK-NEXT: (local.get $none) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) - (func $test (result i32) + (func $test (param $none (ref null $none)) ;; These will be lowered into calls. - (drop (call $cwe-v (ref.func $test))) + (drop (call $cwe-v (ref.func $make-i32))) (drop (call $cwe-dif (f64.const 3.14159) (i32.const 42) (ref.func $dif))) ;; The last must be a call_ref, as we don't see a constant ref.func - (call $cwe-n - (ref.null $none) - ) + (call $cwe-n (local.get $none)) + ) + + ;; CHECK: (func $make-i32 (result i32) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: ) + (func $make-i32 (result i32) (i32.const 1) ) diff --git a/test/lit/passes/type-refining.wast b/test/lit/passes/type-refining.wast index 71a4cb4257b..f578e341624 100644 --- a/test/lit/passes/type-refining.wast +++ b/test/lit/passes/type-refining.wast @@ -795,15 +795,15 @@ ;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner)) (type $Leaf2-Inner (struct_subtype $Root-Inner)) - (type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer)) + ;; CHECK: (type $ref?|$Leaf1-Outer|_=>_none (func_subtype (param (ref null $Leaf1-Outer)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data)) - ;; CHECK: (type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner)) + ;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) - ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data)) + ;; CHECK: (type $Leaf1-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) + (type $Leaf1-Outer (struct_subtype (field (ref $Leaf1-Inner)) $Root-Outer)) - ;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) (type $Root-Outer (struct_subtype (field (ref $Root-Inner)) data)) @@ -812,15 +812,18 @@ (type $Leaf1-Inner (struct_subtype (field i32) $Root-Inner)) - ;; CHECK: (func $func (type $none_=>_none) + ;; CHECK: (func $func (type $ref?|$Leaf1-Outer|_=>_none) (param $Leaf1-Outer (ref null $Leaf1-Outer)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (struct.get $Leaf1-Inner 0 - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $Leaf1-Outer) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -829,7 +832,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $func + (func $func (param $Leaf1-Outer (ref null $Leaf1-Outer)) (drop ;; The situation here is that we have only a get for some types, and no ;; other constraints. As we ignore gets, we work under no constraints at @@ -851,7 +854,7 @@ ;; unreachable here. (struct.get $Leaf1-Inner 0 (struct.get $Leaf1-Outer 0 - (ref.null $Leaf1-Outer) + (local.get $Leaf1-Outer) ) ) ) @@ -867,53 +870,37 @@ ;; CHECK: (type $A (struct_subtype (field (mut (ref null $A))) data)) (type $A (struct_subtype (field (mut (ref null $A))) data)) - ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) + ;; CHECK: (type $ref|$A|_ref?|$A|_=>_none (func_subtype (param (ref $A) (ref null $A)) func)) - ;; CHECK: (func $non-nullability (type $ref|$A|_=>_none) (param $nn (ref $A)) + ;; CHECK: (func $non-nullability (type $ref|$A|_ref?|$A|_=>_none) (param $nn (ref $A)) (param $A (ref null $A)) ;; CHECK-NEXT: (local $temp (ref null $A)) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $nn) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: (local.get $nn) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.tee $temp - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: (local.tee $temp + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $A ;; CHECK-NEXT: (local.tee $temp - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $non-nullability (param $nn (ref $A)) + (func $non-nullability (param $nn (ref $A)) (param $A (ref null $A)) (local $temp (ref null $A)) ;; Set a non-null value to the field. (struct.set $A 0 - (ref.null $A) + (local.get $A) (local.get $nn) ) ;; Set a get of the same field to the field - this is a copy. However, the @@ -922,10 +909,10 @@ ;; the local. We could add casts perhaps, but for now we do not optimize, ;; and type $A's field will remain nullable. (struct.set $A 0 - (ref.null $A) + (local.get $A) (local.tee $temp (struct.get $A 0 - (ref.null $A) + (local.get $A) ) ) ) @@ -934,7 +921,7 @@ (struct.new $A (local.tee $temp (struct.get $A 0 - (ref.null $A) + (local.get $A) ) ) ) @@ -948,9 +935,9 @@ ;; CHECK: (type $B (struct_subtype (field (ref null $B)) $A)) (type $B (struct_subtype (field (ref null $A)) $A)) - ;; CHECK: (type $ref?|$B|_=>_none (func_subtype (param (ref null $B)) func)) + ;; CHECK: (type $ref?|$B|_ref?|$A|_=>_none (func_subtype (param (ref null $B) (ref null $A)) func)) - ;; CHECK: (func $heap-type (type $ref?|$B|_=>_none) (param $b (ref null $B)) + ;; CHECK: (func $heap-type (type $ref?|$B|_ref?|$A|_=>_none) (param $b (ref null $B)) (param $A (ref null $A)) ;; CHECK-NEXT: (local $a (ref null $A)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $B @@ -960,17 +947,14 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $A ;; CHECK-NEXT: (local.tee $a - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $heap-type (param $b (ref null $B)) + (func $heap-type (param $b (ref null $B)) (param $A (ref null $A)) (local $a (ref null $A)) ;; Similar to the above, but instead of non-nullability being the issue, ;; now it is the heap type. We write a B to B's field, so we can trivially @@ -987,7 +971,7 @@ (struct.new $A (local.tee $a (struct.get $A 0 - (ref.null $A) + (local.get $A) ) ) ) @@ -996,68 +980,52 @@ ) (module - ;; CHECK: (type $A (struct_subtype (field (mut (ref null $A))) data)) + ;; CHECK: (type $A (struct_subtype (field (mut (ref $A))) data)) (type $A (struct_subtype (field (mut (ref null $A))) data)) - ;; CHECK: (type $ref|$A|_=>_none (func_subtype (param (ref $A)) func)) + ;; CHECK: (type $ref|$A|_ref?|$A|_=>_none (func_subtype (param (ref $A) (ref null $A)) func)) - ;; CHECK: (func $non-nullability-block (type $ref|$A|_=>_none) (param $nn (ref $A)) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $nn) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK: (func $non-nullability-block (type $ref|$A|_ref?|$A|_=>_none) (param $nn (ref $A)) (param $A (ref null $A)) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: (local.get $nn) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (if (result (ref null $A)) - ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.set $A 0 + ;; CHECK-NEXT: (local.get $A) + ;; CHECK-NEXT: (if (result (ref $A)) + ;; CHECK-NEXT: (i32.const 1) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $A - ;; CHECK-NEXT: (if (result (ref null $A)) + ;; CHECK-NEXT: (if (result (ref $A)) ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (block ;; (replaces something unreachable we can't emit) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $A 0 + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $non-nullability-block (param $nn (ref $A)) + (func $non-nullability-block (param $nn (ref $A)) (param $A (ref null $A)) (struct.set $A 0 - (ref.null $A) + (local.get $A) (local.get $nn) ) ;; As above, but instead of a local.tee fallthrough, use an if. We *can* ;; optimize in this case, as ifs etc do not pose a problem (we'll refinalize ;; the ifs to the proper, non-nullable type, the same as the field). (struct.set $A 0 - (ref.null $A) + (local.get $A) (if (result (ref null $A)) (i32.const 1) (struct.get $A 0 - (ref.null $A) + (local.get $A) ) (unreachable) ) @@ -1067,7 +1035,7 @@ (if (result (ref null $A)) (i32.const 1) (struct.get $A 0 - (ref.null $A) + (local.get $A) ) (unreachable) ) From 63e853ec1822df8601e5c3eee5e2efe7c69aadfd Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 08:28:38 -0700 Subject: [PATCH 09/18] update gufa test --- test/lit/passes/gufa.wast | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/lit/passes/gufa.wast b/test/lit/passes/gufa.wast index dfff06e4fcb..a1ac729c340 100644 --- a/test/lit/passes/gufa.wast +++ b/test/lit/passes/gufa.wast @@ -1001,7 +1001,7 @@ ;; CHECK: (type $funcref_=>_none (func (param funcref))) - ;; CHECK: (type $none_=>_none (func)) + ;; CHECK: (type $ref?|$A|_=>_none (func (param (ref null $A)))) ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call-without-effects (param i32 funcref))) (import "binaryen-intrinsics" "call.without.effects" @@ -1015,10 +1015,10 @@ ;; CHECK: (export "foo" (func $foo)) - ;; CHECK: (func $foo + ;; CHECK: (func $foo (param $A (ref null $A)) ;; CHECK-NEXT: (call $call-without-effects ;; CHECK-NEXT: (i32.const 1) - ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-keep) @@ -1027,14 +1027,14 @@ ;; CHECK-NEXT: (ref.func $target-keep-2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $foo (export "foo") + (func $foo (export "foo") (param $A (ref null $A)) ;; Call the intrinsic without a RefFunc. All we infer here is the type, ;; which means we must assume anything with type $A (and a reference) can be ;; called, which will keep alive the bodies of both $target-keep and ;; $target-keep-2 - no unreachables will be placed in either one. (call $call-without-effects (i32.const 1) - (ref.null $A) + (local.get $A) ) (drop (ref.func $target-keep) @@ -1046,7 +1046,7 @@ ;; CHECK: (func $target-keep (param $x i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $target-keep (type $A) (param $x i32) @@ -1057,7 +1057,7 @@ ;; CHECK: (func $target-keep-2 (param $x i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $target-keep-2 (type $A) (param $x i32) From 6c33c303ca661903ffb925fcfac526a8e9feeaed Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 09:32:53 -0700 Subject: [PATCH 10/18] fix remove-unused-module-elements-refs test --- .../remove-unused-module-elements-refs.wast | 87 +++++++++---------- 1 file changed, 40 insertions(+), 47 deletions(-) diff --git a/test/lit/passes/remove-unused-module-elements-refs.wast b/test/lit/passes/remove-unused-module-elements-refs.wast index 698b0186753..497af29ee69 100644 --- a/test/lit/passes/remove-unused-module-elements-refs.wast +++ b/test/lit/passes/remove-unused-module-elements-refs.wast @@ -4,6 +4,8 @@ (module ;; CHECK: (type $A (func_subtype func)) (type $A (func)) + ;; CHECK: (type $ref?|$A|_=>_none (func_subtype (param (ref null $A)) func)) + ;; CHECK: (type $B (func_subtype func)) (type $B (func)) @@ -11,18 +13,15 @@ ;; CHECK: (export "foo" (func $foo)) - ;; CHECK: (func $foo (type $A) + ;; CHECK: (func $foo (type $ref?|$A|_=>_none) (param $A (ref null $A)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-B) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (call_ref $A + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop @@ -31,7 +30,7 @@ ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $foo (export "foo") + (func $foo (export "foo") (param $A (ref null $A)) ;; This export has two RefFuncs, and one CallRef. (drop (ref.func $target-A) @@ -40,7 +39,7 @@ (ref.func $target-B) ) (call_ref - (ref.null $A) + (local.get $A) ) ;; Verify that we do not crash on an unreachable call_ref, which has no ;; heap type for us to analyze. @@ -50,7 +49,7 @@ ) ;; CHECK: (func $target-A (type $A) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $target-A (type $A) ;; This function is reachable from the export "foo": there is a RefFunc and @@ -123,39 +122,35 @@ (type $A (func)) (type $B (func)) + ;; CHECK: (type $ref?|$A|_=>_none (func_subtype (param (ref null $A)) func)) + ;; CHECK: (elem declare func $target-A-1 $target-A-2) ;; CHECK: (export "foo" (func $foo)) - ;; CHECK: (func $foo (type $A) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK: (func $foo (type $ref?|$A|_=>_none) (param $A (ref null $A)) + ;; CHECK-NEXT: (call_ref $A + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (call_ref $A + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $foo (export "foo") + (func $foo (export "foo") (param $A (ref null $A)) (call_ref - (ref.null $A) + (local.get $A) ) (drop (ref.func $target-A-1) ) (call_ref - (ref.null $A) + (local.get $A) ) (drop (ref.func $target-A-2) @@ -163,14 +158,14 @@ ) ;; CHECK: (func $target-A-1 (type $A) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $target-A-1 (type $A) ;; This function is reachable. ) ;; CHECK: (func $target-A-2 (type $A) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $target-A-2 (type $A) ;; This function is reachable. @@ -188,54 +183,50 @@ (type $A (func)) (type $B (func)) + ;; CHECK: (type $ref?|$A|_=>_none (func_subtype (param (ref null $A)) func)) + ;; CHECK: (elem declare func $target-A-1 $target-A-2) ;; CHECK: (export "foo" (func $foo)) - ;; CHECK: (func $foo (type $A) + ;; CHECK: (func $foo (type $ref?|$A|_=>_none) (param $A (ref null $A)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-1) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (call_ref $A + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-A-2) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null nofunc) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (call_ref $A + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $foo (export "foo") + (func $foo (export "foo") (param $A (ref null $A)) (drop (ref.func $target-A-1) ) (call_ref - (ref.null $A) + (local.get $A) ) (drop (ref.func $target-A-2) ) (call_ref - (ref.null $A) + (local.get $A) ) ) ;; CHECK: (func $target-A-1 (type $A) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $target-A-1 (type $A) ;; This function is reachable. ) ;; CHECK: (func $target-A-2 (type $A) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $target-A-2 (type $A) ;; This function is reachable. @@ -307,6 +298,8 @@ ;; CHECK: (type $funcref_=>_none (func_subtype (param funcref) func)) + ;; CHECK: (type $ref?|$A|_=>_none (func_subtype (param (ref null $A)) func)) + ;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call-without-effects (param funcref))) (import "binaryen-intrinsics" "call.without.effects" (func $call-without-effects (param funcref))) @@ -319,9 +312,9 @@ ;; CHECK: (export "foo" (func $foo)) - ;; CHECK: (func $foo (type $A) + ;; CHECK: (func $foo (type $ref?|$A|_=>_none) (param $A (ref null $A)) ;; CHECK-NEXT: (call $call-without-effects - ;; CHECK-NEXT: (ref.null nofunc) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-keep) @@ -330,12 +323,12 @@ ;; CHECK-NEXT: (ref.func $target-keep-2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $foo (export "foo") + (func $foo (export "foo") (param $A (ref null $A)) ;; Call the intrinsic without a RefFunc. All we infer here is the type, ;; which means we must assume anything with type $A (and a reference) can be ;; called, which will keep alive both $target-keep and $target-keep-2 (call $call-without-effects - (ref.null $A) + (local.get $A) ) (drop (ref.func $target-keep) @@ -346,13 +339,13 @@ ) ;; CHECK: (func $target-keep (type $A) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $target-keep (type $A) ) ;; CHECK: (func $target-keep-2 (type $A) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) (func $target-keep-2 (type $A) ) From be4a1fff9a547acfc8544adc90e0a0da97282e5f Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 10:17:33 -0700 Subject: [PATCH 11/18] remove stale optimize-instructions-tnh test --- .../passes/optimize-instructions-gc-tnh.wast | 33 ------------------- 1 file changed, 33 deletions(-) diff --git a/test/lit/passes/optimize-instructions-gc-tnh.wast b/test/lit/passes/optimize-instructions-gc-tnh.wast index f01be393fdf..d8fe7a67705 100644 --- a/test/lit/passes/optimize-instructions-gc-tnh.wast +++ b/test/lit/passes/optimize-instructions-gc-tnh.wast @@ -52,9 +52,6 @@ ;; TNH-NEXT: (drop ;; TNH-NEXT: (i32.const 1) ;; TNH-NEXT: ) - ;; TNH-NEXT: (drop - ;; TNH-NEXT: (i32.const 1) - ;; TNH-NEXT: ) ;; TNH-NEXT: ) ;; NO_TNH: (func $ref.eq-no (type $eqref_eqref_=>_none) (param $a eqref) (param $b eqref) ;; NO_TNH-NEXT: (drop @@ -73,19 +70,6 @@ ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (ref.eq - ;; NO_TNH-NEXT: (block (result nullref) - ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (ref.null none) - ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (ref.null none) - ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (ref.as_data - ;; NO_TNH-NEXT: (ref.null none) - ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: ) ;; NO_TNH-NEXT: ) (func $ref.eq-no (param $a (ref null eq)) (param $b (ref null eq)) ;; We must leave the inputs to ref.eq of type eqref or a subtype. Note that @@ -106,23 +90,6 @@ ) ) ) - ;; As above, but now with nulls of a non-eq type. - ;; Note that we could in theory change a null's type to get validation in - ;; such cases. - (drop - (ref.eq - (ref.cast_static $struct - (ref.null any) ;; *Not* an eqref! - ) - (ref.as_non_null - (ref.as_data - (ref.as_non_null - (ref.null any) ;; *Not* an eqref! - ) - ) - ) - ) - ) ) ;; TNH: (func $ref.is (type $eqref_=>_i32) (param $a eqref) (result i32) From f8c987b1a4a8ca668ba8385df80bd6855cd03a6c Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 11:41:19 -0700 Subject: [PATCH 12/18] fix merge-blocks test --- test/lit/passes/merge-blocks.wast | 32 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/test/lit/passes/merge-blocks.wast b/test/lit/passes/merge-blocks.wast index cf920d7565f..58ba6f171d6 100644 --- a/test/lit/passes/merge-blocks.wast +++ b/test/lit/passes/merge-blocks.wast @@ -43,26 +43,24 @@ ) ) - ;; CHECK: (func $struct.set + ;; CHECK: (func $struct.set (param $struct (ref null $struct)) ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1234) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (block (result (ref null $struct)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1234) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (i32.const 5) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) - (func $struct.set + (func $struct.set (param $struct (ref null $struct)) (block (nop) (struct.set $struct 0 (block (result (ref null $struct)) (drop (i32.const 1234)) - (ref.null $struct) + (local.get $struct) ) (i32.const 5) ) @@ -70,28 +68,26 @@ ) ) - ;; CHECK: (func $struct.get + ;; CHECK: (func $struct.get (param $struct (ref null $struct)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.const 1234) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (block (result (ref null $struct)) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (i32.const 1234) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) - (func $struct.get + (func $struct.get (param $struct (ref null $struct)) (block (nop) (drop (struct.get $struct 0 (block (result (ref null $struct)) (drop (i32.const 1234)) - (ref.null $struct) + (local.get $struct) ) ) ) From d4fd05c9b3bea617f28126d3caa99f5605b3ead2 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 11:53:48 -0700 Subject: [PATCH 13/18] fix dae-gc-refine-params.wast --- test/lit/passes/dae-gc-refine-params.wast | 77 +++++++++++++---------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/test/lit/passes/dae-gc-refine-params.wast b/test/lit/passes/dae-gc-refine-params.wast index 12165b6401b..a6cfb7ac571 100644 --- a/test/lit/passes/dae-gc-refine-params.wast +++ b/test/lit/passes/dae-gc-refine-params.wast @@ -3,13 +3,14 @@ ;; RUN: wasm-opt %s -all --dae --nominal -S -o - | filecheck %s --check-prefix NOMNL (module + ;; CHECK: (type ${} (struct )) + ;; CHECK: (type ${i32} (struct (field i32))) ;; NOMNL: (type ${} (struct_subtype data)) ;; NOMNL: (type ${i32} (struct_subtype (field i32) ${})) (type ${i32} (struct_subtype (field i32) ${})) - ;; CHECK: (type ${} (struct )) (type ${} (struct)) ;; CHECK: (type ${f64} (struct (field f64))) @@ -218,43 +219,55 @@ ;; its parameters (see last function), however, we reuse the parameters by ;; writing to them, which causes problems in one case. ;; CHECK: (func $various-params-set (param $x (ref null ${i32})) (param $y (ref null ${i32})) - ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local $2 (ref null ${})) + ;; CHECK-NEXT: (local.set $2 ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $y) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $x - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (local.set $y - ;; CHECK-NEXT: (call $get_null_{i32_i64}) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $2 + ;; CHECK-NEXT: (struct.new_default ${}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $2) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (local.set $y + ;; CHECK-NEXT: (call $get_null_{i32_i64}) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (local.get $y) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; NOMNL: (func $various-params-set (type $ref?|${i32}|_ref?|${i32}|_=>_none) (param $x (ref null ${i32})) (param $y (ref null ${i32})) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.get $x) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.get $y) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (local.set $x - ;; NOMNL-NEXT: (ref.null none) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local $2 (ref null ${})) + ;; NOMNL-NEXT: (local.set $2 ;; NOMNL-NEXT: (local.get $x) ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (local.set $y - ;; NOMNL-NEXT: (call $get_null_{i32_i64}) - ;; NOMNL-NEXT: ) - ;; NOMNL-NEXT: (drop - ;; NOMNL-NEXT: (local.get $y) + ;; NOMNL-NEXT: (block + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $y) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $2 + ;; NOMNL-NEXT: (struct.new_default ${}) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $2) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (local.set $y + ;; NOMNL-NEXT: (call $get_null_{i32_i64}) + ;; NOMNL-NEXT: ) + ;; NOMNL-NEXT: (drop + ;; NOMNL-NEXT: (local.get $y) + ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: ) (func $various-params-set (param $x (ref null ${})) (param $y (ref null ${})) @@ -265,7 +278,7 @@ ;; force us to do a fixup: the param will get the new type, and a new local ;; will stay at the old type, and we will use that local throughout the ;; function. - (local.set $x (ref.null ${})) + (local.set $x (struct.new ${})) (drop (local.get $x) ) From 2310c413c67e12a49641485ba0359cc70cdc1ac0 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 11:55:13 -0700 Subject: [PATCH 14/18] Remove unfinished, stale comment --- test/lit/parse-double-unreachable.wast | 1 - 1 file changed, 1 deletion(-) diff --git a/test/lit/parse-double-unreachable.wast b/test/lit/parse-double-unreachable.wast index c647df330d3..0dd657a62a3 100644 --- a/test/lit/parse-double-unreachable.wast +++ b/test/lit/parse-double-unreachable.wast @@ -28,7 +28,6 @@ ) ) - ;; Now we are in unreachable parsing mode. Due to the bug, we would have (array.get_u $array (local.get $x) From 93d3d7d348923b2fe510aac4b0b1fda25b0662f5 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 12:43:45 -0700 Subject: [PATCH 15/18] fix test/heap-types.wast --- test/heap-types.wast | 37 +++--- test/heap-types.wast.from-wast | 128 ++++++------------ test/heap-types.wast.fromBinary | 122 ++++++++++++++--- test/heap-types.wast.fromBinary.noDebugInfo | 140 ++++++++++++++++---- 4 files changed, 274 insertions(+), 153 deletions(-) diff --git a/test/heap-types.wast b/test/heap-types.wast index d34eaf5ebbc..35e866e9b79 100644 --- a/test/heap-types.wast +++ b/test/heap-types.wast @@ -40,7 +40,7 @@ (struct.new_default $struct.A) ) - (func $structs (param $x (ref $struct.A)) (result (ref $struct.B)) + (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)) @@ -62,7 +62,7 @@ (struct.get $struct.A $named (local.get $x)) ) (drop - (struct.get $struct.A.prime $othername (ref.null $struct.A.prime)) + (struct.get $struct.A.prime $othername (local.get $struct.A.prime)) ) (drop (struct.get_u $struct.B 0 (local.get $tB)) @@ -72,10 +72,7 @@ ) ;; immutable fields allow subtyping. (drop - (struct.get $child 0 (ref.null $grandchild)) - ) - (drop - (ref.null $struct.A) + (struct.get $child 0 (local.get $grandchild)) ) (drop (block (result (ref null $struct.A)) @@ -102,14 +99,14 @@ ) ) (struct.set $struct.C 0 - (ref.null $struct.C) + (local.get $struct.C) (f32.const 100) ) ;; values may be subtypes (struct.set $nested-child-struct 0 - (ref.null $nested-child-struct) + (local.get $nested-child-struct) (ref.as_non_null - (ref.null $grandchild) + (local.get $grandchild) ) ) (drop @@ -124,7 +121,7 @@ ) (unreachable) ) - (func $arrays (param $x (ref $vector)) (result (ref $matrix)) + (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)) @@ -153,10 +150,10 @@ ) ;; values may be subtypes (array.set $nested-child-array - (ref.null $nested-child-array) + (local.get $nested-child-array) (i32.const 3) (ref.as_non_null - (ref.null $grandchild) + (local.get $grandchild) ) ) (drop @@ -266,8 +263,8 @@ (struct.get $struct.C 0 (unreachable)) ) ) - (func $unreachables-2 - (struct.set $struct.C 0 (ref.null $struct.C) (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)) @@ -281,9 +278,9 @@ (i32.const 2) ) ) - (func $unreachables-array-2 + (func $unreachables-array-2 (param $vector (ref null $vector)) (array.get $vector - (ref.null $vector) + (local.get $vector) (unreachable) ) ) @@ -294,16 +291,16 @@ (f64.const 2.18281828) ) ) - (func $unreachables-array-4 + (func $unreachables-array-4 (param $vector (ref null $vector)) (array.set $vector - (ref.null $vector) + (local.get $vector) (unreachable) (f64.const 2.18281828) ) ) - (func $unreachables-array-5 + (func $unreachables-array-5 (param $vector (ref null $vector)) (array.set $vector - (ref.null $vector) + (local.get $vector) (i32.const 2) (unreachable) ) diff --git a/test/heap-types.wast.from-wast b/test/heap-types.wast.from-wast index ebe01c76ac5..dd3067e5a38 100644 --- a/test/heap-types.wast.from-wast +++ b/test/heap-types.wast.from-wast @@ -1,20 +1,26 @@ (module (type $struct.A (struct (field i32) (field f32) (field $named f64))) - (type $struct.B (struct (field i8) (field (mut i16)) (field (ref $struct.A)) (field (mut (ref $struct.A))))) (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 $grandchild (struct (field i32) (field i64))) (type $anyref_=>_none (func (param anyref))) + (type $ref?|$vector|_=>_none (func (param (ref null $vector)))) + (type $nested-child-struct (struct (field (mut (ref $child))))) (type $words (array (mut i32))) - (type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B)))) - (type $struct.C (struct (field $named-mut (mut f32)))) - (type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) + (type $nested-child-array (array (mut (ref $child)))) + (type $child (struct (field i32))) + (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 $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 (param $x (ref $struct.A)) (result (ref $struct.B)) + (func $structs (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)) @@ -44,11 +50,8 @@ ) ) (drop - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (unreachable) + (struct.get $struct.A $named + (local.get $struct.A.prime) ) ) (drop @@ -62,16 +65,10 @@ ) ) (drop - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (unreachable) + (struct.get $grandchild 0 + (local.get $grandchild) ) ) - (drop - (ref.null none) - ) (drop (block (result (ref null $struct.A)) (local.get $x) @@ -96,25 +93,15 @@ (i32.const 1) ) ) - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (drop - (f32.const 100) - ) - (unreachable) + (struct.set $struct.C $named-mut + (local.get $struct.C) + (f32.const 100) ) - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (drop - (ref.as_non_null - (ref.null none) - ) + (struct.set $nested-child-struct 0 + (local.get $nested-child-struct) + (ref.as_non_null + (local.get $grandchild) ) - (unreachable) ) (drop (struct.new_default $struct.A) @@ -128,7 +115,7 @@ ) (unreachable) ) - (func $arrays (param $x (ref $vector)) (result (ref $matrix)) + (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)) @@ -155,19 +142,12 @@ (i32.const 2) (f64.const 2.18281828) ) - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (drop - (i32.const 3) - ) - (drop - (ref.as_non_null - (ref.null none) - ) + (array.set $nested-child-array + (local.get $nested-child-array) + (i32.const 3) + (ref.as_non_null + (local.get $grandchild) ) - (unreachable) ) (drop (array.len $vector @@ -328,14 +308,9 @@ ) ) ) - (func $unreachables-2 - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (drop - (unreachable) - ) + (func $unreachables-2 (param $struct.C (ref null $struct.C)) + (struct.set $struct.C $named-mut + (local.get $struct.C) (unreachable) ) ) @@ -372,14 +347,9 @@ (unreachable) ) ) - (func $unreachables-array-2 - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (drop - (unreachable) - ) + (func $unreachables-array-2 (param $vector (ref null $vector)) + (array.get $vector + (local.get $vector) (unreachable) ) ) @@ -397,31 +367,17 @@ (unreachable) ) ) - (func $unreachables-array-4 - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (drop - (unreachable) - ) - (drop - (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 - (block ;; (replaces something unreachable we can't emit) - (drop - (ref.null none) - ) - (drop - (i32.const 2) - ) - (drop - (unreachable) - ) + (func $unreachables-array-5 (param $vector (ref null $vector)) + (array.set $vector + (local.get $vector) + (i32.const 2) (unreachable) ) ) diff --git a/test/heap-types.wast.fromBinary b/test/heap-types.wast.fromBinary index 1cb09864370..dc55e1e8f40 100644 --- a/test/heap-types.wast.fromBinary +++ b/test/heap-types.wast.fromBinary @@ -1,20 +1,26 @@ (module (type $struct.A (struct (field i32) (field f32) (field $named f64))) (type $vector (array (mut f64))) - (type $none_=>_none (func)) (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 $anyref_=>_none (func (param anyref))) - (type $ref|$struct.A|_=>_ref|$struct.B| (func (param (ref $struct.A)) (result (ref $struct.B)))) (type $struct.C (struct (field $named-mut (mut f32)))) - (type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) + (type $grandchild (struct (field i32) (field i64))) + (type $anyref_=>_none (func (param anyref))) + (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 $child (struct (field i32))) + (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 $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 (param $x (ref $struct.A)) (result (ref $struct.B)) + (func $structs (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)) @@ -44,11 +50,70 @@ ) ) (drop - (ref.null none) + (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 (param $x (ref $vector)) (result (ref $matrix)) + (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)) @@ -75,15 +140,34 @@ (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 - (ref.null none) + (array.len $vector + (local.get $x) + ) ) (drop - (i32.const 3) + (array.get $words + (local.get $tw) + (i32.const 1) + ) ) (drop - (ref.as_non_null - (ref.null none) + (array.get_u $bytes + (local.get $tb) + (i32.const 2) + ) + ) + (drop + (array.get_s $bytes + (local.get $tb) + (i32.const 3) ) ) (unreachable) @@ -215,9 +299,9 @@ (func $unreachables-1 (unreachable) ) - (func $unreachables-2 + (func $unreachables-2 (param $struct.C (ref null $struct.C)) (drop - (ref.null none) + (local.get $struct.C) ) (unreachable) ) @@ -230,24 +314,24 @@ (func $unreachables-array-1 (unreachable) ) - (func $unreachables-array-2 + (func $unreachables-array-2 (param $vector (ref null $vector)) (drop - (ref.null none) + (local.get $vector) ) (unreachable) ) (func $unreachables-array-3 (unreachable) ) - (func $unreachables-array-4 + (func $unreachables-array-4 (param $vector (ref null $vector)) (drop - (ref.null none) + (local.get $vector) ) (unreachable) ) - (func $unreachables-array-5 + (func $unreachables-array-5 (param $vector (ref null $vector)) (drop - (ref.null none) + (local.get $vector) ) (drop (i32.const 2) diff --git a/test/heap-types.wast.fromBinary.noDebugInfo b/test/heap-types.wast.fromBinary.noDebugInfo index 9b34b58290b..9c51947507f 100644 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ b/test/heap-types.wast.fromBinary.noDebugInfo @@ -1,25 +1,31 @@ (module (type ${i32_f32_f64} (struct (field i32) (field f32) (field f64))) (type $[mut:f64] (array (mut f64))) - (type $none_=>_none (func)) (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 $anyref_=>_none (func (param anyref))) - (type $ref|{i32_f32_f64}|_=>_ref|{i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|}| (func (param (ref ${i32_f32_f64})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})))) (type ${mut:f32} (struct (field (mut f32)))) - (type $ref|[mut:f64]|_=>_ref|[mut:ref?|[mut:f64]|]| (func (param (ref $[mut:f64])) (result (ref $[mut:ref?|[mut:f64]|])))) + (type ${i32_i64} (struct (field i32) (field i64))) + (type $anyref_=>_none (func (param anyref))) + (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 ${i32} (struct (field i32))) + (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 $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 (param $0 (ref ${i32_f32_f64})) (result (ref ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) - (local $1 (ref null ${i32_f32_f64})) - (local $2 (ref null ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|})) - (local $3 (ref null ${mut:f32})) - (local $4 (ref null $[mut:f64])) - (local $5 (ref null $[mut:ref?|[mut:f64]|])) + (func $0 (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) ) @@ -44,15 +50,74 @@ ) ) (drop - (ref.null none) + (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 (param $0 (ref $[mut:f64])) (result (ref $[mut:ref?|[mut:f64]|])) - (local $1 (ref null $[mut:f64])) - (local $2 (ref null $[mut:ref?|[mut:f64]|])) - (local $3 (ref null $[mut:i8])) - (local $4 (ref null $[mut:i32])) + (func $1 (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) @@ -75,15 +140,34 @@ (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 - (ref.null none) + (array.len $[mut:f64] + (local.get $0) + ) ) (drop - (i32.const 3) + (array.get $[mut:i32] + (local.get $6) + (i32.const 1) + ) ) (drop - (ref.as_non_null - (ref.null none) + (array.get_u $[mut:i8] + (local.get $5) + (i32.const 2) + ) + ) + (drop + (array.get_s $[mut:i8] + (local.get $5) + (i32.const 3) ) ) (unreachable) @@ -215,9 +299,9 @@ (func $5 (unreachable) ) - (func $6 + (func $6 (param $0 (ref null ${mut:f32})) (drop - (ref.null none) + (local.get $0) ) (unreachable) ) @@ -230,24 +314,24 @@ (func $9 (unreachable) ) - (func $10 + (func $10 (param $0 (ref null $[mut:f64])) (drop - (ref.null none) + (local.get $0) ) (unreachable) ) (func $11 (unreachable) ) - (func $12 + (func $12 (param $0 (ref null $[mut:f64])) (drop - (ref.null none) + (local.get $0) ) (unreachable) ) - (func $13 + (func $13 (param $0 (ref null $[mut:f64])) (drop - (ref.null none) + (local.get $0) ) (drop (i32.const 2) From d6a1fda66e91f4ea833d8d9d9db09cb2ed91458b Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 14:02:34 -0700 Subject: [PATCH 16/18] fix test/lit/passes/cfp.wast --- test/lit/passes/cfp.wast | 644 +++++++++++++++++++++------------------ 1 file changed, 344 insertions(+), 300 deletions(-) diff --git a/test/lit/passes/cfp.wast b/test/lit/passes/cfp.wast index cf11b2e66d5..b1790bd174f 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -32,24 +32,26 @@ ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i64) data)) (type $struct (struct i64)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i64.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) ;; The only place this type is created is with a default value, and so we ;; can optimize the later get into a constant (plus a drop of the ref). ;; @@ -62,33 +64,35 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field f32) data)) (type $struct (struct f32)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (f32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) ;; The only place this type is created is with a constant value, and so we ;; can optimize the later get into a constant (plus a drop of the ref). (drop @@ -98,33 +102,30 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) ) (module - ;; CHECK: (type $f32_=>_none (func_subtype (param f32) func)) - ;; CHECK: (type $struct (struct_subtype (field f32) data)) (type $struct (struct f32)) - ;; CHECK: (func $test (type $f32_=>_none) (param $f f32) + ;; CHECK: (type $f32_ref?|$struct|_=>_none (func_subtype (param f32 (ref null $struct)) func)) + + ;; CHECK: (func $test (type $f32_ref?|$struct|_=>_none) (param $f f32) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (local.get $f) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test (param $f f32) + (func $test (param $f f32) (param $struct (ref null $struct)) ;; The value given is not a constant, and so we cannot optimize. (drop (struct.new $struct @@ -133,7 +134,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -142,10 +143,12 @@ ;; Create in one function, get in another. The 10 should be forwarded to the ;; get. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -160,20 +163,22 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -182,25 +187,29 @@ ;; As before, but with the order of functions reversed to check for any ordering ;; issues. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -226,9 +235,9 @@ (module ;; CHECK: (type $struct (struct_subtype (field f32) data)) (type $struct (struct f32)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (f32.const 42) @@ -240,15 +249,12 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $struct (f32.const 42) @@ -261,7 +267,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -322,10 +328,10 @@ (module ;; CHECK: (type $struct (struct_subtype (field (mut f32)) data)) (type $struct (struct (mut f32))) - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -352,20 +358,22 @@ (f32.const 42) ;; The last testcase had 1337 here. ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f32.const 42) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -446,28 +454,30 @@ ;; Test a function reference instead of a number. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) ;; CHECK: (type $struct (struct_subtype (field funcref) data)) (type $struct (struct funcref)) ;; CHECK: (elem declare func $test) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (ref.func $test) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result (ref $ref?|$struct|_=>_none)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (ref.func $test) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $struct (ref.func $test) @@ -475,7 +485,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -539,6 +549,9 @@ ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) + ;; CHECK: (type $ref?|$substruct|_=>_none (func_subtype (param (ref null $substruct)) func)) + + ;; CHECK: (type $substruct (struct_subtype (field i32) $struct)) (type $substruct (struct_subtype i32 $struct)) ;; CHECK: (func $create (type $none_=>_none) @@ -555,20 +568,20 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$substruct|_=>_none) (param $substruct (ref null $substruct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (local.get $substruct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $substruct (ref null $substruct)) (drop (struct.get $substruct 0 - (ref.null $substruct) + (local.get $substruct) ) ) ) @@ -581,11 +594,12 @@ (module ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - (type $substruct (struct_subtype (mut i32) $struct)) - ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$substruct|_=>_none (func_subtype (param (ref null $substruct)) func)) + + ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) $struct)) + (type $substruct (struct_subtype (mut i32) $struct)) ;; CHECK: (func $create (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop @@ -609,20 +623,22 @@ (i32.const 10) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$substruct|_=>_none) (param $substruct (ref null $substruct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $substruct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $substruct (ref null $substruct)) (drop (struct.get $substruct 0 - (ref.null $substruct) + (local.get $substruct) ) ) ) @@ -641,6 +657,8 @@ (type $struct (struct i32)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $substruct @@ -657,20 +675,22 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -679,13 +699,15 @@ ;; Subtyping: Create both a subtype and a supertype, with identical constants ;; for the shared field, and get the supertype. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) (type $substruct (struct_subtype i32 f64 $struct)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -712,20 +734,22 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -735,13 +759,15 @@ ;; for the shared field, preventing optimization, as a get of the ;; supertype may receive an instance of the subtype. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) (type $substruct (struct_subtype i32 f64 $struct)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -768,20 +794,17 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -792,8 +815,6 @@ ;; shared between the types, but we only create the substruct with ;; one value, so we can optimize. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) ;; CHECK: (type $substruct (struct_subtype (field i32) (field f64) $struct)) @@ -801,6 +822,10 @@ (type $struct (struct i32)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $ref?|$substruct|_=>_none (func_subtype (param (ref null $substruct)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -827,20 +852,22 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$substruct|_=>_none) (param $substruct (ref null $substruct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $substruct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $substruct (ref null $substruct)) (drop (struct.get $substruct 0 - (ref.null $substruct) + (local.get $substruct) ) ) ) @@ -851,12 +878,12 @@ ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) - ;; CHECK: (type $substruct (struct_subtype (field (mut i32)) (field f64) $struct)) (type $substruct (struct_subtype (mut i32) f64 $struct)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + + ;; CHECK: (type $ref?|$substruct|_=>_none (func_subtype (param (ref null $substruct)) func)) ;; CHECK: (func $create (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop @@ -892,20 +919,17 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$substruct|_=>_none) (param $substruct (ref null $substruct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $substruct 0 + ;; CHECK-NEXT: (local.get $substruct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $substruct (ref null $substruct)) (drop (struct.get $substruct 0 - (ref.null $substruct) + (local.get $substruct) ) ) ) @@ -914,8 +938,6 @@ ;; Multi-level subtyping, check that we propagate not just to the immediate ;; supertype but all the way as needed. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct1 (struct_subtype (field i32) data)) ;; CHECK: (type $struct2 (struct_subtype (field i32) (field f64) $struct1)) @@ -927,6 +949,10 @@ (type $struct1 (struct i32)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none (func_subtype (param (ref null $struct1) (ref null $struct2) (ref null $struct3)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct3 @@ -941,93 +967,105 @@ (struct.new $struct3 (i32.const 20) (f64.const 3.14159) - (ref.null any) + (ref.null none) ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f64.const 3.14159) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f64.const 3.14159) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; Get field 0 from the $struct1. This can be optimized to a constant ;; since we only ever created an instance of struct3 with a constant there. (drop (struct.get $struct1 0 - (ref.null $struct1) + (local.get $struct1) ) ) ;; Get both fields of $struct2. (drop (struct.get $struct2 0 - (ref.null $struct2) + (local.get $struct2) ) ) (drop (struct.get $struct2 1 - (ref.null $struct2) + (local.get $struct2) ) ) ;; Get all 3 fields of $struct3 (drop (struct.get $struct3 0 - (ref.null $struct3) + (local.get $struct3) ) ) (drop (struct.get $struct3 1 - (ref.null $struct3) + (local.get $struct3) ) ) (drop (struct.get $struct3 2 - (ref.null $struct3) + (local.get $struct3) ) ) ) @@ -1037,8 +1075,6 @@ ;; different values in the sub-most type. Create the top and bottom types, but ;; not the middle one. (module - ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) - ;; CHECK: (type $struct1 (struct_subtype (field i32) (field i32) data)) ;; CHECK: (type $struct2 (struct_subtype (field i32) (field i32) (field f64) (field f64) $struct1)) @@ -1050,7 +1086,9 @@ (type $struct2 (struct_subtype i32 i32 f64 f64 $struct1)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) + + ;; CHECK: (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none (func_subtype (param (ref null $struct1) (ref null $struct2) (ref null $struct3)) func)) ;; CHECK: (func $create (type $anyref_=>_none) (param $any anyref) ;; CHECK-NEXT: (drop @@ -1089,164 +1127,178 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct1) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct1 1 + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f64.const 2.71828) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct2) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f64.const 9.9999999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f64.const 2.71828) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f64.const 9.9999999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct3 5 + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; Get all the fields of all the structs. (drop (struct.get $struct1 0 - (ref.null $struct1) + (local.get $struct1) ) ) (drop (struct.get $struct1 1 - (ref.null $struct1) + (local.get $struct1) ) ) (drop (struct.get $struct2 0 - (ref.null $struct2) + (local.get $struct2) ) ) (drop (struct.get $struct2 1 - (ref.null $struct2) + (local.get $struct2) ) ) (drop (struct.get $struct2 2 - (ref.null $struct2) + (local.get $struct2) ) ) (drop (struct.get $struct2 3 - (ref.null $struct2) + (local.get $struct2) ) ) (drop (struct.get $struct3 0 - (ref.null $struct3) + (local.get $struct3) ) ) (drop (struct.get $struct3 1 - (ref.null $struct3) + (local.get $struct3) ) ) (drop (struct.get $struct3 2 - (ref.null $struct3) + (local.get $struct3) ) ) (drop (struct.get $struct3 3 - (ref.null $struct3) + (local.get $struct3) ) ) (drop (struct.get $struct3 4 - (ref.null $struct3) + (local.get $struct3) ) ) (drop (struct.get $struct3 5 - (ref.null $struct3) + (local.get $struct3) ) ) ) @@ -1255,8 +1307,6 @@ ;; Multi-level subtyping with a different value in the middle of the chain. We ;; can only optimize $struct3. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct1 (struct_subtype (field (mut i32)) data)) (type $struct1 (struct (mut i32))) ;; CHECK: (type $struct2 (struct_subtype (field (mut i32)) (field f64) $struct1)) @@ -1264,6 +1314,10 @@ ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) (type $struct3 (struct_subtype (mut i32) f64 anyref $struct2)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none (func_subtype (param (ref null $struct1) (ref null $struct2) (ref null $struct3)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct1 @@ -1304,47 +1358,43 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct1 0 + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct2 0 + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct3) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; Get field 0 in all the types. (drop (struct.get $struct1 0 - (ref.null $struct1) + (local.get $struct1) ) ) (drop (struct.get $struct2 0 - (ref.null $struct2) + (local.get $struct2) ) ) (drop (struct.get $struct3 0 - (ref.null $struct3) + (local.get $struct3) ) ) ) @@ -1360,12 +1410,12 @@ (type $struct1 (struct (mut i32))) - ;; CHECK: (type $ref?|$struct2|_=>_none (func_subtype (param (ref null $struct2)) func)) - ;; CHECK: (type $struct3 (struct_subtype (field (mut i32)) (field f64) (field anyref) $struct2)) (type $struct3 (struct_subtype (mut i32) f64 anyref $struct2)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$struct2|_=>_none (func_subtype (param (ref null $struct2)) func)) + + ;; CHECK: (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none (func_subtype (param (ref null $struct1) (ref null $struct2) (ref null $struct3)) func)) ;; CHECK: (func $create (type $ref?|$struct2|_=>_none) (param $struct2 (ref null $struct2)) ;; CHECK-NEXT: (drop @@ -1416,47 +1466,38 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct1|_ref?|$struct2|_ref?|$struct3|_=>_none) (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct1 0 + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct2 0 + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct3 0 + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct1 (ref null $struct1)) (param $struct2 (ref null $struct2)) (param $struct3 (ref null $struct3)) ;; Get field 0 in all the types. (drop (struct.get $struct1 0 - (ref.null $struct1) + (local.get $struct1) ) ) (drop (struct.get $struct2 0 - (ref.null $struct2) + (local.get $struct2) ) ) (drop (struct.get $struct3 0 - (ref.null $struct3) + (local.get $struct3) ) ) ) @@ -1465,11 +1506,13 @@ ;; Test for a struct with multiple fields, some of which are constant and hence ;; optimizable, and some not. Also test that some have the same type. (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) (field f64) (field i32) (field f64) (field i32) data)) (type $struct (struct i32 f64 i32 f64 i32)) + ;; CHECK: (type $none_=>_none (func_subtype func)) + + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (func $create (type $none_=>_none) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct @@ -1496,86 +1539,88 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (f64.const 3.14159) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 3 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 30) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $struct) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 30) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $get + (func $get (param $struct (ref null $struct)) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) (drop (struct.get $struct 1 - (ref.null $struct) + (local.get $struct) ) ) (drop (struct.get $struct 2 - (ref.null $struct) + (local.get $struct) ) ) (drop (struct.get $struct 3 - (ref.null $struct) + (local.get $struct) ) ) (drop (struct.get $struct 4 - (ref.null $struct) + (local.get $struct) ) ) ;; Also test for multiple gets of the same field. (drop (struct.get $struct 4 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -1650,9 +1695,9 @@ ;; CHECK: (type $struct (struct_subtype (field (mut i32)) data)) (type $struct (struct (mut i32))) - ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (type $ref?|$struct|_ref?|$struct|_=>_none (func_subtype (param (ref null $struct) (ref null $struct)) func)) - ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) + ;; CHECK: (func $test (type $ref?|$struct|_ref?|$struct|_=>_none) (param $struct (ref null $struct)) (param $other (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new_default $struct) ;; CHECK-NEXT: ) @@ -1668,15 +1713,17 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.as_non_null + ;; CHECK-NEXT: (local.get $other) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test (param $struct (ref null $struct)) + (func $test (param $struct (ref null $struct)) (param $other (ref null $struct)) (drop (struct.new_default $struct) ) @@ -1690,7 +1737,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $other) ) ) ) @@ -1834,30 +1881,27 @@ ) (module - ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $struct (struct_subtype (field i32) data)) (type $struct (struct i32)) + ;; CHECK: (type $ref?|$struct|_=>_none (func_subtype (param (ref null $struct)) func)) + ;; CHECK: (global $global (mut i32) (i32.const 42)) (global $global (mut i32) (i32.const 42)) - ;; CHECK: (func $test (type $none_=>_none) + ;; CHECK: (func $test (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.new $struct ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block - ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null none) - ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (struct.get $struct 0 + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) ;; As above, but the global is *not* immutable, so we cannot optimize. (drop (struct.new $struct @@ -1866,7 +1910,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) From 0d68f7d2f71c727c21fb34ba4ea473e3a0a89308 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 15:47:23 -0700 Subject: [PATCH 17/18] Fix possible-contents handling of nulls --- src/ir/possible-contents.cpp | 31 +++++++++++-------------------- test/gtest/possible-contents.cpp | 2 +- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index d01348e3f19..934011b15db 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -47,23 +47,6 @@ void PossibleContents::combine(const PossibleContents& other) { // First handle the trivial cases of them being equal, or one of them is // None or Many. if (*this == other) { - // Nulls are a special case, since they compare equal even if their type is - // different. We would like to make this function symmetric, that is, that - // combine(a, b) == combine(b, a) (otherwise, things can be odd and we could - // get nondeterminism in the flow analysis which does not have a - // determinstic order). To fix that, pick the LUB. - if (isNull()) { - assert(other.isNull()); - auto lub = HeapType::getLeastUpperBound(type.getHeapType(), - otherType.getHeapType()); - if (!lub) { - // TODO: Remove this workaround once we have bottom types to assign to - // null literals. - value = Many(); - return; - } - value = Literal::makeNull(*lub); - } return; } if (other.isNone()) { @@ -97,10 +80,18 @@ void PossibleContents::combine(const PossibleContents& other) { // Special handling for references from here. - // Nulls are always equal to each other, even if their types differ. + if (isNull() && other.isNull()) { + // These must be nulls in different hierarchies, otherwise this would have + // been handled by the `*this == other` case above. + assert(type != otherType); + value = Many(); + return; + } + + // Nulls can be combined in by just adding nullability to a type. if (isNull() || other.isNull()) { - // Only one of them can be null here, since we already checked if *this == - // other, which would have been true had both been null. + // Only one of them can be null here, since we already handled the case + // where they were both null. assert(!isNull() || !other.isNull()); // If only one is a null, but the other's type is known exactly, then the // combination is to add nullability (if the type is *not* known exactly, diff --git a/test/gtest/possible-contents.cpp b/test/gtest/possible-contents.cpp index 17d1da0d367..2ba008570c7 100644 --- a/test/gtest/possible-contents.cpp +++ b/test/gtest/possible-contents.cpp @@ -139,8 +139,8 @@ TEST_F(PossibleContentsTest, TestComparisons) { // Nulls assertNotEqualSymmetric(i32Zero, anyNull); + assertNotEqualSymmetric(anyNull, funcNull); assertEqualSymmetric(anyNull, anyNull); - assertEqualSymmetric(anyNull, funcNull); // All nulls compare equal. assertEqualSymmetric(exactNonNullAnyref, exactNonNullAnyref); assertNotEqualSymmetric(exactNonNullAnyref, exactAnyref); From 6c4933ecf48712007cff4ceba5e4d796ae61b42b Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 6 Oct 2022 18:14:26 -0700 Subject: [PATCH 18/18] restore and fix ArrayCopy effects test --- test/example/cpp-unit.cpp | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/test/example/cpp-unit.cpp b/test/example/cpp-unit.cpp index df0902f7793..d2339f03054 100644 --- a/test/example/cpp-unit.cpp +++ b/test/example/cpp-unit.cpp @@ -602,6 +602,41 @@ void test_effects() { // Nops... do not. Nop nop; assert_equal(EffectAnalyzer(options, module, &nop).trap, false); + + // ArrayCopy can trap, reads arrays, and writes arrays (but not structs). + { + Type arrayref = Type(HeapType(Array(Field(Type::i32, Mutable))), Nullable); + LocalGet dest; + dest.index = 0; + dest.type = arrayref; + LocalGet destIndex; + destIndex.index = 1; + destIndex.type = Type::i32; + LocalGet src; + src.index = 0; + src.type = arrayref; + LocalGet srcIndex; + srcIndex.index = 1; + srcIndex.type = Type::i32; + LocalGet length; + srcIndex.index = 2; + srcIndex.type = Type::i32; + ArrayCopy arrayCopy(module.allocator); + arrayCopy.destRef = &dest; + arrayCopy.destIndex = &destIndex; + arrayCopy.srcRef = &src; + arrayCopy.srcIndex = &srcIndex; + arrayCopy.length = &length; + arrayCopy.finalize(); + + EffectAnalyzer effects(options, module); + effects.visit(&arrayCopy); + assert_equal(effects.trap, true); + assert_equal(effects.readsArray, true); + assert_equal(effects.writesArray, true); + assert_equal(effects.readsMutableStruct, false); + assert_equal(effects.writesStruct, false); + } } void test_field() {