trans: initial implementation of MIR debuginfo.

This commit is contained in:
Eduard Burtescu 2016-04-07 22:35:11 +03:00
parent f680c623d4
commit ce8d4a2134
11 changed files with 288 additions and 122 deletions

View File

@ -1276,7 +1276,7 @@ pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
}
}
debuginfo::clear_source_location(cx.fcx);
DebugLoc::None.apply(cx.fcx);
Alloca(cx, ty, name)
}
@ -1739,7 +1739,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
self.build_return_block(ret_cx, ret_debug_loc);
debuginfo::clear_source_location(self);
DebugLoc::None.apply(self);
self.cleanup();
}

View File

@ -167,11 +167,11 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
if cv == 1 {
// if true { .. } [else { .. }]
bcx = trans_block(bcx, &thn, dest);
debuginfo::clear_source_location(bcx.fcx);
DebugLoc::None.apply(bcx.fcx);
} else {
if let Some(elexpr) = els {
bcx = expr::trans_into(bcx, &elexpr, dest);
debuginfo::clear_source_location(bcx.fcx);
DebugLoc::None.apply(bcx.fcx);
}
}
@ -181,7 +181,7 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let name = format!("then-block-{}-", thn.id);
let then_bcx_in = bcx.fcx.new_id_block(&name[..], thn.id);
let then_bcx_out = trans_block(then_bcx_in, &thn, dest);
debuginfo::clear_source_location(bcx.fcx);
DebugLoc::None.apply(bcx.fcx);
let cond_source_loc = cond.debug_loc();
@ -204,7 +204,7 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// Clear the source location because it is still set to whatever has been translated
// right before.
debuginfo::clear_source_location(next_bcx.fcx);
DebugLoc::None.apply(next_bcx.fcx);
next_bcx
}

View File

