Skip to content

Commit d757c4b

Browse files
committed
Handle not all immediates having abi::Scalars
1 parent 454bca5 commit d757c4b

File tree

3 files changed

+134
-13
lines changed

3 files changed

+134
-13
lines changed

compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+42-12
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
223223
let OperandValueKind::Immediate(in_scalar) = operand_kind else {
224224
bug!("Found {operand_kind:?} for operand {operand:?}");
225225
};
226-
if let OperandValueKind::Immediate(out_scalar) = cast_kind
227-
&& in_scalar.size(self.cx) == out_scalar.size(self.cx)
228-
{
229-
let cast_bty = bx.backend_type(cast);
230-
Some(OperandValue::Immediate(
231-
self.transmute_immediate(bx, imm, in_scalar, out_scalar, cast_bty),
232-
))
226+
if let OperandValueKind::Immediate(out_scalar) = cast_kind {
227+
match (in_scalar, out_scalar) {
228+
(ScalarOrZst::Zst, ScalarOrZst::Zst) => {
229+
Some(OperandRef::new_zst(bx, cast).val)
230+
}
231+
(ScalarOrZst::Scalar(in_scalar), ScalarOrZst::Scalar(out_scalar))
232+
if in_scalar.size(self.cx) == out_scalar.size(self.cx) =>
233+
{
234+
let cast_bty = bx.backend_type(cast);
235+
Some(OperandValue::Immediate(
236+
self.transmute_immediate(bx, imm, in_scalar, out_scalar, cast_bty),
237+
))
238+
}
239+
_ => None,
240+
}
233241
} else {
234242
None
235243
}
@@ -892,13 +900,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
892900
if self.cx.is_backend_immediate(layout) {
893901
debug_assert!(!self.cx.is_backend_scalar_pair(layout));
894902
OperandValueKind::Immediate(match layout.abi {
895-
abi::Abi::Scalar(s) => s,
896-
abi::Abi::Vector { element, .. } => element,
897-
x => bug!("Couldn't translate {x:?} as backend immediate"),
903+
abi::Abi::Scalar(s) => ScalarOrZst::Scalar(s),
904+
abi::Abi::Vector { element, .. } => ScalarOrZst::Scalar(element),
905+
_ if layout.is_zst() => ScalarOrZst::Zst,
906+
x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"),
898907
})
899908
} else if self.cx.is_backend_scalar_pair(layout) {
900909
let abi::Abi::ScalarPair(s1, s2) = layout.abi else {
901-
bug!("Couldn't translate {:?} as backend scalar pair", layout.abi)
910+
span_bug!(
911+
self.mir.span,
912+
"Couldn't translate {:?} as backend scalar pair",
913+
layout.abi,
914+
);
902915
};
903916
OperandValueKind::Pair(s1, s2)
904917
} else {
@@ -907,9 +920,26 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
907920
}
908921
}
909922

923+
/// The variants of this match [`OperandValue`], giving details about the
924+
/// backend values that will be held in that other type.
910925
#[derive(Debug, Copy, Clone)]
911926
enum OperandValueKind {
912927
Ref,
913-
Immediate(abi::Scalar),
928+
Immediate(ScalarOrZst),
914929
Pair(abi::Scalar, abi::Scalar),
915930
}
931+
932+
#[derive(Debug, Copy, Clone)]
933+
enum ScalarOrZst {
934+
Zst,
935+
Scalar(abi::Scalar),
936+
}
937+
938+
impl ScalarOrZst {
939+
pub fn size(self, cx: &impl abi::HasDataLayout) -> abi::Size {
940+
match self {
941+
ScalarOrZst::Zst => abi::Size::ZERO,
942+
ScalarOrZst::Scalar(s) => s.size(cx),
943+
}
944+
}
945+
}
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// compile-flags: -O -C no-prepopulate-passes
2+
// only-x86_64 (it's using arch-specific types)
3+
// min-llvm-version: 15.0 # this test assumes `ptr`s
4+
5+
#![crate_type = "lib"]
6+
7+
use std::arch::x86_64::{__m128, __m128i, __m256i};
8+
use std::mem::transmute;
9+
10+
// CHECK-LABEL: @check_sse_float_to_int(
11+
#[no_mangle]
12+
pub unsafe fn check_sse_float_to_int(x: __m128) -> __m128i {
13+
// CHECK-NOT: alloca
14+
// CHECK: %1 = load <4 x float>, ptr %x, align 16
15+
// CHECK: store <4 x float> %1, ptr %0, align 16
16+
transmute(x)
17+
}
18+
19+
// CHECK-LABEL: @check_sse_pair_to_avx(
20+
#[no_mangle]
21+
pub unsafe fn check_sse_pair_to_avx(x: (__m128i, __m128i)) -> __m256i {
22+
// CHECK-NOT: alloca
23+
// CHECK: %1 = load <4 x i64>, ptr %x, align 16
24+
// CHECK: store <4 x i64> %1, ptr %0, align 32
25+
transmute(x)
26+
}
27+
28+
// CHECK-LABEL: @check_sse_pair_from_avx(
29+
#[no_mangle]
30+
pub unsafe fn check_sse_pair_from_avx(x: __m256i) -> (__m128i, __m128i) {
31+
// CHECK-NOT: alloca
32+
// CHECK: %1 = load <4 x i64>, ptr %x, align 32
33+
// CHECK: store <4 x i64> %1, ptr %0, align 16
34+
transmute(x)
35+
}

