diff --git a/src/engine/Runtime.v3 b/src/engine/Runtime.v3 index cfa8eba1..61977430 100644 --- a/src/engine/Runtime.v3 +++ b/src/engine/Runtime.v3 @@ -316,6 +316,8 @@ component Runtime { stack.pushu(0); return null; } + def ATOMIC_FENCE() { // XXX: nop on single-threaded targets + } // ext:typed-cont def CONT_NEW(stack: WasmStack, instance: Instance, cont_index: u32, make_stack: void -> WasmStack) -> Throwable { var cont_decl = ContDecl.!(instance.heaptypes[cont_index]); diff --git a/src/engine/v3/V3Interpreter.v3 b/src/engine/v3/V3Interpreter.v3 index 29aac8b1..953ff650 100644 --- a/src/engine/v3/V3Interpreter.v3 +++ b/src/engine/v3/V3Interpreter.v3 @@ -459,11 +459,11 @@ class V3Interpreter extends WasmStack { I64_STORE => doStore(8, DataWriters.write_range_u64, popw()); F32_STORE => doStore(4, DataWriters.write_range_float, popf()); F64_STORE => doStore(8, DataWriters.write_range_double, popd()); - I32_STORE8 => doStore(1, DataWriters.write_range_u8, u8.view(popu())); - I32_STORE16 => doStore(2, DataWriters.write_range_u16, u16.view(popu())); - I64_STORE8 => doStore(1, DataWriters.write_range_u8, u8.view(popw())); - I64_STORE16 => doStore(2, DataWriters.write_range_u16, u16.view(popw())); - I64_STORE32 => doStore(4, DataWriters.write_range_u32, u32.view(popw())); + I32_STORE8 => doStore(1, DataWriters.write_range_u8, popu8()); + I32_STORE16 => doStore(2, DataWriters.write_range_u16, popu16()); + I64_STORE8 => doStore(1, DataWriters.write_range_u8, popw8()); + I64_STORE16 => doStore(2, DataWriters.write_range_u16, popw16()); + I64_STORE32 => doStore(4, DataWriters.write_range_u32, popw32()); // Atomic operations MEMORY_ATOMIC_NOTIFY => { @@ -478,6 +478,11 @@ class V3Interpreter extends WasmStack { var imm = codeptr.read_MemArg(); Runtime.MEMORY_ATOMIC_WAIT64(this, frame.func.instance, imm.memory_index, imm.offset); } + ATOMIC_FENCE => { + codeptr.read1(); // skip zero byte + Runtime.ATOMIC_FENCE(); + } + I32_ATOMIC_LOAD => doAtomicLoad(4, DataReaders.read_range_u32, pushu); I64_ATOMIC_LOAD => doAtomicLoad(8, DataReaders.read_range_u64, pushw); I32_ATOMIC_LOAD8_U => doAtomicLoad(1, DataReaders.read_range_u32_u8, pushu); @@ -486,6 +491,22 @@ class V3Interpreter extends WasmStack { I64_ATOMIC_LOAD16_U => doAtomicLoad(2, DataReaders.read_range_u64_u16, pushw); I64_ATOMIC_LOAD32_U => doAtomicLoad(4, DataReaders.read_range_u64_u32, pushw); + I32_ATOMIC_RMW_ADD => doAtomicRmw(4, DataReaders.read_range_u32, DataWriters.write_range_u32, popu(), V3Eval.I32_ADD, pushu); + I32_ATOMIC_RMW8_ADD_U => doAtomicRmw(1, DataReaders.read_range_u8, DataWriters.write_range_u8, popu8(), u8.+, pushu8); + I32_ATOMIC_RMW16_ADD_U => doAtomicRmw(2, DataReaders.read_range_u16, DataWriters.write_range_u16, popu16(), u16.+, pushu16); + I32_ATOMIC_RMW_SUB => doAtomicRmw(4, DataReaders.read_range_u32, DataWriters.write_range_u32, popu(), V3Eval.I32_SUB, pushu); + I32_ATOMIC_RMW8_SUB_U => doAtomicRmw(1, DataReaders.read_range_u8, DataWriters.write_range_u8, popu8(), u8.-, pushu8); + I32_ATOMIC_RMW16_SUB_U => doAtomicRmw(2, DataReaders.read_range_u16, DataWriters.write_range_u16, popu16(), u16.-, pushu16); + I32_ATOMIC_RMW_AND => doAtomicRmw(4, DataReaders.read_range_u32, DataWriters.write_range_u32, popu(), V3Eval.I32_AND, pushu); + I32_ATOMIC_RMW8_AND_U => doAtomicRmw(1, DataReaders.read_range_u8, DataWriters.write_range_u8, popu8(), u8.&, pushu8); + I32_ATOMIC_RMW16_AND_U => doAtomicRmw(2, DataReaders.read_range_u16, DataWriters.write_range_u16, popu16(), u16.&, pushu16); + I32_ATOMIC_RMW_OR => doAtomicRmw(4, DataReaders.read_range_u32, DataWriters.write_range_u32, popu(), V3Eval.I32_OR, pushu); + I32_ATOMIC_RMW8_OR_U => doAtomicRmw(1, DataReaders.read_range_u8, DataWriters.write_range_u8, popu8(), u8.|, pushu8); + I32_ATOMIC_RMW16_OR_U => doAtomicRmw(2, DataReaders.read_range_u16, DataWriters.write_range_u16, popu16(), u16.|, pushu16); + I32_ATOMIC_RMW_XOR => doAtomicRmw(4, DataReaders.read_range_u32, DataWriters.write_range_u32, popu(), V3Eval.I32_XOR, pushu); + I32_ATOMIC_RMW8_XOR_U => doAtomicRmw(1, DataReaders.read_range_u8, DataWriters.write_range_u8, popu8(), u8.^, pushu8); + I32_ATOMIC_RMW16_XOR_U => doAtomicRmw(2, DataReaders.read_range_u16, DataWriters.write_range_u16, popu16(), u16.^, pushu16); + MEMORY_SIZE => { var index = codeptr.read_uleb32(); var memory = frame.func.instance.memories[index]; @@ -1199,24 +1220,25 @@ class V3Interpreter extends WasmStack { if (t.reason != TrapReason.NONE) return void(trap(t.reason)); push(read(t.result)); } - // Atomic load - def doAtomicLoadReg(size: byte) -> MaybeTrap> { - var memarg = codeptr.read_MemArg(); - var memory = frame.func.instance.memories[memarg.memory_index]; - var index = popa(memory.decl.size); - return memory.range_oil_64(memarg.offset, index, size); - } def doAtomicLoad(size: byte, read: Range -> T, push: T -> void) { - var t = doAtomicLoadReg(size); + var t = decodeMemArgAndGetMemoryRange(size); if (t.reason != TrapReason.NONE) return void(trap(t.reason)); push(read(t.result)); // XXX: assumes "read" function is atomic } + def doAtomicRmw(size: byte, read: Range -> T, write: (Range, T) -> void, val: T, op: (T, T) -> T, push: T -> void) { + var t = decodeMemArgAndGetMemoryRange(size); + if (t.reason != TrapReason.NONE) return void(trap(t.reason)); + var prev = read(t.result); // XXX: assumes no real threads + var updated = op(prev, val); + write(t.result, updated); + push(prev); + } def doLoadLane(size: byte, log2_size: u3, read: Range -> T) { var v = pops(); var t = decodeMemArgAndGetMemoryRange(size); + var idx = codeptr.read1(); if (t.reason != TrapReason.NONE) return void(trap(t.reason)); var val = u64.!(read(t.result)); - var idx = codeptr.read1(); var low = v.0, high = v.1; def half_lanes = 8 >> log2_size; if (idx < half_lanes) { // Update a lane in low @@ -1540,8 +1562,13 @@ class V3Interpreter extends WasmStack { def popV(t: ValueType) -> Value { return values.pop(); } def popi() -> i32 { return Values.unbox_i(values.pop()); } def popu() -> u32 { return Values.unbox_u(values.pop()); } + def popu8() -> u8 { return u8.view(Values.unbox_u(values.pop())); } + def popu16() -> u16 { return u16.view(Values.unbox_u(values.pop())); } def popl() -> i64 { return Values.unbox_l(values.pop()); } def popw() -> u64 { return Values.unbox_w(values.pop()); } + def popw8() -> u8 { return u8.view(Values.unbox_w(values.pop())); } + def popw16() -> u16 { return u16.view(Values.unbox_w(values.pop())); } + def popw32() -> u32 { return u32.view(Values.unbox_w(values.pop())); } def popf() -> float { return Values.unbox_f(values.pop()); } def popd() -> double { return Values.unbox_d(values.pop()); } def pops() -> (u64, u64) { return Values.unbox_s(values.pop()); } @@ -1550,8 +1577,13 @@ class V3Interpreter extends WasmStack { def push(val: Value) { values.push(val); } def pushi(val: i32) { values.push(Value.I32(u32.view(val))); } def pushu(val: u32) { values.push(Value.I32(val)); } + def pushu8(val: u8) { values.push(Value.I32(val)); } + def pushu16(val: u16) { values.push(Value.I32(val)); } def pushl(val: i64) { values.push(Value.I64(u64.view(val))); } def pushw(val: u64) { values.push(Value.I64(val)); } + def pushw8(val: u8) { values.push(Value.I64(val)); } + def pushw16(val: u16) { values.push(Value.I64(val)); } + def pushw32(val: u32) { values.push(Value.I64(val)); } def pushf(val: float) { values.push(Value.F32(u32.view(val))); } def pushd(val: double) { values.push(Value.F64(u64.view(val))); } def pushz(val: bool) { values.push(if(val, Values.I32_1, Values.I32_0)); } diff --git a/src/engine/x86-64/X86_64Interpreter.v3 b/src/engine/x86-64/X86_64Interpreter.v3 index 93387936..50d9618c 100644 --- a/src/engine/x86-64/X86_64Interpreter.v3 +++ b/src/engine/x86-64/X86_64Interpreter.v3 @@ -1367,6 +1367,7 @@ class X86_64InterpreterGen(ic: X86_64InterpreterCode, w: DataWriter) { restoreCallerIVars(); endHandler(); } + // TODO: ATOMIC_FENCE } def genAtomicLoadsAndStores() { // Load Seq_Cst -> MOV (from memory) diff --git a/test/regress.failures b/test/regress.failures index bf4a0d8b..ea3af5b3 100644 --- a/test/regress.failures +++ b/test/regress.failures @@ -1,10 +1,5 @@ test/regress/ext:threads/atomic_load_i32.bin.wast test/regress/ext:threads/atomic_store_i32.bin.wast -test/regress/ext:threads/atomic_add_i32.bin.wast -test/regress/ext:threads/atomic_sub_i32.bin.wast -test/regress/ext:threads/atomic_and_i32.bin.wast -test/regress/ext:threads/atomic_or_i32.bin.wast -test/regress/ext:threads/atomic_xor_i32.bin.wast test/regress/ext:threads/atomic_xchg_i32.bin.wast test/regress/ext:threads/atomic_cmpxchg_i32.bin.wast diff --git a/test/regress/ext:threads/atomic_add_i32.wast b/test/regress/ext:threads/atomic_add_i32.wast index 5f880c22..4c4acf5f 100644 --- a/test/regress/ext:threads/atomic_add_i32.wast +++ b/test/regress/ext:threads/atomic_add_i32.wast @@ -38,4 +38,3 @@ (assert_return (invoke "test_i32_atomic_add_8") (i32.const 5)) (assert_return (invoke "test_i32_atomic_add_16") (i32.const 5)) (assert_return (invoke "main")) -