Skip to content

Commit f4b7477

Browse files
committed
rustc_codegen_ssa: convert mir::VarDebugInfo into a custom PerLocalVarDebugInfo.
1 parent 0b633c8 commit f4b7477

File tree

2 files changed

+133
-54
lines changed

2 files changed

+133
-54
lines changed

Diff for: src/librustc_codegen_ssa/mir/debuginfo.rs

+125-49
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use crate::traits::*;
22
use rustc::mir;
33
use rustc::session::config::DebugInfo;
4+
use rustc::ty;
45
use rustc::ty::layout::{LayoutOf, Size};
5-
use rustc::ty::TyCtxt;
66
use rustc_hir::def_id::CrateNum;
77
use rustc_index::vec::IndexVec;
88

9-
use rustc_span::symbol::kw;
9+
use rustc_span::symbol::{kw, Symbol};
1010
use rustc_span::{BytePos, Span};
1111

1212
use super::OperandValue;
@@ -24,6 +24,19 @@ pub enum VariableKind {
2424
LocalVariable,
2525
}
2626

27+
/// Like `mir::VarDebugInfo`, but within a `mir::Local`.
28+
#[derive(Copy, Clone)]
29+
pub struct PerLocalVarDebugInfo<'tcx, D> {
30+
pub name: Symbol,
31+
pub source_info: mir::SourceInfo,
32+
33+
/// `DIVariable` returned by `create_dbg_var`.
34+
pub dbg_var: Option<D>,
35+
36+
/// `.place.projection` from `mir::VarDebugInfo`.
37+
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
38+
}
39+
2740
#[derive(Clone, Copy, Debug)]
2841
pub struct DebugScope<D> {
2942
pub scope_metadata: Option<D>,
@@ -103,6 +116,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
103116
// FIXME(eddyb) use `llvm.dbg.value` (which would work for operands),
104117
// not just `llvm.dbg.declare` (which requires `alloca`).
105118
pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) {
119+
let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full;
120+
106121
// FIXME(eddyb) maybe name the return place as `_0` or `return`?
107122
if local == mir::RETURN_PLACE {
108123
return;
@@ -112,35 +127,63 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
112127
Some(per_local) => &per_local[local],
113128
None => return,
114129
};
115-
let whole_local_var = vars.iter().copied().find(|var| var.place.projection.is_empty());
116-
let has_proj = || vars.iter().any(|var| !var.place.projection.is_empty());
130+
let whole_local_var = vars.iter().find(|var| var.projection.is_empty()).copied();
131+
let has_proj = || vars.iter().any(|var| !var.projection.is_empty());
117132

118-
let (fallback_var, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg {
133+
let fallback_var = if self.mir.local_kind(local) == mir::LocalKind::Arg {
119134
let arg_index = local.index() - 1;
120135

121136
// Add debuginfo even to unnamed arguments.
122137
// FIXME(eddyb) is this really needed?
123-
let var = if arg_index == 0 && has_proj() {
138+
if arg_index == 0 && has_proj() {
124139
// Hide closure environments from debuginfo.
125140
// FIXME(eddyb) shouldn't `ArgumentVariable` indices
126141
// be offset to account for the hidden environment?
127142
None
143+
} else if whole_local_var.is_some() {
144+
// No need to make up anything, there is a `mir::VarDebugInfo`
145+
// covering the whole local.
146+
// FIXME(eddyb) take `whole_local_var.source_info.scope` into
147+
// account, just in case it doesn't use `ArgumentVariable`
148+
// (after #67586 gets fixed).
149+
None
128150
} else {
129-
Some(mir::VarDebugInfo {
130-
name: kw::Invalid,
131-
source_info: self.mir.local_decls[local].source_info,
132-
place: local.into(),
151+
let name = kw::Invalid;
152+
let decl = &self.mir.local_decls[local];
153+
let (scope, span) = if full_debug_info {
154+
self.debug_loc(decl.source_info)
155+
} else {
156+
(None, decl.source_info.span)
157+
};
158+
let dbg_var = scope.map(|scope| {
159+
// FIXME(eddyb) is this `+ 1` needed at all?
160+
let kind = VariableKind::ArgumentVariable(arg_index + 1);
161+
162+
self.cx.create_dbg_var(
163+
self.debug_context.as_ref().unwrap(),
164+
name,
165+
self.monomorphize(&decl.ty),
166+
scope,
167+
kind,
168+
span,
169+
)
170+
});
171+
172+
Some(PerLocalVarDebugInfo {
173+
name,
174+
source_info: decl.source_info,
175+
dbg_var,
176+
projection: ty::List::empty(),
133177
})
134-
};
135-
(var, VariableKind::ArgumentVariable(arg_index + 1))
178+
}
136179
} else {
137-
(None, VariableKind::LocalVariable)
180+
None
138181
};
139182

140183
let local_ref = &self.locals[local];
141184

142185
if !bx.sess().fewer_names() {
143-
let name = match whole_local_var.or(fallback_var.as_ref()) {
186+
let name = match whole_local_var.or(fallback_var) {
144187
Some(var) if var.name != kw::Invalid => var.name.to_string(),
145188
_ => format!("{:?}", local),
146189
};
@@ -163,7 +206,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
163206
}
164207
}
165208

166-
if bx.sess().opts.debuginfo != DebugInfo::Full {
209+
if !full_debug_info {
167210
return;
168211
}
169212

@@ -178,22 +221,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
178221
_ => return,
179222
};
180223

181-
let vars = vars.iter().copied().chain(if whole_local_var.is_none() {
182-
fallback_var.as_ref()
183-
} else {
184-
None
185-
});
224+
let vars = vars.iter().copied().chain(fallback_var);
186225

187226
for var in vars {
188227
let mut layout = base.layout;
189228
let mut direct_offset = Size::ZERO;
190229
// FIXME(eddyb) use smallvec here.
191230
let mut indirect_offsets = vec![];
192231

193-
let kind =
194-
if var.place.projection.is_empty() { kind } else { VariableKind::LocalVariable };
195-
196-
for elem in &var.place.projection[..] {
232+
for elem in &var.projection[..] {
197233
match *elem {
198234
mir::ProjectionElem::Deref => {
199235
indirect_offsets.push(Size::ZERO);
@@ -202,7 +238,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
202238
.ty
203239
.builtin_deref(true)
204240
.unwrap_or_else(|| {
205-
span_bug!(var.source_info.span, "cannot deref `{}`", layout.ty,)
241+
span_bug!(var.source_info.span, "cannot deref `{}`", layout.ty)
206242
})
207243
.ty,
208244
);
@@ -219,24 +255,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
219255
_ => span_bug!(
220256
var.source_info.span,
221257
"unsupported var debuginfo place `{:?}`",
222-
var.place,
258+
mir::Place { local, projection: var.projection },
223259
),
224260
}
225261
}
226262

227263
let (scope, span) = self.debug_loc(var.source_info);
228264
if let Some(scope) = scope {
229-
let dbg_var =
230-
bx.create_dbg_var(debug_context, var.name, layout.ty, scope, kind, span);
231-
bx.dbg_var_addr(
232-
debug_context,
233-
dbg_var,
234-
scope,
235-
base.llval,
236-
direct_offset,
237-
&indirect_offsets,
238-
span,
239-
);
265+
if let Some(dbg_var) = var.dbg_var {
266+
bx.dbg_var_addr(
267+
debug_context,
268+
dbg_var,
269+
scope,
270+
base.llval,
271+
direct_offset,
272+
&indirect_offsets,
273+
span,
274+
);
275+
}
240276
}
241277
}
242278
}
@@ -248,20 +284,60 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
248284
}
249285
}
250286
}
251-
}
252287

253-
/// Partition all `VarDebuginfo` in `body`, by their base `Local`.
254-
pub fn per_local_var_debug_info(
255-
tcx: TyCtxt<'tcx>,
256-
body: &'a mir::Body<'tcx>,
257-
) -> Option<IndexVec<mir::Local, Vec<&'a mir::VarDebugInfo<'tcx>>>> {
258-
if tcx.sess.opts.debuginfo == DebugInfo::Full || !tcx.sess.fewer_names() {
259-
let mut per_local = IndexVec::from_elem(vec![], &body.local_decls);
260-
for var in &body.var_debug_info {
261-
per_local[var.place.local].push(var);
288+
/// Partition all `VarDebugInfo` in `self.mir`, by their base `Local`.
289+
pub fn compute_per_local_var_debug_info(
290+
&self,
291+
) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
292+
let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
293+
294+
if !(full_debug_info || !self.cx.sess().fewer_names()) {
295+
return None;
296+
}
297+
298+
let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls);
299+
for var in &self.mir.var_debug_info {
300+
let (scope, span) = if full_debug_info {
301+
self.debug_loc(var.source_info)
302+
} else {
303+
(None, var.source_info.span)
304+
};
305+
let dbg_var = scope.map(|scope| {
306+
let place = var.place;
307+
let var_ty = self.monomorphized_place_ty(place.as_ref());
308+
let var_kind = if self.mir.local_kind(place.local) == mir::LocalKind::Arg
309+
&& place.projection.is_empty()
310+
{
311+
// FIXME(eddyb, #67586) take `var.source_info.scope` into
312+
// account to avoid using `ArgumentVariable` more than once
313+
// per argument local.
314+
315+
let arg_index = place.local.index() - 1;
316+
317+
// FIXME(eddyb) shouldn't `ArgumentVariable` indices be
318+
// offset in closures to account for the hidden environment?
319+
// Also, is this `+ 1` needed at all?
320+
VariableKind::ArgumentVariable(arg_index + 1)
321+
} else {
322+
VariableKind::LocalVariable
323+
};
324+
self.cx.create_dbg_var(
325+
self.debug_context.as_ref().unwrap(),
326+
var.name,
327+
var_ty,
328+
scope,
329+
var_kind,
330+
span,
331+
)
332+
});
333+
334+
per_local[var.place.local].push(PerLocalVarDebugInfo {
335+
name: var.name,
336+
source_info: var.source_info,
337+
dbg_var,
338+
projection: var.place.projection,
339+
});
262340
}
263341
Some(per_local)
264-
} else {
265-
None
266342
}
267343
}

Diff for: src/librustc_codegen_ssa/mir/mod.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_index::bit_set::BitSet;
1111
use rustc_index::vec::IndexVec;
1212

1313
use self::analyze::CleanupKind;
14-
use self::debuginfo::FunctionDebugContext;
14+
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
1515
use self::place::PlaceRef;
1616
use rustc::mir::traversal;
1717

@@ -74,9 +74,10 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
7474
/// notably `expect`.
7575
locals: IndexVec<mir::Local, LocalRef<'tcx, Bx::Value>>,
7676

77-
/// All `VarDebuginfo` from the MIR body, partitioned by `Local`.
78-
/// This is `None` if no variable debuginfo/names are needed.
79-
per_local_var_debug_info: Option<IndexVec<mir::Local, Vec<&'tcx mir::VarDebugInfo<'tcx>>>>,
77+
/// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
78+
/// This is `None` if no var`#[non_exhaustive]`iable debuginfo/names are needed.
79+
per_local_var_debug_info:
80+
Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>>,
8081

8182
/// Caller location propagated if this function has `#[track_caller]`.
8283
caller_location: Option<OperandRef<'tcx, Bx::Value>>,
@@ -178,10 +179,12 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
178179
funclets,
179180
locals: IndexVec::new(),
180181
debug_context,
181-
per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir_body),
182+
per_local_var_debug_info: None,
182183
caller_location: None,
183184
};
184185

186+
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info();
187+
185188
let memory_locals = analyze::non_ssa_locals(&fx);
186189

187190
// Allocate variable and temp allocas

0 commit comments

Comments
 (0)