Skip to content

Commit

Permalink
trans: initial implementation of MIR debuginfo.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Apr 11, 2016
1 parent f680c62 commit ce8d4a2
Show file tree
Hide file tree
Showing 11 changed files with 289 additions and 123 deletions.
4 changes: 2 additions & 2 deletions src/librustc_trans/base.rs
Expand Up @@ -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)
}

Expand Down Expand Up @@ -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();
}

Expand Down
8 changes: 4 additions & 4 deletions src/librustc_trans/controlflow.rs
Expand Up @@ -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);
}
}

Expand All @@ -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();

Expand All @@ -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
}
Expand Down
81 changes: 77 additions & 4 deletions src/librustc_trans/debuginfo/create_scope_map.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
48 changes: 22 additions & 26 deletions src/librustc_trans/debuginfo/mod.rs
Expand Up @@ -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};
Expand All @@ -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};
Expand All @@ -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;
Expand Down Expand Up @@ -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
}

Expand All @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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(
Expand All @@ -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 */ }
}
Expand All @@ -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);
}
}

Expand Down

0 comments on commit ce8d4a2

Please sign in to comment.