diff --git a/scripts/gen-s-parser.py b/scripts/gen-s-parser.py index 1ed7d1a189e..c35afc17a2f 100755 --- a/scripts/gen-s-parser.py +++ b/scripts/gen-s-parser.py @@ -640,7 +640,11 @@ ("array.get", "makeArrayGet()"), ("array.get_s", "makeArrayGet(true)"), ("array.get_u", "makeArrayGet(false)"), + ("array.atomic.get", "makeAtomicArrayGet()"), + ("array.atomic.get_s", "makeAtomicArrayGet(true)"), + ("array.atomic.get_u", "makeAtomicArrayGet(false)"), ("array.set", "makeArraySet()"), + ("array.atomic.set", "makeAtomicArraySet()"), ("array.len", "makeArrayLen()"), ("array.copy", "makeArrayCopy()"), ("array.fill", "makeArrayFill()"), diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index bd4746313a2..d5f6fbc7e3c 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -1822,17 +1822,22 @@ BinaryenExpressionRef BinaryenArrayGet(BinaryenModuleRef module, BinaryenExpressionRef index, BinaryenType type, bool signed_) { - return static_cast( - Builder(*(Module*)module) - .makeArrayGet((Expression*)ref, (Expression*)index, Type(type), signed_)); + return static_cast(Builder(*(Module*)module) + .makeArrayGet((Expression*)ref, + (Expression*)index, + MemoryOrder::Unordered, + Type(type), + signed_)); } BinaryenExpressionRef BinaryenArraySet(BinaryenModuleRef module, BinaryenExpressionRef ref, BinaryenExpressionRef index, BinaryenExpressionRef value) { - return static_cast( - Builder(*(Module*)module) - .makeArraySet((Expression*)ref, (Expression*)index, (Expression*)value)); + return static_cast(Builder(*(Module*)module) + .makeArraySet((Expression*)ref, + (Expression*)index, + (Expression*)value, + MemoryOrder::Unordered)); } BinaryenExpressionRef BinaryenArrayLen(BinaryenModuleRef module, BinaryenExpressionRef ref) { diff --git a/src/gen-s-parser.inc b/src/gen-s-parser.inc index 43d7f460370..5baeae40208 100644 --- a/src/gen-s-parser.inc +++ b/src/gen-s-parser.inc @@ -22,6 +22,45 @@ switch (buf[0]) { goto parse_error; case 'r': { switch (buf[6]) { + case 'a': { + switch (buf[13]) { + case 'g': { + switch (buf[16]) { + case '\0': + if (op == "array.atomic.get"sv) { + CHECK_ERR(makeAtomicArrayGet(ctx, pos, annotations)); + return Ok{}; + } + goto parse_error; + case '_': { + switch (buf[17]) { + case 's': + if (op == "array.atomic.get_s"sv) { + CHECK_ERR(makeAtomicArrayGet(ctx, pos, annotations, true)); + return Ok{}; + } + goto parse_error; + case 'u': + if (op == "array.atomic.get_u"sv) { + CHECK_ERR(makeAtomicArrayGet(ctx, pos, annotations, false)); + return Ok{}; + } + goto parse_error; + default: goto parse_error; + } + } + default: goto parse_error; + } + } + case 's': + if (op == "array.atomic.set"sv) { + CHECK_ERR(makeAtomicArraySet(ctx, pos, annotations)); + return Ok{}; + } + goto parse_error; + default: goto parse_error; + } + } case 'c': if (op == "array.copy"sv) { CHECK_ERR(makeArrayCopy(ctx, pos, annotations)); diff --git a/src/ir/possible-contents.cpp b/src/ir/possible-contents.cpp index d604302ce5d..3c50893274a 100644 --- a/src/ir/possible-contents.cpp +++ b/src/ir/possible-contents.cpp @@ -1059,10 +1059,11 @@ 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, curr->srcRef->type); + auto* get = builder.makeArrayGet( + curr->srcRef, curr->srcIndex, MemoryOrder::Unordered, curr->srcRef->type); visitArrayGet(get); - auto* set = builder.makeArraySet(curr->destRef, curr->destIndex, get); + auto* set = builder.makeArraySet( + curr->destRef, curr->destIndex, get, MemoryOrder::Unordered); visitArraySet(set); } void visitArrayFill(ArrayFill* curr) { @@ -1071,7 +1072,8 @@ struct InfoCollector } // See ArrayCopy, above. Builder builder(*getModule()); - auto* set = builder.makeArraySet(curr->ref, curr->index, curr->value); + auto* set = builder.makeArraySet( + curr->ref, curr->index, curr->value, MemoryOrder::Unordered); visitArraySet(set); } template void visitArrayInit(ArrayInit* curr) { @@ -1092,7 +1094,8 @@ struct InfoCollector Builder builder(*getModule()); auto* get = builder.makeLocalGet(-1, valueType); addRoot(get); - auto* set = builder.makeArraySet(curr->ref, curr->index, get); + auto* set = + builder.makeArraySet(curr->ref, curr->index, get, MemoryOrder::Unordered); visitArraySet(set); } void visitArrayInitData(ArrayInitData* curr) { visitArrayInit(curr); } diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 6a303a4a533..fc519119097 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -815,12 +815,13 @@ struct NullInstrParserCtx { return Ok{}; } template - Result<> - makeArrayGet(Index, const std::vector&, HeapTypeT, bool) { + Result<> makeArrayGet( + Index, const std::vector&, HeapTypeT, bool, MemoryOrder) { return Ok{}; } template - Result<> makeArraySet(Index, const std::vector&, HeapTypeT) { + Result<> + makeArraySet(Index, const std::vector&, HeapTypeT, MemoryOrder) { return Ok{}; } Result<> makeArrayLen(Index, const std::vector&) { return Ok{}; } @@ -2693,14 +2694,16 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { Result<> makeArrayGet(Index pos, const std::vector& annotations, HeapType type, - bool signed_) { - return withLoc(pos, irBuilder.makeArrayGet(type, signed_)); + bool signed_, + MemoryOrder order) { + return withLoc(pos, irBuilder.makeArrayGet(type, signed_, order)); } Result<> makeArraySet(Index pos, const std::vector& annotations, - HeapType type) { - return withLoc(pos, irBuilder.makeArraySet(type)); + HeapType type, + MemoryOrder order) { + return withLoc(pos, irBuilder.makeArraySet(type, order)); } Result<> makeArrayLen(Index pos, const std::vector& annotations) { diff --git a/src/parser/parsers.h b/src/parser/parsers.h index c80b8fba888..30b6b8890b7 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -274,8 +274,15 @@ template Result<> makeArrayGet(Ctx&, Index, const std::vector&, bool signed_ = false); template +Result<> makeAtomicArrayGet(Ctx&, + Index, + const std::vector&, + bool signed_ = false); +template Result<> makeArraySet(Ctx&, Index, const std::vector&); template +Result<> makeAtomicArraySet(Ctx&, Index, const std::vector&); +template Result<> makeArrayLen(Ctx&, Index, const std::vector&); template Result<> makeArrayCopy(Ctx&, Index, const std::vector&); @@ -2411,7 +2418,20 @@ Result<> makeArrayGet(Ctx& ctx, bool signed_) { auto type = typeidx(ctx); CHECK_ERR(type); - return ctx.makeArrayGet(pos, annotations, *type, signed_); + return ctx.makeArrayGet( + pos, annotations, *type, signed_, MemoryOrder::Unordered); +} + +template +Result<> makeAtomicArrayGet(Ctx& ctx, + Index pos, + const std::vector& annotations, + bool signed_) { + auto order = memorder(ctx); + CHECK_ERR(order); + auto type = typeidx(ctx); + CHECK_ERR(type); + return ctx.makeArrayGet(pos, annotations, *type, signed_, *order); } template @@ -2419,7 +2439,18 @@ Result<> makeArraySet(Ctx& ctx, Index pos, const std::vector& annotations) { auto type = typeidx(ctx); CHECK_ERR(type); - return ctx.makeArraySet(pos, annotations, *type); + return ctx.makeArraySet(pos, annotations, *type, MemoryOrder::Unordered); +} + +template +Result<> makeAtomicArraySet(Ctx& ctx, + Index pos, + const std::vector& annotations) { + auto order = memorder(ctx); + CHECK_ERR(order); + auto type = typeidx(ctx); + CHECK_ERR(type); + return ctx.makeArraySet(pos, annotations, *type, *order); } template diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp index 8f9763427c8..9269046f86d 100644 --- a/src/passes/Print.cpp +++ b/src/passes/Print.cpp @@ -2372,19 +2372,29 @@ struct PrintExpressionContents } void visitArrayGet(ArrayGet* curr) { const auto& element = curr->ref->type.getHeapType().getArray().element; + printMedium(o, "array"); + if (curr->order != MemoryOrder::Unordered) { + printMedium(o, ".atomic"); + } if (element.type == Type::i32 && element.packedType != Field::not_packed) { if (curr->signed_) { - printMedium(o, "array.get_s "); + printMedium(o, ".get_s "); } else { - printMedium(o, "array.get_u "); + printMedium(o, ".get_u "); } } else { - printMedium(o, "array.get "); + printMedium(o, ".get "); } + printMemoryOrder(curr->order); printHeapTypeName(curr->ref->type.getHeapType()); } void visitArraySet(ArraySet* curr) { - printMedium(o, "array.set "); + if (curr->order == MemoryOrder::Unordered) { + printMedium(o, "array.set "); + } else { + printMedium(o, "array.atomic.set "); + } + printMemoryOrder(curr->order); printHeapTypeName(curr->ref->type.getHeapType()); } void visitArrayLen(ArrayLen* curr) { printMedium(o, "array.len"); } diff --git a/src/tools/fuzzing/fuzzing.cpp b/src/tools/fuzzing/fuzzing.cpp index 9905d00e2aa..b79d9264ab9 100644 --- a/src/tools/fuzzing/fuzzing.cpp +++ b/src/tools/fuzzing/fuzzing.cpp @@ -5058,14 +5058,16 @@ Expression* TranslateToFuzzReader::makeArrayGet(Type type) { // Only rarely emit a plain get which might trap. See related logic in // ::makePointer(). if (allowOOB && oneIn(10)) { - return builder.makeArrayGet(ref, index, type, signed_); + return builder.makeArrayGet( + ref, index, MemoryOrder::Unordered, type, signed_); } // To avoid a trap, check the length dynamically using this pattern: // // index < array.len ? array[index] : ..some fallback value.. // auto check = makeArrayBoundsCheck(ref, index, funcContext->func, builder); - auto* get = builder.makeArrayGet(check.getRef, check.getIndex, type, signed_); + auto* get = builder.makeArrayGet( + check.getRef, check.getIndex, MemoryOrder::Unordered, type, signed_); auto* fallback = makeTrivial(type); return builder.makeIf(check.condition, get, fallback); } @@ -5083,14 +5085,15 @@ Expression* TranslateToFuzzReader::makeArraySet(Type type) { // Only rarely emit a plain get which might trap. See related logic in // ::makePointer(). if (allowOOB && oneIn(10)) { - return builder.makeArraySet(ref, index, value); + return builder.makeArraySet(ref, index, value, MemoryOrder::Unordered); } // To avoid a trap, check the length dynamically using this pattern: // // if (index < array.len) array[index] = value; // auto check = makeArrayBoundsCheck(ref, index, funcContext->func, builder); - auto* set = builder.makeArraySet(check.getRef, check.getIndex, value); + auto* set = builder.makeArraySet( + check.getRef, check.getIndex, value, MemoryOrder::Unordered); return builder.makeIf(check.condition, set); } diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 481c42cb591..0df95aa8b9e 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -960,8 +960,10 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { set = builder.makeStructSet(index, getGlobal, value, MemoryOrder::Unordered); } else { - set = builder.makeArraySet( - getGlobal, builder.makeConst(int32_t(index)), value); + set = builder.makeArraySet(getGlobal, + builder.makeConst(int32_t(index)), + value, + MemoryOrder::Unordered); } (*startBlock)->list.push_back(set); diff --git a/src/wasm-binary.h b/src/wasm-binary.h index fbe151bc472..17ff420c51c 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -1197,6 +1197,10 @@ enum ASTNodes { StructAtomicRMWXor = 0x64, StructAtomicRMWXchg = 0x65, StructAtomicRMWCmpxchg = 0x66, + ArrayAtomicGet = 0x67, + ArrayAtomicGetS = 0x68, + ArrayAtomicGetU = 0x69, + ArrayAtomicSet = 0x6a, // stringref opcodes diff --git a/src/wasm-builder.h b/src/wasm-builder.h index f7eb357c112..f1866ac8717 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -1034,6 +1034,7 @@ class Builder { } ArrayGet* makeArrayGet(Expression* ref, Expression* index, + MemoryOrder order, Type type, bool signed_ = false) { auto* ret = wasm.allocator.alloc(); @@ -1041,15 +1042,19 @@ class Builder { ret->index = index; ret->type = type; ret->signed_ = signed_; + ret->order = order; ret->finalize(); return ret; } - ArraySet* - makeArraySet(Expression* ref, Expression* index, Expression* value) { + ArraySet* makeArraySet(Expression* ref, + Expression* index, + Expression* value, + MemoryOrder order) { auto* ret = wasm.allocator.alloc(); ret->ref = ref; ret->index = index; ret->value = value; + ret->order = order; ret->finalize(); return ret; } diff --git a/src/wasm-delegations-fields.def b/src/wasm-delegations-fields.def index d2165ba9cbc..4464c29154b 100644 --- a/src/wasm-delegations-fields.def +++ b/src/wasm-delegations-fields.def @@ -703,12 +703,14 @@ DELEGATE_FIELD_CASE_START(ArrayGet) DELEGATE_FIELD_CHILD(ArrayGet, index) DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArrayGet, ref) DELEGATE_FIELD_INT(ArrayGet, signed_) +DELEGATE_FIELD_INT(ArraySet, order) DELEGATE_FIELD_CASE_END(ArrayGet) DELEGATE_FIELD_CASE_START(ArraySet) DELEGATE_FIELD_CHILD(ArraySet, value) DELEGATE_FIELD_CHILD(ArraySet, index) DELEGATE_FIELD_IMMEDIATE_TYPED_CHILD(ArraySet, ref) +DELEGATE_FIELD_INT(ArraySet, order) DELEGATE_FIELD_CASE_END(ArraySet) DELEGATE_FIELD_CASE_START(ArrayLen) diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 10ac7b72efb..3120e8ce696 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -228,8 +228,8 @@ class IRBuilder : public UnifiedExpressionVisitor> { Result<> makeArrayNewData(HeapType type, Name data); Result<> makeArrayNewElem(HeapType type, Name elem); Result<> makeArrayNewFixed(HeapType type, uint32_t arity); - Result<> makeArrayGet(HeapType type, bool signed_); - Result<> makeArraySet(HeapType type); + Result<> makeArrayGet(HeapType type, bool signed_, MemoryOrder order); + Result<> makeArraySet(HeapType type, MemoryOrder order); Result<> makeArrayLen(); Result<> makeArrayCopy(HeapType destType, HeapType srcType); Result<> makeArrayFill(HeapType type); diff --git a/src/wasm.h b/src/wasm.h index 70c0617a914..e5752227865 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -1778,6 +1778,7 @@ class ArrayGet : public SpecificExpression { Expression* index; // Packed fields have a sign. bool signed_ = false; + MemoryOrder order = MemoryOrder::Unordered; void finalize(); }; @@ -1790,6 +1791,7 @@ class ArraySet : public SpecificExpression { Expression* ref; Expression* index; Expression* value; + MemoryOrder order = MemoryOrder::Unordered; void finalize(); }; diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 9bd4b3f82d8..6dd5cc22121 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3771,6 +3771,19 @@ Result<> WasmBinaryReader::readInst() { auto field = getU32LEB(); return builder.makeStructCmpxchg(type, field, order); } + case BinaryConsts::ArrayAtomicGet: + case BinaryConsts::ArrayAtomicGetS: + case BinaryConsts::ArrayAtomicGetU: { + auto order = getMemoryOrder(); + auto type = getIndexedHeapType(); + bool signed_ = op == BinaryConsts::ArrayAtomicGetS; + return builder.makeArrayGet(type, signed_, order); + } + case BinaryConsts::ArrayAtomicSet: { + auto order = getMemoryOrder(); + auto type = getIndexedHeapType(); + return builder.makeArraySet(type, order); + } } return Err{"unknown atomic operation " + std::to_string(op)}; } @@ -4559,11 +4572,14 @@ Result<> WasmBinaryReader::readInst() { } case BinaryConsts::ArrayGet: case BinaryConsts::ArrayGetU: - return builder.makeArrayGet(getIndexedHeapType(), false); + return builder.makeArrayGet( + getIndexedHeapType(), false, MemoryOrder::Unordered); case BinaryConsts::ArrayGetS: - return builder.makeArrayGet(getIndexedHeapType(), true); + return builder.makeArrayGet( + getIndexedHeapType(), true, MemoryOrder::Unordered); case BinaryConsts::ArraySet: - return builder.makeArraySet(getIndexedHeapType()); + return builder.makeArraySet(getIndexedHeapType(), + MemoryOrder::Unordered); case BinaryConsts::ArrayLen: return builder.makeArrayLen(); case BinaryConsts::ArrayCopy: { diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index 1fb39b14ec6..663114b3107 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -2256,20 +2256,21 @@ Result<> IRBuilder::makeArrayNewFixed(HeapType type, uint32_t arity) { return Ok{}; } -Result<> IRBuilder::makeArrayGet(HeapType type, bool signed_) { +Result<> +IRBuilder::makeArrayGet(HeapType type, bool signed_, MemoryOrder order) { ArrayGet curr; CHECK_ERR(ChildPopper{*this}.visitArrayGet(&curr, type)); CHECK_ERR(validateTypeAnnotation(type, curr.ref)); push(builder.makeArrayGet( - curr.ref, curr.index, type.getArray().element.type, signed_)); + curr.ref, curr.index, order, type.getArray().element.type, signed_)); return Ok{}; } -Result<> IRBuilder::makeArraySet(HeapType type) { +Result<> IRBuilder::makeArraySet(HeapType type, MemoryOrder order) { ArraySet curr; CHECK_ERR(ChildPopper{*this}.visitArraySet(&curr, type)); CHECK_ERR(validateTypeAnnotation(type, curr.ref)); - push(builder.makeArraySet(curr.ref, curr.index, curr.value)); + push(builder.makeArraySet(curr.ref, curr.index, curr.value, order)); return Ok{}; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index d0065909905..988f333b92f 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2455,15 +2455,20 @@ void BinaryInstWriter::visitArrayGet(ArrayGet* curr) { } auto heapType = curr->ref->type.getHeapType(); const auto& field = heapType.getArray().element; + bool atomic = curr->order != MemoryOrder::Unordered; int8_t op; if (field.type != Type::i32 || field.packedType == Field::not_packed) { - op = BinaryConsts::ArrayGet; + op = atomic ? BinaryConsts::ArrayAtomicGet : BinaryConsts::ArrayGet; } else if (curr->signed_) { - op = BinaryConsts::ArrayGetS; + op = atomic ? BinaryConsts::ArrayAtomicGetS : BinaryConsts::ArrayGetS; } else { - op = BinaryConsts::ArrayGetU; + op = atomic ? BinaryConsts::ArrayAtomicGetU : BinaryConsts::ArrayGetU; + } + auto prefix = atomic ? BinaryConsts::AtomicPrefix : BinaryConsts::GCPrefix; + o << int8_t(prefix) << U32LEB(op); + if (atomic) { + parent.writeMemoryOrder(curr->order); } - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(op); parent.writeIndexedHeapType(heapType); } @@ -2472,7 +2477,13 @@ void BinaryInstWriter::visitArraySet(ArraySet* curr) { emitUnreachable(); return; } - o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArraySet); + if (curr->order == MemoryOrder::Unordered) { + o << int8_t(BinaryConsts::GCPrefix) << U32LEB(BinaryConsts::ArraySet); + } else { + o << int8_t(BinaryConsts::AtomicPrefix) + << U32LEB(BinaryConsts::ArrayAtomicSet); + parent.writeMemoryOrder(curr->order); + } parent.writeIndexedHeapType(curr->ref->type.getHeapType()); } diff --git a/test/lit/basic/gc-atomics.wast b/test/lit/basic/gc-atomics.wast index 7e2d1ef4eda..79a2d89203b 100644 --- a/test/lit/basic/gc-atomics.wast +++ b/test/lit/basic/gc-atomics.wast @@ -8,6 +8,10 @@ (type $struct (struct (field (mut i32)))) ;; CHECK: (type $packed (struct (field (mut i8)))) (type $packed (struct (field (mut i8)))) + ;; CHECK: (type $array (array (mut i32))) + (type $array (array (mut i32))) + ;; CHECK: (type $array-packed (array (mut i8))) + (type $array-packed (array (mut i8))) ;; CHECK: (func $get (type $1) (param $0 (ref null $struct)) (result i32) ;; CHECK-NEXT: (struct.atomic.get $struct 0 @@ -108,7 +112,7 @@ ) ) - ;; CHECK: (func $set (type $4) (param $0 (ref null $struct)) + ;; CHECK: (func $set (type $6) (param $0 (ref null $struct)) ;; CHECK-NEXT: (struct.atomic.set $struct 0 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 0) @@ -121,7 +125,7 @@ ) ) - ;; CHECK: (func $set-seqcst (type $4) (param $0 (ref null $struct)) + ;; CHECK: (func $set-seqcst (type $6) (param $0 (ref null $struct)) ;; CHECK-NEXT: (struct.atomic.set $struct 0 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 0) @@ -134,7 +138,7 @@ ) ) - ;; CHECK: (func $set-acqrel (type $4) (param $0 (ref null $struct)) + ;; CHECK: (func $set-acqrel (type $6) (param $0 (ref null $struct)) ;; CHECK-NEXT: (struct.atomic.set acqrel $struct 0 ;; CHECK-NEXT: (local.get $0) ;; CHECK-NEXT: (i32.const 0) @@ -425,4 +429,58 @@ (i32.const 2) ) ) + + ;; CHECK: (func $array.get (type $8) (param $0 (ref null $array)) (result i32) + ;; CHECK-NEXT: (array.atomic.get $array + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $array.get (param (ref null $array)) (result i32) + (array.atomic.get $array + (local.get 0) + (i32.const 42) + ) + ) + + ;; CHECK: (func $array.get_s (type $7) (param $0 (ref null $array-packed)) (result i32) + ;; CHECK-NEXT: (array.atomic.get_s $array-packed + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $array.get_s (param (ref null $array-packed)) (result i32) + (array.atomic.get_s seqcst $array-packed + (local.get 0) + (i32.const 42) + ) + ) + + ;; CHECK: (func $array.get_u (type $7) (param $0 (ref null $array-packed)) (result i32) + ;; CHECK-NEXT: (array.atomic.get_u acqrel $array-packed + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $array.get_u (param (ref null $array-packed)) (result i32) + (array.atomic.get_u acqrel $array-packed + (local.get 0) + (i32.const 42) + ) + ) + + ;; CHECK: (func $array.set (type $9) (param $0 (ref null $array)) + ;; CHECK-NEXT: (array.atomic.set acqrel $array + ;; CHECK-NEXT: (local.get $0) + ;; CHECK-NEXT: (i32.const 42) + ;; CHECK-NEXT: (i32.const 1337) + ;; CHECK-NEXT: ) + ;; CHECK-NEXT: ) + (func $array.set (param (ref null $array)) + (array.atomic.set acqrel $array + (local.get 0) + (i32.const 42) + (i32.const 1337) + ) + ) )