diff options
-rw-r--r-- | src/wasm/wasm-binary.cpp | 15 | ||||
-rw-r--r-- | test/lit/binary/stacky-nn-tuple.test | 112 | ||||
-rw-r--r-- | test/lit/binary/stacky-nn-tuple.test.wasm | bin | 0 -> 81 bytes |
3 files changed, 120 insertions, 7 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index f43346fdb..b67fe013b 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -2656,24 +2656,25 @@ void WasmBinaryBuilder::pushExpression(Expression* curr) { // Store tuple to local and push individual extracted values Builder builder(wasm); // Non-nullable types require special handling as they cannot be stored to - // a local. - std::vector<Type> finalTypes; + // a local, so we may need to use a different local type than the original. + auto localType = type; if (!wasm.features.hasGCNNLocals()) { + std::vector<Type> finalTypes; for (auto t : type) { if (t.isNonNullable()) { t = Type(t.getHeapType(), Nullable); } finalTypes.push_back(t); } + localType = Type(Tuple(finalTypes)); } - auto nullableType = Type(Tuple(finalTypes)); requireFunctionContext("pushExpression-tuple"); - Index tuple = builder.addVar(currFunction, nullableType); + Index tuple = builder.addVar(currFunction, localType); expressionStack.push_back(builder.makeLocalSet(tuple, curr)); - for (Index i = 0; i < nullableType.size(); ++i) { + for (Index i = 0; i < localType.size(); ++i) { Expression* value = - builder.makeTupleExtract(builder.makeLocalGet(tuple, nullableType), i); - if (nullableType[i] != type[i]) { + builder.makeTupleExtract(builder.makeLocalGet(tuple, localType), i); + if (localType[i] != type[i]) { // We modified this to be nullable; undo that. value = builder.makeRefAs(RefAsNonNull, value); } diff --git a/test/lit/binary/stacky-nn-tuple.test b/test/lit/binary/stacky-nn-tuple.test new file mode 100644 index 000000000..41abc1d7d --- /dev/null +++ b/test/lit/binary/stacky-nn-tuple.test @@ -0,0 +1,112 @@ +# Verify stacky non-nullable tuples binary can be parsed correctly. The wasm +# contains code that uses pops to get a tuple and store it in a local, then +# reads those values. The file contains this: +# +# (module +# (type $A (struct (field (mut i32)))) +# (type $B (struct (field (mut i32)) (field (mut i32)))) +# (tag $tag$0 (param (ref $A) (ref $B))) +# (func $foo +# (local $temp ((ref null $A) (ref null $B))) +# (try $label$3 +# (do +# (nop) +# ) +# (catch $tag$0 +# (local.set $temp +# (pop (ref $A) (ref $B)) +# ) +# (drop +# (ref.as_non_null +# (tuple.extract 0 +# (local.get $temp) +# ) +# ) +# ) +# (drop +# (ref.as_non_null +# (tuple.extract 1 +# (local.get $temp) +# ) +# ) +# ) +# (unreachable) +# ) +# ) +# ) +# ) + +RUN: wasm-opt -all --enable-gc-nn-locals %s.wasm -all --print + +# CHECK: (module +# CHECK-NEXT: (type ${mut:i32} (struct (field (mut i32)))) +# CHECK-NEXT: (type ${mut:i32_mut:i32} (struct (field (mut i32)) (field (mut i32)))) +# CHECK-NEXT: (type $ref|{mut:i32}|_ref|{mut:i32_mut:i32}|_=>_none (func (param (ref ${mut:i32}) (ref ${mut:i32_mut:i32})))) +# CHECK-NEXT: (type $none_=>_none (func)) +# CHECK-NEXT: (tag $tag$0 (param (ref ${mut:i32}) (ref ${mut:i32_mut:i32}))) +# CHECK-NEXT: (func $0 +# CHECK-NEXT: (local $0 (ref null ${mut:i32})) +# CHECK-NEXT: (local $1 (ref null ${mut:i32_mut:i32})) +# CHECK-NEXT: (local $2 (ref null ${mut:i32_mut:i32})) +# CHECK-NEXT: (local $3 ((ref ${mut:i32}) (ref ${mut:i32_mut:i32}))) +# CHECK-NEXT: (local $4 (ref ${mut:i32})) +# CHECK-NEXT: (local $5 (ref null ${mut:i32})) +# CHECK-NEXT: (local $6 (ref null ${mut:i32})) +# CHECK-NEXT: (try $label$3 +# CHECK-NEXT: (do +# CHECK-NEXT: (nop) +# CHECK-NEXT: ) +# CHECK-NEXT: (catch $tag$0 +# CHECK-NEXT: (local.set $3 +# CHECK-NEXT: (pop (ref ${mut:i32}) (ref ${mut:i32_mut:i32})) +# CHECK-NEXT: ) +# CHECK-NEXT: (local.set $0 +# CHECK-NEXT: (block (result (ref ${mut:i32})) +# CHECK-NEXT: (local.set $4 +# CHECK-NEXT: (tuple.extract 0 +# CHECK-NEXT: (local.get $3) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: (local.set $1 +# CHECK-NEXT: (tuple.extract 1 +# CHECK-NEXT: (local.get $3) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: (local.get $4) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: (drop +# CHECK-NEXT: (ref.as_non_null +# CHECK-NEXT: (block (result (ref null ${mut:i32})) +# CHECK-NEXT: (local.set $5 +# CHECK-NEXT: (local.get $0) +# CHECK-NEXT: ) +# CHECK-NEXT: (drop +# CHECK-NEXT: (local.get $1) +# CHECK-NEXT: ) +# CHECK-NEXT: (local.get $5) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: (drop +# CHECK-NEXT: (block (result (ref null ${mut:i32})) +# CHECK-NEXT: (local.set $6 +# CHECK-NEXT: (local.get $0) +# CHECK-NEXT: ) +# CHECK-NEXT: (local.set $2 +# CHECK-NEXT: (local.get $1) +# CHECK-NEXT: ) +# CHECK-NEXT: (local.get $6) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: (drop +# CHECK-NEXT: (ref.as_non_null +# CHECK-NEXT: (local.get $2) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: (unreachable) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: ) +# CHECK-NEXT: diff --git a/test/lit/binary/stacky-nn-tuple.test.wasm b/test/lit/binary/stacky-nn-tuple.test.wasm Binary files differnew file mode 100644 index 000000000..37c8af137 --- /dev/null +++ b/test/lit/binary/stacky-nn-tuple.test.wasm |