Skip to content

Commit 0ce4452

Browse files
committed
rustc_codegen_llvm: add support for inlined function debuginfo.
1 parent 7374995 commit 0ce4452

File tree

5 files changed

+137
-64
lines changed

5 files changed

+137
-64
lines changed

compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,26 @@ use super::utils::DIB;
33
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
44
use rustc_codegen_ssa::traits::*;
55

6+
use crate::abi::FnAbi;
67
use crate::common::CodegenCx;
78
use crate::llvm;
8-
use crate::llvm::debuginfo::DIScope;
9+
use crate::llvm::debuginfo::{DILocation, DIScope};
910
use rustc_middle::mir::{Body, SourceScope};
11+
use rustc_middle::ty::layout::FnAbiExt;
12+
use rustc_middle::ty::{self, Instance};
1013
use rustc_session::config::DebugInfo;
1114

1215
use rustc_index::bit_set::BitSet;
1316
use rustc_index::vec::Idx;
1417

1518
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
19+
// FIXME(eddyb) almost all of this should be in `rustc_codegen_ssa::mir::debuginfo`.
1620
pub fn compute_mir_scopes(
17-
cx: &CodegenCx<'ll, '_>,
18-
mir: &Body<'_>,
21+
cx: &CodegenCx<'ll, 'tcx>,
22+
instance: Instance<'tcx>,
23+
mir: &Body<'tcx>,
1924
fn_dbg_scope: &'ll DIScope,
20-
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
25+
debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
2126
) {
2227
// Find all the scopes with variables defined in them.
2328
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
@@ -37,16 +42,17 @@ pub fn compute_mir_scopes(
3742
// Instantiate all scopes.
3843
for idx in 0..mir.source_scopes.len() {
3944
let scope = SourceScope::new(idx);
40-
make_mir_scope(cx, &mir, fn_dbg_scope, &has_variables, debug_context, scope);
45+
make_mir_scope(cx, instance, &mir, fn_dbg_scope, &has_variables, debug_context, scope);
4146
}
4247
}
4348

4449
fn make_mir_scope(
45-
cx: &CodegenCx<'ll, '_>,
46-
mir: &Body<'_>,
50+
cx: &CodegenCx<'ll, 'tcx>,
51+
instance: Instance<'tcx>,
52+
mir: &Body<'tcx>,
4753
fn_dbg_scope: &'ll DIScope,
4854
has_variables: &BitSet<SourceScope>,
49-
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
55+
debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
5056
scope: SourceScope,
5157
) {
5258
if debug_context.scopes[scope].dbg_scope.is_some() {
@@ -55,40 +61,63 @@ fn make_mir_scope(
5561

5662
let scope_data = &mir.source_scopes[scope];
5763
let parent_scope = if let Some(parent) = scope_data.parent_scope {
58-
make_mir_scope(cx, mir, fn_dbg_scope, has_variables, debug_context, parent);
64+
make_mir_scope(cx, instance, mir, fn_dbg_scope, has_variables, debug_context, parent);
5965
debug_context.scopes[parent]
6066
} else {
6167
// The root is the function itself.
6268
let loc = cx.lookup_debug_loc(mir.span.lo());
6369
debug_context.scopes[scope] = DebugScope {
6470
dbg_scope: Some(fn_dbg_scope),
71+
inlined_at: None,
6572
file_start_pos: loc.file.start_pos,
6673
file_end_pos: loc.file.end_pos,
6774
};
6875
return;
6976
};
7077

71-
if !has_variables.contains(scope) {
72-
// Do not create a DIScope if there are no variables
73-
// defined in this MIR Scope, to avoid debuginfo bloat.
78+
if !has_variables.contains(scope) && scope_data.inlined.is_none() {
79+
// Do not create a DIScope if there are no variables defined in this
80+
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
7481
debug_context.scopes[scope] = parent_scope;
7582
return;
7683
}
7784

7885
let loc = cx.lookup_debug_loc(scope_data.span.lo());
7986
let file_metadata = file_metadata(cx, &loc.file);
8087

81-
let dbg_scope = unsafe {
82-
Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
83-
DIB(cx),
84-
parent_scope.dbg_scope.unwrap(),
85-
file_metadata,
86-
loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
87-
loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
88-
))
88+
let dbg_scope = match scope_data.inlined {
89+
Some((callee, _)) => {
90+
// FIXME(eddyb) this would be `self.monomorphize(&callee)`
91+
// if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
92+
let callee = cx.tcx.subst_and_normalize_erasing_regions(
93+
instance.substs,
94+
ty::ParamEnv::reveal_all(),
95+
&callee,
96+
);
97+
let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]);
98+
cx.dbg_scope_fn(callee, &callee_fn_abi, None)
99+
}
100+
None => unsafe {
101+
llvm::LLVMRustDIBuilderCreateLexicalBlock(
102+
DIB(cx),
103+
parent_scope.dbg_scope.unwrap(),
104+
file_metadata,
105+
loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
106+
loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
107+
)
108+
},
89109
};
110+
111+
let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
112+
// FIXME(eddyb) this doesn't account for the macro-related
113+
// `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
114+
let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
115+
cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
116+
});
117+
90118
debug_context.scopes[scope] = DebugScope {
91-
dbg_scope,
119+
dbg_scope: Some(dbg_scope),
120+
inlined_at: inlined_at.or(parent_scope.inlined_at),
92121
file_start_pos: loc.file.start_pos,
93122
file_end_pos: loc.file.end_pos,
94123
};

