Skip to content

Commit

Permalink
Auto merge of #65718 - eddyb:codegen-var-debuginfo, r=nikomatsakis
Browse files Browse the repository at this point in the history
rustc_codegen_ssa: introduce MIR VarDebugInfo, but only for codegen.

These are all the codegen changes necessary for #56231.

The refactors were performed locally to codegen, and in several steps, to ease reviewing and avoid introducing changes in behavior (as I'm not sure our debuginfo tests cover enough).

r? @michaelwoerister cc @nagisa @rkruppe @oli-obk
  • Loading branch information
bors committed Oct 31, 2019
2 parents 2f16be4 + 2994186 commit 404d42f
Show file tree
Hide file tree
Showing 14 changed files with 642 additions and 654 deletions.
58 changes: 21 additions & 37 deletions src/librustc_codegen_llvm/debuginfo/create_scope_map.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, FunctionDebugContextData, MirDebugScope};
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope};
use super::metadata::file_metadata;
use super::utils::{DIB, span_start};

Expand All @@ -12,34 +12,20 @@ use libc::c_uint;
use syntax_pos::Pos;

use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};

use syntax_pos::BytePos;
use rustc_index::vec::Idx;

/// Produces 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(
pub fn compute_mir_scopes(
cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
debug_context: &FunctionDebugContext<&'ll DISubprogram>,
) -> IndexVec<SourceScope, MirDebugScope<&'ll DIScope>> {
let null_scope = MirDebugScope {
scope_metadata: None,
file_start_pos: BytePos(0),
file_end_pos: BytePos(0)
};
let mut scopes = IndexVec::from_elem(null_scope, &mir.source_scopes);

let debug_context = match *debug_context {
FunctionDebugContext::RegularContext(ref data) => data,
FunctionDebugContext::DebugInfoDisabled |
FunctionDebugContext::FunctionWithoutDebugInfo => {
return scopes;
}
};

fn_metadata: &'ll DISubprogram,
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
) {
// Find all the scopes with variables defined in them.
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
// FIXME(eddyb) base this on `decl.name`, or even better, on debuginfo.
// FIXME(eddyb) take into account that arguments always have debuginfo,
// irrespective of their name (assuming full debuginfo is enabled).
for var in mir.vars_iter() {
let decl = &mir.local_decls[var];
has_variables.insert(decl.visibility_scope);
Expand All @@ -48,31 +34,29 @@ pub fn create_mir_scopes(
// Instantiate all scopes.
for idx in 0..mir.source_scopes.len() {
let scope = SourceScope::new(idx);
make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes);
make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope);
}

scopes
}

fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
fn_metadata: &'ll DISubprogram,
has_variables: &BitSet<SourceScope>,
debug_context: &FunctionDebugContextData<&'ll DISubprogram>,
scope: SourceScope,
scopes: &mut IndexVec<SourceScope, MirDebugScope<&'ll DIScope>>) {
if scopes[scope].is_valid() {
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
scope: SourceScope) {
if debug_context.scopes[scope].is_valid() {
return;
}

let scope_data = &mir.source_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes);
scopes[parent]
make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent);
debug_context.scopes[parent]
} else {
// The root is the function itself.
let loc = span_start(cx, mir.span);
scopes[scope] = MirDebugScope {
scope_metadata: Some(debug_context.fn_metadata),
debug_context.scopes[scope] = DebugScope {
scope_metadata: Some(fn_metadata),
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
Expand All @@ -86,8 +70,8 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
// However, we don't skip creating a nested scope if
// our parent is the root, because we might want to
// put arguments in the root and not have shadowing.
if parent_scope.scope_metadata.unwrap() != debug_context.fn_metadata {
scopes[scope] = parent_scope;
if parent_scope.scope_metadata.unwrap() != fn_metadata {
debug_context.scopes[scope] = parent_scope;
return;
}
}
Expand All @@ -105,7 +89,7 @@ fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
loc.line as c_uint,
loc.col.to_usize() as c_uint))
};
scopes[scope] = MirDebugScope {
debug_context.scopes[scope] = DebugScope {
scope_metadata,
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
Expand Down
159 changes: 83 additions & 76 deletions src/librustc_codegen_llvm/debuginfo/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// See doc.rs for documentation.
mod doc;

use rustc_codegen_ssa::debuginfo::VariableAccess::*;
use rustc_codegen_ssa::debuginfo::VariableKind::*;
use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;

use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
use self::namespace::mangled_name_of_instance;
Expand All @@ -11,7 +10,7 @@ use self::metadata::{type_metadata, file_metadata, TypeMap};
use self::source_loc::InternalDebugLocation::{self, UnknownLocation};

use crate::llvm;
use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags,
use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DIArray, DIFlags,
DISPFlags, DILexicalBlock};
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
Expand All @@ -27,17 +26,19 @@ use rustc::session::config::{self, DebugInfo};
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_index::vec::IndexVec;
use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess,
VariableKind, FunctionDebugContextData, type_names};
use rustc_codegen_ssa::debuginfo::type_names;
use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, DebugScope,
VariableKind};

