Skip to content

Commit c52845f

Browse files
authored
Support signed integers for bswap intrinsic (#174)
Fixes #169
1 parent 8d09cea commit c52845f

File tree

2 files changed

+77
-20
lines changed

2 files changed

+77
-20
lines changed

crates/rustc_codegen_spirv/src/builder/intrinsics.rs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -255,31 +255,39 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
255255
.bit_reverse(args[0].immediate().ty, None, args[0].immediate().def(self))
256256
.unwrap()
257257
.with_type(args[0].immediate().ty),
258-
259258
sym::bswap => {
260259
// https://github.com/KhronosGroup/SPIRV-LLVM/pull/221/files
261260
// TODO: Definitely add tests to make sure this impl is right.
262261
let arg = args[0].immediate();
263-
match int_type_width_signed(arg_tys[0], self)
264-
.expect("bswap must have integer argument")
265-
.0
266-
{
267-
8 => arg,
262+
let (width, is_signed) = int_type_width_signed(arg_tys[0], self)
263+
.expect("bswap must have an integer argument");
264+
265+
// Cast to unsigned type for byte-swapping
266+
let unsigned_ty: u32 =
267+
SpirvType::Integer(width.try_into().unwrap(), false).def(self.span(), self);
268+
let unsigned_arg = if is_signed {
269+
self.bitcast(arg, unsigned_ty)
270+
} else {
271+
arg
272+
};
273+
274+
let swapped = match width {
275+
8 => unsigned_arg,
268276
16 => {
269277
let offset8 = self.constant_u16(self.span(), 8);
270-
let tmp1 = self.shl(arg, offset8);
271-
let tmp2 = self.lshr(arg, offset8);
278+
let tmp1 = self.shl(unsigned_arg, offset8);
279+
let tmp2 = self.lshr(unsigned_arg, offset8);
272280
self.or(tmp1, tmp2)
273281
}
274282
32 => {
275283
let offset8 = self.constant_u32(self.span(), 8);
276284
let offset24 = self.constant_u32(self.span(), 24);
277285
let mask16 = self.constant_u32(self.span(), 0xFF00);
278286
let mask24 = self.constant_u32(self.span(), 0xFF0000);
279-
let tmp4 = self.shl(arg, offset24);
280-
let tmp3 = self.shl(arg, offset8);
281-
let tmp2 = self.lshr(arg, offset8);
282-
let tmp1 = self.lshr(arg, offset24);
287+
let tmp4 = self.shl(unsigned_arg, offset24);
288+
let tmp3 = self.shl(unsigned_arg, offset8);
289+
let tmp2 = self.lshr(unsigned_arg, offset8);
290+
let tmp1 = self.lshr(unsigned_arg, offset24);
283291
let tmp3 = self.and(tmp3, mask24);
284292
let tmp2 = self.and(tmp2, mask16);
285293
let res1 = self.or(tmp1, tmp2);
@@ -297,14 +305,14 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
297305
let mask40 = self.constant_u64(self.span(), 0xff00000000);
298306
let mask48 = self.constant_u64(self.span(), 0xff0000000000);
299307
let mask56 = self.constant_u64(self.span(), 0xff000000000000);
300-
let tmp8 = self.shl(arg, offset56);
301-
let tmp7 = self.shl(arg, offset40);
302-
let tmp6 = self.shl(arg, offset24);
303-
let tmp5 = self.shl(arg, offset8);
304-
let tmp4 = self.lshr(arg, offset8);
305-
let tmp3 = self.lshr(arg, offset24);
306-
let tmp2 = self.lshr(arg, offset40);
307-
let tmp1 = self.lshr(arg, offset56);
308+
let tmp8 = self.shl(unsigned_arg, offset56);
309+
let tmp7 = self.shl(unsigned_arg, offset40);
310+
let tmp6 = self.shl(unsigned_arg, offset24);
311+
let tmp5 = self.shl(unsigned_arg, offset8);
312+
let tmp4 = self.lshr(unsigned_arg, offset8);
313+
let tmp3 = self.lshr(unsigned_arg, offset24);
314+
let tmp2 = self.lshr(unsigned_arg, offset40);
315+
let tmp1 = self.lshr(unsigned_arg, offset56);
308316
let tmp7 = self.and(tmp7, mask56);
309317
let tmp6 = self.and(tmp6, mask48);
310318
let tmp5 = self.and(tmp5, mask40);
@@ -327,6 +335,13 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
327335
);
328336
undef
329337
}
338+
};
339+
340+
// Cast back to the original signed type if necessary
341+
if is_signed {
342+
self.bitcast(swapped, arg.ty)
343+
} else {
344+
swapped
330345
}
331346
}
332347

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Test bswap intrinsic
2+
// build-pass
3+
4+
#![allow(internal_features)]
5+
#![feature(core_intrinsics)]
6+
#![no_std]
7+
8+
use core::intrinsics::bswap;
9+
use spirv_std::spirv;
10+
11+
#[spirv(compute(threads(1)))]
12+
pub fn main() {
13+
let original_i16: i16 = 0x1234;
14+
let swapped_i16 = bswap(original_i16);
15+
16+
let original_neg_i16: i16 = -0x1234;
17+
let swapped_neg_i16 = bswap(original_neg_i16);
18+
19+
let original_i32: i32 = 0x12345678;
20+
let swapped_i32 = bswap(original_i32);
21+
22+
let original_neg_i32: i32 = -0x12345678;
23+
let swapped_neg_i32 = bswap(original_neg_i32);
24+
25+
let original_zero_i16: i16 = 0;
26+
let swapped_zero_i16 = bswap(original_zero_i16);
27+
28+
let original_zero_i32: i32 = 0;
29+
let swapped_zero_i32 = bswap(original_zero_i32);
30+
31+
let original_u8: u8 = 0x12;
32+
let swapped_u8 = bswap(original_u8);
33+
34+
let original_u16: u16 = 0x1234;
35+
let swapped_u16 = bswap(original_u16);
36+
37+
let original_u32: u32 = 0x12345678;
38+
let swapped_u32 = bswap(original_u32);
39+
40+
let original_u64: u64 = 0x123456789ABCDEF0;
41+
let swapped_u64 = bswap(original_u64);
42+
}

0 commit comments

Comments
 (0)