compiler/rustc_codegen_llvm/src/debuginfo/mod.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,22 +265,27 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
265265
instance: Instance<'tcx>,
266266
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
267267
llfn: &'ll Value,
268-
mir: &mir::Body<'_>,
269-
) -> Option<FunctionDebugContext<&'ll DIScope>> {
268+
mir: &mir::Body<'tcx>,
269+
) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> {
270270
if self.sess().opts.debuginfo == DebugInfo::None {
271271
return None;
272272
}
273273

274274
// Initialize fn debug context (including scopes).
275275
// FIXME(eddyb) figure out a way to not need `Option` for `dbg_scope`.
276-
let empty_scope =
277-
DebugScope { dbg_scope: None, file_start_pos: BytePos(0), file_end_pos: BytePos(0) };
276+
let empty_scope = DebugScope {
277+
dbg_scope: None,
278+
inlined_at: None,
279+
file_start_pos: BytePos(0),
280+
file_end_pos: BytePos(0),
281+
};
278282
let mut fn_debug_context =
279283
FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) };
280284

281285
// Fill in all the scopes, with the information from the MIR body.
282286
compute_mir_scopes(
283287
self,
288+
instance,
284289
mir,
285290
self.dbg_scope_fn(instance, fn_abi, Some(llfn)),
286291
&mut fn_debug_context,
@@ -537,7 +542,12 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
537542
}
538543
}
539544

540-
fn dbg_loc(&self, scope: &'ll DIScope, span: Span) -> &'ll DILocation {
545+
fn dbg_loc(
546+
&self,
547+
scope: &'ll DIScope,
548+
inlined_at: Option<&'ll DILocation>,
549+
span: Span,
550+
) -> &'ll DILocation {
541551
let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo());
542552

543553
unsafe {
@@ -546,7 +556,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
546556
line.unwrap_or(UNKNOWN_LINE_NUMBER),
547557
col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
548558
scope,
549-
None,
559+
inlined_at,
550560
)
551561
}
552562
}

compiler/rustc_codegen_ssa/src/mir/debuginfo.rs

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use super::operand::OperandValue;
1212
use super::place::PlaceRef;
1313
use super::{FunctionCx, LocalRef};
1414

15-
pub struct FunctionDebugContext<D> {
16-
pub scopes: IndexVec<mir::SourceScope, DebugScope<D>>,
15+
pub struct FunctionDebugContext<S, L> {
16+
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
1717
}
1818

1919
#[derive(Copy, Clone)]
@@ -36,15 +36,42 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
3636
}
3737

