diff --git a/crates/spirv-std/src/arch/subgroup.rs b/crates/spirv-std/src/arch/subgroup.rs index fafc30ffc2..a9690d4190 100644 --- a/crates/spirv-std/src/arch/subgroup.rs +++ b/crates/spirv-std/src/arch/subgroup.rs @@ -280,9 +280,10 @@ pub fn subgroup_all_equal(value: T) -> bool { /// Requires Capability `GroupNonUniformBallot`. /// /// # Safety -/// * `id` must not be dynamically uniform -/// * before 1.5: `id` must be constant +/// * `id` must be dynamically uniform /// * Result is undefined if `id` is an inactive invocation or out of bounds +/// * This variant with a dynamic `id` requires at least `spv1.5` or `vulkan1.2`. Alternatively, you can use +/// [`subgroup_broadcast_const`] with a constant `id`. #[spirv_std_macros::gpu_only] #[doc(alias = "OpGroupNonUniformBroadcast")] #[inline] @@ -307,6 +308,48 @@ pub unsafe fn subgroup_broadcast(value: T, id: u32) -> T { result } +/// Result is the `value` of the invocation identified by the id `id` to all active invocations in the group. +/// +/// Result Type must be a scalar or vector of floating-point type, integer type, or Boolean type. +/// +/// Execution is a Scope that identifies the group of invocations affected by this command. It must be Subgroup. +/// +/// The type of `value` must be the same as Result Type. +/// +/// `id` must be a scalar of integer type, whose Signedness operand is 0. +/// +/// Before version 1.5, `id` must come from a constant instruction. Starting with version 1.5, this restriction is lifted. However, behavior is undefined when `id` is not dynamically uniform. +/// +/// The resulting value is undefined if `id` is an inactive invocation, or is greater than or equal to the size of the group. +/// +/// Requires Capability `GroupNonUniformBallot`. +/// +/// # Safety +/// * Result is undefined if `id` is an inactive invocation or out of bounds +#[spirv_std_macros::gpu_only] +#[doc(alias = "OpGroupNonUniformBroadcast")] +#[inline] +pub unsafe fn subgroup_broadcast_const(value: T) -> T { + let mut result = T::default(); + + unsafe { + asm! { + "%u32 = OpTypeInt 32 0", + "%subgroup = OpConstant %u32 {subgroup}", + "%id = OpConstant %u32 {id}", + "%value = OpLoad _ {value}", + "%result = OpGroupNonUniformBroadcast _ %subgroup %value %id", + "OpStore {result} %result", + subgroup = const SUBGROUP, + value = in(reg) &value, + id = const ID, + result = in(reg) &mut result, + } + } + + result +} + /// Result is the `value` of the invocation from the active invocation with the lowest id in the group to all active invocations in the group. /// /// Result Type must be a scalar or vector of floating-point type, integer type, or Boolean type. diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_broadcast.rs b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast.rs new file mode 100644 index 0000000000..4d65f6b294 --- /dev/null +++ b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast.rs @@ -0,0 +1,25 @@ +// build-pass +// compile-flags: -C target-feature=+GroupNonUniform,+GroupNonUniformBallot,+ext:SPV_KHR_vulkan_memory_model +// compile-flags: -C llvm-args=--disassemble-fn=subgroup_broadcast::disassembly +// normalize-stderr-test "OpLine .*\n" -> "" +// ignore-vulkan1.0 +// ignore-vulkan1.1 +// ignore-spv1.0 +// ignore-spv1.1 +// ignore-spv1.2 +// ignore-spv1.3 +// ignore-spv1.4 + +use spirv_std::arch::{GroupOperation, SubgroupMask}; +use spirv_std::spirv; + +unsafe fn disassembly(value: i32, id: u32) -> i32 { + spirv_std::arch::subgroup_broadcast(value, id) +} + +#[spirv(compute(threads(32, 1, 1)))] +pub fn main() { + unsafe { + disassembly(42, 5); + } +} diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_broadcast.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast.stderr new file mode 100644 index 0000000000..57d7d6e003 --- /dev/null +++ b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast.stderr @@ -0,0 +1,8 @@ +%1 = OpFunction %2 None %3 +%4 = OpFunctionParameter %2 +%5 = OpFunctionParameter %6 +%7 = OpLabel +%9 = OpGroupNonUniformBroadcast %2 %10 %4 %5 +OpNoLine +OpReturnValue %9 +OpFunctionEnd diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_const.rs b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_const.rs new file mode 100644 index 0000000000..eb9a66dd3d --- /dev/null +++ b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_const.rs @@ -0,0 +1,18 @@ +// build-pass +// compile-flags: -C target-feature=+GroupNonUniform,+GroupNonUniformBallot,+ext:SPV_KHR_vulkan_memory_model +// compile-flags: -C llvm-args=--disassemble-fn=subgroup_broadcast_const::disassembly +// normalize-stderr-test "OpLine .*\n" -> "" + +use spirv_std::arch::{GroupOperation, SubgroupMask}; +use spirv_std::spirv; + +unsafe fn disassembly(value: i32) -> i32 { + spirv_std::arch::subgroup_broadcast_const::<_, 5>(value) +} + +#[spirv(compute(threads(32, 1, 1)))] +pub fn main() { + unsafe { + disassembly(-42); + } +} diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_const.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_const.stderr new file mode 100644 index 0000000000..db3584310b --- /dev/null +++ b/tests/compiletests/ui/arch/subgroup/subgroup_broadcast_const.stderr @@ -0,0 +1,7 @@ +%1 = OpFunction %2 None %3 +%4 = OpFunctionParameter %2 +%5 = OpLabel +%7 = OpGroupNonUniformBroadcast %2 %8 %4 %9 +OpNoLine +OpReturnValue %7 +OpFunctionEnd diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr index a1ffc40545..c292b79934 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_0_fail.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation panicked: `ClusterSize` must be at least 1 - --> $SPIRV_STD_SRC/arch/subgroup.rs:825:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:868:1 | LL | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" LL | | An integer add group operation of all `value` operands contributed by active invocations in the group. @@ -13,7 +13,7 @@ LL | | "); = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `macro_subgroup_op_clustered` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $SPIRV_STD_SRC/arch/subgroup.rs:825:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:868:1 | LL | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" LL | | An integer add group operation of all `value` operands contributed by active invocations in the group. diff --git a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr index 3770c816dd..61d066c3fc 100644 --- a/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr +++ b/tests/compiletests/ui/arch/subgroup/subgroup_cluster_size_non_power_of_two_fail.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation panicked: `ClusterSize` must be a power of 2 - --> $SPIRV_STD_SRC/arch/subgroup.rs:825:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:868:1 | LL | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" LL | | An integer add group operation of all `value` operands contributed by active invocations in the group. @@ -13,7 +13,7 @@ LL | | "); = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `macro_subgroup_op_clustered` (in Nightly builds, run with -Z macro-backtrace for more info) note: erroneous constant encountered - --> $SPIRV_STD_SRC/arch/subgroup.rs:825:1 + --> $SPIRV_STD_SRC/arch/subgroup.rs:868:1 | LL | / macro_subgroup_op_clustered!(impl Integer, "OpGroupNonUniformIAdd", subgroup_clustered_i_add; r" LL | | An integer add group operation of all `value` operands contributed by active invocations in the group.