use libc::c_uint;
use std::cell::RefCell;
use std::ffi::{CStr, CString};

use syntax_pos::{self, Span, Pos};
use smallvec::SmallVec;
use syntax_pos::{self, BytePos, Span, Pos};
use syntax::ast;
use syntax::symbol::Symbol;
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Size};
use rustc_codegen_ssa::traits::*;

pub mod gdb;
Expand All @@ -47,7 +48,7 @@ pub mod metadata;
mod create_scope_map;
mod source_loc;

pub use self::create_scope_map::{create_mir_scopes};
pub use self::create_scope_map::compute_mir_scopes;
pub use self::metadata::create_global_var_metadata;
pub use self::metadata::extend_scope_to_file;
pub use self::source_loc::set_source_location;
Expand Down Expand Up @@ -148,21 +149,23 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn declare_local(
&mut self,
dbg_context: &FunctionDebugContext<&'ll DISubprogram>,
dbg_context: &FunctionDebugContext<&'ll DIScope>,
variable_name: ast::Name,
variable_type: Ty<'tcx>,
scope_metadata: &'ll DIScope,
variable_access: VariableAccess<'_, &'ll Value>,
variable_alloca: Self::Value,
direct_offset: Size,
indirect_offsets: &[Size],
variable_kind: VariableKind,
span: Span,
) {
assert!(!dbg_context.get_ref(span).source_locations_enabled);
assert!(!dbg_context.source_locations_enabled);
let cx = self.cx();

let file = span_start(cx, span).file;
let file_metadata = file_metadata(cx,
&file.name,
dbg_context.get_ref(span).defining_crate);
dbg_context.defining_crate);

let loc = span_start(cx, span);
let type_metadata = type_metadata(cx, variable_type, span);
Expand All @@ -173,49 +176,61 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
};
let align = cx.align_of(variable_type);

let name = SmallCStr::new(&variable_name.as_str());
match (variable_access, &[][..]) {
(DirectVariable { alloca }, address_operations) |
(IndirectVariable {alloca, address_operations}, _) => {
let metadata = unsafe {
llvm::LLVMRustDIBuilderCreateVariable(
DIB(cx),
dwarf_tag,
scope_metadata,
name.as_ptr(),
file_metadata,
loc.line as c_uint,
type_metadata,
cx.sess().opts.optimize != config::OptLevel::No,
DIFlags::FlagZero,
argument_index,
align.bytes() as u32,
)
};
source_loc::set_debug_location(self,
InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
unsafe {
let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder);
let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
DIB(cx),
alloca,
metadata,
address_operations.as_ptr(),
address_operations.len() as c_uint,
debug_loc,
self.llbb());

llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
}
source_loc::set_debug_location(self, UnknownLocation);
// Convert the direct and indirect offsets to address ops.
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
let mut addr_ops = SmallVec::<[_; 8]>::new();

if direct_offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
addr_ops.push(direct_offset.bytes() as i64);
}
for &offset in indirect_offsets {
addr_ops.push(op_deref());
if offset.bytes() > 0 {
addr_ops.push(op_plus_uconst());
addr_ops.push(offset.bytes() as i64);
}
}