3838
#[derive(Clone, Copy, Debug)]
39-
pub struct DebugScope<D> {
39+
pub struct DebugScope<S, L> {
4040
// FIXME(eddyb) this should never be `None`, after initialization.
41-
pub dbg_scope: Option<D>,
41+
pub dbg_scope: Option<S>,
42+
43+
/// Call site location, if this scope was inlined from another function.
44+
pub inlined_at: Option<L>,
45+
4246
// Start and end offsets of the file to which this DIScope belongs.
4347
// These are used to quickly determine whether some span refers to the same file.
4448
pub file_start_pos: BytePos,
4549
pub file_end_pos: BytePos,
4650
}
4751

52+
impl<'tcx, S: Copy, L: Copy> DebugScope<S, L> {
53+
/// DILocations inherit source file name from the parent DIScope. Due to macro expansions
54+
/// it may so happen that the current span belongs to a different file than the DIScope
55+
/// corresponding to span's containing source scope. If so, we need to create a DIScope
56+
/// "extension" into that file.
57+
pub fn adjust_dbg_scope_for_span<Cx: CodegenMethods<'tcx, DIScope = S, DILocation = L>>(
58+
&self,
59+
cx: &Cx,
60+
span: Span,
61+
) -> S {
62+
// FIXME(eddyb) this should never be `None`.
63+
let dbg_scope = self.dbg_scope.unwrap();
64+
65+
let pos = span.lo();
66+
if pos < self.file_start_pos || pos >= self.file_end_pos {
67+
let sm = cx.sess().source_map();
68+
cx.extend_scope_to_file(dbg_scope, &sm.lookup_char_pos(pos).file)
69+
} else {
70+
dbg_scope
71+
}
72+
}
73+
}
74+
4875
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
4976
pub fn set_debug_loc(&self, bx: &mut Bx, source_info: mir::SourceInfo) {
5077
bx.set_span(source_info.span);
@@ -54,19 +81,21 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
5481
}
5582

5683
fn dbg_loc(&self, source_info: mir::SourceInfo) -> Option<Bx::DILocation> {
57-
let (scope, span) = self.dbg_scope_and_span(source_info)?;
58-
Some(self.cx.dbg_loc(scope, span))
84+
let span = self.adjust_span_for_debugging(source_info.span);
85+
let scope = &self.debug_context.as_ref()?.scopes[source_info.scope];
86+
let dbg_scope = scope.adjust_dbg_scope_for_span(self.cx, span);
87+
Some(self.cx.dbg_loc(dbg_scope, scope.inlined_at, span))
5988
}
6089

