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.
This commit is contained in:
parent
a5e3c34e3b
commit
b1dad3e46e
2 changed files with 102 additions and 0 deletions
100
library/stdarch/coresimd/wasm32/atomic.rs
Normal file
100
library/stdarch/coresimd/wasm32/atomic.rs
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
//! Intrinsics associated with WebAssembly's upcoming threads proposal.
|
||||
//!
|
||||
//! These intrinsics are all unstable because they're not actually stable in
|
||||
//! WebAssembly itself yet. The signatures may change as [the
|
||||
//! specification][spec] is updated.
|
||||
//!
|
||||
//! [spec]: https://github.com/WebAssembly/threads
|
||||
|
||||
#![cfg(target_feature = "atomics")]
|
||||
|
||||
#[cfg(test)]
|
||||
use stdsimd_test::assert_instr;
|
||||
#[cfg(test)]
|
||||
use wasm_bindgen_test::wasm_bindgen_test;
|
||||
|
||||
extern "C" {
|
||||
#[link_name = "llvm.wasm.atomic.wait.i32"]
|
||||
fn llvm_atomic_wait_i32(ptr: *mut i32, exp: i32, timeout: i64) -> i32;
|
||||
#[link_name = "llvm.wasm.atomic.wait.i64"]
|
||||
fn llvm_atomic_wait_i64(ptr: *mut i64, exp: i64, timeout: i64) -> i32;
|
||||
#[link_name = "llvm.wasm.atomic.notify"]
|
||||
fn llvm_atomic_notify(ptr: *mut i32, cnt: i32) -> i32;
|
||||
}
|
||||
|
||||
/// Corresponding intrinsic to wasm's [`i32.atomic.wait` instruction][instr]
|
||||
///
|
||||
/// This function, when called, will block the current thread if the memory
|
||||
/// pointed to by `ptr` is equal to `expression` (performing this action
|
||||
/// atomically).
|
||||
///
|
||||
/// The argument `timeout_ns` is a maxinum number of nanoseconds the calling
|
||||
/// thread will be blocked for, if it blocks. If the timeout is negative then
|
||||
/// the calling thread will be blocked forever.
|
||||
///
|
||||
/// The calling thread can only be woken up with a call to the `wake` intrinsic
|
||||
/// once it has been blocked. Changing the memory behind `ptr` will not wake the
|
||||
/// thread once it's blocked.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// * 0 - indicates that the thread blocked and then was woken up
|
||||
/// * 1 - the loaded value from `ptr` didn't match `expression`, the thread
|
||||
/// didn't block
|
||||
/// * 2 - the thread blocked, but the timeout expired.
|
||||
///
|
||||
/// [instr]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#wait
|
||||
#[inline]
|
||||
#[cfg_attr(test, assert_instr("i32.atomic.wait"))]
|
||||
pub unsafe fn wait_i32(ptr: *mut i32, expression: i32, timeout_ns: i64) -> i32 {
|
||||
llvm_atomic_wait_i32(ptr, expression, timeout_ns)
|
||||
}
|
||||
|
||||
/// Corresponding intrinsic to wasm's [`i64.atomic.wait` instruction][instr]
|
||||
///
|
||||
/// This function, when called, will block the current thread if the memory
|
||||
/// pointed to by `ptr` is equal to `expression` (performing this action
|
||||
/// atomically).
|
||||
///
|
||||
/// The argument `timeout_ns` is a maxinum number of nanoseconds the calling
|
||||
/// thread will be blocked for, if it blocks. If the timeout is negative then
|
||||
/// the calling thread will be blocked forever.
|
||||
///
|
||||
/// The calling thread can only be woken up with a call to the `wake` intrinsic
|
||||
/// once it has been blocked. Changing the memory behind `ptr` will not wake the
|
||||
/// thread once it's blocked.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// * 0 - indicates that the thread blocked and then was woken up
|
||||
/// * 1 - the loaded value from `ptr` didn't match `expression`, the thread
|
||||
/// didn't block
|
||||
/// * 2 - the thread blocked, but the timeout expired.
|
||||
///
|
||||
/// [instr]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#wait
|
||||
#[inline]
|
||||
#[cfg_attr(test, assert_instr("i64.atomic.wait"))]
|
||||
pub unsafe fn wait_i64(ptr: *mut i64, expression: i64, timeout_ns: i64) -> i32 {
|
||||
llvm_atomic_wait_i64(ptr, expression, timeout_ns)
|
||||
}
|
||||
|
||||
/// Corresponding intrinsic to wasm's [`atomic.wake` instruction][instr]
|
||||
///
|
||||
/// This function will wake up a number of threads blocked on the address
|
||||
/// indicated by `ptr`. Threads previously blocked with the `wait_i32` and
|
||||
/// `wait_i64` functions above will be woken up.
|
||||
///
|
||||
/// The `waiters` argument indicates how many waiters should be woken up (a
|
||||
/// maximum). If the value is negative all waiters are woken up, and if the
|
||||
/// value is zero no waiters are woken up.
|
||||
///
|
||||
/// # Return value
|
||||
///
|
||||
/// Returns the number of waiters which were actually woken up.
|
||||
///
|
||||
/// [instr]: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#wake
|
||||
#[inline]
|
||||
#[cfg_attr(test, assert_instr("atomic.wake"))]
|
||||
pub unsafe fn wake(ptr: *mut i32, waiters: i32) -> i32 {
|
||||
llvm_atomic_notify(ptr, waiters)
|
||||
}
|
||||
|
|
@ -47,3 +47,5 @@ pub unsafe fn current_memory() -> i32 {
|
|||
pub unsafe fn grow_memory(delta: i32) -> i32 {
|
||||
llvm_grow_memory(delta)
|
||||
}
|
||||
|
||||
pub mod atomic;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue