Skip to content

Commit 60f46da

Browse files
authored
Add wasm32 atomic intrinsics (#561)
Currently these are gated by the `atomics` feature unconditionally, but that may be tweaked in the future! Otherwise this should enable building out some primitives in the standard library using these intrinsics.
1 parent b3bd07b commit 60f46da

File tree

2 files changed

+102
-0
lines changed

2 files changed

+102
-0
lines changed

coresimd/wasm32/atomic.rs

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//! Intrinsics associated with WebAssembly's upcoming threads proposal.
2+
//!
3+
//! These intrinsics are all unstable because they're not actually stable in
4+
//! WebAssembly itself yet. The signatures may change as [the
5+
//! specification][spec] is updated.
6+
//!
7+
//! [spec]: https://github.com/WebAssembly/threads
8+
9+
#![cfg(target_feature = "atomics")]
10+
11+
#[cfg(test)]
12+
use stdsimd_test::assert_instr;
13+
#[cfg(test)]
14+
use wasm_bindgen_test::wasm_bindgen_test;
15+
16+
extern "C" {
17+
#[link_name = "llvm.wasm.atomic.wait.i32"]
18+
fn llvm_atomic_wait_i32(ptr: *mut i32, exp: i32, timeout: i64) -> i32;
19+
#[link_name = "llvm.wasm.atomic.wait.i64"]
20+
fn llvm_atomic_wait_i64(ptr: *mut i64, exp: i64, timeout: i64) -> i32;
21+
#[link_name = "llvm.wasm.atomic.notify"]
22+
fn llvm_atomic_notify(ptr: *mut i32, cnt: i32) -> i32;
23+
}
24+
25+
/// Corresponding intrinsic to wasm's [`i32.atomic.wait` instruction][instr]
26+
///
27+
/// This function, when called, will block the current thread if the memory
28+
/// pointed to by `ptr` is equal to `expression` (performing this action
29+
/// atomically).
30+
///
31+
/// The argument `timeout_ns` is a maxinum number of nanoseconds the calling
32+
/// thread will be blocked for, if it blocks. If the timeout is negative then
33+
/// the calling thread will be blocked forever.
34+
///
35+
/// The calling thread can only be woken up with a call to the `wake` intrinsic
36+
/// once it has been blocked. Changing the memory behind `ptr` will not wake the
37+
/// thread once it's blocked.
38+
///
39+
/// # Return value
40+
///
41+
/// * 0 - indicates that the thread blocked and then was woken up
42+
/// * 1 - the loaded value from `ptr` didn't match `expression`, the thread
43+
/// didn't block
44+
/// * 2 - the thread blocked, but the timeout expired.
45+
///
46+
/// [instr]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#wait
47+
#[inline]
48+
#[cfg_attr(test, assert_instr("i32.atomic.wait"))]
49+
pub unsafe fn wait_i32(ptr: *mut i32, expression: i32, timeout_ns: i64) -> i32 {
50+
llvm_atomic_wait_i32(ptr, expression, timeout_ns)
51+
}
52+
53+
/// Corresponding intrinsic to wasm's [`i64.atomic.wait` instruction][instr]
54+
///
55+
/// This function, when called, will block the current thread if the memory
56+
/// pointed to by `ptr` is equal to `expression` (performing this action
57+
/// atomically).
58+
///
59+
/// The argument `timeout_ns` is a maxinum number of nanoseconds the calling
60+
/// thread will be blocked for, if it blocks. If the timeout is negative then
61+
/// the calling thread will be blocked forever.
62+
///
63+
/// The calling thread can only be woken up with a call to the `wake` intrinsic
64+
/// once it has been blocked. Changing the memory behind `ptr` will not wake the
65+
/// thread once it's blocked.
66+
///
67+
/// # Return value
68+
///
69+
/// * 0 - indicates that the thread blocked and then was woken up
70+
/// * 1 - the loaded value from `ptr` didn't match `expression`, the thread
71+
/// didn't block
72+
/// * 2 - the thread blocked, but the timeout expired.
73+
///
74+
/// [instr]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#wait
75+
#[inline]
76+
#[cfg_attr(test, assert_instr("i64.atomic.wait"))]
77+
pub unsafe fn wait_i64(ptr: *mut i64, expression: i64, timeout_ns: i64) -> i32 {
78+
llvm_atomic_wait_i64(ptr, expression, timeout_ns)
79+
}
80+
81+
/// Corresponding intrinsic to wasm's [`atomic.wake` instruction][instr]
82+
///
83+
/// This function will wake up a number of threads blocked on the address
84+
/// indicated by `ptr`. Threads previously blocked with the `wait_i32` and
85+
/// `wait_i64` functions above will be woken up.
86+
///
87+
/// The `waiters` argument indicates how many waiters should be woken up (a
88+
/// maximum). If the value is negative all waiters are woken up, and if the
89+
/// value is zero no waiters are woken up.
90+
///
91+
/// # Return value
92+
///
93+
/// Returns the number of waiters which were actually woken up.
94+
///
95+
/// [instr]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#wake
96+
#[inline]
97+
#[cfg_attr(test, assert_instr("atomic.wake"))]
98+
pub unsafe fn wake(ptr: *mut i32, waiters: i32) -> i32 {
99+
llvm_atomic_notify(ptr, waiters)
100+
}

coresimd/wasm32/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,5 @@ pub unsafe fn current_memory() -> i32 {
4747
pub unsafe fn grow_memory(delta: i32) -> i32 {
4848
llvm_grow_memory(delta)
4949
}
50+
51+
pub mod atomic;

0 commit comments

Comments
 (0)