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

Support signed integers for bswap intrinsic #174

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
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);
}