Skip to content

Commit c2d05ee

Browse files
Auto merge of #142771 - dianqk:mir-stmt-debuginfo, r=<try>
Introduce debuginfo to statements in MIR
2 parents 84a1747 + f1da428 commit c2d05ee

File tree

73 files changed

+2387
-547
lines changed

Some content is hidden

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

73 files changed

+2387
-547
lines changed

compiler/rustc_codegen_gcc/src/debuginfo.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,24 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
2929
_variable_alloca: Self::Value,
3030
_direct_offset: Size,
3131
_indirect_offsets: &[Size],
32-
_fragment: Option<Range<Size>>,
32+
_fragment: &Option<Range<Size>>,
3333
) {
3434
// FIXME(tempdragon): Not sure if this is correct, probably wrong but still keep it here.
3535
#[cfg(feature = "master")]
3636
_variable_alloca.set_location(_dbg_loc);
3737
}
3838

39+
fn dbg_var_value(
40+
&mut self,
41+
_dbg_var: Self::DIVariable,
42+
_dbg_loc: Self::DILocation,
43+
_value: Self::Value,
44+
_direct_offset: Size,
45+
_indirect_offsets: &[Size],
46+
_fragment: &Option<Range<Size>>,
47+
) {
48+
}
49+
3950
fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
4051
// TODO(antoyo): insert reference to gdb debug scripts section global.
4152
}

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: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
165165
variable_alloca: Self::Value,
166166
direct_offset: Size,
167167
indirect_offsets: &[Size],
168-
fragment: Option<Range<Size>>,
168+
fragment: &Option<Range<Size>>,
169169
) {
170170
use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
171171

@@ -192,7 +192,6 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
192192
}
193193

194194
unsafe {
195-
// FIXME(eddyb) replace `llvm.dbg.declare` with `llvm.dbg.addr`.
196195
llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
197196
DIB(self.cx()),
198197
variable_alloca,
@@ -205,6 +204,53 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
205204
}
206205
}
207206

207+
fn dbg_var_value(
208+
&mut self,
209+
dbg_var: &'ll DIVariable,
210+
dbg_loc: &'ll DILocation,
211+
value: Self::Value,
212+
direct_offset: Size,
213+
indirect_offsets: &[Size],
214+
fragment: &Option<Range<Size>>,
215+
) {
216+
use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst, DW_OP_stack_value};
217+
218+
// Convert the direct and indirect offsets and fragment byte range to address ops.
219+
let mut addr_ops = SmallVec::<[u64; 8]>::new();
220+
221+
if direct_offset.bytes() > 0 {
222+
addr_ops.push(DW_OP_plus_uconst);
223+
addr_ops.push(direct_offset.bytes() as u64);
224+
addr_ops.push(DW_OP_stack_value);
225+
}
226+
for &offset in indirect_offsets {
227+
addr_ops.push(DW_OP_deref);
228+
if offset.bytes() > 0 {
229+
addr_ops.push(DW_OP_plus_uconst);
230+
addr_ops.push(offset.bytes() as u64);
231+
}
232+
}
233+
if let Some(fragment) = fragment {
234+
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
235+
// offset and size, both of them in bits.
236+
addr_ops.push(DW_OP_LLVM_fragment);
237+
addr_ops.push(fragment.start.bits() as u64);
238+
addr_ops.push((fragment.end - fragment.start).bits() as u64);
239+
}
240+
241+
unsafe {
242+
llvm::LLVMRustDIBuilderInsertDbgValueAtEnd(
243+
DIB(self.cx()),
244+
value,
245+
dbg_var,
246+
addr_ops.as_ptr(),
247+
addr_ops.len() as c_uint,
248+
dbg_loc,
249+
self.llbb(),
250+
);
251+
}
252+
}
253+
208254
fn set_dbg_loc(&mut self, dbg_loc: &'ll DILocation) {
209255
unsafe {
210256
llvm::LLVMSetCurrentDebugLocation2(self.llbuilder, dbg_loc);

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2365,6 +2365,16 @@ unsafe extern "C" {
23652365
InsertAtEnd: &'a BasicBlock,
23662366
);
23672367

2368+
pub(crate) fn LLVMRustDIBuilderInsertDbgValueAtEnd<'a>(
2369+
Builder: &DIBuilder<'a>,
2370+
Val: &'a Value,
2371+
VarInfo: &'a DIVariable,
2372+
AddrOps: *const u64,
2373+
AddrOpsCount: c_uint,
2374+
DL: &'a DILocation,
2375+
InsertAtEnd: &'a BasicBlock,
2376+
);
2377+
23682378
pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>(
23692379
Builder: &DIBuilder<'a>,
23702380
Name: *const c_char,

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer
264264
PlaceContext::MutatingUse(MutatingUseContext::Yield) => bug!(),
265265
}
266266
}
267+
268+
fn visit_statement_debuginfo(&mut self, _: &mir::StmtDebugInfo<'tcx>, _: Location) {
269+
// Debuginfo does not generate actual code.
270+
}
267271
}
268272