@ -8,19 +8,24 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::FunctionDebugContext;
use super::metadata::file_metadata;
use super::utils::DIB;
use super::utils::{DIB, span_start};
use llvm;
use llvm::debuginfo::{DIScope, DISubprogram};
use common::CrateContext;
use common::{CrateContext, FunctionContext};
use rustc::hir::pat_util;
use rustc::mir::repr::{Mir, ScopeId};
use rustc::util::nodemap::NodeMap;
use libc::c_uint;
use std::ptr;
use syntax::codemap::{Span, Pos};
use syntax::{ast, codemap};
use rustc_data_structures::bitvec::BitVector;
use rustc::hir::{self, PatKind};
// This procedure builds the *scope map* for a given function, which maps any
@ -65,6 +70,74 @@ pub fn create_scope_map(cx: &CrateContext,
return scope_map;
}
/// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
/// If debuginfo is disabled, the returned vector is empty.
pub fn create_mir_scopes(fcx: &FunctionContext) -> Vec<DIScope> {
let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
let mut scopes = vec![ptr::null_mut(); mir.scopes.len()];
let fn_metadata = match fcx.debug_context {
FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
FunctionDebugContext::DebugInfoDisabled |
FunctionDebugContext::FunctionWithoutDebugInfo => {
return scopes;
}
};
// Find all the scopes with variables defined in them.
let mut has_variables = BitVector::new(mir.scopes.len());
for var in &mir.var_decls {
has_variables.insert(var.scope.index());
}
// Instantiate all scopes.
for idx in 0..mir.scopes.len() {
let scope = ScopeId::new(idx);
make_mir_scope(fcx.ccx, &mir, &has_variables, fn_metadata, scope, &mut scopes);
}
scopes
}
fn make_mir_scope(ccx: &CrateContext,
mir: &Mir,
has_variables: &BitVector,
fn_metadata: DISubprogram,
scope: ScopeId,
scopes: &mut [DIScope]) {
let idx = scope.index();
if !scopes[idx].is_null() {
return;
}
let scope_data = &mir.scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
make_mir_scope(ccx, mir, has_variables, fn_metadata, parent, scopes);
scopes[parent.index()]
} else {
// The root is the function itself.
scopes[idx] = fn_metadata;
return;
};
scopes[idx] = if !has_variables.contains(idx) {
// Do not create a DIScope if there are no variables
// defined in this MIR Scope, to avoid debuginfo bloat.
parent_scope
} else {
let loc = span_start(ccx, scope_data.span);
let file_metadata = file_metadata(ccx, &loc.file.name);
unsafe {
llvm::LLVMDIBuilderCreateLexicalBlock(
DIB(ccx),
parent_scope,
file_metadata,
loc.line as c_uint,
loc.col.to_usize() as c_uint)
}
};
}
// local helper functions for walking the AST.
fn with_new_scope<F>(cx: &CrateContext,
scope_span: Span,
@ -74,7 +147,7 @@ fn with_new_scope<F>(cx: &CrateContext,
F: FnOnce(&CrateContext, &mut Vec<ScopeStackEntry>, &mut NodeMap<DIScope>),
{
// Create a new lexical scope and push it onto the stack
let loc = cx.sess().codemap().lookup_char_pos(scope_span.lo);
let loc = span_start(cx, scope_span);
let file_metadata = file_metadata(cx, &loc.file.name);
let parent_scope = scope_stack.last().unwrap().scope_metadata;
@ -199,7 +272,7 @@ fn walk_pattern(cx: &CrateContext,
if need_new_scope {
// Create a new lexical scope and push it onto the stack
let loc = cx.sess().codemap().lookup_char_pos(pat.span.lo);
let loc = span_start(cx, pat.span);
let file_metadata = file_metadata(cx, &loc.file.name);
let parent_scope = scope_stack.last().unwrap().scope_metadata;

View File

@ -20,7 +20,7 @@ use self::namespace::mangled_name_of_item;
use self::type_names::compute_debuginfo_type_name;
use self::metadata::{type_metadata, diverging_type_metadata};
use self::metadata::{file_metadata, scope_metadata, TypeMap, compile_unit_metadata};
use self::source_loc::InternalDebugLocation;
use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
use llvm;
use llvm::{ModuleRef, ContextRef, ValueRef};
@ -32,7 +32,7 @@ use rustc::ty::subst::Substs;
use rustc::hir;
use abi::Abi;
use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block, BlockAndBuilder};
use monomorphize::Instance;
use rustc::ty::{self, Ty};
use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
@ -55,8 +55,7 @@ mod metadata;
mod create_scope_map;
mod source_loc;
pub use self::source_loc::set_source_location;
pub use self::source_loc::clear_source_location;
pub use self::create_scope_map::create_mir_scopes;
pub use self::source_loc::start_emitting_source_locations;
pub use self::source_loc::get_cleanup_debug_loc_for_ast_node;
pub use self::source_loc::with_source_location_override;
@ -218,7 +217,7 @@ pub fn empty_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>)
}
// Clear the debug location so we don't assign them in the function prelude.
source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
source_loc::set_debug_location(cx, None, UnknownLocation);
FunctionDebugContext::FunctionWithoutDebugInfo
}
@ -239,7 +238,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
// Clear the debug location so we don't assign them in the function prelude.
// Do this here already, in case we do an early exit from this function.
source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
source_loc::set_debug_location(cx, None, UnknownLocation);
// This can be the case for functions inlined from another crate
let (containing_scope, span) = get_namespace_and_span_for_item(cx, instance.def);
@ -425,13 +424,13 @@ pub fn fill_scope_map_for_function<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
}
}
fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
variable_name: ast::Name,
variable_type: Ty<'tcx>,
scope_metadata: DIScope,
variable_access: VariableAccess,
variable_kind: VariableKind,
span: Span) {
pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
variable_name: ast::Name,
variable_type: Ty<'tcx>,
scope_metadata: DIScope,
variable_access: VariableAccess,
variable_kind: VariableKind,
span: Span) {
let cx: &CrateContext = bcx.ccx();
let filename = span_start(cx, span).file.name.clone();
@ -465,9 +464,8 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
address_operations.len() as c_uint,
argument_index)
};
source_loc::set_debug_location(cx, InternalDebugLocation::new(scope_metadata,
loc.line,
loc.col.to_usize()));
source_loc::set_debug_location(cx, None,
InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
unsafe {
let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder());
let instr = llvm::LLVMDIBuilderInsertDeclareAtEnd(
@ -491,7 +489,7 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
.get_ref(span)
.source_locations_enabled
.get());
source_loc::set_debug_location(cx, InternalDebugLocation::UnknownLocation);
source_loc::set_debug_location(cx, None, UnknownLocation);
}
_ => { /* nothing to do */ }
}
@ -500,19 +498,17 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum DebugLoc {
At(ast::NodeId, Span),
ScopeAt(DIScope, Span),
None
}
impl DebugLoc {
pub fn apply(&self, fcx: &FunctionContext) {
match *self {
DebugLoc::At(node_id, span) => {
source_loc::set_source_location(fcx, node_id, span);
}
DebugLoc::None => {
source_loc::clear_source_location(fcx);
}
}
pub fn apply(self, fcx: &FunctionContext) {
source_loc::set_source_location(fcx, None, self);
}
pub fn apply_to_bcx(self, bcx: &BlockAndBuilder) {
source_loc::set_source_location(bcx.fcx(), Some(bcx), self);
}
}

View File

@ -10,12 +10,13 @@
use self::InternalDebugLocation::*;
use super::utils::{debug_context, span_start, fn_should_be_ignored};
use super::utils::{debug_context, span_start};
use super::metadata::{scope_metadata,UNKNOWN_COLUMN_NUMBER};
use super::{FunctionDebugContext, DebugLoc};
use llvm;
use llvm::debuginfo::DIScope;
use builder::Builder;
use common::{NodeIdAndSpan, CrateContext, FunctionContext};
use libc::c_uint;
@ -86,41 +87,46 @@ pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
/// Sets the current debug location at the beginning of the span.
///
/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...). The node_id
/// parameter is used to reliably find the correct visibility scope for the code
/// position.
/// Maps to a call to llvm::LLVMSetCurrentDebugLocation(...).
pub fn set_source_location(fcx: &FunctionContext,
node_id: ast::NodeId,
span: Span) {
match fcx.debug_context {
builder: Option<&Builder>,
debug_loc: DebugLoc) {
let builder = builder.map(|b| b.llbuilder);
let function_debug_context = match fcx.debug_context {
FunctionDebugContext::DebugInfoDisabled => return,
FunctionDebugContext::FunctionWithoutDebugInfo => {
set_debug_location(fcx.ccx, UnknownLocation);
set_debug_location(fcx.ccx, builder, UnknownLocation);
return;
}
FunctionDebugContext::RegularContext(box ref function_debug_context) => {
if function_debug_context.source_location_override.get() {
// Just ignore any attempts to set a new debug location while
// the override is active.
FunctionDebugContext::RegularContext(box ref data) => data
};
if function_debug_context.source_location_override.get() {
// Just ignore any attempts to set a new debug location while
// the override is active.
return;
}
let dbg_loc = if function_debug_context.source_locations_enabled.get() {
let (scope, span) = match debug_loc {
DebugLoc::At(node_id, span) => {
(scope_metadata(fcx, node_id, span), span)
}
DebugLoc::ScopeAt(scope, span) => (scope, span),
DebugLoc::None => {
set_debug_location(fcx.ccx, builder, UnknownLocation);
return;
}
};
let cx = fcx.ccx;
debug!("set_source_location: {}", cx.sess().codemap().span_to_string(span));
if function_debug_context.source_locations_enabled.get() {
let loc = span_start(cx, span);
let scope = scope_metadata(fcx, node_id, span);
set_debug_location(cx, InternalDebugLocation::new(scope,
loc.line,
loc.col.to_usize()));
} else {
set_debug_location(cx, UnknownLocation);
}
}
}
debug!("set_source_location: {}",
fcx.ccx.sess().codemap().span_to_string(span));
let loc = span_start(fcx.ccx, span);
InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
} else {
UnknownLocation
};
set_debug_location(fcx.ccx, builder, dbg_loc);
}
/// This function makes sure that all debug locations emitted while executing
@ -135,7 +141,7 @@ pub fn with_source_location_override<F, R>(fcx: &FunctionContext,
wrapped_function()
}
FunctionDebugContext::FunctionWithoutDebugInfo => {
set_debug_location(fcx.ccx, UnknownLocation);
set_debug_location(fcx.ccx, None, UnknownLocation);
wrapped_function()
}
FunctionDebugContext::RegularContext(box ref function_debug_context) => {
@ -152,17 +158,6 @@ pub fn with_source_location_override<F, R>(fcx: &FunctionContext,
}
}
/// Clears the current debug location.
///
/// Instructions generated hereafter won't be assigned a source location.
pub fn clear_source_location(fcx: &FunctionContext) {
if fn_should_be_ignored(fcx) {
return;
}
set_debug_location(fcx.ccx, UnknownLocation);
}
/// Enables emitting source locations for the given functions.
///
/// Since we don't want source locations to be emitted for the function prelude,
@ -195,37 +190,42 @@ impl InternalDebugLocation {
}
}
pub fn set_debug_location(cx: &CrateContext, debug_location: InternalDebugLocation) {
if debug_location == debug_context(cx).current_debug_location.get() {
return;
pub fn set_debug_location(cx: &CrateContext,
builder: Option<llvm::BuilderRef>,
debug_location: InternalDebugLocation) {
if builder.is_none() {
if debug_location == debug_context(cx).current_debug_location.get() {
return;
}
}
let metadata_node;
match debug_location {
let metadata_node = match debug_location {
KnownLocation { scope, line, .. } => {
// Always set the column to zero like Clang and GCC
let col = UNKNOWN_COLUMN_NUMBER;
debug!("setting debug location to {} {}", line, col);
unsafe {
metadata_node = llvm::LLVMDIBuilderCreateDebugLocation(
llvm::LLVMDIBuilderCreateDebugLocation(
debug_context(cx).llcontext,
line as c_uint,
col as c_uint,
scope,
ptr::null_mut());
ptr::null_mut())
}
}
UnknownLocation => {
debug!("clearing debug location ");
metadata_node = ptr::null_mut();
ptr::null_mut()
}
};
unsafe {
llvm::LLVMSetCurrentDebugLocation(cx.raw_builder(), metadata_node);
if builder.is_none() {
debug_context(cx).current_debug_location.set(debug_location);
}
debug_context(cx).current_debug_location.set(debug_location);
let builder = builder.unwrap_or_else(|| cx.raw_builder());
unsafe {
llvm::LLVMSetCurrentDebugLocation(builder, metadata_node);
}
}

View File

@ -115,7 +115,7 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> Block<'blk, 'tcx> {
let mut bcx = bcx;
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
expr.debug_loc().apply(bcx.fcx);
if adjustment_required(bcx, expr) {
// use trans, which may be less efficient but
@ -587,7 +587,7 @@ fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
debug!("trans_unadjusted(expr={:?})", expr);
let _indenter = indenter();
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
expr.debug_loc().apply(bcx.fcx);
return match expr_kind(bcx.tcx(), expr) {
ExprKind::Lvalue | ExprKind::RvalueDatum => {
@ -923,7 +923,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
return bcx;
}
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
expr.debug_loc().apply(bcx.fcx);
match expr.node {
hir::ExprBreak(label_opt) => {
@ -987,7 +987,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
//
// We could avoid this intermediary with some analysis
// to determine whether `dst` may possibly own `src`.
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
expr.debug_loc().apply(bcx.fcx);
let src_datum = unpack_datum!(
bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign"));
let opt_hint_datum = dst_datum.kind.drop_flag_info.hint_datum(bcx);
@ -1062,7 +1062,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
let mut bcx = bcx;
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
expr.debug_loc().apply(bcx.fcx);
// Entry into the method table if this is an overloaded call/op.
let method_call = MethodCall::expr(expr.id);

View File

@ -195,8 +195,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let name = tcx.item_name(def_id).as_str();
let span = match call_debug_location {
DebugLoc::At(_, span) => span,
DebugLoc::None => fcx.span.unwrap_or(DUMMY_SP)
DebugLoc::At(_, span) | DebugLoc::ScopeAt(_, span) => span,
DebugLoc::None => {
span_bug!(fcx.span.unwrap_or(DUMMY_SP),
"intrinsic `{}` called with missing span", name);
}
};
let cleanup_scope = fcx.push_custom_cleanup_scope();

View File

@ -54,9 +54,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
bcx = self.trans_statement(bcx, statement);
}
debug!("trans_block: terminator: {:?}", data.terminator());
let terminator = data.terminator();
debug!("trans_block: terminator: {:?}", terminator);
match data.terminator().kind {
let debug_loc = DebugLoc::ScopeAt(self.scopes[terminator.scope.index()],
terminator.span);
debug_loc.apply_to_bcx(&bcx);
debug_loc.apply(bcx.fcx());
match terminator.kind {
mir::TerminatorKind::Resume => {
if let Some(cleanup_pad) = cleanup_pad {
bcx.cleanup_ret(cleanup_pad, None);
@ -117,7 +122,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
mir::TerminatorKind::Return => {
bcx.with_block(|bcx| {
self.fcx.build_return_block(bcx, DebugLoc::None);
self.fcx.build_return_block(bcx, debug_loc);
})
}
@ -144,7 +149,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
self.llblock(target),
unwind.llbb(),
cleanup_bundle.as_ref());
self.bcx(target).at_start(|bcx| drop::drop_fill(bcx, lvalue.llval, ty));
self.bcx(target).at_start(|bcx| {
debug_loc.apply_to_bcx(bcx);
drop::drop_fill(bcx, lvalue.llval, ty)
});
} else {
bcx.call(drop_fn, &[llvalue], cleanup_bundle.as_ref());
drop::drop_fill(&bcx, lvalue.llval, ty);
@ -267,7 +275,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
bcx.with_block(|bcx| {
trans_intrinsic_call(bcx, callee.ty, &fn_ty,
ArgVals(llargs), dest,
DebugLoc::None);
debug_loc);
});
if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
@ -311,13 +319,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
cleanup_bundle.as_ref());
fn_ty.apply_attrs_callsite(invokeret);
landingpad.at_start(|bcx| for op in args {
self.set_operand_dropped(bcx, op);
landingpad.at_start(|bcx| {
debug_loc.apply_to_bcx(bcx);
for op in args {
self.set_operand_dropped(bcx, op);
}
});
if destination.is_some() {
let ret_bcx = ret_bcx.build();
ret_bcx.at_start(|ret_bcx| {
debug_loc.apply_to_bcx(ret_bcx);
let op = OperandRef {
val: OperandValue::Immediate(invokeret),
ty: sig.output.unwrap()
@ -514,7 +526,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let use_funclets = base::wants_msvc_seh(bcx.sess()) && data.is_cleanup;
let cleanup_pad = if use_funclets {
bcx.set_personality_fn(self.fcx.eh_personality());
bcx.at_start(|bcx| Some(bcx.cleanup_pad(None, &[])))
bcx.at_start(|bcx| {
DebugLoc::None.apply_to_bcx(bcx);
Some(bcx.cleanup_pad(None, &[]))
})
} else {
None
};

View File

@ -10,11 +10,19 @@
use libc::c_uint;
use llvm::{self, ValueRef};
use llvm::debuginfo::DIScope;
use rustc::ty;
use rustc::mir::repr as mir;
use rustc::mir::tcx::LvalueTy;
use session::config::FullDebugInfo;
use base;
use common::{self, Block, BlockAndBuilder, FunctionContext};
use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind};
use machine;
use type_of;
use syntax::codemap::DUMMY_SP;
use syntax::parse::token;
use std::ops::Deref;
use std::rc::Rc;
@ -44,8 +52,6 @@ impl<'mir, 'tcx: 'mir> Deref for CachedMir<'mir, 'tcx> {
}
}
// FIXME DebugLoc is always None right now
/// Master context for translating MIR.
pub struct MirContext<'bcx, 'tcx:'bcx> {
mir: CachedMir<'bcx, 'tcx>,
@ -92,6 +98,9 @@ pub struct MirContext<'bcx, 'tcx:'bcx> {
/// always indirect, though we try to avoid creating an alloca
/// when we can (and just reuse the pointer the caller provided).
args: Vec<LvalueRef<'tcx>>,
/// Debug information for MIR scopes.
scopes: Vec<DIScope>
}
enum TempRef<'tcx> {
@ -113,11 +122,26 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
analyze::lvalue_temps(bcx, &mir)
});
// Compute debuginfo scopes from MIR scopes.
let scopes = debuginfo::create_mir_scopes(fcx);
// Allocate variable and temp allocas
let vars = mir.var_decls.iter()
.map(|decl| (bcx.monomorphize(&decl.ty), decl.name))
.map(|(mty, name)| LvalueRef::alloca(&bcx, mty, &name.as_str()))
.collect();
.map(|decl| (bcx.monomorphize(&decl.ty), decl))
.map(|(mty, decl)| {
let lvalue = LvalueRef::alloca(&bcx, mty, &decl.name.as_str());
let scope = scopes[decl.scope.index()];
if !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
bcx.with_block(|bcx| {
declare_local(bcx, decl.name, mty, scope,
VariableAccess::DirectVariable { alloca: lvalue.llval },
VariableKind::LocalVariable, decl.span);
});
}
lvalue
}).collect();
let temps = mir.temp_decls.iter()
.map(|decl| bcx.monomorphize(&decl.ty))
.enumerate()
@ -132,7 +156,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
TempRef::Operand(None)
})
.collect();
let args = arg_value_refs(&bcx, &mir);
let args = arg_value_refs(&bcx, &mir, &scopes);
// Allocate a `Block` for every basic block
let block_bcxs: Vec<Block<'blk,'tcx>> =
@ -152,6 +176,11 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
let start_bcx = block_bcxs[mir::START_BLOCK.index()];
bcx.br(start_bcx.llbb);
// Up until here, IR instructions for this function have explicitly not been annotated with
// source code location, so we don't step into call setup code. From here on, source location
// emitting should be enabled.
debuginfo::start_emitting_source_locations(fcx);
let mut mircx = MirContext {
mir: mir.clone(),
fcx: fcx,
@ -161,6 +190,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
vars: vars,
temps: temps,
args: args,
scopes: scopes
};
let mut visited = BitVector::new(mir_blocks.len());
@ -185,6 +215,7 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
}
}
DebugLoc::None.apply(fcx);
fcx.cleanup();
}
@ -192,12 +223,25 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
/// argument's value. As arguments are lvalues, these are always
/// indirect.
fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
mir: &mir::Mir<'tcx>)
mir: &mir::Mir<'tcx>,
scopes: &[DIScope])
-> Vec<LvalueRef<'tcx>> {
let fcx = bcx.fcx();
let tcx = bcx.tcx();
let mut idx = 0;
let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
// Get the argument scope assuming ScopeId(0) has no parent.
let arg_scope = mir.scopes.get(0).and_then(|data| {
let scope = scopes[0];
if data.parent_scope.is_none() && !scope.is_null() &&
bcx.sess().opts.debuginfo == FullDebugInfo {
Some(scope)
} else {
None
}
});
mir.arg_decls.iter().enumerate().map(|(arg_index, arg_decl)| {
let arg_ty = bcx.monomorphize(&arg_decl.ty);
if arg_decl.spread {
@ -211,13 +255,14 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
_ => bug!("spread argument isn't a tuple?!")
};
let lltuplety = type_of::type_of(bcx.ccx(), arg_ty);
let lltemp = bcx.with_block(|bcx| {
base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
});
for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
let dst = bcx.struct_gep(lltemp, i);
let arg = &fcx.fn_ty.args[idx];
idx += 1;
idx += 1;
if common::type_is_fat_ptr(tcx, tupled_arg_ty) {
// We pass fat pointers as two words, but inside the tuple
// they are the two sub-fields of a single aggregate field.
@ -228,17 +273,37 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
} else {
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
}
bcx.with_block(|bcx| arg_scope.map(|scope| {
let byte_offset_of_var_in_tuple =
machine::llelement_offset(bcx.ccx(), lltuplety, i);
let address_operations = unsafe {
[llvm::LLVMDIBuilderCreateOpDeref(),
llvm::LLVMDIBuilderCreateOpPlus(),
byte_offset_of_var_in_tuple as i64]
};
let variable_access = VariableAccess::IndirectVariable {
alloca: lltemp,
address_operations: &address_operations
};
declare_local(bcx, token::special_idents::invalid.name,
tupled_arg_ty, scope, variable_access,
VariableKind::ArgumentVariable(arg_index + i + 1),
bcx.fcx().span.unwrap_or(DUMMY_SP));
}));
}
return LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty));
}
let arg = &fcx.fn_ty.args[idx];
idx += 1;
let llval = if arg.is_indirect() {
let llval = if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo {
// Don't copy an indirect argument to an alloca, the caller
// already put it in a temporary alloca and gave it up, unless
// we emit extra-debug-info, which requires local allocas :(.
// FIXME: lifetimes, debug info
// FIXME: lifetimes
let llarg = llvm::get_param(fcx.llfn, llarg_idx as c_uint);
llarg_idx += 1;
llarg
@ -261,6 +326,12 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
}
lltemp
};
bcx.with_block(|bcx| arg_scope.map(|scope| {
declare_local(bcx, token::special_idents::invalid.name, arg_ty, scope,
VariableAccess::DirectVariable { alloca: llval },
VariableKind::ArgumentVariable(arg_index + 1),
bcx.fcx().span.unwrap_or(DUMMY_SP));
}));
LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty))
}).collect()
}

