diff --git a/interpreter/valid/valid.ml b/interpreter/valid/valid.ml index 259d3cd7..15dd28e5 100644 --- a/interpreter/valid/valid.ml +++ b/interpreter/valid/valid.ml @@ -189,7 +189,7 @@ let check_vec_binop binop at = error at "invalid lane index" | _ -> () -let check_memop (c : context) (memop : ('t, 's) memop) ty_size get_sz at = +let check_memop (c : context) (memop : ('t, 's) memop) ty_size get_sz at ~(isAtomic : bool) = let _mt = memory c (0l @@ at) in let size = match get_sz memop.pack with @@ -199,7 +199,9 @@ let check_memop (c : context) (memop : ('t, 's) memop) ty_size get_sz at = packed_size sz in require (1 lsl memop.align <= size) at - "alignment must not be larger than natural" + "alignment must not be larger than natural"; + if isAtomic then + require (1 lsl memop.align == size) at "atomic memory instruction's alignment must equal the instruction's natural alignment" (* @@ -354,29 +356,29 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type [] --> [] | Load memop -> - check_memop c memop num_size (Lib.Option.map fst) e.at; + check_memop ~isAtomic:false c memop num_size (Lib.Option.map fst) e.at; [NumType I32Type] --> [NumType memop.ty] | Store memop -> - check_memop c memop num_size (fun sz -> sz) e.at; + check_memop ~isAtomic:false c memop num_size (fun sz -> sz) e.at; [NumType I32Type; NumType memop.ty] --> [] | VecLoad memop -> - check_memop c memop vec_size (Lib.Option.map fst) e.at; + check_memop ~isAtomic:false c memop vec_size (Lib.Option.map fst) e.at; [NumType I32Type] --> [VecType memop.ty] | VecStore memop -> - check_memop c memop vec_size (fun _ -> None) e.at; + check_memop ~isAtomic:false c memop vec_size (fun _ -> None) e.at; [NumType I32Type; VecType memop.ty] --> [] | VecLoadLane (memop, i) -> - check_memop c memop vec_size (fun sz -> Some sz) e.at; + check_memop ~isAtomic:false c memop vec_size (fun sz -> Some sz) e.at; require (i < vec_size memop.ty / packed_size memop.pack) e.at "invalid lane index"; [NumType I32Type; VecType memop.ty] --> [VecType memop.ty] | VecStoreLane (memop, i) -> - check_memop c memop vec_size (fun sz -> Some sz) e.at; + check_memop ~isAtomic:false c memop vec_size (fun sz -> Some sz) e.at; require (i < vec_size memop.ty / packed_size memop.pack) e.at "invalid lane index"; [NumType I32Type; VecType memop.ty] --> [] @@ -514,23 +516,23 @@ let rec check_instr (c : context) (e : instr) (s : infer_result_type) : op_type "invalid lane index"; [t; NumType t2] --> [t] | MemoryAtomicWait atomicop -> - check_memop c atomicop num_size (fun sz -> sz) e.at; + check_memop ~isAtomic:true c atomicop num_size (fun sz -> sz) e.at; [NumType I32Type; NumType atomicop.ty; NumType I64Type] --> [NumType I32Type] | MemoryAtomicNotify atomicop -> - check_memop c atomicop num_size (fun sz -> sz) e.at; + check_memop ~isAtomic:true c atomicop num_size (fun sz -> sz) e.at; [NumType I32Type; NumType I32Type] --> [NumType I32Type] | AtomicFence -> [] --> [] | AtomicLoad atomicop -> - check_memop c atomicop num_size (fun sz -> sz) e.at; + check_memop ~isAtomic:true c atomicop num_size (fun sz -> sz) e.at; [NumType I32Type] --> [NumType atomicop.ty] | AtomicStore atomicop -> - check_memop c atomicop num_size (fun sz -> sz) e.at; + check_memop ~isAtomic:true c atomicop num_size (fun sz -> sz) e.at; [NumType I32Type; NumType atomicop.ty] --> [] | AtomicRmw (rmwop, atomicop) -> - check_memop c atomicop num_size (fun sz -> sz) e.at; + check_memop ~isAtomic:true c atomicop num_size (fun sz -> sz) e.at; [NumType I32Type; NumType atomicop.ty] --> [NumType atomicop.ty] | AtomicRmwCmpXchg atomicop -> - check_memop c atomicop num_size (fun sz -> sz) e.at; + check_memop ~isAtomic: true c atomicop num_size (fun sz -> sz) e.at; [NumType I32Type; NumType atomicop.ty; NumType atomicop.ty] --> [NumType atomicop.ty] and check_seq (c : context) (s : infer_result_type) (es : instr list) diff --git a/test/core/threads/atomic.wast b/test/core/threads/atomic.wast index 3ddbdc6a..8a0f61e9 100644 --- a/test/core/threads/atomic.wast +++ b/test/core/threads/atomic.wast @@ -70,12 +70,12 @@ (func (export "i64.atomic.rmw32.xchg_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32.xchg_u (local.get $addr) (local.get $value))) (func (export "i32.atomic.rmw.cmpxchg") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw.cmpxchg (local.get $addr) (local.get $expected) (local.get $value))) - (func (export "i64.atomic.rmw.cmpxchg") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw.cmpxchg (local.get $addr) (local.get $expected) (local.get $value))) - (func (export "i32.atomic.rmw8.cmpxchg_u") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw8.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) - (func (export "i32.atomic.rmw16.cmpxchg_u") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw16.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) - (func (export "i64.atomic.rmw8.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw8.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) - (func (export "i64.atomic.rmw16.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw16.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) - (func (export "i64.atomic.rmw32.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw32.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) + (func (export "i64.atomic.rmw.cmpxchg") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw.cmpxchg (local.get $addr) (local.get $expected) (local.get $value))) + (func (export "i32.atomic.rmw8.cmpxchg_u") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw8.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) + (func (export "i32.atomic.rmw16.cmpxchg_u") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw16.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) + (func (export "i64.atomic.rmw8.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw8.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) + (func (export "i64.atomic.rmw16.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw16.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) + (func (export "i64.atomic.rmw32.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw32.cmpxchg_u (local.get $addr) (local.get $expected) (local.get $value))) ) @@ -437,6 +437,414 @@ (assert_trap (invoke "i64.atomic.rmw16.cmpxchg_u" (i32.const 1) (i64.const 0) (i64.const 0)) "unaligned atomic") (assert_trap (invoke "i64.atomic.rmw32.cmpxchg_u" (i32.const 1) (i64.const 0) (i64.const 0)) "unaligned atomic") +;; non-natural alignment + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.load") (param $addr i32) (result i32) (i32.atomic.load align=1 (local.get $addr))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.load") (param $addr i32) (result i64) (i64.atomic.load align=1 (local.get $addr))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.load16_u") (param $addr i32) (result i32) (i32.atomic.load16_u align=1 (local.get $addr))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.load16_u") (param $addr i32) (result i64) (i64.atomic.load16_u align=1 (local.get $addr))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.load32_u") (param $addr i32) (result i64) (i64.atomic.load32_u align=1 (local.get $addr))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.store") (param $addr i32) (param $value i32) (i32.atomic.store align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.store") (param $addr i32) (param $value i64) (i64.atomic.store align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.store16") (param $addr i32) (param $value i32) (i32.atomic.store16 align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.store16") (param $addr i32) (param $value i64) (i64.atomic.store16 align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.store32") (param $addr i32) (param $value i64) (i64.atomic.store32 align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw.add") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.add align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw.add") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.add align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw16.add_u") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16.add_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw16.add_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16.add_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw32.add_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32.add_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw.sub") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.sub align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw.sub") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.sub align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw16.sub_u") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16.sub_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw16.sub_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16.sub_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw32.sub_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32.sub_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw.and") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.and align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw.and") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.and align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw16.and_u") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16.and_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw16.and_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16.and_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw32.and_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32.and_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw.or") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.or align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw.or") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.or align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw16.or_u") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16.or_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw16.or_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16.or_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw32.or_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32.or_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw.xor") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.xor align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw.xor") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.xor align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw16.xor_u") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16.xor_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw16.xor_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16.xor_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw32.xor_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32.xor_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw.xchg") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw.xchg align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw.xchg") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw.xchg align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw16.xchg_u") (param $addr i32) (param $value i32) (result i32) (i32.atomic.rmw16.xchg_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw16.xchg_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw16.xchg_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw32.xchg_u") (param $addr i32) (param $value i64) (result i64) (i64.atomic.rmw32.xchg_u align=1 (local.get $addr) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw.cmpxchg") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw.cmpxchg align=1 (local.get $addr) (local.get $expected) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw.cmpxchg") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw.cmpxchg align=1 (local.get $addr) (local.get $expected) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i32.atomic.rmw16.cmpxchg_u") (param $addr i32) (param $expected i32) (param $value i32) (result i32) (i32.atomic.rmw16.cmpxchg_u align=1 (local.get $addr) (local.get $expected) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw16.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw16.cmpxchg_u align=1 (local.get $addr) (local.get $expected) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + +(assert_invalid + (module + (memory 1 1 shared) + + (func (export "i64.atomic.rmw32.cmpxchg_u") (param $addr i32) (param $expected i64) (param $value i64) (result i64) (i64.atomic.rmw32.cmpxchg_u align=1 (local.get $addr) (local.get $expected) (local.get $value))) + ) + "atomic memory instruction's alignment must equal the instruction's natural alignment" +) + + ;; wait/notify (module (memory 1 1 shared)