tests/codegen/intrinsics/transmute.rs

+57-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#![feature(inline_const)]
99
#![allow(unreachable_code)]
1010

11-
use std::mem::transmute;
11+
use std::mem::{transmute, MaybeUninit};
1212

1313
// Some of the cases here are statically rejected by `mem::transmute`, so
1414
// we need to generate custom MIR for those cases to get to codegen.
@@ -373,3 +373,59 @@ pub unsafe fn check_pair_to_dst_ref<'a>(x: (usize, usize)) -> &'a [u8] {
373373
// CHECK: ret { ptr, i64 } %2
374374
transmute(x)
375375
}
376+
377+
// CHECK-LABEL: @check_issue_109992(
378+
#[no_mangle]
379+
#[custom_mir(dialect = "runtime", phase = "optimized")]
380+
pub unsafe fn check_issue_109992(x: ()) -> [(); 1] {
381+
// This uses custom MIR to avoid MIR optimizations having removed ZST ops.
382+
383+
// CHECK: start
384+
// CHECK-NEXT: ret void
385+
mir!{
386+
{
387+
RET = CastTransmute(x);
388+
Return()
389+
}
390+
}
391+
}
392+
393+
// CHECK-LABEL: @check_maybe_uninit_pair(i16 %x.0, i64 %x.1)
394+
#[no_mangle]
395+
pub unsafe fn check_maybe_uninit_pair(
396+
x: (MaybeUninit<u16>, MaybeUninit<u64>),
397+
) -> (MaybeUninit<i64>, MaybeUninit<i16>) {
398+
// Thanks to `MaybeUninit` this is actually defined behaviour,
399+
// unlike the examples above with pairs of primitives.
400+
401+
// CHECK: store i16 %x.0
402+
// CHECK: store i64 %x.1
403+
// CHECK: load i64
404+
// CHECK-NOT: noundef
405+
// CHECK: load i16
406+
// CHECK-NOT: noundef
407+
// CHECK: ret { i64, i16 }
408+
transmute(x)
409+
}
410+
411+
#[repr(align(8))]
412+
pub struct HighAlignScalar(u8);
413+
414+
// CHECK-LABEL: @check_to_overalign(
415+
#[no_mangle]
416+
pub unsafe fn check_to_overalign(x: u64) -> HighAlignScalar {
417+
// CHECK: %0 = alloca %HighAlignScalar, align 8
418+
// CHECK: store i64 %x, ptr %0, align 8
419+
// CHECK: %1 = load i64, ptr %0, align 8
420+
// CHECK: ret i64 %1
421+
transmute(x)
422+
}
423+
424+
// CHECK-LABEL: @check_from_overalign(
425+
#[no_mangle]
426+
pub unsafe fn check_from_overalign(x: HighAlignScalar) -> u64 {
427+
// CHECK: %x = alloca %HighAlignScalar, align 8
428+
// CHECK: %[[VAL:.+]] = load i64, ptr %x, align 8
429+
// CHECK: ret i64 %[[VAL]]
430+
transmute(x)
431+
}

0 commit comments

Comments
 (0)