let name = SmallCStr::new(&variable_name.as_str());
let metadata = unsafe {
llvm::LLVMRustDIBuilderCreateVariable(
DIB(cx),
dwarf_tag,
scope_metadata,
name.as_ptr(),
file_metadata,
loc.line as c_uint,
type_metadata,
cx.sess().opts.optimize != config::OptLevel::No,
DIFlags::FlagZero,
argument_index,
align.bytes() as u32,
)
};
source_loc::set_debug_location(self,
InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
unsafe {
let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder);
let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
DIB(cx),
variable_alloca,
metadata,
addr_ops.as_ptr(),
addr_ops.len() as c_uint,
debug_loc,
self.llbb());

llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
}
source_loc::set_debug_location(self, UnknownLocation);
}

fn set_source_location(
&mut self,
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
scope: Option<&'ll DIScope>,
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
scope: &'ll DIScope,
span: Span,
) {
set_source_location(debug_context, &self, scope, span)
Expand All @@ -224,7 +239,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
}

fn set_var_name(&mut self, value: &'ll Value, name: impl ToString) {
fn set_var_name(&mut self, value: &'ll Value, name: &str) {
// Avoid wasting time if LLVM value names aren't even enabled.
if self.sess().fewer_names() {
return;
Expand Down Expand Up @@ -254,7 +269,7 @@ impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
Err(_) => return,
}

let cname = CString::new(name.to_string()).unwrap();
let cname = SmallCStr::new(name);
unsafe {
llvm::LLVMSetValueName(value, cname.as_ptr());
}
Expand All @@ -268,14 +283,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
sig: ty::FnSig<'tcx>,
llfn: &'ll Value,
mir: &mir::Body<'_>,
) -> FunctionDebugContext<&'ll DISubprogram> {
) -> Option<FunctionDebugContext<&'ll DIScope>> {
if self.sess().opts.debuginfo == DebugInfo::None {
return FunctionDebugContext::DebugInfoDisabled;
return None;
}

if let InstanceDef::Item(def_id) = instance.def {
if self.tcx().codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) {
return FunctionDebugContext::FunctionWithoutDebugInfo;
return None;
}
}

Expand All @@ -284,7 +299,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// This can be the case for functions inlined from another crate
if span.is_dummy() {
// FIXME(simulacrum): Probably can't happen; remove.
return FunctionDebugContext::FunctionWithoutDebugInfo;
return None;
}

let def_id = instance.def_id();
Expand Down Expand Up @@ -357,14 +372,23 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
None)
};

// Initialize fn debug context (including scope map and namespace map)
let fn_debug_context = FunctionDebugContextData {
fn_metadata,
// Initialize fn debug context (including scopes).
// FIXME(eddyb) figure out a way to not need `Option` for `scope_metadata`.
let null_scope = DebugScope {
scope_metadata: None,
file_start_pos: BytePos(0),
file_end_pos: BytePos(0)
};
let mut fn_debug_context = FunctionDebugContext {
scopes: IndexVec::from_elem(null_scope, &mir.source_scopes),
source_locations_enabled: false,
defining_crate: def_id.krate,
};

return FunctionDebugContext::RegularContext(fn_debug_context);
// Fill in all the scopes, with the information from the MIR body.
compute_mir_scopes(self, mir, fn_metadata, &mut fn_debug_context);

return Some(fn_debug_context);

fn get_function_signature<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
Expand Down Expand Up @@ -549,14 +573,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
metadata::create_vtable_metadata(self, ty, vtable)
}

fn create_mir_scopes(
&self,
mir: &mir::Body<'_>,
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
) -> IndexVec<mir::SourceScope, MirDebugScope<&'ll DIScope>> {
create_scope_map::create_mir_scopes(self, mir, debug_context)
}

fn extend_scope_to_file(
&self,
scope_metadata: &'ll DIScope,
Expand All @@ -569,13 +585,4 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn debuginfo_finalize(&self) {
finalize(self)
}

fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] {
unsafe {
[llvm::LLVMRustDIBuilderCreateOpDeref(),
llvm::LLVMRustDIBuilderCreateOpPlusUconst(),
byte_offset_of_var_in_env as i64,
llvm::LLVMRustDIBuilderCreateOpDeref()]
}
}
}
Loading

0 comments on commit 404d42f

Please sign in to comment.