Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add arch functions for the GLSL.std.450 S/U Min/Max functions #763

Merged
merged 2 commits into from
Oct 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion crates/spirv-std/src/arch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -200,3 +204,44 @@ pub unsafe fn read_clock_uvec2_khr<V: Vector<u32, 2>, const SCOPE: u32>() -> V {

result
}

#[spirv_std_macros::gpu_only]
unsafe fn call_glsl_op_with_ints<T: Integer, const OP: u32>(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<T: UnsignedInteger>(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<T: UnsignedInteger>(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<T: SignedInteger>(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<T: SignedInteger>(a: T, b: T) -> T {
unsafe { call_glsl_op_with_ints::<_, 42>(a, b) }
}
26 changes: 26 additions & 0 deletions tests/ui/arch/integer_min_and_max.rs
Original file line number Diff line number Diff line change
@@ -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);
}