Skip to content

Commit eb83156

Browse files
Auto merge of #142771 - dianqk:mir-stmt-debuginfo, r=<try>
Introduce debuginfo to statements in MIR Not ready for reviewing. Something known: - [ ] Retain debuginfo when concatenating bbs - [ ] Document about when to drop debuginfos (don't be worse than the optimized LLVM IR) - [ ] Missing tests r? ghost
2 parents 18491d5 + 51576e7 commit eb83156

File tree

103 files changed

+2322
-1380
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+2322
-1380
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,12 +1162,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
11621162
let opt_assignment_rhs_span =
11631163
self.find_assignments(local).first().map(|&location| {
11641164
if let Some(mir::Statement {
1165-
source_info: _,
11661165
kind:
11671166
mir::StatementKind::Assign(box (
11681167
_,
11691168
mir::Rvalue::Use(mir::Operand::Copy(place)),
11701169
)),
1170+
..
11711171
}) = self.body[location.block].statements.get(location.statement_index)
11721172
{
11731173
self.body.local_decls[place.local].source_info.span

compiler/rustc_codegen_gcc/src/debuginfo.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,17 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
2626
&mut self,
2727
_dbg_var: Self::DIVariable,
2828
_dbg_loc: Self::DILocation,
29-
_variable_alloca: Self::Value,
29+
is_declared: bool,
30+
val: Self::Value,
3031
_direct_offset: Size,
3132
_indirect_offsets: &[Size],
3233
_fragment: Option<Range<Size>>,
3334
) {
3435
// FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here.
3536
#[cfg(feature = "master")]
36-
_variable_alloca.set_location(_dbg_loc);
37+
if is_declared {
38+
val.set_location(_dbg_loc);
39+
}
3740
}
3841

3942
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {

compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,6 @@ declare_constant!(DW_OP_plus_uconst: u64);
3535
/// Double-checked by a static assertion in `RustWrapper.cpp`.
3636
#[allow(non_upper_case_globals)]
3737
pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000;
38+
// It describes the actual value of a source variable which might not exist in registers or in memory.
39+
#[allow(non_upper_case_globals)]
40+
pub(crate) const DW_OP_stack_value: u64 = 0x9f;

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,46 +160,67 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
160160
&mut self,
161161
dbg_var: &'ll DIVariable,
162162
dbg_loc: &'ll DILocation,
163-
variable_alloca: Self::Value,
163+
is_declared: bool,
164+
val: Self::Value,
164165
direct_offset: Size,
165166
indirect_offsets: &[Size],
166167
fragment: Option<Range<Size>>,
167168
) {
168-
use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
169+
use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
169170

170171
// Convert the direct and indirect offsets and fragment byte range to address ops.
171172
let mut addr_ops = SmallVec::<[u64; 8]>::new();
173+
let mut need_stack_value = false;
172174

173175
if direct_offset.bytes() > 0 {
176+
need_stack_value = true;
174177
addr_ops.push(DW_OP_plus_uconst);
175178
addr_ops.push(direct_offset.bytes() as u64);
176179
}
177180
for &offset in indirect_offsets {
181+
need_stack_value = true;
178182
addr_ops.push(DW_OP_deref);
179183
if offset.bytes() > 0 {
180184
addr_ops.push(DW_OP_plus_uconst);
181185
addr_ops.push(offset.bytes() as u64);
182186
}
183187
}
184188
if let Some(fragment) = fragment {
189+
need_stack_value = true;
185190
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
186191
// offset and size, both of them in bits.
187192
addr_ops.push(DW_OP_LLVM_fragment);
188193
addr_ops.push(fragment.start.bits() as u64);
189194
addr_ops.push((fragment.end - fragment.start).bits() as u64);
190195
}
191196

192-
unsafe {
193-
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
194-
llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
195-
DIB(self.cx()),
196-
variable_alloca,
197-
dbg_var,
198-
addr_ops.as_ptr(),
199-
addr_ops.len() as c_uint,
200-
dbg_loc,
201-
self.llbb(),
202-
);
197+
if is_declared {
198+
unsafe {
199+
llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
200+
DIB(self.cx()),
201+
val,
202+
dbg_var,
203+
addr_ops.as_ptr(),
204+
addr_ops.len() as c_uint,
205+
dbg_loc,
206+
self.llbb(),
207+
);
208+
}
209+
} else {
210+
if need_stack_value {
211+
addr_ops.push(DW_OP_stack_value);
212+
}
213+
unsafe {
214+
llvm::LLVMRustDIBuilderInsertDbgValueAtEnd(
215+
DIB(self.cx()),
216+
val,
217+
dbg_var,
218+
addr_ops.as_ptr(),
219+
addr_ops.len() as c_uint,
220+
dbg_loc,
221+
self.llbb(),
222+
);
223+
}
203224
}
204225
}
205226

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2314,6 +2314,16 @@ unsafe extern "C" {
23142314
InsertAtEnd: &'a BasicBlock,
23152315
);
23162316

2317+
pub(crate) fn LLVMRustDIBuilderInsertDbgValueAtEnd<'a>(
2318+
Builder: &DIBuilder<'a>,
2319+
Val: &'a Value,
2320+
VarInfo: &'a DIVariable,
2321+
AddrOps: *const u64,
2322+
AddrOpsCount: c_uint,
2323+
DL: &'a DILocation,
2324+
InsertAtEnd: &'a BasicBlock,
2325+
);
2326+
23172327
pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>(
23182328
Builder: &DIBuilder<'a>,
23192329
Name: *const c_char,

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1317,6 +1317,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
13171317
for statement in &data.statements {
13181318
self.codegen_statement(bx, statement);
13191319
}
1320+
self.codegen_stmt_debuginfos(bx, &data.after_last_stmt_debuginfos);
13201321

13211322
let merging_succ = self.codegen_terminator(bx, bb, data.terminator());
13221323
if let MergingSucc::False = merging_succ {

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,52 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
253253
spill_slot
254254
}
255255

256+
pub(crate) fn debug_new_value_to_local(
257+
&self,
258+
bx: &mut Bx,
259+
local: mir::Local,
260+
base: PlaceValue<Bx::Value>,
261+
layout: TyAndLayout<'tcx>,
262+
projection: &[mir::PlaceElem<'tcx>],
263+
) {
264+
let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
265+
if !full_debug_info {
266+
return;
267+
}
268+
269+
let vars = match &self.per_local_var_debug_info {
270+
Some(per_local) => &per_local[local],
271+
None => return,
272+
};
273+
274+
for var in vars.iter().cloned() {
275+
self.debug_new_value_to_local_as_var(bx, base, layout, projection, var);
276+
}
277+
}
278+
279+
fn debug_new_value_to_local_as_var(
280+
&self,
281+
bx: &mut Bx,
282+
base: PlaceValue<Bx::Value>,
283+
layout: TyAndLayout<'tcx>,
284+
projection: &[mir::PlaceElem<'tcx>],
285+
var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
286+
) {
287+
let Some(dbg_var) = var.dbg_var else { return };
288+
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };
289+
let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
290+
calculate_debuginfo_offset(bx, projection, layout);
291+
bx.dbg_var_addr(
292+
dbg_var,
293+
dbg_loc,
294+
false,
295+
base.llval,
296+
direct_offset,
297+
&indirect_offsets,
298+
var.fragment,
299+
);
300+
}
301+
256302
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
257303
/// or initializing the local with an operand (whichever applies).
258304
pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
@@ -421,6 +467,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
421467
bx.dbg_var_addr(
422468
dbg_var,
423469
dbg_loc,
470+
true,
424471
alloca.val.llval,
425472
Size::ZERO,
426473
&[Size::ZERO],
@@ -430,6 +477,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
430477
bx.dbg_var_addr(
431478
dbg_var,
432479
dbg_loc,
480+
true,
433481
base.val.llval,
434482
direct_offset,
435483
&indirect_offsets,
@@ -455,7 +503,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
455503
let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx);
456504
bx.clear_dbg_loc();
457505

458-
bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], fragment);
506+
bx.dbg_var_addr(dbg_var, dbg_loc, true, base.val.llval, Size::ZERO, &[], fragment);
459507
}
460508
}
461509
}

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,15 +354,15 @@ fn optimize_use_clone<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
354354

