diff --git a/crates/spirv-std/src/arch/atomics.rs b/crates/spirv-std/src/arch/atomics.rs index bb0f75992e..aec12d5860 100644 --- a/crates/spirv-std/src/arch/atomics.rs +++ b/crates/spirv-std/src/arch/atomics.rs @@ -576,6 +576,64 @@ pub unsafe fn atomic_f_max( old } +/// Atomically sets the flag value pointed to by Pointer to the set state. +/// Pointer must be a pointer to a 32-bit integer type representing an atomic flag. +/// The instruction’s result is true if the flag was in the set state or false if the flag was in the clear state immediately before the operation. +/// **Important:** Kernel capabilities have to be set beforehand. +/// +/// Result Type must be a Boolean type. +/// The resulting values are undefined if an atomic flag is modified by an instruction other than OpAtomicFlagTestAndSet or OpAtomicFlagClear. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicFlagTestAndSet")] +#[inline] +pub unsafe fn atomic_flag_test_and_set( + ptr: &mut I, +) -> bool { + let mut old: bool = false; + + asm! { + "%bool = OpTypeBool", + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%old = OpAtomicFlagTestAndSet %bool {ptr} %scope %semantics", + "OpStore {old} %old", + scope = const SCOPE, + semantics = const SEMANTICS, + ptr = in(reg) ptr, + old = in(reg) &mut old + } + + old +} + +/// Atomically sets the flag value pointed to by Pointer to the clear state. +/// +/// Pointer must be a pointer to a 32-bit integer type representing an atomic flag. +/// **Important:** Memory Semantics must not be Acquire or AcquireRelease +/// +/// The resulting values are undefined if an atomic flag is modified by an instruction other than OpAtomicFlagTestAndSet or OpAtomicFlagClear. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicFlagClear")] +#[inline] +pub unsafe fn atomic_flag_clear(ptr: &mut I) { + // Ensure the memory semantic is not Acquire or AcquireRelease + assert!( + SEMANTICS + != (crate::memory::Semantics::ACQUIRE.bits() as u32 + | crate::memory::Semantics::ACQUIRE_RELEASE.bits() as u32) + ); + asm! { + "%u32 = OpTypeInt 32 0", + "%semantics = OpConstant %u32 {semantics}", + "%scope = OpConstant %u32 {scope}", + "OpAtomicFlagClear {ptr} %scope %semantics", + scope = const SCOPE, + semantics = const SEMANTICS, + ptr = in(reg) ptr + } +} + /// Perform the following steps atomically with respect to any other atomic /// accesses within `SCOPE` to the same location: /// diff --git a/tests/ui/arch/atomics/atomic_and.rs b/tests/ui/arch/atomics/atomic_and.rs new file mode 100644 index 0000000000..f5004c1e73 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_and.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_and::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_compare_exchange.rs b/tests/ui/arch/atomics/atomic_compare_exchange.rs new file mode 100644 index 0000000000..d1ad72a4c7 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_compare_exchange.rs @@ -0,0 +1,18 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + unsafe { + let old = spirv_std::arch::atomic_compare_exchange::< + _, + { Scope::Device as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5, 10); + } +} diff --git a/tests/ui/arch/atomics/atomic_exchange.rs b/tests/ui/arch/atomics/atomic_exchange.rs new file mode 100644 index 0000000000..23008780c5 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_exchange.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + unsafe { + let old = spirv_std::arch::atomic_exchange::< + _, + { Scope::Device as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5); + } +} diff --git a/tests/ui/arch/atomics/atomic_flag_clear.rs b/tests/ui/arch/atomics/atomic_flag_clear.rs new file mode 100644 index 0000000000..64405440cc --- /dev/null +++ b/tests/ui/arch/atomics/atomic_flag_clear.rs @@ -0,0 +1,23 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[cfg(target_arch = "spirv")] +use core::arch::asm; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + // Ensure kernel capabilities. + unsafe { asm!("OpCapability Kernel") }; + + let old = unsafe { + spirv_std::arch::atomic_flag_clear::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0)) + }; +} diff --git a/tests/ui/arch/atomics/atomic_flag_test_and_set.rs b/tests/ui/arch/atomics/atomic_flag_test_and_set.rs new file mode 100644 index 0000000000..01baef9af5 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_flag_test_and_set.rs @@ -0,0 +1,23 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[cfg(target_arch = "spirv")] +use core::arch::asm; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + // Ensure kernel capabilities. + unsafe { asm!("OpCapability Kernel") }; + + let old = unsafe { + spirv_std::arch::atomic_flag_test_and_set::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0)) + }; +} diff --git a/tests/ui/arch/atomics/atomic_i_add.rs b/tests/ui/arch/atomics/atomic_i_add.rs new file mode 100644 index 0000000000..6a53dc3042 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_i_add.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_i_add::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_i_decrement.rs b/tests/ui/arch/atomics/atomic_i_decrement.rs new file mode 100644 index 0000000000..c2159339a8 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_i_decrement.rs @@ -0,0 +1,19 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let reference = unsafe { buffer.index_unchecked_mut(0) }; + + let old = unsafe { + spirv_std::arch::atomic_i_decrement::< + _, + { Scope::Workgroup as u32 }, + { Semantics::NONE.bits() }, + >(reference) + }; +} diff --git a/tests/ui/arch/atomics/atomic_i_increment.rs b/tests/ui/arch/atomics/atomic_i_increment.rs new file mode 100644 index 0000000000..d5db757c13 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_i_increment.rs @@ -0,0 +1,19 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let reference = unsafe { buffer.index_unchecked_mut(0) }; + + let old = unsafe { + spirv_std::arch::atomic_i_increment::< + _, + { Scope::Workgroup as u32 }, + { Semantics::NONE.bits() }, + >(reference) + }; +} diff --git a/tests/ui/arch/atomics/atomic_i_sub.rs b/tests/ui/arch/atomics/atomic_i_sub.rs new file mode 100644 index 0000000000..4dd034a507 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_i_sub.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_i_sub::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_load.rs b/tests/ui/arch/atomics/atomic_load.rs new file mode 100644 index 0000000000..b999b56807 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_load.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + unsafe { + let output = spirv_std::arch::atomic_load::< + _, + { Scope::Device as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0)); + } +} diff --git a/tests/ui/arch/atomics/atomic_or.rs b/tests/ui/arch/atomics/atomic_or.rs new file mode 100644 index 0000000000..677e8d2fe5 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_or.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_or::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_s_max.rs b/tests/ui/arch/atomics/atomic_s_max.rs new file mode 100644 index 0000000000..e1aec67ca2 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_s_max.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [i32]) { + let old = unsafe { + spirv_std::arch::atomic_s_max::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_s_min.rs b/tests/ui/arch/atomics/atomic_s_min.rs new file mode 100644 index 0000000000..6a1e558ba5 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_s_min.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [i32]) { + let old = unsafe { + spirv_std::arch::atomic_s_min::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_store.rs b/tests/ui/arch/atomics/atomic_store.rs new file mode 100644 index 0000000000..de422c3c73 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_store.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_store::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_u_max.rs b/tests/ui/arch/atomics/atomic_u_max.rs new file mode 100644 index 0000000000..905f9b6532 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_u_max.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_u_max::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_u_min.rs b/tests/ui/arch/atomics/atomic_u_min.rs new file mode 100644 index 0000000000..073306c4ec --- /dev/null +++ b/tests/ui/arch/atomics/atomic_u_min.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_u_min::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +} diff --git a/tests/ui/arch/atomics/atomic_xor.rs b/tests/ui/arch/atomics/atomic_xor.rs new file mode 100644 index 0000000000..2dc14e2f35 --- /dev/null +++ b/tests/ui/arch/atomics/atomic_xor.rs @@ -0,0 +1,17 @@ +// build-pass + +use spirv_std::{ + arch::IndexUnchecked, + memory::{Scope, Semantics}, +}; + +#[spirv(compute(threads(64)))] +pub fn main(#[spirv(descriptor_set = 0, binding = 0, storage_buffer)] buffer: &mut [u32]) { + let old = unsafe { + spirv_std::arch::atomic_xor::< + _, + { Scope::Workgroup as u32 }, + { Semantics::UNIFORM_MEMORY.bits() }, + >(&mut *buffer.index_unchecked_mut(0), 5) + }; +}