Skip to content

Commit 5d4c792

Browse files
authored
Unrolled build for #143194
Rollup merge of #143194 - folkertdev:fix-single-element-simd-bitcast, r=workingjubilee fix bitcast of single-element SIMD vectors in effect this reverts #142768 and adds additional tests. That PR relaxed the conditions on an early return in an incorrect way that would create broken LLVM IR. https://godbolt.org/z/PaaGWTv5a ```rust #![feature(repr_simd)] #[repr(simd)] #[derive(Clone, Copy)] struct S([i64; 1]); #[no_mangle] pub extern "C" fn single_element_simd(b: S) -> i64 { unsafe { std::mem::transmute(b) } } ``` at the time of writing generates this LLVM IR, where the type of the return is different from the function's return type. ```llvm define noundef i64 ``````@single_element_simd(<1`````` x i64> %b) unnamed_addr { start: ret <1 x i64> %b } ``` The test output is actually the same for the existing tests, showing that the change didn't actually matter for any tested behavior. It is probably a bit faster to do the early return, but, well, it's incorrect in general. zullip thread: [#t-compiler > Is transmuting a &#96;T&#96; to &#96;Tx1&#96; (one-element SIMD vector) UB?](https://rust-lang.zulipchat.com/#narrow/channel/131828-t-compiler/topic/Is.20transmuting.20a.20.60T.60.20to.20.60Tx1.60.20.28one-element.20SIMD.20vector.29.20UB.3F/with/526262799) cc ``````@sayantn`````` r? ``````@scottmcm``````
2 parents 1ce9c97 + e86fddc commit 5d4c792

File tree

2 files changed

+47
-18
lines changed

2 files changed

+47
-18
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
11171117
// While optimizations will remove no-op transmutes, they might still be
11181118
// there in debug or things that aren't no-op in MIR because they change
11191119
// the Rust type but not the underlying layout/niche.
1120-
if from_scalar == to_scalar {
1120+
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
11211121
return imm;
11221122
}
11231123

@@ -1136,13 +1136,7 @@ pub(super) fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
11361136
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
11371137

