Skip to content

Commit

Permalink
rustc_codegen_ssa: move local variable debuginfo to mir::debuginfo.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Oct 31, 2019
1 parent 5059a3c commit c58e6b5
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 241 deletions.
22 changes: 15 additions & 7 deletions src/librustc_codegen_ssa/mir/analyze.rs
Expand Up @@ -7,6 +7,7 @@ use rustc_index::vec::{Idx, IndexVec};
use rustc::mir::{self, Location, TerminatorKind};
use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
use rustc::mir::traversal;
use rustc::session::config::DebugInfo;
use rustc::ty;
use rustc::ty::layout::{LayoutOf, HasTyCtxt};
use syntax_pos::DUMMY_SP;
Expand All @@ -21,13 +22,20 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(

analyzer.visit_body(mir);

for (index, (ty, span)) in mir.local_decls.iter()
.map(|l| (l.ty, l.source_info.span))
.enumerate()
for (local, decl) in mir.local_decls.iter_enumerated()
{
let ty = fx.monomorphize(&ty);
debug!("local {} has type {:?}", index, ty);
let layout = fx.cx.spanned_layout_of(ty, span);
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
// of putting everything in allocas just so we can use llvm.dbg.declare.
if fx.cx.sess().opts.debuginfo == DebugInfo::Full {
if mir.local_kind(local) == mir::LocalKind::Arg || decl.name.is_some() {
analyzer.not_ssa(local);
continue;
}
}

let ty = fx.monomorphize(&decl.ty);
debug!("local {:?} has type `{}`", local, ty);
let layout = fx.cx.spanned_layout_of(ty, decl.source_info.span);
if fx.cx.is_backend_immediate(layout) {
// These sorts of types are immediates that we can store
// in an Value without an alloca.
Expand All @@ -40,7 +48,7 @@ pub fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// (e.g., structs) into an alloca unconditionally, just so
// that we don't have to deal with having two pathways
// (gep vs extractvalue etc).
analyzer.not_ssa(mir::Local::new(index));
analyzer.not_ssa(local);
}
}

Expand Down
179 changes: 178 additions & 1 deletion src/librustc_codegen_ssa/mir/debuginfo.rs
@@ -1,10 +1,16 @@
use rustc_index::vec::Idx;
use rustc::hir::def_id::CrateNum;
use rustc::mir;
use rustc::session::config::DebugInfo;
use rustc::ty::{self, UpvarSubsts};
use rustc::ty::layout::HasTyCtxt;
use rustc_target::abi::{Variants, VariantIdx};
use crate::traits::*;

use syntax_pos::{DUMMY_SP, BytePos, Span};
use syntax::symbol::kw;

use super::FunctionCx;
use super::{FunctionCx, LocalRef};

pub enum FunctionDebugContext<D> {
RegularContext(FunctionDebugContextData<D>),
Expand Down Expand Up @@ -142,4 +148,175 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
scope_metadata
}
}

