Skip to content

Commit

Permalink
[threads/v3] Implement some i32 atomic rmw in V3Interpreter
Browse files Browse the repository at this point in the history
  • Loading branch information
titzer committed Dec 16, 2024
1 parent 8f39b2b commit 06f8611
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 20 deletions.
2 changes: 2 additions & 0 deletions src/engine/Runtime.v3
Original file line number Diff line number Diff line change
Expand Up @@ -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]);
Expand Down
60 changes: 46 additions & 14 deletions src/engine/v3/V3Interpreter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand All @@ -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);
Expand All @@ -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];
Expand Down Expand Up @@ -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<T>(size: byte) -> MaybeTrap<Range<byte>> {
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<T>(size: byte, read: Range<byte> -> 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<T>(size: byte, read: Range<byte> -> T, write: (Range<byte>, 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<T>(size: byte, log2_size: u3, read: Range<byte> -> 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
Expand Down Expand Up @@ -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()); }
Expand All @@ -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)); }
Expand Down
1 change: 1 addition & 0 deletions src/engine/x86-64/X86_64Interpreter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 0 additions & 5 deletions test/regress.failures
Original file line number Diff line number Diff line change
@@ -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

Expand Down
1 change: 0 additions & 1 deletion test/regress/ext:threads/atomic_add_i32.wast
Original file line number Diff line number Diff line change
Expand Up @@ -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"))

0 comments on commit 06f8611

Please sign in to comment.