Skip to content

Commit efe4e70

Browse files
Rollup merge of rust-lang#157127 - scottmcm:tweak-layout-of-alternative, r=nikic
cg_LLVM: Stop needing an alloca for volatile loads This ended up also being reimplementing it to not use `load` of the `llvm_type`, since without doing that everything blew up horribly. cc the zulip conversation [#t-opsem > Defining volatile splitting @ 💬](https://rust-lang.zulipchat.com/#narrow/channel/136281-t-opsem/topic/Defining.20volatile.20splitting/near/597451615). And while I'm here, improve the tests to check that the unaligned ones are actually unaligned, since `unaligned_volatile_load::<u8>` doesn't actually test anything. r? @nikic cc @RalfJung MCP tracking issue rust-lang#153250
2 parents 417e0fd + 9b188dd commit efe4e70

9 files changed

Lines changed: 161 additions & 36 deletions

File tree

compiler/rustc_codegen_gcc/src/builder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
993993
loaded_value.to_rvalue()
994994
}
995995

996-
fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
996+
fn volatile_load(&mut self, ty: Type<'gcc>, ptr: RValue<'gcc>, _: Align) -> RValue<'gcc> {
997+
// FIXME(antoyo): set alignment.
997998
let ptr = self.context.new_cast(self.location, ptr, ty.make_volatile().make_pointer());
998999
// (FractalFir): We insert a local here, to ensure this volatile load can't move across
9991000
// blocks.

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod simd;
55
use std::iter;
66

77
use gccjit::{ComparisonOp, Function, FunctionType, RValue, ToRValue, Type, UnaryOp};
8-
use rustc_abi::{BackendRepr, HasDataLayout, WrappingRange};
8+
use rustc_abi::{Align, BackendRepr, HasDataLayout, WrappingRange};
99
use rustc_codegen_ssa::base::wants_msvc_seh;
1010
use rustc_codegen_ssa::common::IntPredicate;
1111
use rustc_codegen_ssa::errors::InvalidMonomorphization;
@@ -368,8 +368,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
368368

369369
sym::volatile_load | sym::unaligned_volatile_load => {
370370
let ptr = args[0].immediate();
371-
let load = self.volatile_load(result.layout.gcc_type(self), ptr);
372-
// FIXME(antoyo): set alignment.
371+
let abi_align = result_layout.align.abi;
372+
let ptr_align = if name == sym::volatile_load { abi_align } else { Align::ONE };
373+
let load = self.volatile_load(result.layout.gcc_type(self), ptr, ptr_align);
373374
if let BackendRepr::Scalar(scalar) = result.layout.backend_repr {
374375
self.to_immediate_scalar(load, scalar)
375376
} else {

compiler/rustc_codegen_llvm/src/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -682,9 +682,9 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
682682
}
683683
}
684684

685-
fn volatile_load(&mut self, ty: &'ll Type, ptr: &'ll Value) -> &'ll Value {
685+
fn volatile_load(&mut self, ty: &'ll Type, ptr: &'ll Value, align: Align) -> &'ll Value {
686686
unsafe {
687-
let load = llvm::LLVMBuildLoad2(self.llbuilder, ty, ptr, UNNAMED);
687+
let load = self.load(ty, ptr, align);
688688
llvm::LLVMSetVolatile(load, llvm::TRUE);
689689
load
690690
}

compiler/rustc_codegen_llvm/src/context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
978978
}
979979

980980
fn intrinsic_call_expects_place_always(&self, name: Symbol) -> bool {
981-
matches!(name, sym::volatile_load | sym::unaligned_volatile_load | sym::black_box)
981+
matches!(name, sym::black_box)
982982
}
983983
}
984984

compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// .debug_gdb_scripts binary section.
22

3+
use rustc_abi::Align;
34
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
45
use rustc_codegen_ssa::traits::*;
56
use rustc_hir::attrs::DebuggerVisualizerType;
@@ -18,10 +19,7 @@ pub(crate) fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Buil
1819
let gdb_debug_scripts_section = get_or_insert_gdb_debug_scripts_section_global(bx);
1920
// Load just the first byte as that's all that's necessary to force
2021
// LLVM to keep around the reference to the global.
21-
let volatile_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
22-
unsafe {
23-
llvm::LLVMSetAlignment(volatile_load_instruction, 1);
24-
}
22+
bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section, Align::ONE);
2523
}
2624
}
2725

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -354,25 +354,39 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
354354
}
355355