pub fn debug_declare_locals(&self, bx: &mut Bx) {
let tcx = self.cx.tcx();
let upvar_debuginfo = &self.mir.__upvar_debuginfo_codegen_only_do_not_use;

if bx.sess().opts.debuginfo != DebugInfo::Full {
return;
}

for (local, local_ref) in self.locals.iter_enumerated() {
if local == mir::RETURN_PLACE {
continue;
}

// FIXME(eddyb) add debuginfo for unsized places too.
let place = match local_ref {
LocalRef::Place(place) => place,
_ => continue,
};

let decl = &self.mir.local_decls[local];
let (name, kind) = if self.mir.local_kind(local) == mir::LocalKind::Arg {
let arg_index = local.index() - 1;

// Add debuginfo even to unnamed arguments.
// FIXME(eddyb) is this really needed?
let name = if arg_index == 0 && !upvar_debuginfo.is_empty() {
// Hide closure environments from debuginfo.
// FIXME(eddyb) shouldn't `ArgumentVariable` indices
// be offset to account for the hidden environment?
None
} else {
Some(decl.name.unwrap_or(kw::Invalid))
};
(name, VariableKind::ArgumentVariable(arg_index + 1))
} else {
(decl.name, VariableKind::LocalVariable)
};
if let Some(name) = name {
let (scope, span) = self.debug_loc(mir::SourceInfo {
span: decl.source_info.span,
scope: decl.visibility_scope,
});
if let Some(scope) = scope {
bx.declare_local(&self.debug_context, name, place.layout.ty, scope,
VariableAccess::DirectVariable { alloca: place.llval },
kind, span);
}
}
}

// Declare closure captures as if they were local variables.
// FIXME(eddyb) generalize this to `name => place` mappings.
let upvar_scope = if !upvar_debuginfo.is_empty() {
self.scopes[mir::OUTERMOST_SOURCE_SCOPE].scope_metadata
} else {
None
};
if let Some(scope) = upvar_scope {
let place = match self.locals[mir::Local::new(1)] {
LocalRef::Place(place) => place,
_ => bug!(),
};

let pin_did = tcx.lang_items().pin_type();
let (closure_layout, env_ref) = match place.layout.ty.kind {
ty::RawPtr(ty::TypeAndMut { ty, .. }) |
ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
ty::Adt(def, substs) if Some(def.did) == pin_did => {
match substs.type_at(0).kind {
ty::Ref(_, ty, _) => (bx.layout_of(ty), true),
_ => (place.layout, false),
}
}
_ => (place.layout, false)
};

let (def_id, upvar_substs) = match closure_layout.ty.kind {
ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)),
ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)),
_ => bug!("upvar debuginfo with non-closure arg0 type `{}`", closure_layout.ty)
};
let upvar_tys = upvar_substs.upvar_tys(def_id, tcx);

let extra_locals = {
let upvars = upvar_debuginfo
.iter()
.zip(upvar_tys)
.enumerate()
.map(|(i, (upvar, ty))| {
(None, i, upvar.debug_name, upvar.by_ref, ty, scope, DUMMY_SP)
});

let generator_fields = self.mir.generator_layout.as_ref().map(|generator_layout| {
let (def_id, gen_substs) = match closure_layout.ty.kind {
ty::Generator(def_id, substs, _) => (def_id, substs),
_ => bug!("generator layout without generator substs"),
};
let state_tys = gen_substs.as_generator().state_tys(def_id, tcx);

generator_layout.variant_fields.iter()
.zip(state_tys)
.enumerate()
.flat_map(move |(variant_idx, (fields, tys))| {
let variant_idx = Some(VariantIdx::from(variant_idx));
fields.iter()
.zip(tys)
.enumerate()
.filter_map(move |(i, (field, ty))| {
let decl = &generator_layout.
__local_debuginfo_codegen_only_do_not_use[*field];
if let Some(name) = decl.name {
let ty = self.monomorphize(&ty);
let (var_scope, var_span) = self.debug_loc(mir::SourceInfo {
span: decl.source_info.span,
scope: decl.visibility_scope,
});
let var_scope = var_scope.unwrap_or(scope);
Some((variant_idx, i, name, false, ty, var_scope, var_span))
} else {
None
}
})
})
}).into_iter().flatten();

upvars.chain(generator_fields)
};

for (variant_idx, field, name, by_ref, ty, var_scope, var_span) in extra_locals {
let fields = match variant_idx {
Some(variant_idx) => {
match &closure_layout.variants {
Variants::Multiple { variants, .. } => {
&variants[variant_idx].fields
},
_ => bug!("variant index on univariant layout"),
}
}
None => &closure_layout.fields,
};
let byte_offset_of_var_in_env = fields.offset(field).bytes();

let ops = bx.debuginfo_upvar_ops_sequence(byte_offset_of_var_in_env);

// The environment and the capture can each be indirect.
let mut ops = if env_ref { &ops[..] } else { &ops[1..] };

let ty = if let (true, &ty::Ref(_, ty, _)) = (by_ref, &ty.kind) {
ty
} else {
ops = &ops[..ops.len() - 1];
ty
};

let variable_access = VariableAccess::IndirectVariable {
alloca: place.llval,
address_operations: &ops
};
bx.declare_local(
&self.debug_context,
name,
ty,
var_scope,
variable_access,
VariableKind::LocalVariable,
var_span
);
}
}
}
}

0 comments on commit c58e6b5

Please sign in to comment.