Skip to content

Commit f8a1130

Browse files
authored
Add arch functions for the GLSL.std.450 S/U Min/Max functions (#763)
* Add (un)signed_(min|max) glsl functinos * Add gpu_only to call glsl op
1 parent 14e2152 commit f8a1130

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

crates/spirv-std/src/arch.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
//! This module is intended as a low level abstraction over SPIR-V instructions.
44
//! These functions will typically map to a single instruction, and will perform
55
//! no additional safety checks beyond type-checking.
6-
use crate::{scalar::Scalar, vector::Vector};
6+
use crate::{
7+
integer::{Integer, SignedInteger, UnsignedInteger},
8+
scalar::Scalar,
9+
vector::Vector,
10+
};
711

812
mod barrier;
913
mod demote_to_helper_invocation_ext;
@@ -200,3 +204,44 @@ pub unsafe fn read_clock_uvec2_khr<V: Vector<u32, 2>, const SCOPE: u32>() -> V {
200204

201205
result
202206
}
207+
208+
#[spirv_std_macros::gpu_only]
209+
unsafe fn call_glsl_op_with_ints<T: Integer, const OP: u32>(a: T, b: T) -> T {
210+
let mut result = T::default();
211+
asm!(
212+
"%glsl = OpExtInstImport \"GLSL.std.450\"",
213+
"%a = OpLoad _ {a}",
214+
"%b = OpLoad _ {b}",
215+
"%result = OpExtInst typeof*{result} %glsl {op} %a %b",
216+
"OpStore {result} %result",
217+
a = in(reg) &a,
218+
b = in(reg) &b,
219+
result = in(reg) &mut result,
220+
op = const OP
221+
);
222+
result
223+
}
224+
225+
/// Compute the minimum of two unsigned integers via a GLSL extended instruction.
226+
#[spirv_std_macros::gpu_only]
227+
pub fn unsigned_min<T: UnsignedInteger>(a: T, b: T) -> T {
228+
unsafe { call_glsl_op_with_ints::<_, 38>(a, b) }
229+
}
230+
231+
/// Compute the maximum of two unsigned integers via a GLSL extended instruction.
232+
#[spirv_std_macros::gpu_only]
233+
pub fn unsigned_max<T: UnsignedInteger>(a: T, b: T) -> T {
234+
unsafe { call_glsl_op_with_ints::<_, 41>(a, b) }
235+
}
236+
237+
/// Compute the minimum of two signed integers via a GLSL extended instruction.
238+
#[spirv_std_macros::gpu_only]
239+
pub fn signed_min<T: SignedInteger>(a: T, b: T) -> T {
240+
unsafe { call_glsl_op_with_ints::<_, 39>(a, b) }
241+
}
242+
243+
/// Compute the maximum of two signed integers via a GLSL extended instruction.
244+
#[spirv_std_macros::gpu_only]
245+
pub fn signed_max<T: SignedInteger>(a: T, b: T) -> T {
246+
unsafe { call_glsl_op_with_ints::<_, 42>(a, b) }
247+
}

tests/ui/arch/integer_min_and_max.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// build-pass
2+
3+
use spirv_std::arch::{signed_max, signed_min, unsigned_max, unsigned_min};
4+
5+
#[spirv(fragment)]
6+
pub fn main() {
7+
assert!(unsigned_min(39_u8, 13) == 13);
8+
assert!(unsigned_min(39_u16, 13) == 13);
9+
assert!(unsigned_min(39_u32, 13) == 13);
10+
assert!(unsigned_min(39_u64, 13) == 13);
11+
12+
assert!(unsigned_max(39_u8, 13) == 39);
13+
assert!(unsigned_max(39_u16, 13) == 39);
14+
assert!(unsigned_max(39_u32, 13) == 39);
15+
assert!(unsigned_max(39_u64, 13) == 39);
16+
17+
assert!(signed_min(-112_i8, -45) == -112);
18+
assert!(signed_min(-112_i16, -45) == -112);
19+
assert!(signed_min(-112_i32, -45) == -112);
20+
assert!(signed_min(-112_i64, -45) == -112);
21+
22+
assert!(signed_max(-112_i8, -45) == -45);
23+
assert!(signed_max(-112_i16, -45) == -45);
24+
assert!(signed_max(-112_i32, -45) == -45);
25+
assert!(signed_max(-112_i64, -45) == -45);
26+
}

0 commit comments

Comments
 (0)