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 ---- diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index cc7ed5b1569..f2908920c5c 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); } @@ -1484,7 +1508,8 @@ 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, @@ -1699,10 +1724,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..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, @@ -785,7 +776,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..7d7c778bcbf 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.isNull(); } + 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..f325f70c649 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,25 @@ struct Updater : public PostWalker { } void visitCall(Call* curr) { if (curr->isReturn) { - handleReturnCall(curr, module->getFunction(curr->target)->type); + handleReturnCall(curr, module->getFunction(curr->target)->getResults()); } } 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 +314,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 +352,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 +1017,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 +1131,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..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; @@ -1509,6 +1513,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 +1579,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 +1736,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 +1753,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-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/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..b07af462751 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.isNull()); 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.isNull()) { 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-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-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..09022eea098 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; } @@ -325,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; } @@ -350,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; @@ -361,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"); @@ -463,52 +475,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 +500,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..b5bfabb039a 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,14 @@ void WasmBinaryBuilder::skipUnreachableCode() { expressionStack = savedStack; return; } - pushExpression(curr); + if (curr->type == Type::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); + } } } @@ -6525,7 +6586,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 +6997,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 +7079,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..43b381a1b9f 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); @@ -585,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: @@ -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..ba309ddeacc 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -2110,13 +2110,12 @@ void FunctionValidator::visitRefNull(RefNull* curr) { shouldBeTrue(!getFunction() || getModule()->features.hasReferenceTypes(), curr, "ref.null requires reference-types to be enabled"); + if (!shouldBeTrue( + curr->type.isNullable(), curr, "ref.null types must be nullable")) { + return; + } 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"); + curr->type.isNull(), curr, "ref.null must have a bottom heap type"); } void FunctionValidator::visitRefIs(RefIs* curr) { @@ -2454,12 +2453,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 +2582,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 +2612,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 +2696,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 +2725,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 +2766,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/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 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..d2339f03054 100644 --- a/test/example/cpp-unit.cpp +++ b/test/example/cpp-unit.cpp @@ -605,7 +605,30 @@ void test_effects() { // 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); @@ -616,19 +639,6 @@ void test_effects() { } } -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() { // Simple types assert_equal(Field(Type::i32, Immutable).getByteSize(), 4); @@ -681,7 +691,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/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); 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 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 09a12833f2b..dd3067e5a38 100644 --- a/test/heap-types.wast.from-wast +++ b/test/heap-types.wast.from-wast @@ -8,17 +8,19 @@ (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 $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 $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) + (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)) @@ -49,7 +51,7 @@ ) (drop (struct.get $struct.A $named - (ref.null $struct.A) + (local.get $struct.A.prime) ) ) (drop @@ -64,12 +66,9 @@ ) (drop (struct.get $grandchild 0 - (ref.null $grandchild) + (local.get $grandchild) ) ) - (drop - (ref.null $struct.A) - ) (drop (block (result (ref null $struct.A)) (local.get $x) @@ -95,13 +94,13 @@ ) ) (struct.set $struct.C $named-mut - (ref.null $struct.C) + (local.get $struct.C) (f32.const 100) ) (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 @@ -116,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)) @@ -144,10 +143,10 @@ (f64.const 2.18281828) ) (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 @@ -237,7 +236,7 @@ (local.get $x) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -247,7 +246,7 @@ (local.get $x) ) ) - (ref.null data) + (ref.null none) ) ) (drop @@ -257,7 +256,7 @@ (local.get $x) ) ) - (ref.null i31) + (ref.null none) ) ) (drop @@ -275,7 +274,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -285,7 +284,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -295,7 +294,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) ) @@ -305,12 +304,13 @@ (drop (unreachable) ) + (unreachable) ) ) ) - (func $unreachables-2 + (func $unreachables-2 (param $struct.C (ref null $struct.C)) (struct.set $struct.C $named-mut - (ref.null $struct.C) + (local.get $struct.C) (unreachable) ) ) @@ -322,6 +322,7 @@ (drop (unreachable) ) + (unreachable) ) ) (func $unreachables-4 @@ -332,6 +333,7 @@ (drop (f32.const 1) ) + (unreachable) ) ) (func $unreachables-array-1 @@ -342,11 +344,12 @@ (drop (i32.const 2) ) + (unreachable) ) ) - (func $unreachables-array-2 + (func $unreachables-array-2 (param $vector (ref null $vector)) (array.get $vector - (ref.null $vector) + (local.get $vector) (unreachable) ) ) @@ -361,25 +364,29 @@ (drop (f64.const 2.18281828) ) + (unreachable) ) ) - (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) ) ) (func $unreachables-array-6 (drop - (block + (block ;; (replaces something unreachable we can't emit) + (drop + (unreachable) + ) (unreachable) ) ) @@ -413,19 +420,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 +442,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..dc55e1e8f40 100644 --- a/test/heap-types.wast.fromBinary +++ b/test/heap-types.wast.fromBinary @@ -8,17 +8,19 @@ (type $struct.C (struct (field $named-mut (mut f32)))) (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.B| (func (param (ref $struct.A)) (result (ref $struct.B)))) - (type $ref|$vector|_=>_ref|$matrix| (func (param (ref $vector)) (result (ref $matrix)))) + (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)) @@ -49,7 +51,7 @@ ) (drop (struct.get $struct.A $named - (ref.null $struct.A) + (local.get $struct.A.prime) ) ) (drop @@ -64,12 +66,9 @@ ) (drop (struct.get $grandchild 0 - (ref.null $grandchild) + (local.get $grandchild) ) ) - (drop - (ref.null $struct.A) - ) (drop (local.get $x) ) @@ -93,13 +92,13 @@ ) ) (struct.set $struct.C $named-mut - (ref.null $struct.C) + (local.get $struct.C) (f32.const 100) ) (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 @@ -114,7 +113,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)) @@ -142,10 +141,10 @@ (f64.const 2.18281828) ) (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 @@ -235,7 +234,7 @@ (local.get $x) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -245,7 +244,7 @@ (local.get $x) ) ) - (ref.null data) + (ref.null none) ) ) (drop @@ -255,7 +254,7 @@ (local.get $x) ) ) - (ref.null i31) + (ref.null none) ) ) (drop @@ -273,7 +272,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -283,7 +282,7 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -293,16 +292,16 @@ (local.get $x) ) ) - (ref.null any) + (ref.null none) ) ) ) (func $unreachables-1 (unreachable) ) - (func $unreachables-2 + (func $unreachables-2 (param $struct.C (ref null $struct.C)) (drop - (ref.null $struct.C) + (local.get $struct.C) ) (unreachable) ) @@ -315,24 +314,24 @@ (func $unreachables-array-1 (unreachable) ) - (func $unreachables-array-2 + (func $unreachables-array-2 (param $vector (ref null $vector)) (drop - (ref.null $vector) + (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 $vector) + (local.get $vector) ) (unreachable) ) - (func $unreachables-array-5 + (func $unreachables-array-5 (param $vector (ref null $vector)) (drop - (ref.null $vector) + (local.get $vector) ) (drop (i32.const 2) @@ -371,19 +370,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 +392,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..9c51947507f 100644 --- a/test/heap-types.wast.fromBinary.noDebugInfo +++ b/test/heap-types.wast.fromBinary.noDebugInfo @@ -8,22 +8,24 @@ (type ${mut:f32} (struct (field (mut f32)))) (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|{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 $ref|[mut:f64]|_=>_ref|[mut:ref?|[mut:f64]|]| (func (param (ref $[mut:f64])) (result (ref $[mut:ref?|[mut:f64]|])))) + (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) ) @@ -49,27 +51,24 @@ ) (drop (struct.get ${i32_f32_f64} 2 - (ref.null ${i32_f32_f64}) + (local.get $1) ) ) (drop (struct.get_u ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 - (local.get $2) + (local.get $6) ) ) (drop (struct.get_s ${i8_mut:i16_ref|{i32_f32_f64}|_mut:ref|{i32_f32_f64}|} 0 - (local.get $2) + (local.get $6) ) ) (drop (struct.get ${i32_i64} 0 - (ref.null ${i32_i64}) + (local.get $2) ) ) - (drop - (ref.null ${i32_f32_f64}) - ) (drop (local.get $0) ) @@ -93,13 +92,13 @@ ) ) (struct.set ${mut:f32} 0 - (ref.null ${mut:f32}) + (local.get $3) (f32.const 100) ) (struct.set ${mut:ref|{i32}|} 0 - (ref.null ${mut:ref|{i32}|}) + (local.get $4) (ref.as_non_null - (ref.null ${i32_i64}) + (local.get $2) ) ) (drop @@ -114,11 +113,11 @@ ) (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) @@ -142,10 +141,10 @@ (f64.const 2.18281828) ) (array.set $[mut:ref|{i32}|] - (ref.null $[mut:ref|{i32}|]) + (local.get $1) (i32.const 3) (ref.as_non_null - (ref.null ${i32_i64}) + (local.get $2) ) ) (drop @@ -155,19 +154,19 @@ ) (drop (array.get $[mut:i32] - (local.get $4) + (local.get $6) (i32.const 1) ) ) (drop (array.get_u $[mut:i8] - (local.get $3) + (local.get $5) (i32.const 2) ) ) (drop (array.get_s $[mut:i8] - (local.get $3) + (local.get $5) (i32.const 3) ) ) @@ -235,7 +234,7 @@ (local.get $0) ) ) - (ref.null func) + (ref.null nofunc) ) ) (drop @@ -245,7 +244,7 @@ (local.get $0) ) ) - (ref.null data) + (ref.null none) ) ) (drop @@ -255,7 +254,7 @@ (local.get $0) ) ) - (ref.null i31) + (ref.null none) ) ) (drop @@ -273,7 +272,7 @@ (local.get $0) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -283,7 +282,7 @@ (local.get $0) ) ) - (ref.null any) + (ref.null none) ) ) (drop @@ -293,16 +292,16 @@ (local.get $0) ) ) - (ref.null any) + (ref.null none) ) ) ) (func $5 (unreachable) ) - (func $6 + (func $6 (param $0 (ref null ${mut:f32})) (drop - (ref.null ${mut:f32}) + (local.get $0) ) (unreachable) ) @@ -315,24 +314,24 @@ (func $9 (unreachable) ) - (func $10 + (func $10 (param $0 (ref null $[mut:f64])) (drop - (ref.null $[mut:f64]) + (local.get $0) ) (unreachable) ) (func $11 (unreachable) ) - (func $12 + (func $12 (param $0 (ref null $[mut:f64])) (drop - (ref.null $[mut:f64]) + (local.get $0) ) (unreachable) ) - (func $13 + (func $13 (param $0 (ref null $[mut:f64])) (drop - (ref.null $[mut:f64]) + (local.get $0) ) (drop (i32.const 2) @@ -371,19 +370,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 +392,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..0dd657a62a3 --- /dev/null +++ b/test/lit/parse-double-unreachable.wast @@ -0,0 +1,43 @@ +;; 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) + ) + ) + + (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..b1790bd174f 100644 --- a/test/lit/passes/cfp.wast +++ b/test/lit/passes/cfp.wast @@ -9,22 +9,23 @@ ;; 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 $struct) + ;; 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) ) ) ) @@ -33,9 +34,9 @@ (module ;; CHECK: (type $struct (struct_subtype (field i64) data)) (type $struct (struct i64)) - ;; 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_default $struct) ;; CHECK-NEXT: ) @@ -43,14 +44,14 @@ ;; CHECK-NEXT: (block (result i64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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). ;; @@ -63,7 +64,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -72,9 +73,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) @@ -84,14 +85,14 @@ ;; CHECK-NEXT: (block (result f32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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 @@ -101,7 +102,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -110,9 +111,9 @@ (module ;; CHECK: (type $struct (struct_subtype (field f32) data)) (type $struct (struct f32)) - ;; CHECK: (type $f32_=>_none (func_subtype (param f32) func)) + ;; CHECK: (type $f32_ref?|$struct|_=>_none (func_subtype (param f32 (ref null $struct)) func)) - ;; CHECK: (func $test (type $f32_=>_none) (param $f f32) + ;; 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) @@ -120,11 +121,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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,22 +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 (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -184,27 +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 (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -230,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) @@ -245,11 +250,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) @@ -262,7 +267,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -272,6 +277,8 @@ (module ;; 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) @@ -288,29 +295,29 @@ ) ) ) - ;; CHECK: (func $set (type $none_=>_none) + ;; CHECK: (func $set (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -321,6 +328,8 @@ (module ;; 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) @@ -337,34 +346,34 @@ ) ) ) - ;; CHECK: (func $set (type $none_=>_none) + ;; CHECK: (func $set (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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. ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result f32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -376,7 +385,9 @@ (type $struct (struct (mut f32))) ;; CHECK: (type $none_=>_none (func_subtype func)) - ;; CHECK: (type $i32_=>_none (func_subtype (param i32) 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 @@ -399,9 +410,9 @@ ) ) ) - ;; CHECK: (func $set (type $i32_=>_none) (param $x i32) + ;; CHECK: (func $set (type $i32_ref?|$struct|_=>_none) (param $x i32) (param $struct (ref null $struct)) ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (if (result f32) ;; CHECK-NEXT: (local.get $x) ;; CHECK-NEXT: (unreachable) @@ -409,9 +420,9 @@ ;; CHECK-NEXT: ) ;; 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) @@ -420,22 +431,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 (result f32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -443,30 +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 (result (ref $none_=>_none)) + ;; CHECK-NEXT: (block (result (ref $ref?|$struct|_=>_none)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) @@ -474,7 +485,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -491,6 +502,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -498,6 +510,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 +520,7 @@ ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.const 20) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) (func $test @@ -535,6 +549,8 @@ ;; 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)) @@ -552,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 $substruct) + ;; 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) ) ) ) @@ -578,49 +594,51 @@ (module ;; 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: (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 $none_=>_none) + ;; 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: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$substruct|_=>_none) (param $substruct (ref null $substruct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $substruct) + ;; CHECK-NEXT: (local.get $substruct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -639,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 @@ -655,22 +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 (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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,22 +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 (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -744,6 +766,8 @@ ;; 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 @@ -770,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -791,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)) @@ -800,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 @@ -826,22 +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 (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $substruct) + ;; CHECK-NEXT: (local.get $substruct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -855,16 +881,18 @@ ;; 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: (func $create (type $none_=>_none) + ;; 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 ;; 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: (local.get $struct) ;; CHECK-NEXT: (i32.const 10) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -874,14 +902,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 @@ -891,17 +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: (struct.get $substruct 0 - ;; CHECK-NEXT: (ref.null $substruct) + ;; 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) ) ) ) @@ -923,12 +951,14 @@ ;; 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 ;; 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: ) @@ -937,16 +967,16 @@ (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 (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 20) @@ -956,7 +986,7 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 20) @@ -966,7 +996,7 @@ ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.const 3.14159) @@ -976,7 +1006,7 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 20) @@ -986,56 +1016,56 @@ ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.const 3.14159) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; 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) ) ) ) @@ -1058,7 +1088,7 @@ ;; CHECK: (type $anyref_=>_none (func_subtype (param anyref) func)) - ;; 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 $anyref_=>_none) (param $any anyref) ;; CHECK-NEXT: (drop @@ -1073,7 +1103,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: ) @@ -1097,12 +1127,12 @@ ) ) ) - ;; 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 (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 10) @@ -1110,14 +1140,14 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct1 1 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 10) @@ -1127,7 +1157,7 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 999) @@ -1137,7 +1167,7 @@ ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.const 2.71828) @@ -1147,7 +1177,7 @@ ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.const 9.9999999) @@ -1157,7 +1187,7 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 10) @@ -1167,7 +1197,7 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 999) @@ -1177,7 +1207,7 @@ ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.const 2.71828) @@ -1187,88 +1217,88 @@ ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.const 9.9999999) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (block (result anyref) + ;; CHECK-NEXT: (block (result nullref) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - ;; CHECK-NEXT: (ref.null any) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct3 5 - ;; CHECK-NEXT: (ref.null $struct3) + ;; 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) ) ) ) @@ -1281,11 +1311,13 @@ (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)) + ;; 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 @@ -1302,7 +1334,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: ) @@ -1326,43 +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: (struct.get $struct1 0 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct3) + ;; CHECK-NEXT: (local.get $struct3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -1381,9 +1413,11 @@ ;; 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: (func $create (type $none_=>_none) + ;; 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 ;; CHECK-NEXT: (struct.new $struct1 ;; CHECK-NEXT: (i32.const 10) @@ -1396,18 +1430,18 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: (i32.const 9999) ;; 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: ) - (func $create + (func $create (param $struct2 (ref null $struct2)) (drop (struct.new $struct1 (i32.const 10) @@ -1420,7 +1454,7 @@ ) ) (struct.set $struct2 0 - (ref.null $struct2) + (local.get $struct2) (i32.const 9999) ;; use a different value here (f64.const 0) ) @@ -1432,38 +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: (struct.get $struct1 0 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct3 0 - ;; CHECK-NEXT: (ref.null $struct3) + ;; 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) ) ) ) @@ -1477,6 +1511,8 @@ ;; 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 @@ -1503,17 +1539,17 @@ ) ) ) - ;; CHECK: (func $get (type $none_=>_none) + ;; CHECK: (func $get (type $ref?|$struct|_=>_none) (param $struct (ref null $struct)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result f64) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (f64.const 3.14159) @@ -1523,7 +1559,7 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 20) @@ -1531,14 +1567,14 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 3 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 30) @@ -1548,43 +1584,43 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -1659,18 +1695,18 @@ ;; 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|_ref?|$struct|_=>_none (func_subtype (param (ref null $struct) (ref null $struct)) func)) - ;; CHECK: (func $test (type $none_=>_none) + ;; 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: ) ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) @@ -1680,28 +1716,28 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $other) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (param $other (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 (struct.get $struct 0 - (ref.null $struct) + (local.get $other) ) ) ) @@ -1712,44 +1748,44 @@ (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 $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: (struct.set $struct 1 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null $other) + ;; 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: (ref.null $struct) + ;; 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) ) ) ) @@ -1760,18 +1796,18 @@ ;; 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: (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_default $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (i32.const 0) @@ -1779,24 +1815,24 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -1806,12 +1842,12 @@ ;; 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 $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) @@ -1821,14 +1857,14 @@ ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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 @@ -1838,7 +1874,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -1848,12 +1884,12 @@ ;; 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 $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) @@ -1861,11 +1897,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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 @@ -1874,7 +1910,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -1884,33 +1920,33 @@ ;; 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 $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: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (global.get $global) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (block (result i32) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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) @@ -1920,12 +1956,12 @@ ;; 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) ) ) ) @@ -1935,30 +1971,30 @@ ;; 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 $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: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (global.get $global-2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) @@ -1966,12 +2002,12 @@ ) ;; 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) ) ) ) @@ -1981,30 +2017,30 @@ ;; 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 $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: (struct.set $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) @@ -2013,12 +2049,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) ) ) ) @@ -2038,11 +2074,11 @@ ;; 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: (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 func) + ;; CHECK-NEXT: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.new $vtable ;; CHECK-NEXT: (ref.func $test) @@ -2057,7 +2093,7 @@ ) )) - ;; 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) @@ -2068,7 +2104,7 @@ ;; CHECK-NEXT: (block (result (ref $itable)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $object) + ;; CHECK-NEXT: (local.get $object) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global) @@ -2077,7 +2113,7 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test (result funcref) + (func $test (param $object (ref null $object)) (result funcref) (drop (struct.new $object (global.get $global) @@ -2092,7 +2128,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/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..a6cfb7ac571 100644 --- a/test/lit/passes/dae-gc-refine-params.wast +++ b/test/lit/passes/dae-gc-refine-params.wast @@ -3,27 +3,28 @@ ;; 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))) + ;; 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 @@ -230,7 +231,7 @@ ;; CHECK-NEXT: (local.get $y) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $2 - ;; CHECK-NEXT: (ref.null ${}) + ;; CHECK-NEXT: (struct.new_default ${}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (local.get $2) @@ -256,7 +257,7 @@ ;; NOMNL-NEXT: (local.get $y) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (local.set $2 - ;; NOMNL-NEXT: (ref.null ${}) + ;; NOMNL-NEXT: (struct.new_default ${}) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (drop ;; NOMNL-NEXT: (local.get $2) @@ -277,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) ) @@ -345,32 +346,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 +389,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 +401,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 +543,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 +551,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 +586,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 +598,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..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,27 +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: (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: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -56,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) @@ -72,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -93,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) @@ -102,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -123,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) @@ -146,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -168,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) @@ -191,24 +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: (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: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -219,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) @@ -242,24 +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: (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: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global2) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -270,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) @@ -293,24 +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: (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: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global3) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -321,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) @@ -351,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -373,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) @@ -403,24 +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: (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: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global3) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -431,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) @@ -447,7 +447,7 @@ (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) @@ -455,11 +455,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) @@ -467,7 +467,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -479,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))) @@ -498,24 +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: (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: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -530,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,7 +550,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 @@ -559,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -584,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) @@ -601,32 +601,32 @@ )) ;; 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) (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: (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: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -637,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) @@ -653,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -674,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)) @@ -693,7 +693,7 @@ (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) @@ -701,11 +701,11 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) @@ -713,7 +713,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -728,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) @@ -744,7 +744,7 @@ (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) @@ -756,14 +756,14 @@ ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) - (func $test + (func $test (param $struct (ref null $struct)) (drop (struct.new $super-struct (i32.const 999999) @@ -771,7 +771,7 @@ ) (drop (struct.get $struct 0 - (ref.null $struct) + (local.get $struct) ) ) ) @@ -786,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) @@ -802,10 +802,10 @@ (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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -814,25 +814,25 @@ ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $super-struct) + ;; CHECK-NEXT: (local.get $super-struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) ;; 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) ) ) ) @@ -843,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 @@ -865,17 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -894,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) @@ -921,40 +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: (struct.get $super-struct 0 - ;; CHECK-NEXT: (ref.null $super-struct) + ;; CHECK-NEXT: (local.get $super-struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct1 0 - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct2 0 - ;; CHECK-NEXT: (ref.null $struct2) + ;; 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) ) ) ) @@ -972,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) @@ -1017,10 +1017,10 @@ (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: (struct.get $super-struct 0 - ;; CHECK-NEXT: (ref.null $super-struct) + ;; CHECK-NEXT: (local.get $super-struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -1029,7 +1029,7 @@ ;; CHECK-NEXT: (i32.const 1338) ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct1) + ;; CHECK-NEXT: (local.get $struct1) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global1) ;; CHECK-NEXT: ) @@ -1041,29 +1041,29 @@ ;; CHECK-NEXT: (i32.const 99998) ;; CHECK-NEXT: (ref.eq ;; CHECK-NEXT: (ref.as_non_null - ;; CHECK-NEXT: (ref.null $struct2) + ;; CHECK-NEXT: (local.get $struct2) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (global.get $global2) ;; CHECK-NEXT: ) ;; 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 4ecab4f8c82..edcf43bb2fc 100644 --- a/test/lit/passes/gto-mutability.wast +++ b/test/lit/passes/gto-mutability.wast @@ -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) @@ -33,18 +33,18 @@ ;; 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: (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: (ref.null nofunc) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (local.set $temp ;; CHECK-NEXT: (local.get $x) @@ -108,7 +108,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 @@ -153,17 +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: (struct.get $struct 2 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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))) ) ) @@ -178,12 +178,12 @@ ;; 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: (struct.set $A 0 ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $A 1 ;; CHECK-NEXT: (local.get $x) @@ -201,33 +201,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: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (ref.null $B) + ;; 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))) ) ) @@ -242,12 +242,12 @@ ;; 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: (struct.set $B 0 ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $B 1 ;; CHECK-NEXT: (local.get $x) @@ -265,53 +265,54 @@ ) ) - ;; 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: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (ref.null $B) + ;; 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 (field (mut (ref null $B))) (field i32) 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)) )) - ;; 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)) - ;; 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: (struct.set $A 0 ;; CHECK-NEXT: (local.get $x) - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (ref.null none) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $B 1 ;; CHECK-NEXT: (local.get $y) @@ -329,33 +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: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $A 1 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $B 0 - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (local.get $B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $B 1 - ;; CHECK-NEXT: (ref.null $B) + ;; 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))) ) ) @@ -369,7 +370,7 @@ ;; 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: (struct.set $struct 2 @@ -384,27 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 1 - ;; CHECK-NEXT: (ref.null $struct) + ;; CHECK-NEXT: (local.get $struct) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $struct 2 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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))) ) ) @@ -419,6 +420,8 @@ ;; 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 $super @@ -445,21 +448,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: (struct.get $super 0 - ;; CHECK-NEXT: (ref.null $super) + ;; CHECK-NEXT: (local.get $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $sub 0 - ;; CHECK-NEXT: (ref.null $sub) + ;; 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))) ) ) @@ -473,7 +476,7 @@ ;; CHECK: (type $ref|$super|_=>_none (func_subtype (param (ref $super)) 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|$super|_=>_none) (param $x (ref $super)) ;; CHECK-NEXT: (drop @@ -509,21 +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: (struct.get $super 0 - ;; CHECK-NEXT: (ref.null $super) + ;; CHECK-NEXT: (local.get $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $sub 0 - ;; CHECK-NEXT: (ref.null $sub) + ;; 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))) ) ) @@ -538,7 +541,7 @@ ;; 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: (struct.set $sub 0 @@ -553,20 +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: (struct.get $super 0 - ;; CHECK-NEXT: (ref.null $super) + ;; CHECK-NEXT: (local.get $super) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (struct.get $sub 0 - ;; CHECK-NEXT: (ref.null $sub) + ;; 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 5dd6ab4d19b..184359f49ba 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: ) @@ -405,6 +405,8 @@ ;; 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,18 +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: (struct.get $struct 0 - ;; CHECK-NEXT: (ref.null $struct) + ;; 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) ) ) ) @@ -562,6 +564,7 @@ ;; CHECK-NEXT: (i32.const 3) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -781,43 +784,45 @@ ;; 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: (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: (ref.null ${mut:i8}) + ;; CHECK-NEXT: (local.get ${mut:i8}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; 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: (drop ;; CHECK-NEXT: (ref.as_non_null ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null ${mut:i8}) + ;; CHECK-NEXT: (local.get ${mut:i8}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (br $block) @@ -827,24 +832,24 @@ ;; 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: (drop ;; CHECK-NEXT: (ref.as_non_null ;; CHECK-NEXT: (block ;; CHECK-NEXT: (drop - ;; CHECK-NEXT: (ref.null ${mut:i8}) + ;; CHECK-NEXT: (local.get ${mut:i8}) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (unreachable) @@ -853,14 +858,14 @@ ;; CHECK-NEXT: ) ;; 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 905ce0a80ef..f75b0dd9661 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: ) @@ -3605,11 +3607,13 @@ ;; 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: (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) @@ -3861,7 +3865,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: ) @@ -3902,17 +3906,23 @@ ) ) - ;; CHECK: (func $arrays (type $none_=>_none) + ;; CHECK: (func $arrays (type $ref|$B|_=>_none) (param $B (ref $B)) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (array.len $B - ;; CHECK-NEXT: (ref.null $B) + ;; CHECK-NEXT: (array.init_static $B + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: (ref.null none) + ;; CHECK-NEXT: ) ;; 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/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..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 $A) + ;; 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) diff --git a/test/lit/passes/heap2local.wast b/test/lit/passes/heap2local.wast index 6fd7442789b..aace567f722 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 @@ -1278,28 +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: (struct.set $struct.recursive 0 - ;; CHECK-NEXT: (ref.null $struct.recursive) + ;; CHECK-NEXT: (local.get $struct.recursive) ;; CHECK-NEXT: (local.tee $ref ;; CHECK-NEXT: (struct.new_default $struct.recursive) ;; CHECK-NEXT: ) ;; 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: (struct.set $struct.recursive 0 - ;; NOMNL-NEXT: (ref.null $struct.recursive) + ;; NOMNL-NEXT: (local.get $struct.recursive) ;; NOMNL-NEXT: (local.tee $ref ;; NOMNL-NEXT: (struct.new_default $struct.recursive) ;; NOMNL-NEXT: ) ;; 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 @@ -1313,20 +1313,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 +1337,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 +1454,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 +1474,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 +1508,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 +1521,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 +1537,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 +1554,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 +1577,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 +1585,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 +1602,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 +1615,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 +1631,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 +1648,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 +1671,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 +1679,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 +1755,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 +1771,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 +1787,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 +1811,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 +1827,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 +1843,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 +1883,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 +1928,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 +1996,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 +2028,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 +2042,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 +2074,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 +2112,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 +2129,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 +2172,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 +2189,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 +2218,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 +2233,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 +2250,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 +2265,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 +2313,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 +2338,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 +2515,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 +2535,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 +2544,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 +2564,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 +2595,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 +2620,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 +2671,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 +2684,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 +2706,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 +2719,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 +2760,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 +2781,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 +2814,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 +2834,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..34e994f7f89 100644 --- a/test/lit/passes/intrinsic-lowering.wast +++ b/test/lit/passes/intrinsic-lowering.wast @@ -17,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 @@ -28,18 +28,21 @@ ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call_ref $none - ;; CHECK-NEXT: (ref.null $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/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..58ba6f171d6 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: ) @@ -43,24 +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: (ref.null $struct) + ;; 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) ) @@ -68,26 +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: (ref.null $struct) + ;; 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) ) ) ) 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..d8fe7a67705 100644 --- a/test/lit/passes/optimize-instructions-gc-tnh.wast +++ b/test/lit/passes/optimize-instructions-gc-tnh.wast @@ -52,19 +52,6 @@ ;; TNH-NEXT: (drop ;; 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: ) ;; TNH-NEXT: ) ;; NO_TNH: (func $ref.eq-no (type $eqref_eqref_=>_none) (param $a eqref) (param $b eqref) ;; NO_TNH-NEXT: (drop @@ -83,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 (ref null $struct)) - ;; NO_TNH-NEXT: (drop - ;; NO_TNH-NEXT: (ref.null any) - ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (ref.null $struct) - ;; NO_TNH-NEXT: ) - ;; NO_TNH-NEXT: (ref.as_data - ;; NO_TNH-NEXT: (ref.null any) - ;; 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 @@ -116,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) diff --git a/test/lit/passes/optimize-instructions-gc.wast b/test/lit/passes/optimize-instructions-gc.wast index da2411eedf0..c0d106250a4 100644 --- a/test/lit/passes/optimize-instructions-gc.wast +++ b/test/lit/passes/optimize-instructions-gc.wast @@ -14,30 +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 $A (struct_subtype (field i32) data)) (type $A (struct (field i32))) - ;; CHECK: (type $array (array (mut i8))) + ;; 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))) @@ -45,10 +54,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) @@ -58,25 +67,25 @@ ) ) ;; 2. if its `ifTrue` and `ifFalse` arms are not identical (cannot fold) - ;; CHECK: (func $if-arms-subtype-nofold (result anyref) + ;; 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 data) - ;; CHECK-NEXT: (ref.null i31) + ;; 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: (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 data) - ;; NOMNL-NEXT: (ref.null i31) + ;; 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) ) ) @@ -708,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) @@ -730,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) @@ -761,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) @@ -793,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 @@ -839,6 +854,11 @@ ) ) ) + (call_ref $void + (ref.as_non_null + (local.get $f) + ) + ) ) ;; CHECK: (func $get-eqref (result eqref) @@ -945,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) @@ -1254,7 +1274,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 +1283,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: ) @@ -1880,29 +1900,29 @@ ) ) - ;; CHECK: (func $hoist-LUB-danger (param $x i32) (result i32) + ;; 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: (ref.null $B) + ;; CHECK-NEXT: (local.get $b) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.get $C 1 - ;; CHECK-NEXT: (ref.null $C) + ;; 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: (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: (ref.null $B) + ;; NOMNL-NEXT: (local.get $b) ;; NOMNL-NEXT: ) ;; NOMNL-NEXT: (struct.get $C 1 - ;; NOMNL-NEXT: (ref.null $C) + ;; 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. @@ -1914,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) ) ) ) @@ -1952,44 +1972,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: (func $incompatible-cast-of-null (type $void) ;; 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 +2191,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: (func $ref-cast-static-null (type $void) ;; 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: ) @@ -3089,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) + ) + ) ) 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..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,7 +13,7 @@ ;; 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: ) @@ -19,13 +21,16 @@ ;; CHECK-NEXT: (ref.func $target-B) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (block + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: ) ;; 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) @@ -34,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. @@ -80,8 +85,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 +105,7 @@ ) ;; CHECK: (func $target-A (type $A) - ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) (func $target-A (type $A) ;; This function is reachable. @@ -114,33 +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: (func $foo (type $ref?|$A|_=>_none) (param $A (ref null $A)) ;; CHECK-NEXT: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; 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: (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) @@ -173,36 +183,38 @@ (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: (call_ref $A - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; 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: (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) ) ) @@ -286,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))) @@ -298,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 $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (ref.func $target-keep) @@ -309,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) 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..f578e341624 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,14 +795,15 @@ ;; CHECK: (type $Leaf2-Inner (struct_subtype $Root-Inner)) (type $Leaf2-Inner (struct_subtype $Root-Inner)) - ;; CHECK: (type $none_=>_none (func_subtype func)) + ;; CHECK: (type $ref?|$Leaf1-Outer|_=>_none (func_subtype (param (ref null $Leaf1-Outer)) func)) ;; CHECK: (type $Root-Outer (struct_subtype (field (ref $Leaf2-Inner)) data)) + ;; CHECK: (type $Leaf2-Outer (struct_subtype (field (ref $Leaf2-Inner)) $Root-Outer)) + ;; 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)) @@ -811,17 +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: (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: (local.get $Leaf1-Outer) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop @@ -830,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 @@ -852,7 +854,7 @@ ;; unreachable here. (struct.get $Leaf1-Inner 0 (struct.get $Leaf1-Outer 0 - (ref.null $Leaf1-Outer) + (local.get $Leaf1-Outer) ) ) ) @@ -868,19 +870,19 @@ ;; 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: (struct.set $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: (local.get $nn) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: (local.tee $temp ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) @@ -888,17 +890,17 @@ ;; CHECK-NEXT: (struct.new $A ;; CHECK-NEXT: (local.tee $temp ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; 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 @@ -907,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) ) ) ) @@ -919,7 +921,7 @@ (struct.new $A (local.tee $temp (struct.get $A 0 - (ref.null $A) + (local.get $A) ) ) ) @@ -933,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 @@ -946,13 +948,13 @@ ;; CHECK-NEXT: (struct.new $A ;; CHECK-NEXT: (local.tee $a ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; 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 @@ -969,7 +971,7 @@ (struct.new $A (local.tee $a (struct.get $A 0 - (ref.null $A) + (local.get $A) ) ) ) @@ -981,19 +983,19 @@ ;; 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: (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: (ref.null $A) + ;; CHECK-NEXT: (local.get $A) ;; CHECK-NEXT: (local.get $nn) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (struct.set $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; CHECK-NEXT: (local.get $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: (local.get $A) ;; CHECK-NEXT: ) ;; CHECK-NEXT: (unreachable) ;; CHECK-NEXT: ) @@ -1003,27 +1005,27 @@ ;; CHECK-NEXT: (if (result (ref $A)) ;; CHECK-NEXT: (i32.const 1) ;; CHECK-NEXT: (struct.get $A 0 - ;; CHECK-NEXT: (ref.null $A) + ;; 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) ) @@ -1033,7 +1035,7 @@ (if (result (ref null $A)) (i32.const 1) (struct.get $A 0 - (ref.null $A) + (local.get $A) ) (unreachable) ) 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 df5ab9cc0c7..30b1b21b66e 100644 Binary files a/test/unit/input/gc_target_feature.wasm and b/test/unit/input/gc_target_feature.wasm differ