Skip to content

Commit

Permalink
Auto merge of rust-lang#68965 - eddyb:mir-inline-scope, r=nagisa,oli-obk
Browse files Browse the repository at this point in the history
 rustc_mir: track inlined callees in SourceScopeData.

We now record which MIR scopes are the roots of *other* (inlined) functions's scope trees, which allows us to generate the correct debuginfo in codegen, similar to what LLVM inlining generates.
This PR makes the `ui` test `backtrace-debuginfo` pass, if the MIR inliner is turned on by default.

Also, `#[track_caller]` is now correct in the face of MIR inlining (cc `@anp).`

Fixes rust-lang#76997.

r? `@rust-lang/wg-mir-opt`
  • Loading branch information
bors committed Oct 26, 2020
2 parents 35debd4 + 2b3f009 commit 0da6d42
Show file tree
Hide file tree
Showing 68 changed files with 878 additions and 618 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/builder.rs
Expand Up @@ -56,6 +56,7 @@ impl BackendTypes for Builder<'_, 'll, 'tcx> {
type Funclet = <CodegenCx<'ll, 'tcx> as BackendTypes>::Funclet;

type DIScope = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIScope;
type DILocation = <CodegenCx<'ll, 'tcx> as BackendTypes>::DILocation;
type DIVariable = <CodegenCx<'ll, 'tcx> as BackendTypes>::DIVariable;
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_llvm/src/common.rs
Expand Up @@ -80,13 +80,15 @@ impl Funclet<'ll> {

impl BackendTypes for CodegenCx<'ll, 'tcx> {
type Value = &'ll Value;
// FIXME(eddyb) replace this with a `Function` "subclass" of `Value`.
type Function = &'ll Value;

type BasicBlock = &'ll BasicBlock;
type Type = &'ll Type;
type Funclet = Funclet<'ll>;

type DIScope = &'ll llvm::debuginfo::DIScope;
type DILocation = &'ll llvm::debuginfo::DILocation;
type DIVariable = &'ll llvm::debuginfo::DIVariable;
}

Expand Down
81 changes: 55 additions & 26 deletions compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
Expand Up @@ -3,21 +3,26 @@ use super::utils::DIB;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
use rustc_codegen_ssa::traits::*;

use crate::abi::FnAbi;
use crate::common::CodegenCx;
use crate::llvm;
use crate::llvm::debuginfo::{DIScope, DISubprogram};
use crate::llvm::debuginfo::{DILocation, DIScope};
use rustc_middle::mir::{Body, SourceScope};
use rustc_middle::ty::layout::FnAbiExt;
use rustc_middle::ty::{self, Instance};
use rustc_session::config::DebugInfo;

use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx;

/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
// FIXME(eddyb) almost all of this should be in `rustc_codegen_ssa::mir::debuginfo`.
pub fn compute_mir_scopes(
cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
fn_metadata: &'ll DISubprogram,
debug_context: &mut FunctionDebugContext<&'ll DIScope>,
cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>,
mir: &Body<'tcx>,
fn_dbg_scope: &'ll DIScope,
debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
) {
// Find all the scopes with variables defined in them.
let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
Expand All @@ -37,58 +42,82 @@ pub fn compute_mir_scopes(
// Instantiate all scopes.
for idx in 0..mir.source_scopes.len() {
let scope = SourceScope::new(idx);
make_mir_scope(cx, &mir, fn_metadata, &has_variables, debug_context, scope);
make_mir_scope(cx, instance, &mir, fn_dbg_scope, &has_variables, debug_context, scope);
}
}

fn make_mir_scope(
cx: &CodegenCx<'ll, '_>,
mir: &Body<'_>,
fn_metadata: &'ll DISubprogram,
cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>,
mir: &Body<'tcx>,
fn_dbg_scope: &'ll DIScope,
has_variables: &BitSet<SourceScope>,
debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
scope: SourceScope,
) {
if debug_context.scopes[scope].is_valid() {
if debug_context.scopes[scope].dbg_scope.is_some() {
return;
}

let scope_data = &mir.source_scopes[scope];
let parent_scope = if let Some(parent) = scope_data.parent_scope {
make_mir_scope(cx, mir, fn_metadata, has_variables, debug_context, parent);
make_mir_scope(cx, instance, mir, fn_dbg_scope, has_variables, debug_context, parent);
debug_context.scopes[parent]
} else {
// The root is the function itself.
let loc = cx.lookup_debug_loc(mir.span.lo());
debug_context.scopes[scope] = DebugScope {
scope_metadata: Some(fn_metadata),
dbg_scope: Some(fn_dbg_scope),
inlined_at: None,
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
return;
};

if !has_variables.contains(scope) {
// Do not create a DIScope if there are no variables
// defined in this MIR Scope, to avoid debuginfo bloat.
if !has_variables.contains(scope) && scope_data.inlined.is_none() {
// Do not create a DIScope if there are no variables defined in this
// MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat.
debug_context.scopes[scope] = parent_scope;
return;
}

let loc = cx.lookup_debug_loc(scope_data.span.lo());
let file_metadata = file_metadata(cx, &loc.file, debug_context.defining_crate);
let file_metadata = file_metadata(cx, &loc.file);

let scope_metadata = unsafe {
Some(llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope.scope_metadata.unwrap(),
file_metadata,
loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
))
let dbg_scope = match scope_data.inlined {
Some((callee, _)) => {
// FIXME(eddyb) this would be `self.monomorphize(&callee)`
// if this is moved to `rustc_codegen_ssa::mir::debuginfo`.
let callee = cx.tcx.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
&callee,
);
let callee_fn_abi = FnAbi::of_instance(cx, callee, &[]);
cx.dbg_scope_fn(callee, &callee_fn_abi, None)
}
None => unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope.dbg_scope.unwrap(),
file_metadata,
loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
loc.col.unwrap_or(UNKNOWN_COLUMN_NUMBER),
)
},
};

let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {
// FIXME(eddyb) this doesn't account for the macro-related
// `Span` fixups that `rustc_codegen_ssa::mir::debuginfo` does.
let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span);
cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span)
});

