Skip to content

Commit 7a59bfd

Browse files
committed
Auto merge of #127168 - DianQK:cast-size, r=workingjubilee
Use the aligned size for alloca at args/ret when the pass mode is cast Fixes #75839. Fixes #121028. The `load` and `store` instructions in LLVM access the aligned size. For example, `load { i64, i32 }` accesses 16 bytes on x86_64: https://alive2.llvm.org/ce/z/n8CHAp. BTW, this example is expected to be optimized to immediate UB by Alive2: https://rust.godbolt.org/z/b7xK7hv1c and https://alive2.llvm.org/ce/z/vZDtZH. r? compiler
2 parents 7d97c59 + 2ef8280 commit 7a59bfd

File tree

7 files changed

+377
-35
lines changed

7 files changed

+377
-35
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,8 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
226226
// when passed by value, making it smaller.
227227
// - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
228228
// when passed by value, making it larger.
229-
let copy_bytes = cmp::min(scratch_size.bytes(), self.layout.size.bytes());
229+
let copy_bytes =
230+
cmp::min(cast.unaligned_size(bx).bytes(), self.layout.size.bytes());
230231
// Allocate some scratch space...
231232
let llscratch = bx.alloca(scratch_size, scratch_align);
232233
bx.lifetime_start(llscratch, scratch_size);

compiler/rustc_codegen_ssa/src/mir/block.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1521,7 +1521,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15211521
// when passed by value, making it smaller.
15221522
// - On some ABIs, the Rust layout { u16, u16, u16 } may be padded up to 8 bytes
15231523
// when passed by value, making it larger.
1524-
let copy_bytes = cmp::min(scratch_size.bytes(), arg.layout.size.bytes());
1524+
let copy_bytes = cmp::min(cast.unaligned_size(bx).bytes(), arg.layout.size.bytes());
15251525
// Allocate some scratch space...
15261526
let llscratch = bx.alloca(scratch_size, scratch_align);
15271527
bx.lifetime_start(llscratch, scratch_size);

compiler/rustc_codegen_ssa/src/mir/mod.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -230,10 +230,20 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
230230
let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
231231
assert!(!layout.ty.has_erasable_regions());
232232

233-
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
234-
debug!("alloc: {:?} (return place) -> place", local);
235-
let llretptr = start_bx.get_param(0);
236-
return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
233+
if local == mir::RETURN_PLACE {
234+
match fx.fn_abi.ret.mode {
235+
PassMode::Indirect { .. } => {
236+
debug!("alloc: {:?} (return place) -> place", local);
237+
let llretptr = start_bx.get_param(0);
238+
return LocalRef::Place(PlaceRef::new_sized(llretptr, layout));
239+
}
240+
PassMode::Cast { ref cast, .. } => {
241+
debug!("alloc: {:?} (return place) -> place", local);
242+
let size = cast.size(&start_bx);
243+
return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
244+
}
245+
_ => {}
246+
};
237247
}
238248

239249
if memory_locals.contains(local) {

compiler/rustc_codegen_ssa/src/mir/place.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,17 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
108108
pub fn alloca<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
109109
bx: &mut Bx,
110110
layout: TyAndLayout<'tcx>,
111+
) -> Self {
112+
Self::alloca_size(bx, layout.size, layout)
113+
}
114+
115+
pub fn alloca_size<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
116+
bx: &mut Bx,
117+
size: Size,
118+
layout: TyAndLayout<'tcx>,
111119
) -> Self {
112120
assert!(layout.is_sized(), "tried to statically allocate unsized place");
113-
PlaceValue::alloca(bx, layout.size, layout.align.abi).with_type(layout)
121+
PlaceValue::alloca(bx, size, layout.align.abi).with_type(layout)
114122
}
115123

116124
/// Returns a place for an indirect reference to an unsized place.

compiler/rustc_target/src/abi/call/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ impl CastTarget {
339339
}
340340
}
341341

342-
pub fn size<C: HasDataLayout>(&self, _cx: &C) -> Size {
342+
/// When you only access the range containing valid data, you can use this unaligned size;
343+
/// otherwise, use the safer `size` method.
344+
pub fn unaligned_size<C: HasDataLayout>(&self, _cx: &C) -> Size {
343345
// Prefix arguments are passed in specific designated registers
344346
let prefix_size = self
345347
.prefix
@@ -353,6 +355,10 @@ impl CastTarget {
353355
prefix_size + rest_size
354356
}
355357

358+
pub fn size<C: HasDataLayout>(&self, cx: &C) -> Size {
359+
self.unaligned_size(cx).align_to(self.align(cx))
360+
}
361+
356362
pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align {
357363
self.prefix
358364
.iter()

0 commit comments

Comments
 (0)