269273
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

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: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,54 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
253253
spill_slot
254254
}
255255

256+
// Indicates that local is set to a new value. The `layout` and `projection` are used to
257+
// calculate the offset.
258+
pub(crate) fn debug_new_val_to_local(
259+
&self,
260+
bx: &mut Bx,
261+
local: mir::Local,
262+
base: PlaceValue<Bx::Value>,
263+
layout: TyAndLayout<'tcx>,
264+
projection: &[mir::PlaceElem<'tcx>],
265+
) {
266+
let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
267+
if !full_debug_info {
268+
return;
269+
}
270+
271+
let vars = match &self.per_local_var_debug_info {
272+
Some(per_local) => &per_local[local],
273+
None => return,
274+
};
275+
276+
let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
277+
calculate_debuginfo_offset(bx, projection, layout);
278+
for var in vars.iter() {
279+
let Some(dbg_var) = var.dbg_var else {
280+
continue;
281+
};
282+
let Some(dbg_loc) = self.dbg_loc(var.source_info) else {
283+
continue;
284+
};
285+
bx.dbg_var_value(
286+
dbg_var,
287+
dbg_loc,
288+
base.llval,
289+
direct_offset,
290+
&indirect_offsets,
291+
&var.fragment,
292+
);
293+
}
294+
}
295+
296+
pub(crate) fn debug_poison_to_local(&self, bx: &mut Bx, local: mir::Local) {
297+
let ty = self.monomorphize(self.mir.local_decls[local].ty);
298+
let layout = bx.cx().layout_of(ty);
299+
let to_backend_ty = bx.cx().immediate_backend_type(layout);
300+
let place_ref = PlaceRef::new_sized(bx.cx().const_poison(to_backend_ty), layout);
301+
self.debug_new_val_to_local(bx, local, place_ref.val, layout, &[]);
302+
}
303+
256304
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
257305
/// or initializing the local with an operand (whichever applies).
258306
pub(crate) fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
@@ -424,7 +472,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
424472
alloca.val.llval,
425473
Size::ZERO,
426474
&[Size::ZERO],
427-
var.fragment,
475+
&var.fragment,
428476
);
429477
} else {
430478
bx.dbg_var_addr(
@@ -433,7 +481,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
433481
base.val.llval,
434482
direct_offset,
435483
&indirect_offsets,
436-
var.fragment,
484+
&var.fragment,
437485
);
438486
}
439487
}
@@ -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, base.val.llval, Size::ZERO, &[], &fragment);
459507
}
460508
}
461509
}

compiler/rustc_codegen_ssa/src/mir/operand.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,23 @@ pub enum OperandValue<V> {
7171
}
7272

7373
impl<V: CodegenObject> OperandValue<V> {
74+
/// Return the data pointer and optional metadata as backend values
75+
/// if this value can be treat as a pointer.
76+
pub(crate) fn try_pointer_parts(self) -> Option<(V, Option<V>)> {
77+
match self {
78+
OperandValue::Immediate(llptr) => Some((llptr, None)),
79+
OperandValue::Pair(llptr, llextra) => Some((llptr, Some(llextra))),
80+
OperandValue::Ref(_) | OperandValue::ZeroSized => None,
81+
}
82+
}
83+
7484
/// Treat this value as a pointer and return the data pointer and
7585
/// optional metadata as backend values.
7686
///
7787
/// If you're making a place, use [`Self::deref`] instead.
7888
pub(crate) fn pointer_parts(self) -> (V, Option<V>) {
79-
match self {
80-
OperandValue::Immediate(llptr) => (llptr, None),
81-
OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
82-
_ => bug!("OperandValue cannot be a pointer: {self:?}"),
83-
}
89+
self.try_pointer_parts()
90+
.unwrap_or_else(|| bug!("OperandValue cannot be a pointer: {self:?}"))
8491
}
8592

8693
/// Treat this value as a pointer and return the place to which it points.

compiler/rustc_codegen_ssa/src/mir/statement.rs

Lines changed: 71 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, RETURN_PLACE, StmtDebugInfo};
2+
use rustc_middle::{bug, span_bug};
3+
use rustc_target::callconv::PassMode;
34
use tracing::instrument;
45

