From 8ecef7e5c5578bbb4dba52edb274b946444e554b Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 21 Jul 2026 18:54:37 +0000 Subject: [PATCH 1/2] [multibyte] Support offset and align for array load and store Add offset and alignment immediates to ArrayLoad and ArrayStore AST nodes, text format, and binary encoding. Multibyte array access operations in the WebAssembly GC spec reuse memarg immediates to specify a static byte offset and alignment hint. This adds support for parsing, printing, and binary reading/writing of these attributes for array load and store instructions. --- src/parser/contexts.h | 29 ++++++--- src/parser/parsers.h | 26 +++++--- src/passes/DeAlign.cpp | 4 ++ src/passes/Print.cpp | 12 ++++ src/wasm-builder.h | 8 +++ src/wasm-delegations-fields.def | 4 ++ src/wasm-ir-builder.h | 14 ++++- src/wasm.h | 4 ++ src/wasm/wasm-binary.cpp | 18 +++--- src/wasm/wasm-ir-builder.cpp | 15 +++-- src/wasm/wasm-stack.cpp | 16 ++++- test/lit/array-multibyte.wast | 59 +++++++++++++++++++ .../lit/parse-bad-array-multibyte-memidx.wast | 10 ++++ 13 files changed, 184 insertions(+), 35 deletions(-) create mode 100644 test/lit/parse-bad-array-multibyte-memidx.wast diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 31a3aa253e3..be69c38c8bc 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -578,14 +578,19 @@ struct NullInstrParserCtx { MemoryOrder) { return Ok{}; } - template - Result<> makeArrayLoad( - Index, const std::vector&, Type, int, bool, HeapTypeT) { + template + Result<> makeArrayLoad(Index, + const std::vector&, + Type, + int, + bool, + MemargT, + HeapTypeT) { return Ok{}; } - template - Result<> - makeArrayStore(Index, const std::vector&, Type, int, HeapTypeT) { + template + Result<> makeArrayStore( + Index, const std::vector&, Type, int, MemargT, HeapTypeT) { return Ok{}; } Result<> makeAtomicRMW(Index, @@ -2388,17 +2393,23 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { Type type, int bytes, bool signed_, + Memarg memarg, HeapTypeT arrayType) { - return withLoc(pos, - irBuilder.makeArrayLoad(arrayType, bytes, signed_, type)); + return withLoc( + pos, + irBuilder.makeArrayLoad( + arrayType, bytes, signed_, memarg.offset, memarg.align, type)); } Result<> makeArrayStore(Index pos, const std::vector& annotations, Type type, int bytes, + Memarg memarg, HeapTypeT arrayType) { - return withLoc(pos, irBuilder.makeArrayStore(arrayType, bytes, type)); + return withLoc(pos, + irBuilder.makeArrayStore( + arrayType, bytes, memarg.offset, memarg.align, type)); } Result<> makeAtomicRMW(Index pos, diff --git a/src/parser/parsers.h b/src/parser/parsers.h index d6f2297ff57..7066b3516d6 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -1807,8 +1807,13 @@ Result<> makeLoad(Ctx& ctx, bool signed_, int bytes, bool isAtomic) { + auto mem = maybeMemidx(ctx); + CHECK_ERR(mem); if (ctx.in.takeSExprStart("type"sv)) { + if (mem) { + return ctx.in.err("memory index is not allowed for array load"); + } auto arrayType = typeidx(ctx); CHECK_ERR(arrayType); @@ -1816,13 +1821,13 @@ Result<> makeLoad(Ctx& ctx, return ctx.in.err("expected end of type use"); } + auto arg = memarg(ctx, bytes); + CHECK_ERR(arg); + return ctx.makeArrayLoad( - pos, annotations, type, bytes, signed_, *arrayType); + pos, annotations, type, bytes, signed_, *arg, *arrayType); } - auto mem = maybeMemidx(ctx); - CHECK_ERR(mem); - // We could only parse this when `isAtomic`, but this way gives a clearer // error when a memorder is given for non-atomic operations // since the next token can never be mistaken for a `memOrder`. @@ -1855,7 +1860,13 @@ Result<> makeStore(Ctx& ctx, Type type, int bytes, bool isAtomic) { + auto mem = maybeMemidx(ctx); + CHECK_ERR(mem); + if (ctx.in.takeSExprStart("type"sv)) { + if (mem) { + return ctx.in.err("memory index is not allowed for array store"); + } auto arrayType = typeidx(ctx); CHECK_ERR(arrayType); @@ -1863,10 +1874,11 @@ Result<> makeStore(Ctx& ctx, return ctx.in.err("expected end of type use"); } - return ctx.makeArrayStore(pos, annotations, type, bytes, *arrayType); + auto arg = memarg(ctx, bytes); + CHECK_ERR(arg); + + return ctx.makeArrayStore(pos, annotations, type, bytes, *arg, *arrayType); } - auto mem = maybeMemidx(ctx); - CHECK_ERR(mem); auto maybeOrder = maybeMemOrder(ctx); CHECK_ERR(maybeOrder); diff --git a/src/passes/DeAlign.cpp b/src/passes/DeAlign.cpp index 15adc2ed644..4de36cc88ce 100644 --- a/src/passes/DeAlign.cpp +++ b/src/passes/DeAlign.cpp @@ -36,6 +36,10 @@ struct DeAlign : public WalkerPass> { void visitStore(Store* curr) { curr->align = 1; } void visitSIMDLoad(SIMDLoad* curr) { curr->align = 1; } + + void visitArrayLoad(ArrayLoad* curr) { curr->align = 1; } + + void visitArrayStore(ArrayStore* curr) { curr->align = 1; } }; Pass* createDeAlignPass() { return new DeAlign(); } diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index d171caa3080..63381ae552c 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2479,6 +2479,12 @@ struct PrintExpressionContents printMinor(o, "type "); printHeapTypeName(curr->ref->type.getHeapType()); o << ')'; + if (curr->offset) { + o << " offset=" << curr->offset; + } + if (curr->align != curr->bytes) { + o << " align=" << curr->align; + } } void visitArrayStore(ArrayStore* curr) { @@ -2492,6 +2498,12 @@ struct PrintExpressionContents printMinor(o, "type "); printHeapTypeName(curr->ref->type.getHeapType()); o << ')'; + if (curr->offset) { + o << " offset=" << curr->offset; + } + if (curr->align != curr->bytes) { + o << " align=" << curr->align; + } } void visitArrayLen(ArrayLen* curr) { printMedium(o, "array.len"); } void visitArrayCopy(ArrayCopy* curr) { diff --git a/src/wasm-builder.h b/src/wasm-builder.h index de26f090dc5..0e1b8fecc2a 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -1162,12 +1162,16 @@ class Builder { } ArrayLoad* makeArrayLoad(unsigned bytes, bool signed_, + Address offset, + Address align, Expression* ref, Expression* index, Type type) { auto* ret = wasm.allocator.alloc(); ret->bytes = bytes; ret->signed_ = signed_; + ret->offset = offset; + ret->align = align ? align : Address(bytes); ret->ref = ref; ret->index = index; ret->type = type; @@ -1176,11 +1180,15 @@ class Builder { } ArrayStore* makeArrayStore(unsigned bytes, + Address offset, + Address align, Expression* ref, Expression* index, Expression* value) { auto* ret = wasm.allocator.alloc(); ret->bytes = bytes; + ret->offset = offset; + ret->align = align ? align : Address(bytes); ret->ref = ref; ret->index = index; ret->value = value; diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index 79ac534864f..836151ec93e 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -762,6 +762,8 @@ DELEGATE_FIELD_CASE_END(ArraySet) DELEGATE_FIELD_CASE_START(ArrayLoad) DELEGATE_FIELD_CHILD(ArrayLoad, index) DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArrayLoad, ref) +DELEGATE_FIELD_ADDRESS(ArrayLoad, offset) +DELEGATE_FIELD_ADDRESS(ArrayLoad, align) DELEGATE_FIELD_INT(ArrayLoad, bytes) DELEGATE_FIELD_INT(ArrayLoad, signed_) DELEGATE_FIELD_TYPE(ArrayLoad, type) @@ -771,6 +773,8 @@ DELEGATE_FIELD_CASE_START(ArrayStore) DELEGATE_FIELD_CHILD(ArrayStore, value) DELEGATE_FIELD_CHILD(ArrayStore, index) DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArrayStore, ref) +DELEGATE_FIELD_ADDRESS(ArrayStore, offset) +DELEGATE_FIELD_ADDRESS(ArrayStore, align) DELEGATE_FIELD_INT(ArrayStore, bytes) DELEGATE_FIELD_CASE_END(ArrayStore) diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 8c07ce54649..ea0de1662dc 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -253,9 +253,17 @@ class IRBuilder : public UnifiedExpressionVisitor> { Result<> makeArrayNewFixed(HeapType type, uint32_t arity); Result<> makeArrayGet(HeapType type, bool signed_, MemoryOrder order); Result<> makeArraySet(HeapType type, MemoryOrder order); - Result<> - makeArrayLoad(HeapType arrayType, unsigned bytes, bool signed_, Type type); - Result<> makeArrayStore(HeapType arrayType, unsigned bytes, Type type); + Result<> makeArrayLoad(HeapType arrayType, + unsigned bytes, + bool signed_, + Address offset, + Address align, + Type type); + Result<> makeArrayStore(HeapType arrayType, + unsigned bytes, + Address offset, + Address align, + Type type); Result<> makeArrayLen(); Result<> makeArrayCopy(HeapType destType, HeapType srcType); Result<> makeArrayFill(HeapType type); diff --git a/src/wasm.h b/src/wasm.h index f5cade544e6..641310653eb 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1918,6 +1918,8 @@ class ArrayLoad : public SpecificExpression { uint8_t bytes; bool signed_ = false; + Address offset = 0; + Address align = 0; Expression* ref; Expression* index; @@ -1930,6 +1932,8 @@ class ArrayStore : public SpecificExpression { ArrayStore(MixedArena& allocator) {} uint8_t bytes; + Address offset = 0; + Address align = 0; Expression* ref; Expression* index; Expression* value; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 34ab5ec51ee..00de9f37e5b 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3394,7 +3394,8 @@ Result<> WasmBinaryReader::readLoad(unsigned bytes, bool signed_, Type type) { auto [mem, align, offset, backing] = getMemarg(); if (backing == BackingType::Array) { HeapType arrayType = getIndexedHeapType(); - return builder.makeArrayLoad(arrayType, bytes, signed_, type); + return builder.makeArrayLoad( + arrayType, bytes, signed_, offset, align, type); } return builder.makeLoad(bytes, signed_, offset, align, type, mem); } @@ -3403,7 +3404,7 @@ Result<> WasmBinaryReader::readStore(unsigned bytes, Type type) { auto [mem, align, offset, backing] = getMemarg(); if (backing == BackingType::Array) { HeapType arrayType = getIndexedHeapType(); - return builder.makeArrayStore(arrayType, bytes, type); + return builder.makeArrayStore(arrayType, bytes, offset, align, type); } return builder.makeStore(bytes, offset, align, type, mem); } @@ -4111,12 +4112,10 @@ Result<> WasmBinaryReader::readInst() { return builder.makeElemDrop(elem); } case BinaryConsts::F32_F16LoadMem: { - auto [mem, align, offset, backing] = getMemarg(); - return builder.makeLoad(2, false, offset, align, Type::f32, mem); + return readLoad(2, false, Type::f32); } case BinaryConsts::F32_F16StoreMem: { - auto [mem, align, offset, backing] = getMemarg(); - return builder.makeStore(2, offset, align, Type::f32, mem); + return readStore(2, Type::f32); } } return Err{"unknown misc operation: " + std::to_string(op)}; @@ -4666,12 +4665,10 @@ Result<> WasmBinaryReader::readInst() { case BinaryConsts::V128Const: return builder.makeConst(getVec128Literal()); case BinaryConsts::V128Store: { - auto [mem, align, offset, backing] = getMemarg(); - return builder.makeStore(16, offset, align, Type::v128, mem); + return readStore(16, Type::v128); } case BinaryConsts::V128Load: { - auto [mem, align, offset, backing] = getMemarg(); - return builder.makeLoad(16, false, offset, align, Type::v128, mem); + return readLoad(16, false, Type::v128); } case BinaryConsts::V128Load8Splat: { auto [mem, align, offset, backing] = getMemarg(); @@ -5759,6 +5756,7 @@ WasmBinaryReader::readMemoryAccess(bool isAtomic, bool isRMW) { throwError( "Memory index and memory order are not allowed for array backing."); } + offset = getU32LEB(); } else { WASM_UNREACHABLE("Invalid backing type"); } diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 3a67d9c5a50..7c7ba089523 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -2463,8 +2463,11 @@ Result<> IRBuilder::makeArraySet(HeapType type, MemoryOrder order) { return Ok{}; } -Result<> -IRBuilder::makeArrayStore(HeapType arrayType, unsigned bytes, Type type) { +Result<> IRBuilder::makeArrayStore(HeapType arrayType, + unsigned bytes, + Address offset, + Address align, + Type type) { if (!arrayType.isArray()) { return Err{"expected array type annotation on array store"}; } @@ -2473,13 +2476,16 @@ IRBuilder::makeArrayStore(HeapType arrayType, unsigned bytes, Type type) { CHECK_ERR(ChildPopper{*this}.visitArrayStore(&curr, arrayType, type)); CHECK_ERR(validateTypeAnnotation(arrayType, curr.ref)); - push(builder.makeArrayStore(bytes, curr.ref, curr.index, curr.value)); + push(builder.makeArrayStore( + bytes, offset, align, curr.ref, curr.index, curr.value)); return Ok{}; } Result<> IRBuilder::makeArrayLoad(HeapType arrayType, unsigned bytes, bool signed_, + Address offset, + Address align, Type type) { if (!arrayType.isArray()) { return Err{"expected array type annotation on array load"}; @@ -2489,7 +2495,8 @@ Result<> IRBuilder::makeArrayLoad(HeapType arrayType, CHECK_ERR(ChildPopper{*this}.visitArrayLoad(&curr, arrayType)); CHECK_ERR(validateTypeAnnotation(arrayType, curr.ref)); - push(builder.makeArrayLoad(bytes, signed_, curr.ref, curr.index, type)); + push(builder.makeArrayLoad( + bytes, signed_, offset, align, curr.ref, curr.index, type)); return Ok{}; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index b065b7aad36..4ec0bbf672a 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2828,24 +2828,36 @@ void BinaryInstWriter::visitArraySet(ArraySet* curr) { } void BinaryInstWriter::visitArrayLoad(ArrayLoad* curr) { + if (curr->type == Type::unreachable) { + return; + } if (curr->ref->type.isNull()) { emitUnreachable(); return; } emitLoadOpcode(curr->bytes, curr->signed_, curr->type); - uint32_t alignmentBits = BinaryConsts::HasBackingArrayMask; + uint32_t alignmentBits = + Bits::log2(curr->align ? curr->align : Address(curr->bytes)) | + BinaryConsts::HasBackingArrayMask; o << U32LEB(alignmentBits); + o << U32LEB(curr->offset); parent.writeIndexedHeapType(curr->ref->type.getHeapType()); } void BinaryInstWriter::visitArrayStore(ArrayStore* curr) { + if (curr->type == Type::unreachable) { + return; + } if (curr->ref->type.isNull()) { emitUnreachable(); return; } emitStoreOpcode(curr->bytes, curr->value->type); - uint32_t alignmentBits = BinaryConsts::HasBackingArrayMask; + uint32_t alignmentBits = + Bits::log2(curr->align ? curr->align : Address(curr->bytes)) | + BinaryConsts::HasBackingArrayMask; o << U32LEB(alignmentBits); + o << U32LEB(curr->offset); parent.writeIndexedHeapType(curr->ref->type.getHeapType()); } diff --git a/test/lit/array-multibyte.wast b/test/lit/array-multibyte.wast index eab1bc21f46..2e5b693de6d 100644 --- a/test/lit/array-multibyte.wast +++ b/test/lit/array-multibyte.wast @@ -16,9 +16,13 @@ ;; RTRIP: (type $i8_array (array (mut i8))) (type $i8_array (array (mut i8))) + ;; CHECK: (type $2 (func (param (ref $i8_array)))) + ;; CHECK: (global $arr (ref $i8_array) (array.new_default $i8_array ;; CHECK-NEXT: (i32.const 4) ;; CHECK-NEXT: )) + ;; RTRIP: (type $2 (func (param (ref $i8_array)))) + ;; RTRIP: (global $arr (ref $i8_array) (array.new_default $i8_array ;; RTRIP-NEXT: (i32.const 4) ;; RTRIP-NEXT: )) @@ -1008,4 +1012,59 @@ (func $loads_index_unreachable (drop (i32.load8_u (type $i8_array) (global.get $arr) (unreachable))) ) + + ;; CHECK: (func $immediates (type $2) (param $arr (ref $i8_array)) + ;; CHECK-NEXT: (i32.store8 (type $i8_array) offset=4 + ;; CHECK-NEXT: (local.get $arr) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store (type $i8_array) offset=8 + ;; CHECK-NEXT: (local.get $arr) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load8_u (type $i8_array) offset=4 + ;; CHECK-NEXT: (local.get $arr) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load (type $i8_array) offset=8 + ;; CHECK-NEXT: (local.get $arr) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + ;; RTRIP: (func $immediates (type $2) (param $arr (ref $i8_array)) + ;; RTRIP-NEXT: (i32.store8 (type $i8_array) offset=4 + ;; RTRIP-NEXT: (local.get $arr) + ;; RTRIP-NEXT: (i32.const 0) + ;; RTRIP-NEXT: (i32.const 42) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (i32.store (type $i8_array) offset=8 + ;; RTRIP-NEXT: (local.get $arr) + ;; RTRIP-NEXT: (i32.const 0) + ;; RTRIP-NEXT: (i32.const 1337) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (i32.load8_u (type $i8_array) offset=4 + ;; RTRIP-NEXT: (local.get $arr) + ;; RTRIP-NEXT: (i32.const 0) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (i32.load (type $i8_array) offset=8 + ;; RTRIP-NEXT: (local.get $arr) + ;; RTRIP-NEXT: (i32.const 0) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) + (func $immediates (param $arr (ref $i8_array)) + (i32.store8 (type $i8_array) offset=4 align=1 (local.get $arr) (i32.const 0) (i32.const 42)) + (i32.store (type $i8_array) offset=8 align=4 (local.get $arr) (i32.const 0) (i32.const 1337)) + (drop (i32.load8_u (type $i8_array) offset=4 align=1 (local.get $arr) (i32.const 0))) + (drop (i32.load (type $i8_array) offset=8 align=4 (local.get $arr) (i32.const 0))) + ) ) diff --git a/test/lit/parse-bad-array-multibyte-memidx.wast b/test/lit/parse-bad-array-multibyte-memidx.wast new file mode 100644 index 00000000000..df1f92b5ade --- /dev/null +++ b/test/lit/parse-bad-array-multibyte-memidx.wast @@ -0,0 +1,10 @@ +;; RUN: not wasm-opt -all %s 2>&1 | filecheck %s + +(module + (memory $m 1 1) + (type $arr (array (mut i8))) + ;; CHECK: Fatal: {{.*}}: error: memory index is not allowed for array load + (func $load-memidx (param $a (ref $arr)) + (drop (i32.load8_u $m (type $arr) (local.get $a) (i32.const 0))) + ) +) From 3daa7ba2ef0cb14099fc738f25e6db5055661555 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 22 Jul 2026 20:57:18 +0000 Subject: [PATCH 2/2] review comments --- src/wasm/wasm-stack.cpp | 6 ++---- test/lit/array-multibyte.wast | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 4ec0bbf672a..ee3a77a5f2d 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2837,8 +2837,7 @@ void BinaryInstWriter::visitArrayLoad(ArrayLoad* curr) { } emitLoadOpcode(curr->bytes, curr->signed_, curr->type); uint32_t alignmentBits = - Bits::log2(curr->align ? curr->align : Address(curr->bytes)) | - BinaryConsts::HasBackingArrayMask; + Bits::log2(curr->align) | BinaryConsts::HasBackingArrayMask; o << U32LEB(alignmentBits); o << U32LEB(curr->offset); parent.writeIndexedHeapType(curr->ref->type.getHeapType()); @@ -2854,8 +2853,7 @@ void BinaryInstWriter::visitArrayStore(ArrayStore* curr) { } emitStoreOpcode(curr->bytes, curr->value->type); uint32_t alignmentBits = - Bits::log2(curr->align ? curr->align : Address(curr->bytes)) | - BinaryConsts::HasBackingArrayMask; + Bits::log2(curr->align) | BinaryConsts::HasBackingArrayMask; o << U32LEB(alignmentBits); o << U32LEB(curr->offset); parent.writeIndexedHeapType(curr->ref->type.getHeapType()); diff --git a/test/lit/array-multibyte.wast b/test/lit/array-multibyte.wast index 2e5b693de6d..ece8506893e 100644 --- a/test/lit/array-multibyte.wast +++ b/test/lit/array-multibyte.wast @@ -1024,6 +1024,11 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: (i32.const 1337) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (i32.store (type $i8_array) offset=12 align=2 + ;; CHECK-NEXT: (local.get $arr) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: (drop ;; CHECK-NEXT: (i32.load8_u (type $i8_array) offset=4 ;; CHECK-NEXT: (local.get $arr) @@ -1036,6 +1041,12 @@ ;; CHECK-NEXT: (i32.const 0) ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) + ;; CHECK-NEXT: (drop + ;; CHECK-NEXT: (i32.load (type $i8_array) offset=12 align=2 + ;; CHECK-NEXT: (local.get $arr) + ;; CHECK-NEXT: (i32.const 0) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) ;; CHECK-NEXT: ) ;; RTRIP: (func $immediates (type $2) (param $arr (ref $i8_array)) ;; RTRIP-NEXT: (i32.store8 (type $i8_array) offset=4 @@ -1048,6 +1059,11 @@ ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: (i32.const 1337) ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (i32.store (type $i8_array) offset=12 align=2 + ;; RTRIP-NEXT: (local.get $arr) + ;; RTRIP-NEXT: (i32.const 0) + ;; RTRIP-NEXT: (i32.const 1337) + ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: (drop ;; RTRIP-NEXT: (i32.load8_u (type $i8_array) offset=4 ;; RTRIP-NEXT: (local.get $arr) @@ -1060,11 +1076,19 @@ ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: (drop + ;; RTRIP-NEXT: (i32.load (type $i8_array) offset=12 align=2 + ;; RTRIP-NEXT: (local.get $arr) + ;; RTRIP-NEXT: (i32.const 0) + ;; RTRIP-NEXT: ) + ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) (func $immediates (param $arr (ref $i8_array)) (i32.store8 (type $i8_array) offset=4 align=1 (local.get $arr) (i32.const 0) (i32.const 42)) (i32.store (type $i8_array) offset=8 align=4 (local.get $arr) (i32.const 0) (i32.const 1337)) + (i32.store (type $i8_array) offset=12 align=2 (local.get $arr) (i32.const 0) (i32.const 1337)) (drop (i32.load8_u (type $i8_array) offset=4 align=1 (local.get $arr) (i32.const 0))) (drop (i32.load (type $i8_array) offset=8 align=4 (local.get $arr) (i32.const 0))) + (drop (i32.load (type $i8_array) offset=12 align=2 (local.get $arr) (i32.const 0))) ) )