debug_context.scopes[scope] = DebugScope {
scope_metadata,
dbg_scope: Some(dbg_scope),
inlined_at: inlined_at.or(parent_scope.inlined_at),
file_start_pos: loc.file.start_pos,
file_end_pos: loc.file.end_pos,
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/doc.rs
Expand Up @@ -28,7 +28,7 @@
//! utilizing a cache. The way to get a shared metadata node when needed is
//! thus to just call the corresponding function in this module:
//!
//! let file_metadata = file_metadata(crate_context, path);
//! let file_metadata = file_metadata(cx, file);
//!
//! The function will take care of probing the cache for an existing node for
//! that exact file path.
Expand Down
21 changes: 8 additions & 13 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Expand Up @@ -26,7 +26,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_fs_util::path_to_c_string;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ich::NodeIdHashingMode;
use rustc_middle::mir::interpret::truncate;
Expand Down Expand Up @@ -760,16 +760,12 @@ fn hex_encode(data: &[u8]) -> String {
hex_string
}

pub fn file_metadata(
cx: &CodegenCx<'ll, '_>,
source_file: &SourceFile,
defining_crate: CrateNum,
) -> &'ll DIFile {
debug!("file_metadata: file_name: {}, defining_crate: {}", source_file.name, defining_crate);
pub fn file_metadata(cx: &CodegenCx<'ll, '_>, source_file: &SourceFile) -> &'ll DIFile {
debug!("file_metadata: file_name: {}", source_file.name);

let hash = Some(&source_file.src_hash);
let file_name = Some(source_file.name.to_string());
let directory = if defining_crate == LOCAL_CRATE {
let directory = if source_file.is_real_file() && !source_file.is_imported() {
Some(cx.sess().working_dir.0.to_string_lossy().to_string())
} else {
// If the path comes from an upstream crate we assume it has been made
Expand Down Expand Up @@ -1835,7 +1831,7 @@ impl<'tcx> VariantInfo<'_, 'tcx> {
if !span.is_dummy() {
let loc = cx.lookup_debug_loc(span.lo());
return Some(SourceInfo {
file: file_metadata(cx, &loc.file, def_id.krate),
file: file_metadata(cx, &loc.file),
line: loc.line.unwrap_or(UNKNOWN_LINE_NUMBER),
});
}
Expand Down Expand Up @@ -2474,7 +2470,7 @@ pub fn create_global_var_metadata(cx: &CodegenCx<'ll, '_>, def_id: DefId, global

let (file_metadata, line_number) = if !span.is_dummy() {
let loc = cx.lookup_debug_loc(span.lo());
(file_metadata(cx, &loc.file, LOCAL_CRATE), loc.line)
(file_metadata(cx, &loc.file), loc.line)
} else {
(unknown_file_metadata(cx), None)
};
Expand Down Expand Up @@ -2576,9 +2572,8 @@ pub fn create_vtable_metadata(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, vtable: &
pub fn extend_scope_to_file(
cx: &CodegenCx<'ll, '_>,
scope_metadata: &'ll DIScope,
file: &rustc_span::SourceFile,
defining_crate: CrateNum,
file: &SourceFile,
) -> &'ll DILexicalBlock {
let file_metadata = file_metadata(cx, &file, defining_crate);
let file_metadata = file_metadata(cx, file);
unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) }
}

0 comments on commit 0da6d42

Please sign in to comment.