Skip to content

Commit 7253057

Browse files
committed
Don't generate pointer loads to spills unless necessary
In order for LLVM to correctly generate debuginfo for msvc, we sometimes need to spill arguments to the stack and perform some direct & indirect offsets into the value. Previously, this code always performed those actions, even when not required as LLVM would clean it up during optimization. However, when MIR inlining is enabled, this can cause problems as the operations occur prior to the spilled value being initialized. To solve this, we first calculate the necessary offsets using just the type which is side-effect free and does not alter the LLVM IR. Then, if we are in a situation which requires us to generate the LLVM IR (and this situation only occurs for arguments, not local variables) then we perform the same calculation again, this time generating the appropriate LLVM IR as we go.
1 parent b33d1e2 commit 7253057

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

+27-2
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
103103
}
104104
}
105105

106+
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
107+
for TyAndLayout<'tcx>
108+
{
109+
fn deref(&self, bx: &mut Bx) -> Self {
110+
bx.cx().layout_of(
111+
self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty,
112+
)
113+
}
114+
115+
fn layout(&self) -> TyAndLayout<'tcx> {
116+
*self
117+
}
118+
119+
fn project_field(&self, bx: &mut Bx, field: mir::Field) -> Self {
120+
self.field(bx.cx(), field.index())
121+
}
122+
123+
fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
124+
self.for_variant(bx.cx(), variant)
125+
}
126+
}
127+
106128
struct DebugInfoOffset<T> {
107129
/// Offset from the `base` used to calculate the debuginfo offset.
108130
direct_offset: Size,
@@ -340,8 +362,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
340362
let Some(dbg_var) = var.dbg_var else { continue };
341363
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
342364

343-
let DebugInfoOffset { direct_offset, indirect_offsets, result: place } =
344-
calculate_debuginfo_offset(bx, local, &var, base);
365+
let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
366+
calculate_debuginfo_offset(bx, local, &var, base.layout);
345367

346368
// When targeting MSVC, create extra allocas for arguments instead of pointing multiple
347369
// dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
@@ -359,6 +381,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
359381
|| !matches!(&indirect_offsets[..], [Size::ZERO] | []));
360382

361383
if should_create_individual_allocas {
384+
let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
385+
calculate_debuginfo_offset(bx, local, &var, base);
386+
362387
// Create a variable which will be a pointer to the actual value
363388
let ptr_ty = bx.tcx().mk_ty(ty::RawPtr(ty::TypeAndMut {
364389
mutbl: mir::Mutability::Mut,

src/test/codegen/issue-105386-ub-in-debuginfo.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ pub fn outer_function(x: S, y: S) -> usize {
1616
// when generating debuginfo.
1717
// CHECK-LABEL: @outer_function
1818
// CHECK: [[spill:%.*]] = alloca %"[closure@{{.*.rs}}:9:23: 9:25]"
19-
// CHECK: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
20-
// CHECK: [[load:%.*]] = load ptr, ptr [[ptr_tmp]]
19+
// CHECK-NOT: [[ptr_tmp:%.*]] = getelementptr inbounds %"[closure@{{.*.rs}}:9:23: 9:25]", ptr [[spill]]
20+
// CHECK-NOT: [[load:%.*]] = load ptr, ptr
2121
// CHECK: call void @llvm.lifetime.start{{.*}}({{.*}}, ptr [[spill]])
2222
// CHECK: call void @llvm.memcpy{{.*}}(ptr {{align .*}} [[spill]], ptr {{align .*}} %x
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// run-pass
2+
// compile-flags: --edition 2021 -Copt-level=3 -Cdebuginfo=2 -Zmir-opt-level=3
3+
4+
fn main() {
5+
TranslatorI.visit_pre();
6+
}
7+
8+
impl TranslatorI {
9+
fn visit_pre(self) {
10+
Some(())
11+
.map(|_| self.flags())
12+
.unwrap_or_else(|| self.flags());
13+
}
14+
}
15+
16+
struct TranslatorI;
17+
18+
impl TranslatorI {
19+
fn flags(&self) {}
20+
}

0 commit comments

Comments
 (0)