diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b28dee98d3..d6b25c71a76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ full changeset diff at the end of each section. Current Trunk ------------- +- Reject non-natural alignment for atomic memory operations at parse time (#8962) + v132 ---- diff --git a/scripts/test/shared.py b/scripts/test/shared.py index cad9ce4b930..77b36105abf 100644 --- a/scripts/test/shared.py +++ b/scripts/test/shared.py @@ -415,9 +415,6 @@ def get_tests(test_dir, extensions=[], recursive=False): # Requires better support for multi-threaded tests 'threads/wait_notify.wast', - - # Non-natural alignment is invalid for atomic operations - 'threads/atomic.wast', ] SPEC_TESTSUITE_PROPOSALS_TO_SKIP = [ ] diff --git a/src/parser/contexts.h b/src/parser/contexts.h index 9602a17ce1f..75ab7cb0637 100644 --- a/src/parser/contexts.h +++ b/src/parser/contexts.h @@ -2394,8 +2394,9 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { auto m = getMemory(pos, mem); CHECK_ERR(m); if (isAtomic) { - return withLoc( - pos, irBuilder.makeAtomicLoad(bytes, memarg.offset, type, *m, order)); + return withLoc(pos, + irBuilder.makeAtomicLoad( + bytes, memarg.offset, memarg.align, type, *m, order)); } return withLoc(pos, irBuilder.makeLoad( @@ -2413,8 +2414,9 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { auto m = getMemory(pos, mem); CHECK_ERR(m); if (isAtomic) { - return withLoc( - pos, irBuilder.makeAtomicStore(bytes, memarg.offset, type, *m, order)); + return withLoc(pos, + irBuilder.makeAtomicStore( + bytes, memarg.offset, memarg.align, type, *m, order)); } return withLoc( pos, irBuilder.makeStore(bytes, memarg.offset, memarg.align, type, *m)); @@ -2454,8 +2456,14 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { MemoryOrder order) { auto m = getMemory(pos, mem); CHECK_ERR(m); - return withLoc( - pos, irBuilder.makeAtomicRMW(op, bytes, memarg.offset, type, *m, order)); + return withLoc(pos, + irBuilder.makeAtomicRMW(op, + bytes, + memarg.offset, + memarg.align, + type, + *m, + order)); } Result<> makeAtomicCmpxchg(Index pos, @@ -2467,8 +2475,9 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { MemoryOrder order) { auto m = getMemory(pos, mem); CHECK_ERR(m); - return withLoc( - pos, irBuilder.makeAtomicCmpxchg(bytes, memarg.offset, type, *m, order)); + return withLoc(pos, + irBuilder.makeAtomicCmpxchg( + bytes, memarg.offset, memarg.align, type, *m, order)); } Result<> makeAtomicWait(Index pos, @@ -2478,7 +2487,8 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { Memarg memarg) { auto m = getMemory(pos, mem); CHECK_ERR(m); - return withLoc(pos, irBuilder.makeAtomicWait(type, memarg.offset, *m)); + return withLoc( + pos, irBuilder.makeAtomicWait(type, memarg.offset, memarg.align, *m)); } Result<> makeAtomicNotify(Index pos, @@ -2487,7 +2497,8 @@ struct ParseDefsCtx : TypeParserCtx, AnnotationParserCtx { Memarg memarg) { auto m = getMemory(pos, mem); CHECK_ERR(m); - return withLoc(pos, irBuilder.makeAtomicNotify(memarg.offset, *m)); + return withLoc( + pos, irBuilder.makeAtomicNotify(memarg.offset, memarg.align, *m)); } Result<> makeAtomicFence(Index pos, diff --git a/src/passes/DeAlign.cpp b/src/passes/DeAlign.cpp index 4de36cc88ce..52b20b28634 100644 --- a/src/passes/DeAlign.cpp +++ b/src/passes/DeAlign.cpp @@ -31,9 +31,19 @@ struct DeAlign : public WalkerPass> { return std::make_unique(); } - void visitLoad(Load* curr) { curr->align = 1; } + void visitLoad(Load* curr) { + if (curr->isAtomic()) { + return; + } + curr->align = 1; + } - void visitStore(Store* curr) { curr->align = 1; } + void visitStore(Store* curr) { + if (curr->isAtomic()) { + return; + } + curr->align = 1; + } void visitSIMDLoad(SIMDLoad* curr) { curr->align = 1; } diff --git a/src/wasm-ir-builder.h b/src/wasm-ir-builder.h index 5998dc87428..6b68c27b686 100644 --- a/src/wasm-ir-builder.h +++ b/src/wasm-ir-builder.h @@ -155,20 +155,33 @@ class IRBuilder : public UnifiedExpressionVisitor> { Name mem); Result<> makeStore( unsigned bytes, Address offset, unsigned align, Type type, Name mem); - Result<> makeAtomicLoad( - unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order); - Result<> makeAtomicStore( - unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order); + Result<> makeAtomicLoad(unsigned bytes, + Address offset, + Address align, + Type type, + Name mem, + MemoryOrder order); + Result<> makeAtomicStore(unsigned bytes, + Address offset, + Address align, + Type type, + Name mem, + MemoryOrder order); Result<> makeAtomicRMW(AtomicRMWOp op, unsigned bytes, Address offset, + Address align, Type type, Name mem, MemoryOrder order); - Result<> makeAtomicCmpxchg( - unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order); - Result<> makeAtomicWait(Type type, Address offset, Name mem); - Result<> makeAtomicNotify(Address offset, Name mem); + Result<> makeAtomicCmpxchg(unsigned bytes, + Address offset, + Address align, + Type type, + Name mem, + MemoryOrder order); + Result<> makeAtomicWait(Type type, Address offset, Address align, Name mem); + Result<> makeAtomicNotify(Address offset, Address align, Name mem); Result<> makeAtomicFence(MemoryOrder order); Result<> makePause(); Result<> makeSIMDExtract(SIMDExtractOp op, uint8_t lane); diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index fc88a5dd997..a92dcd047e5 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3934,105 +3934,111 @@ Result<> WasmBinaryReader::readInst() { auto op = getU32LEB(); switch (op) { case BinaryConsts::I32AtomicLoad8U: { - // TODO: pass align through for validation. auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicLoad(1, offset, Type::i32, mem, memoryOrder); + return builder.makeAtomicLoad( + 1, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I32AtomicLoad16U: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicLoad(2, offset, Type::i32, mem, memoryOrder); + return builder.makeAtomicLoad( + 2, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I32AtomicLoad: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicLoad(4, offset, Type::i32, mem, memoryOrder); + return builder.makeAtomicLoad( + 4, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I64AtomicLoad8U: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicLoad(1, offset, Type::i64, mem, memoryOrder); + return builder.makeAtomicLoad( + 1, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicLoad16U: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicLoad(2, offset, Type::i64, mem, memoryOrder); + return builder.makeAtomicLoad( + 2, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicLoad32U: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicLoad(4, offset, Type::i64, mem, memoryOrder); + return builder.makeAtomicLoad( + 4, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicLoad: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicLoad(8, offset, Type::i64, mem, memoryOrder); + return builder.makeAtomicLoad( + 8, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I32AtomicStore8: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); return builder.makeAtomicStore( - 1, offset, Type::i32, mem, memoryOrder); + 1, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I32AtomicStore16: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); return builder.makeAtomicStore( - 2, offset, Type::i32, mem, memoryOrder); + 2, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I32AtomicStore: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); return builder.makeAtomicStore( - 4, offset, Type::i32, mem, memoryOrder); + 4, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I64AtomicStore8: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); return builder.makeAtomicStore( - 1, offset, Type::i64, mem, memoryOrder); + 1, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicStore16: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); return builder.makeAtomicStore( - 2, offset, Type::i64, mem, memoryOrder); + 2, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicStore32: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); return builder.makeAtomicStore( - 4, offset, Type::i64, mem, memoryOrder); + 4, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicStore: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); return builder.makeAtomicStore( - 8, offset, Type::i64, mem, memoryOrder); + 8, offset, align, Type::i64, mem, memoryOrder); } #define RMW(op) \ case BinaryConsts::I32AtomicRMW##op: { \ auto [mem, align, offset, memoryOrder] = getRMWMemarg(); \ - return builder.makeAtomicRMW( \ - RMW##op, 4, offset, Type::i32, mem, memoryOrder); \ + return builder.makeAtomicRMW( \ + RMW##op, 4, offset, align, Type::i32, mem, memoryOrder); \ } \ case BinaryConsts::I32AtomicRMW##op##8U: { \ auto [mem, align, offset, memoryOrder] = getRMWMemarg(); \ return builder.makeAtomicRMW( \ - RMW##op, 1, offset, Type::i32, mem, memoryOrder); \ + RMW##op, 1, offset, align, Type::i32, mem, memoryOrder); \ } \ case BinaryConsts::I32AtomicRMW##op##16U: { \ auto [mem, align, offset, memoryOrder] = getRMWMemarg(); \ return builder.makeAtomicRMW( \ - RMW##op, 2, offset, Type::i32, mem, memoryOrder); \ + RMW##op, 2, offset, align, Type::i32, mem, memoryOrder); \ } \ case BinaryConsts::I64AtomicRMW##op: { \ auto [mem, align, offset, memoryOrder] = getRMWMemarg(); \ return builder.makeAtomicRMW( \ - RMW##op, 8, offset, Type::i64, mem, memoryOrder); \ + RMW##op, 8, offset, align, Type::i64, mem, memoryOrder); \ } \ case BinaryConsts::I64AtomicRMW##op##8U: { \ auto [mem, align, offset, memoryOrder] = getRMWMemarg(); \ return builder.makeAtomicRMW( \ - RMW##op, 1, offset, Type::i64, mem, memoryOrder); \ + RMW##op, 1, offset, align, Type::i64, mem, memoryOrder); \ } \ case BinaryConsts::I64AtomicRMW##op##16U: { \ auto [mem, align, offset, memoryOrder] = getRMWMemarg(); \ return builder.makeAtomicRMW( \ - RMW##op, 2, offset, Type::i64, mem, memoryOrder); \ + RMW##op, 2, offset, align, Type::i64, mem, memoryOrder); \ } \ case BinaryConsts::I64AtomicRMW##op##32U: { \ auto [mem, align, offset, memoryOrder] = getRMWMemarg(); \ return builder.makeAtomicRMW( \ - RMW##op, 4, offset, Type::i64, mem, memoryOrder); \ + RMW##op, 4, offset, align, Type::i64, mem, memoryOrder); \ } RMW(Add); @@ -4045,49 +4051,49 @@ Result<> WasmBinaryReader::readInst() { case BinaryConsts::I32AtomicCmpxchg: { auto [mem, align, offset, memoryOrder] = getRMWMemarg(); return builder.makeAtomicCmpxchg( - 4, offset, Type::i32, mem, memoryOrder); + 4, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I32AtomicCmpxchg8U: { auto [mem, align, offset, memoryOrder] = getRMWMemarg(); return builder.makeAtomicCmpxchg( - 1, offset, Type::i32, mem, memoryOrder); + 1, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I32AtomicCmpxchg16U: { auto [mem, align, offset, memoryOrder] = getRMWMemarg(); return builder.makeAtomicCmpxchg( - 2, offset, Type::i32, mem, memoryOrder); + 2, offset, align, Type::i32, mem, memoryOrder); } case BinaryConsts::I64AtomicCmpxchg: { auto [mem, align, offset, memoryOrder] = getRMWMemarg(); return builder.makeAtomicCmpxchg( - 8, offset, Type::i64, mem, memoryOrder); + 8, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicCmpxchg8U: { auto [mem, align, offset, memoryOrder] = getRMWMemarg(); return builder.makeAtomicCmpxchg( - 1, offset, Type::i64, mem, memoryOrder); + 1, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicCmpxchg16U: { auto [mem, align, offset, memoryOrder] = getRMWMemarg(); return builder.makeAtomicCmpxchg( - 2, offset, Type::i64, mem, memoryOrder); + 2, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I64AtomicCmpxchg32U: { auto [mem, align, offset, memoryOrder] = getRMWMemarg(); return builder.makeAtomicCmpxchg( - 4, offset, Type::i64, mem, memoryOrder); + 4, offset, align, Type::i64, mem, memoryOrder); } case BinaryConsts::I32AtomicWait: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicWait(Type::i32, offset, mem); + return builder.makeAtomicWait(Type::i32, offset, align, mem); } case BinaryConsts::I64AtomicWait: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicWait(Type::i64, offset, mem); + return builder.makeAtomicWait(Type::i64, offset, align, mem); } case BinaryConsts::AtomicNotify: { auto [mem, align, offset, memoryOrder] = getAtomicMemarg(); - return builder.makeAtomicNotify(offset, mem); + return builder.makeAtomicNotify(offset, align, mem); } case BinaryConsts::AtomicFence: { MemoryOrder order = getMemoryOrder(/*isRMW=*/false); diff --git a/src/wasm/wasm-ir-builder.cpp b/src/wasm/wasm-ir-builder.cpp index e4c753fb220..e559e39a38b 100644 --- a/src/wasm/wasm-ir-builder.cpp +++ b/src/wasm/wasm-ir-builder.cpp @@ -92,6 +92,13 @@ Result<> validateTypeAnnotation(HeapType type, Expression* child) { return validateTypeAnnotation(Type(type, Nullable), child); } +Result<> requireNaturalAtomicAlign(Address align, Address natural) { + if (align != natural) { + return Err{"atomic accesses must have natural alignment"}; + } + return Ok{}; +} + } // anonymous namespace Result IRBuilder::addScratchLocal(Type type) { @@ -1634,8 +1641,13 @@ Result<> IRBuilder::makeStore( return Ok{}; } -Result<> IRBuilder::makeAtomicLoad( - unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order) { +Result<> IRBuilder::makeAtomicLoad(unsigned bytes, + Address offset, + Address align, + Type type, + Name mem, + MemoryOrder order) { + CHECK_ERR(requireNaturalAtomicAlign(align, bytes)); Load curr; curr.memory = mem; CHECK_ERR(visitLoad(&curr)); @@ -1643,8 +1655,13 @@ Result<> IRBuilder::makeAtomicLoad( return Ok{}; } -Result<> IRBuilder::makeAtomicStore( - unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order) { +Result<> IRBuilder::makeAtomicStore(unsigned bytes, + Address offset, + Address align, + Type type, + Name mem, + MemoryOrder order) { + CHECK_ERR(requireNaturalAtomicAlign(align, bytes)); Store curr; curr.memory = mem; curr.valueType = type; @@ -1657,9 +1674,11 @@ Result<> IRBuilder::makeAtomicStore( Result<> IRBuilder::makeAtomicRMW(AtomicRMWOp op, unsigned bytes, Address offset, + Address align, Type type, Name mem, MemoryOrder order) { + CHECK_ERR(requireNaturalAtomicAlign(align, bytes)); AtomicRMW curr; curr.memory = mem; curr.type = type; @@ -1669,8 +1688,13 @@ Result<> IRBuilder::makeAtomicRMW(AtomicRMWOp op, return Ok{}; } -Result<> IRBuilder::makeAtomicCmpxchg( - unsigned bytes, Address offset, Type type, Name mem, MemoryOrder order) { +Result<> IRBuilder::makeAtomicCmpxchg(unsigned bytes, + Address offset, + Address align, + Type type, + Name mem, + MemoryOrder order) { + CHECK_ERR(requireNaturalAtomicAlign(align, bytes)); AtomicCmpxchg curr; curr.memory = mem; CHECK_ERR(ChildPopper{*this}.visitAtomicCmpxchg(&curr, type)); @@ -1685,7 +1709,8 @@ Result<> IRBuilder::makeAtomicCmpxchg( return Ok{}; } -Result<> IRBuilder::makeAtomicWait(Type type, Address offset, Name mem) { +Result<> IRBuilder::makeAtomicWait(Type type, Address offset, Address align, Name mem) { + CHECK_ERR(requireNaturalAtomicAlign(align, type == Type::i32 ? 4 : 8)); AtomicWait curr; curr.memory = mem; curr.expectedType = type; @@ -1695,7 +1720,8 @@ Result<> IRBuilder::makeAtomicWait(Type type, Address offset, Name mem) { return Ok{}; } -Result<> IRBuilder::makeAtomicNotify(Address offset, Name mem) { +Result<> IRBuilder::makeAtomicNotify(Address offset, Address align, Name mem) { + CHECK_ERR(requireNaturalAtomicAlign(align, 4)); AtomicNotify curr; curr.memory = mem; CHECK_ERR(visitAtomicNotify(&curr)); diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 5f1c6a13e8d..29d9a38c15b 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -608,14 +608,22 @@ void BinaryInstWriter::visitAtomicWait(AtomicWait* curr) { switch (curr->expectedType.getBasic()) { case Type::i32: { o << static_cast(BinaryConsts::I32AtomicWait); - emitMemoryAccess( - 4, 4, curr->offset, curr->memory, MemoryOrder::SeqCst, /*isRMW=*/false); + emitMemoryAccess(4, + 4, + curr->offset, + curr->memory, + MemoryOrder::SeqCst, + /*isRMW=*/false); break; } case Type::i64: { o << static_cast(BinaryConsts::I64AtomicWait); - emitMemoryAccess( - 8, 8, curr->offset, curr->memory, MemoryOrder::SeqCst, /*isRMW=*/false); + emitMemoryAccess(8, + 8, + curr->offset, + curr->memory, + MemoryOrder::SeqCst, + /*isRMW=*/false); break; } default: @@ -626,8 +634,12 @@ void BinaryInstWriter::visitAtomicWait(AtomicWait* curr) { void BinaryInstWriter::visitAtomicNotify(AtomicNotify* curr) { o << static_cast(BinaryConsts::AtomicPrefix) << static_cast(BinaryConsts::AtomicNotify); - emitMemoryAccess( - 4, 4, curr->offset, curr->memory, MemoryOrder::SeqCst, /*isRMW=*/false); + emitMemoryAccess(4, + 4, + curr->offset, + curr->memory, + MemoryOrder::SeqCst, + /*isRMW=*/false); } void BinaryInstWriter::visitAtomicFence(AtomicFence* curr) { diff --git a/test/lit/basic/relaxed-atomics.wast b/test/lit/basic/relaxed-atomics.wast index 0484c8465b8..c9994e43d94 100644 --- a/test/lit/basic/relaxed-atomics.wast +++ b/test/lit/basic/relaxed-atomics.wast @@ -8,21 +8,21 @@ ;; RTRIP: (func $acqrel (type $0) ;; RTRIP-NEXT: (atomic.fence acqrel) ;; RTRIP-NEXT: (i32.atomic.store acqrel - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: (i32.const 1) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: (drop ;; RTRIP-NEXT: (i32.atomic.load acqrel - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) (func $acqrel (atomic.fence acqrel) - (i32.atomic.store acqrel (i32.const 1) (i32.const 1)) + (i32.atomic.store acqrel (i32.const 0) (i32.const 1)) (drop (i32.atomic.load acqrel - (i32.const 1) + (i32.const 0) )) ) @@ -30,56 +30,56 @@ ;; RTRIP: (func $seqcst (type $0) ;; RTRIP-NEXT: (atomic.fence) ;; RTRIP-NEXT: (i32.atomic.store - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: (i32.const 1) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: (i32.atomic.store - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: (i32.const 1) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: (drop ;; RTRIP-NEXT: (i32.atomic.load - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: (drop ;; RTRIP-NEXT: (i32.atomic.load - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) (func $seqcst (atomic.fence seqcst) - (i32.atomic.store seqcst (i32.const 1) (i32.const 1)) - (i32.atomic.store 0 seqcst (i32.const 1) (i32.const 1)) + (i32.atomic.store seqcst (i32.const 0) (i32.const 1)) + (i32.atomic.store 0 seqcst (i32.const 0) (i32.const 1)) (drop (i32.atomic.load seqcst - (i32.const 1) + (i32.const 0) )) ;; allows memory index before memory ordering immediate (drop (i32.atomic.load 0 seqcst - (i32.const 1) + (i32.const 0) )) ) ;; RTRIP: (func $relaxed (type $0) ;; RTRIP-NEXT: (atomic.fence relaxed) ;; RTRIP-NEXT: (i32.atomic.store relaxed - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: (i32.const 1) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: (drop ;; RTRIP-NEXT: (i32.atomic.load relaxed - ;; RTRIP-NEXT: (i32.const 1) + ;; RTRIP-NEXT: (i32.const 0) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) ;; RTRIP-NEXT: ) (func $relaxed (atomic.fence relaxed) - (i32.atomic.store relaxed (i32.const 1) (i32.const 1)) + (i32.atomic.store relaxed (i32.const 0) (i32.const 1)) (drop (i32.atomic.load relaxed - (i32.const 1) + (i32.const 0) ) ) ) diff --git a/test/lit/passes/dealign-atomics.wast b/test/lit/passes/dealign-atomics.wast new file mode 100644 index 00000000000..3bf612d2f0b --- /dev/null +++ b/test/lit/passes/dealign-atomics.wast @@ -0,0 +1,19 @@ +;; RUN: wasm-opt %s --enable-threads --dealign -S -o - | filecheck %s + +(module + (memory 1 1 shared) + + (func $test + (drop (i32.load align=4 (i32.const 0))) + (drop (i32.atomic.load (i32.const 4))) + (i32.store align=4 (i32.const 8) (i32.const 0)) + (i32.atomic.store (i32.const 12) (i32.const 0)) + ) +) + +;; CHECK: (i32.load align=1 +;; CHECK: (i32.atomic.load +;; CHECK-NOT: i32.atomic.load align=1 +;; CHECK: (i32.store align=1 +;; CHECK: (i32.atomic.store +;; CHECK-NOT: i32.atomic.store align=1 diff --git a/test/lit/validation/atomic-alignment.wast b/test/lit/validation/atomic-alignment.wast new file mode 100644 index 00000000000..0b424259282 --- /dev/null +++ b/test/lit/validation/atomic-alignment.wast @@ -0,0 +1,59 @@ +;; Non-natural alignment on atomic memory ops is a parse error. + +;; RUN: foreach %s %t not wasm-opt --enable-threads -o /dev/null 2>&1 | filecheck %s + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func (result i32) + (i32.atomic.load align=1 (i32.const 0))) +) + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func + (i32.atomic.store align=2 (i32.const 0) (i32.const 0))) +) + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func (result i32) + (i32.atomic.rmw.add align=1 (i32.const 0) (i32.const 0))) +) + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func (result i32) + (i32.atomic.rmw.cmpxchg align=1 (i32.const 0) (i32.const 0) (i32.const 0))) +) + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func (result i32) + (memory.atomic.wait32 align=1 (i32.const 0) (i32.const 0) (i64.const 0))) +) + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func (result i32) + (memory.atomic.wait64 align=4 (i32.const 0) (i64.const 0) (i64.const 0))) +) + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func (result i32) + (memory.atomic.notify align=1 (i32.const 0) (i32.const 0))) +) + +;; CHECK: Fatal: {{.*}}: error: atomic accesses must have natural alignment +(module + (memory 1 1 shared) + (func (result i64) + (i64.atomic.load32_u align=8 (i32.const 0))) +) diff --git a/test/lit/validation/relaxed-atomics.wast b/test/lit/validation/relaxed-atomics.wast index aa316cda94a..5f419190fe2 100644 --- a/test/lit/validation/relaxed-atomics.wast +++ b/test/lit/validation/relaxed-atomics.wast @@ -14,7 +14,7 @@ (func $relaxed (result i32) ;; CHECK: Relaxed operations require relaxed atomics [--enable-relaxed-atomics] (i32.atomic.load relaxed - (i32.const 1) + (i32.const 0) ) ) )