diff --git a/crates/spirv-builder/src/lib.rs b/crates/spirv-builder/src/lib.rs index 7733f10acf..a056ceceb0 100644 --- a/crates/spirv-builder/src/lib.rs +++ b/crates/spirv-builder/src/lib.rs @@ -201,7 +201,7 @@ fn invoke_rustc(builder: &SpirvBuilder, multimodule: bool) -> Result(ptr: &N) -> N { + let mut result = N::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%result = OpAtomicLoad _ {ptr} %scope %semantics", + "OpStore {result} %result", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + result = in(reg) &mut result + } + + result +} + +/// Atomically store through `ptr` using the given `SEMANTICS`. All subparts of +/// `value` are written atomically with respect to all other atomic accesses to +/// it within `SCOPE`. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicStore")] +#[inline] +pub unsafe fn atomic_store( + ptr: &mut N, + value: N, +) { + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "OpAtomicStore {ptr} %scope %semantics %value", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + value = in(reg) &value, + } +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within `SCOPE` to the same location: +/// +/// 1. Load through `ptr` to get the original value, +/// 2. Get a new value from copying `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicExchange")] +#[inline] +pub unsafe fn atomic_exchange( + ptr: &mut N, + value: N, +) -> N { + let mut old = N::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicExchange _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + value = in(reg) &value, + old = in(reg) &mut old, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within `SCOPE` to the same location: +/// +/// 1. Load through `ptr` to get the original value +/// 2. Get a new value from `value` only if the original value equals +/// `comparator`, and +/// 3. Store the new value back through `ptr`, only if the original value +/// equaled `comparator`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicCompareExchange")] +#[inline] +pub unsafe fn atomic_compare_exchange< + I: Integer, + const SCOPE: Scope, + const EQUAL: Semantics, + const UNEQUAL: Semantics, +>( + ptr: &mut I, + value: I, + comparator: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%equal = OpConstant %u32 {equal}", + "%unequal = OpConstant %u32 {unequal}", + "%value = OpLoad _ {value}", + "%comparator = OpLoad _ {comparator}", + "%old = OpAtomicCompareExchange _ {ptr} %scope %equal %unequal %value %comparator", + "OpStore {old} %old", + scope = const SCOPE as u8, + equal = const EQUAL as u8, + unequal = const UNEQUAL as u8, + ptr = in(reg) ptr, + value = in(reg) &value, + comparator = in(reg) &comparator, + old = in(reg) &mut old, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within `SCOPE` to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value through integer addition of 1 to original value, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicIIncrement")] +#[inline] +pub unsafe fn atomic_i_increment( + ptr: &mut I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%old = OpAtomicIIncrement _ {ptr} %scope %semantics", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within `SCOPE` to the same location: +/// +/// 1) load through `ptr` to get an original value, +/// 2) get a new value through integer subtraction of 1 from original value, and +/// 3) store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicIDecrement")] +#[inline] +pub unsafe fn atomic_i_decrement( + ptr: &mut I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%old = OpAtomicIIncrement _ {ptr} %scope %semantics", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within `SCOPE` to the same location: +/// +/// 1) load through `ptr` to get an original value, +/// 2) get a new value by integer addition of original value and `value`, and +/// 3) store the new value back through `ptr`. +/// +/// The result is the Original Value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicIAdd")] +#[inline] +pub unsafe fn atomic_i_add( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicIAdd _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within `SCOPE` to the same location: +/// +/// 1) load through `ptr` to get an original value, +/// 2) get a new value by integer subtraction of original value and `value`, and +/// 3) store the new value back through `ptr`. +/// +/// The result is the Original Value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicISub")] +#[inline] +pub unsafe fn atomic_i_sub( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicISub _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within Scope to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value by finding the smallest signed integer of original value +/// and `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicSMin")] +#[inline] +pub unsafe fn atomic_s_min( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicSMin _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within Scope to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value by finding the smallest unsigned integer of original +/// value and `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicUMin")] +#[inline] +pub unsafe fn atomic_u_min( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicUMin _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within Scope to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value by finding the largest signed integer of original value +/// and `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicSMax")] +#[inline] +pub unsafe fn atomic_s_max( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicSMax _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within Scope to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value by finding the largest unsigned integer of original +/// value and `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicUMax")] +#[inline] +pub unsafe fn atomic_u_max( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicUMax _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within Scope to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value by the bitwise AND of the original value and `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicAnd")] +#[inline] +pub unsafe fn atomic_and( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicAnd _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within Scope to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value by the bitwise OR of the original value and `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicOr")] +#[inline] +pub unsafe fn atomic_or( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicOr _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} + +/// Perform the following steps atomically with respect to any other atomic +/// accesses within Scope to the same location: +/// +/// 1. Load through `ptr` to get an original value, +/// 2. Get a new value by the bitwise XOR of the original value and `value`, and +/// 3. Store the new value back through `ptr`. +/// +/// The result is the original value. +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpAtomicXor")] +#[inline] +pub unsafe fn atomic_xor( + ptr: &mut I, + value: I, +) -> I { + let mut old = I::default(); + + asm! { + "%u32 = OpTypeInt 32 0", + "%scope = OpConstant %u32 {scope}", + "%semantics = OpConstant %u32 {semantics}", + "%value = OpLoad _ {value}", + "%old = OpAtomicXor _ {ptr} %scope %semantics %value", + "OpStore {old} %old", + scope = const SCOPE as u8, + semantics = const SEMANTICS as u8, + ptr = in(reg) ptr, + old = in(reg) &mut old, + value = in(reg) &value, + } + + old +} diff --git a/crates/spirv-std/src/lib.rs b/crates/spirv-std/src/lib.rs index 2ecde0ab1a..a65391c7a7 100644 --- a/crates/spirv-std/src/lib.rs +++ b/crates/spirv-std/src/lib.rs @@ -83,6 +83,7 @@ pub mod integer; pub mod memory; pub mod ray_tracing; mod sampler; +pub mod number; pub mod scalar; pub(crate) mod sealed; mod textures; diff --git a/crates/spirv-std/src/number.rs b/crates/spirv-std/src/number.rs new file mode 100644 index 0000000000..f12745fd3e --- /dev/null +++ b/crates/spirv-std/src/number.rs @@ -0,0 +1,13 @@ +/// Abstract trait representing a SPIR-V integer type. +pub trait Number: crate::scalar::Scalar {} + +impl Number for u8 {} +impl Number for u16 {} +impl Number for u32 {} +impl Number for u64 {} +impl Number for i8 {} +impl Number for i16 {} +impl Number for i32 {} +impl Number for i64 {} +impl Number for f32 {} +impl Number for f64 {} diff --git a/tests/ui/arch/atomic_and.rs b/tests/ui/arch/atomic_and.rs new file mode 100644 index 0000000000..a4b27e6f0d --- /dev/null +++ b/tests/ui/arch/atomic_and.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_and::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_compare_exchange.rs b/tests/ui/arch/atomic_compare_exchange.rs new file mode 100644 index 0000000000..fee7aa0c2d --- /dev/null +++ b/tests/ui/arch/atomic_compare_exchange.rs @@ -0,0 +1,18 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_compare_exchange::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + { Semantics::ImageMemory }, + >(&mut *output, 5, 10); + } +} diff --git a/tests/ui/arch/atomic_exchange.rs b/tests/ui/arch/atomic_exchange.rs new file mode 100644 index 0000000000..1dd0f52c33 --- /dev/null +++ b/tests/ui/arch/atomic_exchange.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_exchange::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory } + >(&mut *output, 5.0); + } +} diff --git a/tests/ui/arch/atomic_i_add.rs b/tests/ui/arch/atomic_i_add.rs new file mode 100644 index 0000000000..9ddf3166ab --- /dev/null +++ b/tests/ui/arch/atomic_i_add.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_i_add::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_i_decrement.rs b/tests/ui/arch/atomic_i_decrement.rs new file mode 100644 index 0000000000..d55d1a7c03 --- /dev/null +++ b/tests/ui/arch/atomic_i_decrement.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_i_decrement::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output); + } +} diff --git a/tests/ui/arch/atomic_i_increment.rs b/tests/ui/arch/atomic_i_increment.rs new file mode 100644 index 0000000000..8def977582 --- /dev/null +++ b/tests/ui/arch/atomic_i_increment.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_i_increment::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output); + } +} diff --git a/tests/ui/arch/atomic_i_sub.rs b/tests/ui/arch/atomic_i_sub.rs new file mode 100644 index 0000000000..5f402e331b --- /dev/null +++ b/tests/ui/arch/atomic_i_sub.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_i_sub::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_load.rs b/tests/ui/arch/atomic_load.rs new file mode 100644 index 0000000000..37c5105b0b --- /dev/null +++ b/tests/ui/arch/atomic_load.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(output: Image) { + unsafe { + let output = spirv_std::arch::atomic_load::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory } + >(&*output); + } +} diff --git a/tests/ui/arch/atomic_or.rs b/tests/ui/arch/atomic_or.rs new file mode 100644 index 0000000000..41d4c2092d --- /dev/null +++ b/tests/ui/arch/atomic_or.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_or::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_s_max.rs b/tests/ui/arch/atomic_s_max.rs new file mode 100644 index 0000000000..8af8b593dd --- /dev/null +++ b/tests/ui/arch/atomic_s_max.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_s_max::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_s_min.rs b/tests/ui/arch/atomic_s_min.rs new file mode 100644 index 0000000000..09f98651b0 --- /dev/null +++ b/tests/ui/arch/atomic_s_min.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_s_min::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_store.rs b/tests/ui/arch/atomic_store.rs new file mode 100644 index 0000000000..7acd8a4479 --- /dev/null +++ b/tests/ui/arch/atomic_store.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + spirv_std::arch::atomic_store::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory } + >(&mut *output, 5.0); + } +} diff --git a/tests/ui/arch/atomic_u_max.rs b/tests/ui/arch/atomic_u_max.rs new file mode 100644 index 0000000000..50c04af473 --- /dev/null +++ b/tests/ui/arch/atomic_u_max.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_u_min::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_u_min.rs b/tests/ui/arch/atomic_u_min.rs new file mode 100644 index 0000000000..f5094c96d1 --- /dev/null +++ b/tests/ui/arch/atomic_u_min.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_u_max::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +} diff --git a/tests/ui/arch/atomic_xor.rs b/tests/ui/arch/atomic_xor.rs new file mode 100644 index 0000000000..ad10e4a03d --- /dev/null +++ b/tests/ui/arch/atomic_xor.rs @@ -0,0 +1,17 @@ +// build-pass + +#![feature(const_generics)] +#![allow(incomplete_features)] + +use spirv_std::{memory::{Scope, Semantics}, storage_class::Image}; + +#[spirv(fragment)] +pub fn main(mut output: Image) { + unsafe { + let old = spirv_std::arch::atomic_xor::< + _, + { Scope::CrossDevice }, + { Semantics::ImageMemory }, + >(&mut *output, 10); + } +}