diff --git a/crates/spirv-std/src/arch.rs b/crates/spirv-std/src/arch.rs index 6c563f33cf..2319751dac 100644 --- a/crates/spirv-std/src/arch.rs +++ b/crates/spirv-std/src/arch.rs @@ -3,7 +3,11 @@ //! This module is intended as a low level abstraction over SPIR-V instructions. //! These functions will typically map to a single instruction, and will perform //! no additional safety checks beyond type-checking. -use crate::{scalar::Scalar, vector::Vector}; +use crate::{ + integer::{Integer, SignedInteger, UnsignedInteger}, + scalar::Scalar, + vector::Vector, +}; mod barrier; mod demote_to_helper_invocation_ext; @@ -200,3 +204,44 @@ pub unsafe fn read_clock_uvec2_khr, const SCOPE: u32>() -> V { result } + +#[spirv_std_macros::gpu_only] +unsafe fn call_glsl_op_with_ints(a: T, b: T) -> T { + let mut result = T::default(); + asm!( + "%glsl = OpExtInstImport \"GLSL.std.450\"", + "%a = OpLoad _ {a}", + "%b = OpLoad _ {b}", + "%result = OpExtInst typeof*{result} %glsl {op} %a %b", + "OpStore {result} %result", + a = in(reg) &a, + b = in(reg) &b, + result = in(reg) &mut result, + op = const OP + ); + result +} + +/// Compute the minimum of two unsigned integers via a GLSL extended instruction. +#[spirv_std_macros::gpu_only] +pub fn unsigned_min(a: T, b: T) -> T { + unsafe { call_glsl_op_with_ints::<_, 38>(a, b) } +} + +/// Compute the maximum of two unsigned integers via a GLSL extended instruction. +#[spirv_std_macros::gpu_only] +pub fn unsigned_max(a: T, b: T) -> T { + unsafe { call_glsl_op_with_ints::<_, 41>(a, b) } +} + +/// Compute the minimum of two signed integers via a GLSL extended instruction. +#[spirv_std_macros::gpu_only] +pub fn signed_min(a: T, b: T) -> T { + unsafe { call_glsl_op_with_ints::<_, 39>(a, b) } +} + +/// Compute the maximum of two signed integers via a GLSL extended instruction. +#[spirv_std_macros::gpu_only] +pub fn signed_max(a: T, b: T) -> T { + unsafe { call_glsl_op_with_ints::<_, 42>(a, b) } +} diff --git a/tests/ui/arch/integer_min_and_max.rs b/tests/ui/arch/integer_min_and_max.rs new file mode 100644 index 0000000000..74f6e0cc8d --- /dev/null +++ b/tests/ui/arch/integer_min_and_max.rs @@ -0,0 +1,26 @@ +// build-pass + +use spirv_std::arch::{signed_max, signed_min, unsigned_max, unsigned_min}; + +#[spirv(fragment)] +pub fn main() { + assert!(unsigned_min(39_u8, 13) == 13); + assert!(unsigned_min(39_u16, 13) == 13); + assert!(unsigned_min(39_u32, 13) == 13); + assert!(unsigned_min(39_u64, 13) == 13); + + assert!(unsigned_max(39_u8, 13) == 39); + assert!(unsigned_max(39_u16, 13) == 39); + assert!(unsigned_max(39_u32, 13) == 39); + assert!(unsigned_max(39_u64, 13) == 39); + + assert!(signed_min(-112_i8, -45) == -112); + assert!(signed_min(-112_i16, -45) == -112); + assert!(signed_min(-112_i32, -45) == -112); + assert!(signed_min(-112_i64, -45) == -112); + + assert!(signed_max(-112_i8, -45) == -45); + assert!(signed_max(-112_i16, -45) == -45); + assert!(signed_max(-112_i32, -45) == -45); + assert!(signed_max(-112_i64, -45) == -45); +}