56
use super::{FunctionCx, LocalRef};
7+
use crate::common::TypeKind;
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)) => {
@@ -101,4 +105,69 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
101105
| mir::StatementKind::Nop => {}
102106
}
103107
}
108+
109+
pub(crate) fn codegen_stmt_debuginfo(&mut self, bx: &mut Bx, debuginfo: &StmtDebugInfo<'tcx>) {
110+
match debuginfo {
111+
StmtDebugInfo::AssignRef(dest, place) => {
112+
let local_ref = match self.locals[place.local] {
113+
LocalRef::Place(place_ref) | LocalRef::UnsizedPlace(place_ref) => {
114+
Some(place_ref)
115+
}
116+
LocalRef::Operand(operand_ref) => operand_ref
117+
.val
118+
.try_pointer_parts()
119+
.map(|(pointer, _)| PlaceRef::new_sized(pointer, operand_ref.layout)),
120+
LocalRef::PendingOperand => None,
121+
}
122+
.filter(|place_ref| {
123+
// For the reference of an argument (e.x. `&_1`), it's only valid if the pass mode is indirect, and its reference is
124+
// llval.
125+
let local_ref_pass_mode = place.as_local().and_then(|local| {
126+
if local == RETURN_PLACE {
127+
None
128+
} else {
129+
self.fn_abi.args.get(local.as_usize() - 1).map(|arg| &arg.mode)
130+
}
131+
});
132+
matches!(local_ref_pass_mode, Some(&PassMode::Indirect {..}) | None) &&
133+
// Drop unsupported projections.
134+
place.projection.iter().all(|p| p.can_use_in_debuginfo()) &&
135+
// Only pointers can be calculated addresses.
136+
bx.type_kind(bx.val_ty(place_ref.val.llval)) == TypeKind::Pointer
137+
});
138+
if let Some(local_ref) = local_ref {
139+
let (base_layout, projection) = if place.is_indirect_first_projection() {
140+
// For `_n = &((*_1).0: i32);`, we are calculating the address of `_1.0`, so
141+
// we should drop the deref projection.
142+
let projected_ty = local_ref
143+
.layout
144+
.ty
145+
.builtin_deref(true)
146+
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", local_ref));
147+
let layout = bx.cx().layout_of(projected_ty);
148+
(layout, &place.projection[1..])
149+
} else {
150+
(local_ref.layout, place.projection.as_slice())
151+
};
152+
self.debug_new_val_to_local(bx, *dest, local_ref.val, base_layout, projection);
153+
} else {
154+
// If the address cannot be computed, use poison to indicate that the value has been optimized out.
155+
self.debug_poison_to_local(bx, *dest);
156+
}
157+
}
158+
StmtDebugInfo::InvalidAssign(local) => {
159+
self.debug_poison_to_local(bx, *local);
160+
}
161+
}
162+
}
163+
164+
pub(crate) fn codegen_stmt_debuginfos(
165+
&mut self,
166+
bx: &mut Bx,
167+
debuginfos: &[StmtDebugInfo<'tcx>],
168+
) {
169+
for debuginfo in debuginfos {
170+
self.codegen_stmt_debuginfo(bx, debuginfo);
171+
}
172+
}
104173
}

compiler/rustc_codegen_ssa/src/traits/debuginfo.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,19 @@ pub trait DebugInfoBuilderMethods: BackendTypes {
7777
indirect_offsets: &[Size],
7878
// Byte range in the `dbg_var` covered by this fragment,
7979
// if this is a fragment of a composite `DIVariable`.
80-
fragment: Option<Range<Size>>,
80+
fragment: &Option<Range<Size>>,
81+
);
82+
fn dbg_var_value(
83+
&mut self,
84+
dbg_var: Self::DIVariable,
85+
dbg_loc: Self::DILocation,
86+
value: Self::Value,
87+
direct_offset: Size,
88+
// NB: each offset implies a deref (i.e. they're steps in a pointer chain).
89+
indirect_offsets: &[Size],
90+
// Byte range in the `dbg_var` covered by this fragment,
91+
// if this is a fragment of a composite `DIVariable`.
92+
fragment: &Option<Range<Size>>,
8193
);
8294
fn set_dbg_loc(&mut self, dbg_loc: Self::DILocation);
8395
fn clear_dbg_loc(&mut self);

0 commit comments

Comments
 (0)