Skip to content

Commit c58e6b5

Browse files
committed
rustc_codegen_ssa: move local variable debuginfo to mir::debuginfo.
1 parent 5059a3c commit c58e6b5

File tree

4 files changed

+227
-241
lines changed

4 files changed

+227
-241
lines changed

src/librustc_codegen_ssa/mir/analyze.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_index::vec::{Idx, IndexVec};
77
use rustc::mir::{self, Location, TerminatorKind};
88
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
99
use rustc::mir::traversal;
10+
use rustc::session::config::DebugInfo;
1011
use rustc::ty;
1112
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
1213
use syntax_pos::DUMMY_SP;
@@ -21,13 +22,20 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
2122

2223
analyzer.visit_body(mir);
2324

24-
for (index, (ty, span)) in mir.local_decls.iter()
25-
.map(|l| (l.ty, l.source_info.span))
26-
.enumerate()
25+
for (local, decl) in mir.local_decls.iter_enumerated()
2726
{
28-
let ty = fx.monomorphize(&ty);
29-
debug!("local {} has type {:?}", index, ty);
30-
let layout = fx.cx.spanned_layout_of(ty, span);
27+
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
28+
// of putting everything in allocas just so we can use llvm.dbg.declare.
29+
if fx.cx.sess().opts.debuginfo == DebugInfo::Full {
30+
if mir.local_kind(local) == mir::LocalKind::Arg || decl.name.is_some() {
31+
analyzer.not_ssa(local);
32+
continue;
33+
}
34+
}
35+
36+
let ty = fx.monomorphize(&decl.ty);
37+
debug!("local {:?} has type `{}`", local, ty);
38+
let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
3139
if fx.cx.is_backend_immediate(layout) {
3240
// These sorts of types are immediates that we can store
3341
// in an Value without an alloca.
@@ -40,7 +48,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
4048
// (e.g., structs) into an alloca unconditionally, just so
4149
// that we don't have to deal with having two pathways
4250
// (gep vs extractvalue etc).
43-
analyzer.not_ssa(mir::Local::new(index));
51+
analyzer.not_ssa(local);
4452
}
4553
}
4654

src/librustc_codegen_ssa/mir/debuginfo.rs

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
use rustc_index::vec::Idx;
12
use rustc::hir::def_id::CrateNum;
23
use rustc::mir;
4+
use rustc::session::config::DebugInfo;
5+
use rustc::ty::{self, UpvarSubsts};
6+
use rustc::ty::layout::HasTyCtxt;
7+
use rustc_target::abi::{Variants, VariantIdx};
38
use crate::traits::*;
49

510
use syntax_pos::{DUMMY_SP, BytePos, Span};
11+
use syntax::symbol::kw;
612

7-
use super::FunctionCx;
13+
use super::{FunctionCx, LocalRef};
814

