Skip to content

Commit

Permalink
Support signed integers for bswap intrinsic (#174)
Browse files Browse the repository at this point in the history
Fixes #169
  • Loading branch information
LegNeato authored Dec 13, 2024
1 parent 8d09cea commit c52845f
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 20 deletions.
55 changes: 35 additions & 20 deletions crates/rustc_codegen_spirv/src/builder/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,31 +255,39 @@ 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 => {
let offset8 = self.constant_u32(self.span(), 8);
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);
Expand All @@ -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);
Expand All @@ -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
}
}

Expand Down
42 changes: 42 additions & 0 deletions tests/ui/lang/core/intrinsics/bswap.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit c52845f

Please sign in to comment.