Skip to content

Commit e170e0a

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 f51c987 + 2a645c9 commit e170e0a

File tree

76 files changed

+1912
-845
lines changed

Some content is hidden

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

76 files changed

+1912
-845
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1162,7 +1162,6 @@ 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
_,

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: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -160,19 +160,23 @@ 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();
172173

173174
if direct_offset.bytes() > 0 {
174175
addr_ops.push(DW_OP_plus_uconst);
175176
addr_ops.push(direct_offset.bytes() as u64);
177+
if !is_declared {
178+
addr_ops.push(DW_OP_stack_value);
179+
}
176180
}
177181
for &offset in indirect_offsets {
178182
addr_ops.push(DW_OP_deref);
@@ -189,17 +193,30 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
189193
addr_ops.push((fragment.end - fragment.start).bits() as u64);
190194
}
191195

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-
);
196+
if is_declared {
197+
unsafe {
198+
llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
199+
DIB(self.cx()),
200+
val,
201+
dbg_var,
202+
addr_ops.as_ptr(),
203+
addr_ops.len() as c_uint,
204+
dbg_loc,
205+
self.llbb(),
206+
);
207+
}
208+
} else {
209+
unsafe {
210+
llvm::LLVMRustDIBuilderInsertDbgValueAtEnd(
211+
DIB(self.cx()),
212+
val,
213+
dbg_var,
214+
addr_ops.as_ptr(),
215+
addr_ops.len() as c_uint,
216+
dbg_loc,
217+
self.llbb(),
218+
);
219+
}
203220
}
204221
}
205222

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
@@ -1252,6 +1252,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12521252
for statement in &data.statements {
12531253
self.codegen_statement(bx, statement);
12541254
}
1255+
self.codegen_stmt_debuginfos(bx, &data.after_last_stmt_debuginfos);
12551256

12561257
let merging_succ = self.codegen_terminator(bx, bb, data.terminator());
12571258
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/statement.rs

Lines changed: 68 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,66 @@ 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::Immediate(v) => {
113+
Some(PlaceRef::new_sized(v, operand_ref.layout))
114+
}
115+
OperandValue::Ref(_)
116+
| OperandValue::Pair(_, _)
117+
| OperandValue::ZeroSized => None,
118+
},
119+
LocalRef::PendingOperand => None,
120+
}
121+
.filter(|place_ref| {
122+
// Drop unsupported projections.
123+
// FIXME: Add a test case.
124+
place.projection.iter().all(|p| p.can_use_in_debuginfo()) &&
125+
// Only pointers can calculate addresses.
126+
bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer
127+
});
128+
let (val, layout, projection) =
129+
match (place_ref, place.is_indirect_first_projection()) {
130+
(Some(place_ref), false) => {
131+
(place_ref.val, place_ref.layout, place.projection.as_slice())
132+
}
133+
(Some(place_ref), true) => {
134+
let projected_ty =
135+
place_ref.layout.ty.builtin_deref(true).unwrap_or_else(|| {
136+
bug!("deref of non-pointer {:?}", place_ref)
137+
});
138+
let layout = bx.cx().layout_of(projected_ty);
139+
(place_ref.val, layout, &place.projection[1..])
140+
}
141+
_ => {
142+
// If the address cannot be computed, use poison to indicate that the value has been optimized out.
143+
let ty = self.monomorphize(self.mir.local_decls[*dest].ty);
144+
let layout = bx.cx().layout_of(ty);
145+
let to_backend_ty = bx.cx().immediate_backend_type(layout);
146+
let place_ref =
147+
PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout);
148+
(place_ref.val, layout, [].as_slice())
149+
}
150+
};
151+
self.debug_new_value_to_local(bx, *dest, val, layout, projection);
152+
}
153+
}
154+
}
155+
156+
pub(crate) fn codegen_stmt_debuginfos(
157+
&mut self,
158+
bx: &mut Bx,
159+
debuginfos: &[StmtDebugInfo<'tcx>],
160+
) {
161+
for debuginfo in debuginfos {
162+
self.codegen_stmt_debuginfo(bx, debuginfo);
163+
}
164+
}
99165
}

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)