61-
fn dbg_scope_and_span(&self, source_info: mir::SourceInfo) -> Option<(Bx::DIScope, Span)> {
90+
/// In order to have a good line stepping behavior in debugger, we overwrite debug
91+
/// locations of macro expansions with that of the outermost expansion site
92+
/// (unless the crate is being compiled with `-Z debug-macros`).
93+
fn adjust_span_for_debugging(&self, mut span: Span) -> Span {
6294
// Bail out if debug info emission is not enabled.
63-
let debug_context = self.debug_context.as_ref()?;
64-
let scope = &debug_context.scopes[source_info.scope];
95+
if self.debug_context.is_none() {
96+
return span;
97+
}
6598

66-
// In order to have a good line stepping behavior in debugger, we overwrite debug
67-
// locations of macro expansions with that of the outermost expansion site
68-
// (unless the crate is being compiled with `-Z debug-macros`).
69-
let mut span = source_info.span;
7099
if span.from_expansion() && !self.cx.sess().opts.debugging_opts.debug_macros {
71100
// Walk up the macro expansion chain until we reach a non-expanded span.
72101
// We also stop at the function body level because no line stepping can occur
@@ -75,20 +104,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
75104
span = rustc_span::hygiene::walk_chain(span, self.mir.span.ctxt());
76105
}
77106

78-
// FIXME(eddyb) this should never be `None`.
79-
let mut dbg_scope = scope.dbg_scope?;
80-
81-
// DILocations inherit source file name from the parent DIScope. Due to macro expansions
82-
// it may so happen that the current span belongs to a different file than the DIScope
83-
// corresponding to span's containing source scope. If so, we need to create a DIScope
84-
// "extension" into that file.
85-
let pos = span.lo();
86-
if pos < scope.file_start_pos || pos >= scope.file_end_pos {
87-
let sm = self.cx.sess().source_map();
88-
dbg_scope = self.cx.extend_scope_to_file(dbg_scope, &sm.lookup_char_pos(pos).file);
89-
}
90-
91-
Some((dbg_scope, span))
107+
span
92108
}
93109

94110
/// Apply debuginfo and/or name, after creating the `alloca` for a local,
@@ -130,11 +146,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
130146
let name = kw::Invalid;
131147
let decl = &self.mir.local_decls[local];
132148
let dbg_var = if full_debug_info {
133-
self.dbg_scope_and_span(decl.source_info).map(|(scope, span)| {
149+
self.debug_context.as_ref().map(|debug_context| {
134150
// FIXME(eddyb) is this `+ 1` needed at all?
135151
let kind = VariableKind::ArgumentVariable(arg_index + 1);
136152

137-
self.cx.create_dbg_var(name, self.monomorphize(&decl.ty), scope, kind, span)
153+
let arg_ty = self.monomorphize(&decl.ty);
154+
155+
let span = self.adjust_span_for_debugging(decl.source_info.span);
156+
let scope = &debug_context.scopes[decl.source_info.scope];
157+
let dbg_scope = scope.adjust_dbg_scope_for_span(self.cx, span);
158+
159+
self.cx.create_dbg_var(name, arg_ty, dbg_scope, kind, span)
138160
})
139161
} else {
140162
None
@@ -288,9 +310,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
288310

289311
let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls);
290312
for var in &self.mir.var_debug_info {
291-
let scope_and_span =
292-
if full_debug_info { self.dbg_scope_and_span(var.source_info) } else { None };
293-
let dbg_var = scope_and_span.map(|(scope, span)| {
313+
let dbg_scope_and_span = if full_debug_info {
314+
self.debug_context.as_ref().map(|debug_context| {
315+
let span = self.adjust_span_for_debugging(var.source_info.span);
316+
let scope = &debug_context.scopes[var.source_info.scope];
317+
(scope.adjust_dbg_scope_for_span(self.cx, span), span)
318+
})
319+
} else {
320+
None
321+
};
322+
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, span)| {
294323
let place = var.place;
295324
let var_ty = self.monomorphized_place_ty(place.as_ref());
296325
let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
@@ -306,7 +335,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
306335
} else {
307336
VariableKind::LocalVariable
308337
};
309-
self.cx.create_dbg_var(var.name, var_ty, scope, var_kind, span)
338+
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
310339
});
311340

312341
per_local[var.place.local].push(PerLocalVarDebugInfo {

compiler/rustc_codegen_ssa/src/mir/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
2626

2727
mir: &'tcx mir::Body<'tcx>,
2828

29-
debug_context: Option<FunctionDebugContext<Bx::DIScope>>,
29+
debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>,
3030

3131
llfn: Bx::Function,
3232

compiler/rustc_codegen_ssa/src/traits/debuginfo.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
1818
instance: Instance<'tcx>,
1919
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
2020
llfn: Self::Function,
21-
mir: &mir::Body<'_>,
22-
) -> Option<FunctionDebugContext<Self::DIScope>>;
21+
mir: &mir::Body<'tcx>,
22+
) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>;
2323

2424
// FIXME(eddyb) find a common convention for all of the debuginfo-related
2525
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
@@ -30,7 +30,12 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
3030
maybe_definition_llfn: Option<Self::Function>,
3131
) -> Self::DIScope;
3232

33-
fn dbg_loc(&self, scope: Self::DIScope, span: Span) -> Self::DILocation;
33+
fn dbg_loc(
34+
&self,
35+
scope: Self::DIScope,
36+
inlined_at: Option<Self::DILocation>,
37+
span: Span,
38+
) -> Self::DILocation;
3439

3540
fn extend_scope_to_file(
3641
&self,

0 commit comments

Comments
 (0)