From 6274ea22b1ae90e56240249e2dcaf38ba36c0d7e Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Mon, 9 Dec 2024 15:48:38 -0400 Subject: [PATCH] Support signed integers for `bswap` intrinsic Fixes https://github.com/Rust-GPU/rust-gpu/issues/169 --- .../src/builder/intrinsics.rs | 55 ++++++++++++------- tests/ui/lang/core/intrinsics/bswap.rs | 42 ++++++++++++++ 2 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 tests/ui/lang/core/intrinsics/bswap.rs diff --git a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs index ad48100fa0..121cc23db4 100644 --- a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs +++ b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs @@ -255,20 +255,28 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { .bit_reverse(args[0].immediate().ty, None, args[0].immediate().def(self)) .unwrap() .with_type(args[0].immediate().ty), - sym::bswap => { // https://github.com/KhronosGroup/SPIRV-LLVM/pull/221/files // TODO: Definitely add tests to make sure this impl is right. let arg = args[0].immediate(); - match int_type_width_signed(arg_tys[0], self) - .expect("bswap must have integer argument") - .0 - { - 8 => arg, + let (width, is_signed) = int_type_width_signed(arg_tys[0], self) + .expect("bswap must have an integer argument"); + + // Cast to unsigned type for byte-swapping + let unsigned_ty: u32 = + SpirvType::Integer(width.try_into().unwrap(), false).def(self.span(), self); + let unsigned_arg = if is_signed { + self.bitcast(arg, unsigned_ty) + } else { + arg + }; + + let swapped = match width { + 8 => unsigned_arg, 16 => { let offset8 = self.constant_u16(self.span(), 8); - let tmp1 = self.shl(arg, offset8); - let tmp2 = self.lshr(arg, offset8); + let tmp1 = self.shl(unsigned_arg, offset8); + let tmp2 = self.lshr(unsigned_arg, offset8); self.or(tmp1, tmp2) } 32 => { @@ -276,10 +284,10 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { let offset24 = self.constant_u32(self.span(), 24); let mask16 = self.constant_u32(self.span(), 0xFF00); let mask24 = self.constant_u32(self.span(), 0xFF0000); - let tmp4 = self.shl(arg, offset24); - let tmp3 = self.shl(arg, offset8); - let tmp2 = self.lshr(arg, offset8); - let tmp1 = self.lshr(arg, offset24); + let tmp4 = self.shl(unsigned_arg, offset24); + let tmp3 = self.shl(unsigned_arg, offset8); + let tmp2 = self.lshr(unsigned_arg, offset8); + let tmp1 = self.lshr(unsigned_arg, offset24); let tmp3 = self.and(tmp3, mask24); let tmp2 = self.and(tmp2, mask16); let res1 = self.or(tmp1, tmp2); @@ -297,14 +305,14 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { let mask40 = self.constant_u64(self.span(), 0xff00000000); let mask48 = self.constant_u64(self.span(), 0xff0000000000); let mask56 = self.constant_u64(self.span(), 0xff000000000000); - let tmp8 = self.shl(arg, offset56); - let tmp7 = self.shl(arg, offset40); - let tmp6 = self.shl(arg, offset24); - let tmp5 = self.shl(arg, offset8); - let tmp4 = self.lshr(arg, offset8); - let tmp3 = self.lshr(arg, offset24); - let tmp2 = self.lshr(arg, offset40); - let tmp1 = self.lshr(arg, offset56); + let tmp8 = self.shl(unsigned_arg, offset56); + let tmp7 = self.shl(unsigned_arg, offset40); + let tmp6 = self.shl(unsigned_arg, offset24); + let tmp5 = self.shl(unsigned_arg, offset8); + let tmp4 = self.lshr(unsigned_arg, offset8); + let tmp3 = self.lshr(unsigned_arg, offset24); + let tmp2 = self.lshr(unsigned_arg, offset40); + let tmp1 = self.lshr(unsigned_arg, offset56); let tmp7 = self.and(tmp7, mask56); let tmp6 = self.and(tmp6, mask48); let tmp5 = self.and(tmp5, mask40); @@ -327,6 +335,13 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { ); undef } + }; + + // Cast back to the original signed type if necessary + if is_signed { + self.bitcast(swapped, arg.ty) + } else { + swapped } } diff --git a/tests/ui/lang/core/intrinsics/bswap.rs b/tests/ui/lang/core/intrinsics/bswap.rs new file mode 100644 index 0000000000..27589f1284 --- /dev/null +++ b/tests/ui/lang/core/intrinsics/bswap.rs @@ -0,0 +1,42 @@ +// Test bswap intrinsic +// build-pass + +#![allow(internal_features)] +#![feature(core_intrinsics)] +#![no_std] + +use core::intrinsics::bswap; +use spirv_std::spirv; + +#[spirv(compute(threads(1)))] +pub fn main() { + let original_i16: i16 = 0x1234; + let swapped_i16 = bswap(original_i16); + + let original_neg_i16: i16 = -0x1234; + let swapped_neg_i16 = bswap(original_neg_i16); + + let original_i32: i32 = 0x12345678; + let swapped_i32 = bswap(original_i32); + + let original_neg_i32: i32 = -0x12345678; + let swapped_neg_i32 = bswap(original_neg_i32); + + let original_zero_i16: i16 = 0; + let swapped_zero_i16 = bswap(original_zero_i16); + + let original_zero_i32: i32 = 0; + let swapped_zero_i32 = bswap(original_zero_i32); + + let original_u8: u8 = 0x12; + let swapped_u8 = bswap(original_u8); + + let original_u16: u16 = 0x1234; + let swapped_u16 = bswap(original_u16); + + let original_u32: u32 = 0x12345678; + let swapped_u32 = bswap(original_u32); + + let original_u64: u64 = 0x123456789ABCDEF0; + let swapped_u64 = bswap(original_u64); +}