From 6e209817c6eb34eb7c6daad7cac2631def26b495 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 13 Feb 2023 21:20:08 -0800 Subject: [PATCH 1/2] [wasm2js] Support nonzero offsets in memory.atomic.wait32 The assertion that the offset is zero does not necessarily hold for code that uses this instruction via the clang builtin. Add support so that Emscripten wasm2js tests pass in the presence of such code. --- src/abi/js.h | 5 +++-- src/passes/I64ToI32Lowering.cpp | 4 ++-- src/wasm2js.h | 5 +++-- test/wasm2js/atomics_32.2asm.js | 7 ++++--- test/wasm2js/atomics_32.2asm.js.opt | 7 ++++--- test/wasm2js/atomics_32.wast | 2 +- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/abi/js.h b/src/abi/js.h index 735f71af763..d22376c13a1 100644 --- a/src/abi/js.h +++ b/src/abi/js.h @@ -82,8 +82,9 @@ inline void ensureHelpers(Module* wasm, IString specific = IString()) { ensureImport(MEMORY_FILL, {Type::i32, Type::i32, Type::i32}, Type::none); ensureImport(MEMORY_COPY, {Type::i32, Type::i32, Type::i32}, Type::none); ensureImport(DATA_DROP, {Type::i32}, Type::none); - ensureImport( - ATOMIC_WAIT_I32, {Type::i32, Type::i32, Type::i32, Type::i32}, Type::i32); + ensureImport(ATOMIC_WAIT_I32, + {Type::i32, Type::i32, Type::i32, Type::i32, Type::i32}, + Type::i32); ensureImport( ATOMIC_RMW_I64, {Type::i32, Type::i32, Type::i32, Type::i32, Type::i32, Type::i32}, diff --git a/src/passes/I64ToI32Lowering.cpp b/src/passes/I64ToI32Lowering.cpp index aee65c22aef..dfcc65a5149 100644 --- a/src/passes/I64ToI32Lowering.cpp +++ b/src/passes/I64ToI32Lowering.cpp @@ -478,10 +478,10 @@ struct I64ToI32Lowering : public WalkerPass> { void visitAtomicWait(AtomicWait* curr) { // The last parameter is an i64, so we cannot leave it as it is - assert(curr->offset == 0); replaceCurrent(builder->makeCall( ABI::wasm2js::ATOMIC_WAIT_I32, - {curr->ptr, + {builder->makeConst(int32_t(curr->offset)), + curr->ptr, curr->expected, curr->timeout, builder->makeLocalGet(fetchOutParam(curr->timeout), Type::i32)}, diff --git a/src/wasm2js.h b/src/wasm2js.h index eddb26866eb..08969b8bab6 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2989,7 +2989,8 @@ void Wasm2JSGlue::emitSpecialSupport() { )"; } else if (import->base == ABI::wasm2js::ATOMIC_WAIT_I32) { out << R"( - function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) { + function wasm2js_atomic_wait_i32(offset, ptr, expected, timeoutLow, timeoutHigh) { + ptr = (ptr + offset) >> 2; var timeout = Infinity; if (timeoutHigh >= 0) { // Convert from nanoseconds to milliseconds @@ -2997,7 +2998,7 @@ void Wasm2JSGlue::emitSpecialSupport() { timeout = ((timeoutLow >>> 0) / 1e6) + timeoutHigh * (4294967296 / 1e6); } var view = new Int32Array(bufferView.buffer); // TODO cache - var result = Atomics.wait(view, ptr >> 2, expected, timeout); + var result = Atomics.wait(view, ptr, expected, timeout); if (result == 'ok') return 0; if (result == 'not-equal') return 1; if (result == 'timed-out') return 2; diff --git a/test/wasm2js/atomics_32.2asm.js b/test/wasm2js/atomics_32.2asm.js index 66a9c1769a6..98c5677e635 100644 --- a/test/wasm2js/atomics_32.2asm.js +++ b/test/wasm2js/atomics_32.2asm.js @@ -24,7 +24,8 @@ memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s"); memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh"); - function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) { + function wasm2js_atomic_wait_i32(offset, ptr, expected, timeoutLow, timeoutHigh) { + ptr = (ptr + offset) >> 2; var timeout = Infinity; if (timeoutHigh >= 0) { // Convert from nanoseconds to milliseconds @@ -32,7 +33,7 @@ memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29y timeout = ((timeoutLow >>> 0) / 1e6) + timeoutHigh * (4294967296 / 1e6); } var view = new Int32Array(bufferView.buffer); // TODO cache - var result = Atomics.wait(view, ptr >> 2, expected, timeout); + var result = Atomics.wait(view, ptr, expected, timeout); if (result == 'ok') return 0; if (result == 'not-equal') return 1; if (result == 'timed-out') return 2; @@ -119,7 +120,7 @@ function asmFunc(imports) { Atomics.load(HEAP32, 1028 >> 2) | 0; Atomics.store(HEAP32, 100 >> 2, 200); i64toi32_i32$0 = -1; - wasm2js_atomic_wait_i32(4 | 0, 8 | 0, -1 | 0, i64toi32_i32$0 | 0) | 0; + wasm2js_atomic_wait_i32(4 | 0, 8 | 0, 16 | 0, -1 | 0, i64toi32_i32$0 | 0) | 0; wasm2js_memory_init(0, 512, 0, 4); wasm2js_memory_init(1, 1024, 4, 2); Atomics.notify(HEAP32, 4 >> 2, 2); diff --git a/test/wasm2js/atomics_32.2asm.js.opt b/test/wasm2js/atomics_32.2asm.js.opt index 6f42d5df551..5cb990b7d6f 100644 --- a/test/wasm2js/atomics_32.2asm.js.opt +++ b/test/wasm2js/atomics_32.2asm.js.opt @@ -24,7 +24,8 @@ memorySegments[0] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "aGVsbG8s"); memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29ybGQh"); - function wasm2js_atomic_wait_i32(ptr, expected, timeoutLow, timeoutHigh) { + function wasm2js_atomic_wait_i32(offset, ptr, expected, timeoutLow, timeoutHigh) { + ptr = (ptr + offset) >> 2; var timeout = Infinity; if (timeoutHigh >= 0) { // Convert from nanoseconds to milliseconds @@ -32,7 +33,7 @@ memorySegments[1] = base64DecodeToExistingUint8Array(new Uint8Array(6), 0, "d29y timeout = ((timeoutLow >>> 0) / 1e6) + timeoutHigh * (4294967296 / 1e6); } var view = new Int32Array(bufferView.buffer); // TODO cache - var result = Atomics.wait(view, ptr >> 2, expected, timeout); + var result = Atomics.wait(view, ptr, expected, timeout); if (result == 'ok') return 0; if (result == 'not-equal') return 1; if (result == 'timed-out') return 2; @@ -117,7 +118,7 @@ function asmFunc(imports) { Atomics.load(HEAPU16, 514); Atomics.load(HEAP32, 257); Atomics.store(HEAP32, 25, 200); - wasm2js_atomic_wait_i32(4, 8, -1, -1) | 0; + wasm2js_atomic_wait_i32(4, 8, 16, -1, -1) | 0; wasm2js_memory_init(0, 512, 0, 4); wasm2js_memory_init(1, 1024, 4, 2); Atomics.notify(HEAP32, 1, 2); diff --git a/test/wasm2js/atomics_32.wast b/test/wasm2js/atomics_32.wast index c6408f16262..73ec8f1528e 100644 --- a/test/wasm2js/atomics_32.wast +++ b/test/wasm2js/atomics_32.wast @@ -12,7 +12,7 @@ (local.set $x (i32.atomic.load16_u (i32.const 1028))) (local.set $x (i32.atomic.load (i32.const 1028))) (i32.atomic.store (i32.const 100) (i32.const 200)) - (local.set $x (memory.atomic.wait32 (i32.const 4) (i32.const 8) (i64.const -1))) + (local.set $x (memory.atomic.wait32 offset=4 (i32.const 8) (i32.const 16) (i64.const -1))) (memory.init 0 (i32.const 512) (i32.const 0) (i32.const 4)) (memory.init 1 (i32.const 1024) (i32.const 4) (i32.const 2)) (local.set $x (memory.atomic.notify (i32.const 4) (i32.const 2))) From 80166276a989c06cae9ad48ddf0bd14f92b17551 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Tue, 14 Feb 2023 12:46:54 -0800 Subject: [PATCH 2/2] update more tests --- test/passes/remove-non-js-ops.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/passes/remove-non-js-ops.txt b/test/passes/remove-non-js-ops.txt index d3fa090a574..ec42a28e1cb 100644 --- a/test/passes/remove-non-js-ops.txt +++ b/test/passes/remove-non-js-ops.txt @@ -14,7 +14,7 @@ (type $f64_=>_none (func (param f64))) (type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32))) (type $i32_=>_none (func (param i32))) - (type $i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32) (result i32))) + (type $i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32) (result i32))) (type $i32_i32_i32_i32_i32_i32_=>_i32 (func (param i32 i32 i32 i32 i32 i32) (result i32))) (type $none_=>_i32 (func (result i32))) (type $none_=>_none (func)) @@ -28,7 +28,7 @@ (import "env" "wasm2js_memory_fill" (func $wasm2js_memory_fill (param i32 i32 i32))) (import "env" "wasm2js_memory_copy" (func $wasm2js_memory_copy (param i32 i32 i32))) (import "env" "wasm2js_data_drop" (func $wasm2js_data_drop (param i32))) - (import "env" "wasm2js_atomic_wait_i32" (func $wasm2js_atomic_wait_i32 (param i32 i32 i32 i32) (result i32))) + (import "env" "wasm2js_atomic_wait_i32" (func $wasm2js_atomic_wait_i32 (param i32 i32 i32 i32 i32) (result i32))) (import "env" "wasm2js_atomic_rmw_i64" (func $wasm2js_atomic_rmw_i64 (param i32 i32 i32 i32 i32 i32) (result i32))) (import "env" "wasm2js_get_stashed_bits" (func $wasm2js_get_stashed_bits (result i32))) (import "env" "wasm2js_trap" (func $wasm2js_trap))