11381138
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
1139-
(Int(..) | Float(_), Int(..) | Float(_)) => {
1140-
if from_backend_ty == to_backend_ty {
1141-
imm
1142-
} else {
1143-
bx.bitcast(imm, to_backend_ty)
1144-
}
1145-
}
1139+
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
11461140
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
11471141
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
11481142
(Pointer(..), Int(..)) => {

tests/codegen/transmute-scalar.rs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
//@ add-core-stubs
12
//@ compile-flags: -C opt-level=0 -C no-prepopulate-passes
23

34
#![crate_type = "lib"]
5+
#![feature(no_core, repr_simd, arm_target_feature, mips_target_feature, s390x_target_feature)]
6+
#![no_core]
7+
extern crate minicore;
8+
9+
use minicore::*;
410

511
// With opaque ptrs in LLVM, `transmute` can load/store any `alloca` as any type,
612
// without needing to pointercast, and SRoA will turn that into a `bitcast`.
@@ -14,46 +20,46 @@
1420
// CHECK-NEXT: ret i32 %_0
1521
#[no_mangle]
1622
pub fn f32_to_bits(x: f32) -> u32 {
17-
unsafe { std::mem::transmute(x) }
23+
unsafe { mem::transmute(x) }
1824
}
1925

2026
// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
2127
// CHECK: %_0 = zext i1 %b to i8
2228
// CHECK-NEXT: ret i8 %_0
2329
#[no_mangle]
2430
pub fn bool_to_byte(b: bool) -> u8 {
25-
unsafe { std::mem::transmute(b) }
31+
unsafe { mem::transmute(b) }
2632
}
2733

2834
// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8{{.*}} %byte)
2935
// CHECK: %_0 = trunc{{( nuw)?}} i8 %byte to i1
3036
// CHECK-NEXT: ret i1 %_0
3137
#[no_mangle]
3238
pub unsafe fn byte_to_bool(byte: u8) -> bool {
33-
std::mem::transmute(byte)
39+
mem::transmute(byte)
3440
}
3541

3642
// CHECK-LABEL: define{{.*}}ptr @ptr_to_ptr(ptr %p)
3743
// CHECK: ret ptr %p
3844
#[no_mangle]
3945
pub fn ptr_to_ptr(p: *mut u16) -> *mut u8 {
40-
unsafe { std::mem::transmute(p) }
46+
unsafe { mem::transmute(p) }
4147
}
4248

4349
// CHECK: define{{.*}}[[USIZE:i[0-9]+]] @ptr_to_int(ptr %p)
4450
// CHECK: %_0 = ptrtoint ptr %p to [[USIZE]]
4551
// CHECK-NEXT: ret [[USIZE]] %_0
4652
#[no_mangle]
4753
pub fn ptr_to_int(p: *mut u16) -> usize {
48-
unsafe { std::mem::transmute(p) }
54+
unsafe { mem::transmute(p) }
4955
}
5056

5157
// CHECK: define{{.*}}ptr @int_to_ptr([[USIZE]] %i)
5258
// CHECK: %_0 = getelementptr i8, ptr null, [[USIZE]] %i
5359
// CHECK-NEXT: ret ptr %_0
5460
#[no_mangle]
5561
pub fn int_to_ptr(i: usize) -> *mut u16 {
56-
unsafe { std::mem::transmute(i) }
62+
unsafe { mem::transmute(i) }
5763
}
5864

5965
// This is the one case where signedness matters to transmuting:
@@ -70,15 +76,15 @@ pub enum FakeBoolSigned {
7076
// CHECK-NEXT: ret i8 %_0
7177
#[no_mangle]
7278
pub fn bool_to_fake_bool_signed(b: bool) -> FakeBoolSigned {
73-
unsafe { std::mem::transmute(b) }
79+
unsafe { mem::transmute(b) }
7480
}
7581

7682
// CHECK-LABEL: define{{.*}}i1 @fake_bool_signed_to_bool(i8 %b)
7783
// CHECK: %_0 = trunc nuw i8 %b to i1
7884
// CHECK-NEXT: ret i1 %_0
7985
#[no_mangle]
8086
pub fn fake_bool_signed_to_bool(b: FakeBoolSigned) -> bool {
81-
unsafe { std::mem::transmute(b) }
87+
unsafe { mem::transmute(b) }
8288
}
8389

8490
#[repr(u8)]
@@ -91,12 +97,41 @@ pub enum FakeBoolUnsigned {
9197
// CHECK: ret i1 %b
9298
#[no_mangle]
9399
pub fn bool_to_fake_bool_unsigned(b: bool) -> FakeBoolUnsigned {
94-
unsafe { std::mem::transmute(b) }
100+
unsafe { mem::transmute(b) }
95101
}
96102

97103
// CHECK-LABEL: define{{.*}}i1 @fake_bool_unsigned_to_bool(i1 zeroext %b)
98104
// CHECK: ret i1 %b
99105
#[no_mangle]
100106
pub fn fake_bool_unsigned_to_bool(b: FakeBoolUnsigned) -> bool {
101-
unsafe { std::mem::transmute(b) }
107+
unsafe { mem::transmute(b) }
108+
}
109+
110+
#[repr(simd)]
111+
struct S([i64; 1]);
112+
113+
// CHECK-LABEL: define{{.*}}i64 @single_element_simd_to_scalar(<1 x i64> %b)
114+
// CHECK: bitcast <1 x i64> %b to i64
115+
// CHECK: ret i64
116+
#[no_mangle]
117+
#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
118+
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
119+
#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
120+
#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
121+
#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
122+
pub extern "C" fn single_element_simd_to_scalar(b: S) -> i64 {
123+
unsafe { mem::transmute(b) }
124+
}
125+
126+
// CHECK-LABEL: define{{.*}}<1 x i64> @scalar_to_single_element_simd(i64 %b)
127+
// CHECK: bitcast i64 %b to <1 x i64>
128+
// CHECK: ret <1 x i64>
129+
#[no_mangle]
130+
#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
131+
#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
132+
#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
133+
#[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))]
134+
#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))]
135+
pub extern "C" fn scalar_to_single_element_simd(b: i64) -> S {
136+
unsafe { mem::transmute(b) }
102137
}

0 commit comments

Comments
 (0)