355355
let destination_block = target.unwrap();
356356

357-
bb.statements.push(mir::Statement {
358-
source_info: bb.terminator().source_info,
359-
kind: mir::StatementKind::Assign(Box::new((
357+
bb.statements.push(mir::Statement::new(
358+
bb.terminator().source_info,
359+
mir::StatementKind::Assign(Box::new((
360360
*destination,
361361
mir::Rvalue::Use(mir::Operand::Copy(
362362
arg_place.project_deeper(&[mir::ProjectionElem::Deref], tcx),
363363
)),
364364
))),
365-
});
365+
));
366366

367367
bb.terminator_mut().kind = mir::TerminatorKind::Goto { target: destination_block };
368368
}

compiler/rustc_codegen_ssa/src/mir/statement.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
use rustc_middle::mir::{self, NonDivergingIntrinsic};
2-
use rustc_middle::span_bug;
1+
use rustc_middle::mir::{self, NonDivergingIntrinsic, StmtDebugInfo};
2+
use rustc_middle::{bug, span_bug};
33
use tracing::instrument;
44

55
use super::{FunctionCx, LocalRef};
6+
use crate::common::TypeKind;
7+
use crate::mir::operand::OperandValue;
8+
use crate::mir::place::PlaceRef;
69
use crate::traits::*;
710

811
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
912
#[instrument(level = "debug", skip(self, bx))]
1013
pub(crate) fn codegen_statement(&mut self, bx: &mut Bx, statement: &mir::Statement<'tcx>) {
14+
self.codegen_stmt_debuginfos(bx, &statement.debuginfos);
1115
self.set_debug_loc(bx, statement.source_info);
1216
match statement.kind {
1317
mir::StatementKind::Assign(box (ref place, ref rvalue)) => {
@@ -96,4 +100,68 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
96100
| mir::StatementKind::Nop => {}
97101
}
98102
}
103+
104+
pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) {
105+
match debuginfo {
106+
StmtDebugInfo::AssignRef(dest, place) => {
107+
let place_ref = match self.locals[place.local] {
108+
LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => {
109+
Some(place_ref)
110+
}
111+
LocalRef::Operand(operand_ref) => match operand_ref.val {
112+
OperandValue::Ref(_place_value) => {
113+
todo!("supports OperandValue::Ref")
114+
}
115+
OperandValue::Immediate(v) => {
116+
// FIXME: add ref to layout?
117+
Some(PlaceRef::new_sized(v, operand_ref.layout))
118+
}
119+
OperandValue::Pair(_, _) => None,
120+
OperandValue::ZeroSized => None,
121+
},
122+
LocalRef::PendingOperand => None,
123+
}
124+
.filter(|place_ref| {
125+
// Drop unsupported projections.
126+
// FIXME: Add a test case.
127+
place.projection.iter().all(|p| p.can_use_in_debuginfo()) &&
128+
// Only pointers can calculate addresses.
129+
bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer
130+
});
131+
let (val, layout, projection) =
132+
match (place_ref, place.is_indirect_first_projection()) {
133+
(Some(place_ref), false) => {
134+
(place_ref.val, place_ref.layout, place.projection.as_slice())
135+
}
136+
(Some(place_ref), true) => {
137+
let projected_ty =
138+
place_ref.layout.ty.builtin_deref(true).unwrap_or_else(|| {
139+
bug!("deref of non-pointer {:?}", place_ref)
140+
});
141+
let layout = bx.cx().layout_of(projected_ty);
142+
(place_ref.val, layout, &place.projection[1..])
143+
}
144+
_ => {
145+
// If the address cannot be computed, use poison to indicate that the value has been optimized out.
146+
let ty = self.monomorphize(self.mir.local_decls[*dest].ty);
147+
let layout = bx.cx().layout_of(ty);
148+
let to_backend_ty = bx.cx().immediate_backend_type(layout);
149+
let place_ref =
150+
PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout);
151+
(place_ref.val, layout, [].as_slice())
152+
}
153+
};
154+
self.debug_new_value_to_local(bx, *dest, val, layout, projection);
155+
}
156+
}
157+
}
158+
pub(crate) fn codegen_stmt_debuginfos(
159+
&mut self,
160+
bx: &mut Bx,
161+
debuginfos: &[StmtDebugInfo<'tcx>],
162+
) {
163+
for debuginfo in debuginfos {
164+
self.codegen_stmt_debuginfo(bx, debuginfo);
165+
}
166+
}
99167
}

compiler/rustc_codegen_ssa/src/traits/debuginfo.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
7171
&mut self,
7272
dbg_var: Self::DIVariable,
7373
dbg_loc: Self::DILocation,
74-
variable_alloca: Self::Value,
74+
is_declared: bool,
75+
val: Self::Value,
7576
direct_offset: Size,
7677
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
7778
indirect_offsets: &[Size],

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ using namespace llvm::object;
5858
// This opcode is an LLVM detail that could hypothetically change (?), so
5959
// verify that the hard-coded value in `dwarf_const.rs` still agrees with LLVM.
6060
static_assert(dwarf::DW_OP_LLVM_fragment == 0x1000);
61+
static_assert(dwarf::DW_OP_stack_value == 0x9f);
6162

6263
// LLVMAtomicOrdering is already an enum - don't create another
6364
// one.
@@ -1241,6 +1242,18 @@ LLVMRustDIBuilderInsertDeclareAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V,
12411242
DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd));
12421243
}
12431244

1245+
extern "C" void
1246+
LLVMRustDIBuilderInsertDbgValueAtEnd(LLVMDIBuilderRef Builder, LLVMValueRef V,
1247+
LLVMMetadataRef VarInfo, uint64_t *AddrOps,
1248+
unsigned AddrOpsCount, LLVMMetadataRef DL,
1249+
LLVMBasicBlockRef InsertAtEnd) {
1250+
unwrap(Builder)->insertDbgValueIntrinsic(
1251+
unwrap(V), unwrap<DILocalVariable>(VarInfo),
1252+
unwrap(Builder)->createExpression(
1253+
llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
1254+
DebugLoc(cast<MDNode>(unwrap(DL))), unwrap(InsertAtEnd));
1255+
}
1256+
12441257
extern "C" LLVMMetadataRef
12451258
LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name,
12461259
size_t NameLen, const uint64_t Value[2],

0 commit comments

Comments
 (0)