356356
sym::volatile_load | sym::unaligned_volatile_load => {
357-
let result = PlaceRef {
358-
val: result_place.unwrap(),
359-
layout: result_layout,
360-
};
361-
357+
// Note that we cannot just load the `llvm_type` because we should never load non-scalars.
358+
// Trying to do so blows up horribly in some cases -- for example loading a
359+
// `MaybeUninint<&dyn Trait>` would load as `{ [i64x2] }` which gives assertions later
360+
// (if we're lucky) from things not being pointers that ought to be.
362361
let ptr = args[0].immediate();
363-
let load = self.volatile_load(result_layout.llvm_type(self), ptr);
364-
let align = if name == sym::unaligned_volatile_load {
365-
1
362+
let abi_align = result_layout.align.abi;
363+
let ptr_align = if name == sym::volatile_load { abi_align } else { Align::ONE };
364+
if result_layout.is_zst() {
365+
return IntrinsicResult::Operand(OperandValue::ZeroSized);
366+
} else if let BackendRepr::Scalar(scalar) = result_layout.backend_repr {
367+
let load = self.volatile_load(self.type_from_scalar(scalar), ptr, ptr_align);
368+
self.to_immediate_scalar(load, scalar)
366369
} else {
367-
result_layout.align.bytes() as u32
368-
};
369-
unsafe {
370-
llvm::LLVMSetAlignment(load, align);
371-
}
372-
if !result_layout.is_zst() {
373-
self.store_to_place(load, result.val);
370+
// One day Rust will probably want to define how we split up a volatile load
371+
// of something that's *not* just an ordinary scalar, but for now we can just
372+
// use an LLVM integer type of the correct width and let it split it however.
373+
let llty = self.type_ix(result_layout.size.bits());
374+
let temp = if let Some(result_place) = result_place {
375+
PlaceRef {
376+
val: result_place,
377+
layout: result_layout,
378+
}
379+
} else {
380+
PlaceRef::alloca(self, result_layout)
381+
};
382+
let llval = self.volatile_load(llty, ptr, ptr_align);
383+
self.store(llval, temp.val.llval, abi_align);
384+
return if result_place.is_none() {
385+
IntrinsicResult::Operand(self.load_operand(temp).val)
386+
} else {
387+
IntrinsicResult::WroteIntoPlace
388+
};
374389
}
375-
return IntrinsicResult::WroteIntoPlace;
376390
}
377391
sym::volatile_store => {
378392
let dst = args[0].deref(self.cx());

compiler/rustc_codegen_ssa/src/traits/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ pub trait BuilderMethods<'a, 'tcx>:
242242
fn alloca_with_ty(&mut self, layout: TyAndLayout<'tcx>) -> Self::Value;
243243

244244
fn load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
245-
fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value) -> Self::Value;
245+
fn volatile_load(&mut self, ty: Self::Type, ptr: Self::Value, align: Align) -> Self::Value;
246246
fn atomic_load(
247247
&mut self,
248248
ty: Self::Type,

tests/codegen-llvm/i128-x86-align.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
// while rustc wants it to have 16 byte alignment. This test checks that we handle this
66
// correctly.
77

8-
// CHECK: %ScalarPair = type { i32, [3 x i32], i128 }
9-
108
#![feature(core_intrinsics)]
119

1210
#[repr(C)]
@@ -62,8 +60,8 @@ pub fn load_volatile(x: &ScalarPair) -> ScalarPair {
6260
// CHECK-SAME: dereferenceable(32) %_0,
6361
// CHECK-SAME: align 16
6462
// CHECK-SAME: dereferenceable(32) %x
65-
// CHECK: [[LOAD:%.*]] = load volatile %ScalarPair, ptr %x, align 16
66-
// CHECK-NEXT: store %ScalarPair [[LOAD]], ptr %_0, align 16
63+
// CHECK: [[LOAD:%.*]] = load volatile i256, ptr %x, align 16
64+
// CHECK-NEXT: store i256 [[LOAD]], ptr %_0, align 16
6765
// CHECK-NEXT: ret void
6866
unsafe { std::intrinsics::volatile_load(x) }
6967
}

tests/codegen-llvm/intrinsics/volatile.rs

Lines changed: 117 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55

66
use std::intrinsics;
77

8+
#[repr(align(32))]
9+
pub struct CustomZst;
10+
11+
type UninitFatPointer = std::mem::MaybeUninit<&'static dyn std::fmt::Debug>;
12+
813
// CHECK-LABEL: @volatile_copy_memory
914
#[no_mangle]
1015
pub unsafe fn volatile_copy_memory(a: *mut u8, b: *const u8) {
@@ -28,8 +33,62 @@ pub unsafe fn volatile_set_memory(a: *mut u8, b: u8) {
2833

2934
// CHECK-LABEL: @volatile_load
3035
#[no_mangle]
31-
pub unsafe fn volatile_load(a: *const u8) -> u8 {
32-
// CHECK: load volatile
36+
pub unsafe fn volatile_load(a: *const u16) -> u16 {
37+
// CHECK: [[TEMP:%.+]] = load volatile i16, ptr %a
38+
// CHECK-SAME: align 2{{,|$}}
39+
// CHECK-NEXT: ret i16 [[TEMP]]
40+
intrinsics::volatile_load(a)
41+
}
42+
43+
// CHECK-LABEL: @volatile_load_bool
44+
#[no_mangle]
45+
pub unsafe fn volatile_load_bool(a: *const bool) -> bool {
46+
// CHECK: [[TEMP:%.+]] = load volatile i8, ptr %a
47+
// CHECK-SAME: align 1{{,|$}}
48+
// CHECK: [[TRUNC:%.+]] = trunc nuw i8 [[TEMP]] to i1
49+
// CHECK: ret i1 [[TRUNC]]
50+
intrinsics::volatile_load(a)
51+
}
52+
53+
// CHECK-LABEL: @volatile_load_zst
54+
#[no_mangle]
55+
pub unsafe fn volatile_load_zst(a: *const CustomZst) -> CustomZst {
56+
// CHECK: start:
57+
// CHECK-NEXT: ret void
58+
intrinsics::volatile_load(a)
59+
}
60+
61+
// CHECK-LABEL: @volatile_load_array
62+
// CHECK-SAME: ptr{{.+}}sret([16 x i8]){{.+}}%_0
63+
#[no_mangle]
64+
pub unsafe fn volatile_load_array(a: *const [u16; 8]) -> [u16; 8] {
65+
// CHECK-NOT: alloca
66+
// CHECK: [[TEMP:%.+]] = load volatile i128, ptr %a,
67+
// CHECK-SAME: align 2{{,|$}}
68+
// CHECK: store i128 [[TEMP]], ptr %_0,
69+
// CHECK-SAME: align 2{{,|$}}
70+
// CHECK-NEXT: ret void
71+
intrinsics::volatile_load(a)
72+
}
73+
74+
// CHECK-LABEL: @volatile_load_fat
75+
#[no_mangle]
76+
pub unsafe fn volatile_load_fat(a: *const UninitFatPointer) -> UninitFatPointer {
77+
// CHECK: [[ALLOCA:%.+]] = alloca
78+
// CHECK-SAME: [[SIZE:4|8|16]] x i8
79+
// CHECK-SAME: align [[ALIGN:2|4|8]]
80+
81+
// CHECK: [[TEMP:%.+]] = load volatile [[INT:i32|i64|i128]], ptr %a,
82+
// CHECK-SAME: align [[ALIGN]]{{,|$}}
83+
// CHECK: store [[INT]] [[TEMP]], ptr [[ALLOCA]],
84+
// CHECK-SAME: align [[ALIGN]]{{,|$}}
85+
86+
// CHECK: [[T0:%.+]] = load ptr, ptr [[ALLOCA]], align [[ALIGN]]
87+
// CHECK: [[T1:%.+]] = getelementptr inbounds i8, ptr [[ALLOCA]]
88+
// CHECK: [[T2:%.+]] = load ptr, ptr [[T1]], align [[ALIGN]]
89+
// CHECK: [[P1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[T0]], 0
90+
// CHECK: [[P2:%.+]] = insertvalue { ptr, ptr } [[P1]], ptr [[T2]], 1
91+
// CHECK: ret { ptr, ptr } [[P2]]
3392
intrinsics::volatile_load(a)
3493
}
3594

@@ -42,8 +101,62 @@ pub unsafe fn volatile_store(a: *mut u8, b: u8) {
42101

43102
// CHECK-LABEL: @unaligned_volatile_load
44103
#[no_mangle]
45-
pub unsafe fn unaligned_volatile_load(a: *const u8) -> u8 {
46-
// CHECK: load volatile
104+
pub unsafe fn unaligned_volatile_load(a: *const u16) -> u16 {
105+
// CHECK: [[TEMP:%.+]] = load volatile i16, ptr %a
106+
// CHECK-SAME: align 1{{,|$}}
107+
// CHECK-NEXT: ret i16 [[TEMP]]
108+
intrinsics::unaligned_volatile_load(a)
109+
}
110+
111+
// CHECK-LABEL: @unaligned_volatile_load_bool
112+
#[no_mangle]
113+
pub unsafe fn unaligned_volatile_load_bool(a: *const bool) -> bool {
114+
// CHECK: [[TEMP:%.+]] = load volatile i8, ptr %a
115+
// CHECK-SAME: align 1{{,|$}}
116+
// CHECK: [[TRUNC:%.+]] = trunc nuw i8 [[TEMP]] to i1
117+
// CHECK: ret i1 [[TRUNC]]
118+
intrinsics::unaligned_volatile_load(a)
119+
}
120+
121+
// CHECK-LABEL: @unaligned_volatile_load_zst
122+
#[no_mangle]
123+
pub unsafe fn unaligned_volatile_load_zst(a: *const CustomZst) -> CustomZst {
124+
// CHECK: start:
125+
// CHECK-NEXT: ret void
126+
intrinsics::unaligned_volatile_load(a)
127+
}
128+
129+
// CHECK-LABEL: @unaligned_volatile_load_array
130+
// CHECK-SAME: ptr{{.+}}sret([16 x i8]){{.+}}%_0,
131+
#[no_mangle]
132+
pub unsafe fn unaligned_volatile_load_array(a: *const [u16; 8]) -> [u16; 8] {
133+
// CHECK-NOT: alloca
134+
// CHECK: [[TEMP:%.+]] = load volatile i128, ptr %a,
135+
// CHECK-SAME: align 1{{,|$}}
136+
// CHECK: store i128 [[TEMP]], ptr %_0,
137+
// CHECK-SAME: align 2{{,|$}}
138+
// CHECK-NEXT: ret void
139+
intrinsics::unaligned_volatile_load(a)
140+
}
141+
142+
// CHECK-LABEL: @unaligned_volatile_load_fat
143+
#[no_mangle]
144+
pub unsafe fn unaligned_volatile_load_fat(a: *const UninitFatPointer) -> UninitFatPointer {
145+
// CHECK: [[ALLOCA:%.+]] = alloca
146+
// CHECK-SAME: [[SIZE]] x i8
147+
// CHECK-SAME: align [[ALIGN]]
148+
149+
// CHECK: [[TEMP:%.+]] = load volatile [[INT]], ptr %a,
150+
// CHECK-SAME: align 1{{,|$}}
151+
// CHECK: store [[INT]] [[TEMP]], ptr [[ALLOCA]],
152+
// CHECK-SAME: align [[ALIGN]]{{,|$}}
153+
154+
// CHECK: [[T0:%.+]] = load ptr, ptr [[ALLOCA]], align [[ALIGN]]
155+
// CHECK: [[T1:%.+]] = getelementptr inbounds i8, ptr [[ALLOCA]]
156+
// CHECK: [[T2:%.+]] = load ptr, ptr [[T1]], align [[ALIGN]]
157+
// CHECK: [[P1:%.+]] = insertvalue { ptr, ptr } poison, ptr [[T0]], 0
158+
// CHECK: [[P2:%.+]] = insertvalue { ptr, ptr } [[P1]], ptr [[T2]], 1
159+
// CHECK: ret { ptr, ptr } [[P2]]
47160
intrinsics::unaligned_volatile_load(a)
48161
}
49162

0 commit comments

Comments
 (0)