915
pub enum FunctionDebugContext<D> {
1016
RegularContext(FunctionDebugContextData<D>),
@@ -142,4 +148,175 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
142148
scope_metadata
143149
}
144150
}
151+
152+
pub fn debug_declare_locals(&self, bx: &mut Bx) {
153+
let tcx = self.cx.tcx();
154+
let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use;
155+
156+
if bx.sess().opts.debuginfo != DebugInfo::Full {
157+
return;
158+
}
159+
160+
for (local, local_ref) in self.locals.iter_enumerated() {
161+
if local == mir::RETURN_PLACE {
162+
continue;
163+
}
164+
165+
// FIXME(eddyb) add debuginfo for unsized places too.
166+
let place = match local_ref {
167+
LocalRef::Place(place) => place,
168+
_ => continue,
169+
};
170+
171+
let decl = &self.mir.local_decls[local];
172+
let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg {
173+
let arg_index = local.index() - 1;
174+
175+
// Add debuginfo even to unnamed arguments.
176+
// FIXME(eddyb) is this really needed?
177+
let name = if arg_index == 0 && !upvar_debuginfo.is_empty() {
178+
// Hide closure environments from debuginfo.
179+
// FIXME(eddyb) shouldn't `ArgumentVariable` indices
180+
// be offset to account for the hidden environment?
181+
None
182+
} else {
183+
Some(decl.name.unwrap_or(kw::Invalid))
184+
};
185+
(name, VariableKind::ArgumentVariable(arg_index + 1))
186+
} else {
187+
(decl.name, VariableKind::LocalVariable)
188+
};
189+
if let Some(name) = name {
190+
let (scope, span) = self.debug_loc(mir::SourceInfo {
191+
span: decl.source_info.span,
192+
scope: decl.visibility_scope,
193+
});
194+
if let Some(scope) = scope {
195+
bx.declare_local(&self.debug_context, name, place.layout.ty, scope,
196+
VariableAccess::DirectVariable { alloca: place.llval },
197+
kind, span);
198+
}
199+
}
200+
}
201+
202+
// Declare closure captures as if they were local variables.
203+
// FIXME(eddyb) generalize this to `name => place` mappings.
204+
let upvar_scope = if !upvar_debuginfo.is_empty() {
205+
self.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata
206+
} else {
207+
None
208+
};
209+
if let Some(scope) = upvar_scope {
210+
let place = match self.locals[mir::Local::new(1)] {
211+
LocalRef::Place(place) => place,
212+
_ => bug!(),
213+
};
214+
215+
let pin_did = tcx.lang_items().pin_type();
216+
let (closure_layout, env_ref) = match place.layout.ty.kind {
217+
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
218+
ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
219+
ty::Adt(def, substs) if Some(def.did) == pin_did => {
220+
match substs.type_at(0).kind {
221+
ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
222+
_ => (place.layout, false),
223+
}
224+
}
225+
_ => (place.layout, false)
226+
};
227+
228+
let (def_id, upvar_substs) = match closure_layout.ty.kind {
229+
ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
230+
ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
231+
_ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty)
232+
};
233+
let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);
234+
235+
let extra_locals = {
236+
let upvars = upvar_debuginfo
237+
.iter()
238+
.zip(upvar_tys)
239+
.enumerate()
240+
.map(|(i, (upvar, ty))| {
241+
(None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP)
242+
});
243+
244+
let generator_fields = self.mir.generator_layout.as_ref().map(|generator_layout| {
245+
let (def_id, gen_substs) = match closure_layout.ty.kind {
246+
ty::Generator(def_id, substs, _) => (def_id, substs),
247+
_ => bug!("generator layout without generator substs"),
248+
};
249+
let state_tys = gen_substs.as_generator().state_tys(def_id, tcx);
250+
251+
generator_layout.variant_fields.iter()
252+
.zip(state_tys)
253+
.enumerate()
254+
.flat_map(move |(variant_idx, (fields, tys))| {
255+
let variant_idx = Some(VariantIdx::from(variant_idx));
256+
fields.iter()
257+
.zip(tys)
258+
.enumerate()
259+
.filter_map(move |(i, (field, ty))| {
260+
let decl = &generator_layout.
261+
__local_debuginfo_codegen_only_do_not_use[*field];
262+
if let Some(name) = decl.name {
263+
let ty = self.monomorphize(&ty);
264+
let (var_scope, var_span) = self.debug_loc(mir::SourceInfo {
265+
span: decl.source_info.span,
266+
scope: decl.visibility_scope,
267+
});
268+
let var_scope = var_scope.unwrap_or(scope);
269+
Some((variant_idx, i, name, false, ty, var_scope, var_span))
270+
} else {
271+
None
272+
}
273+
})
274+
})
275+
}).into_iter().flatten();
276+
277+
upvars.chain(generator_fields)
278+
};
279+
280+
for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals {
281+
let fields = match variant_idx {
282+
Some(variant_idx) => {
283+
match &closure_layout.variants {
284+
Variants::Multiple { variants, .. } => {
285+
&variants[variant_idx].fields
286+
},
287+
_ => bug!("variant index on univariant layout"),
288+
}
289+
}
290+
None => &closure_layout.fields,
291+
};
292+
let byte_offset_of_var_in_env = fields.offset(field).bytes();
293+
294+
let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env);
295+
296+
// The environment and the capture can each be indirect.
297+
let mut ops = if env_ref { &ops[..] } else { &ops[1..] };
298+
299+
let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) {
300+
ty
301+
} else {
302+
ops = &ops[..ops.len() - 1];
303+
ty
304+
};
305+
306+
let variable_access = VariableAccess::IndirectVariable {
307+
alloca: place.llval,
308+
address_operations: &ops
309+
};
310+
bx.declare_local(
311+
&self.debug_context,
312+
name,
313+
ty,
314+
var_scope,
315+
variable_access,
316+
VariableKind::LocalVariable,
317+
var_span
318+
);
319+
}
320+
}
321+
}
145322
}

0 commit comments

Comments
 (0)