View File

@ -38,7 +38,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_rvalue(&mut self,
bcx: BlockAndBuilder<'bcx, 'tcx>,
dest: LvalueRef<'tcx>,
rvalue: &mir::Rvalue<'tcx>)
rvalue: &mir::Rvalue<'tcx>,
debug_loc: DebugLoc)
-> BlockAndBuilder<'bcx, 'tcx>
{
debug!("trans_rvalue(dest.llval={:?}, rvalue={:?})",
@ -58,7 +59,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
// into-coerce of a thin pointer to a fat pointer - just
// use the operand path.
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue, debug_loc);
self.store_operand(&bcx, dest.llval, temp);
return bcx;
}
@ -217,7 +218,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
_ => {
assert!(rvalue_creates_operand(rvalue));
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue, debug_loc);
self.store_operand(&bcx, dest.llval, temp);
bcx
}
@ -226,7 +227,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_rvalue_operand(&mut self,
bcx: BlockAndBuilder<'bcx, 'tcx>,
rvalue: &mir::Rvalue<'tcx>)
rvalue: &mir::Rvalue<'tcx>,
debug_loc: DebugLoc)
-> (BlockAndBuilder<'bcx, 'tcx>, OperandRef<'tcx>)
{
assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue);
@ -419,7 +421,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
lhs_addr, lhs_extra,
rhs_addr, rhs_extra,
lhs.ty, op.to_hir_binop(),
DebugLoc::None)
debug_loc)
})
}
_ => bug!()
@ -470,7 +472,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
box_ty,
llsize,
llalign,
DebugLoc::None);
debug_loc);
llval = Some(val);
bcx
});

View File

@ -10,6 +10,7 @@
use rustc::mir::repr as mir;
use common::BlockAndBuilder;
use debuginfo::DebugLoc;
use super::MirContext;
use super::TempRef;
@ -21,6 +22,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
-> BlockAndBuilder<'bcx, 'tcx> {
debug!("trans_statement(statement={:?})", statement);
let debug_loc = DebugLoc::ScopeAt(self.scopes[statement.scope.index()],
statement.span);
debug_loc.apply_to_bcx(&bcx);
debug_loc.apply(bcx.fcx());
match statement.kind {
mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
match *lvalue {
@ -28,10 +33,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let index = index as usize;
match self.temps[index as usize] {
TempRef::Lvalue(tr_dest) => {
self.trans_rvalue(bcx, tr_dest, rvalue)
self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
}
TempRef::Operand(None) => {
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue,
debug_loc);
self.temps[index] = TempRef::Operand(Some(operand));
bcx
}
@ -44,7 +50,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
_ => {
let tr_dest = self.trans_lvalue(&bcx, lvalue);
self.trans_rvalue(bcx, tr_dest, rvalue)
self.trans_rvalue(bcx, tr_dest, rvalue, debug_loc)
}
}
}