Skip to content

Commit 97c7022

Browse files
committed
rustc_codegen_ssa: use bitcasts instead of type punning for scalar transmutes.
1 parent e5721a5 commit 97c7022

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

Diff for: compiler/rustc_codegen_ssa/src/mir/block.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13951395
dst: PlaceRef<'tcx, Bx::Value>,
13961396
) {
13971397
let src = self.codegen_operand(bx, src);
1398+
1399+
// Special-case transmutes between scalars as simple bitcasts.
1400+
match (&src.layout.abi, &dst.layout.abi) {
1401+
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
1402+
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
1403+
if (src_scalar.value == abi::Pointer) == (dst_scalar.value == abi::Pointer) {
1404+
assert_eq!(src.layout.size, dst.layout.size);
1405+
1406+
// NOTE(eddyb) the `from_immediate` and `to_immediate_scalar`
1407+
// conversions allow handling `bool`s the same as `u8`s.
1408+
let src = bx.from_immediate(src.immediate());
1409+
let src_as_dst = bx.bitcast(src, bx.backend_type(dst.layout));
1410+
Immediate(bx.to_immediate_scalar(src_as_dst, dst_scalar)).store(bx, dst);
1411+
return;
1412+
}
1413+
}
1414+
_ => {}
1415+
}
1416+
13981417
let llty = bx.backend_type(src.layout);
13991418
let cast_ptr = bx.pointercast(dst.llval, bx.type_ptr_to(llty));
14001419
let align = src.layout.align.abi.min(dst.align);

Diff for: src/test/codegen/transmute-scalar.rs

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// compile-flags: -C no-prepopulate-passes
2+
3+
#![crate_type = "lib"]
4+
5+
// CHECK: define i32 @f32_to_bits(float %x)
6+
// CHECK: %2 = bitcast float %x to i32
7+
// CHECK-NEXT: store i32 %2, i32* %0
8+
// CHECK-NEXT: %3 = load i32, i32* %0
9+
// CHECK: ret i32 %3
10+
#[no_mangle]
11+
pub fn f32_to_bits(x: f32) -> u32 {
12+
unsafe { std::mem::transmute(x) }
13+
}
14+
15+
// CHECK: define i8 @bool_to_byte(i1 zeroext %b)
16+
// CHECK: %1 = zext i1 %b to i8
17+
// CHECK-NEXT: store i8 %1, i8* %0
18+
// CHECK-NEXT: %2 = load i8, i8* %0
19+
// CHECK: ret i8 %2
20+
#[no_mangle]
21+
pub fn bool_to_byte(b: bool) -> u8 {
22+
unsafe { std::mem::transmute(b) }
23+
}
24+
25+
// CHECK: define zeroext i1 @byte_to_bool(i8 %byte)
26+
// CHECK: %1 = trunc i8 %byte to i1
27+
// CHECK-NEXT: %2 = zext i1 %1 to i8
28+
// CHECK-NEXT: store i8 %2, i8* %0
29+
// CHECK-NEXT: %3 = load i8, i8* %0
30+
// CHECK-NEXT: %4 = trunc i8 %3 to i1
31+
// CHECK: ret i1 %4
32+
#[no_mangle]
33+
pub unsafe fn byte_to_bool(byte: u8) -> bool {
34+
std::mem::transmute(byte)
35+
}

0 commit comments

Comments
 (0)