Skip to content
50 changes: 26 additions & 24 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ pub(super) const UNKNOWN_COLUMN_NUMBER: c_uint = 0;

const NO_SCOPE_METADATA: Option<&DIScope> = None;
/// A function that returns an empty list of generic parameter debuginfo nodes.
const NO_GENERICS: for<'ll> fn(&CodegenCx<'ll, '_>) -> SmallVec<&'ll DIType> = |_| SmallVec::new();
const NO_GENERICS: for<'ll> fn(&CodegenCx<'ll, '_>) -> SmallVec<Option<&'ll DIType>> =
|_| SmallVec::new();

// SmallVec is used quite a bit in this module, so create a shorthand.
// The actual number of elements is not so important.
Expand Down Expand Up @@ -1287,32 +1288,33 @@ fn build_union_type_di_node<'ll, 'tcx>(
fn build_generic_type_param_di_nodes<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
ty: Ty<'tcx>,
) -> SmallVec<&'ll DIType> {
) -> SmallVec<Option<&'ll DIType>> {
if let ty::Adt(def, args) = *ty.kind() {
if args.types().next().is_some() {
let generics = cx.tcx.generics_of(def.did());
let names = get_parameter_names(cx, generics);
let template_params: SmallVec<_> = iter::zip(args, names)
.filter_map(|(kind, name)| {
kind.as_type().map(|ty| {
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
let actual_type_di_node = type_di_node(cx, actual_type);
let name = name.as_str();
unsafe {
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
None,
name.as_c_char_ptr(),
name.len(),
actual_type_di_node,
)
}
})
let generics = cx.tcx.generics_of(def.did());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generics_of is now called unconditionally and is likely the source of the perf regression

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out that wasn't it

return get_template_parameters(cx, generics, args);
}

return smallvec![];
}

pub(super) fn get_template_parameters<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
generics: &ty::Generics,
args: ty::GenericArgsRef<'tcx>,
) -> SmallVec<Option<&'ll DIType>> {
if args.types().next().is_some() {
let names = get_parameter_names(cx, generics);
let template_params: SmallVec<_> = iter::zip(args, names)
.filter_map(|(kind, name)| {
kind.as_type().map(|ty| {
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
let actual_type_di_node = type_di_node(cx, actual_type);
Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
})
.collect();
})
.collect();

return template_params;
}
return template_params;
}

return smallvec![];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(

state_specific_fields.into_iter().chain(common_fields).collect()
},
// FIXME: this is a no-op. `build_generic_type_param_di_nodes` only works for Adts.
|cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
)
.di_node
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,16 +257,15 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
stub_info: StubInfo<'ll, 'tcx>,
members: impl FnOnce(&CodegenCx<'ll, 'tcx>, &'ll DIType) -> SmallVec<&'ll DIType>,
generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<&'ll DIType>,
generics: impl FnOnce(&CodegenCx<'ll, 'tcx>) -> SmallVec<Option<&'ll DIType>>,
) -> DINodeCreationResult<'ll> {
assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None);

debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata);

let members: SmallVec<_> =
members(cx, stub_info.metadata).into_iter().map(|node| Some(node)).collect();
let generics: SmallVec<Option<&'ll DIType>> =
generics(cx).into_iter().map(|node| Some(node)).collect();
let generics = generics(cx);

if !(members.is_empty() && generics.is_empty()) {
unsafe {
Expand Down
62 changes: 21 additions & 41 deletions compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use std::cell::{OnceCell, RefCell};
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
use std::{iter, ptr};

use libc::c_uint;
use rustc_abi::Size;
Expand Down Expand Up @@ -34,8 +34,8 @@ use crate::builder::Builder;
use crate::common::{AsCCharPtr, CodegenCx};
use crate::llvm;
use crate::llvm::debuginfo::{
DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
DIVariable,
DIArray, DIBuilderBox, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope,
DITemplateTypeParameter, DIType, DIVariable,
};
use crate::value::Value;

Expand Down Expand Up @@ -251,7 +251,7 @@ struct DebugLoc {
col: u32,
}

impl CodegenCx<'_, '_> {
impl<'ll> CodegenCx<'ll, '_> {
/// Looks up debug source information about a `BytePos`.
// FIXME(eddyb) rename this to better indicate it's a duplicate of
// `lookup_char_pos` rather than `dbg_loc`, perhaps by making
Expand Down Expand Up @@ -279,6 +279,22 @@ impl CodegenCx<'_, '_> {
DebugLoc { file, line, col }
}
}

fn create_template_type_parameter(
&self,
name: &str,
actual_type_metadata: &'ll DIType,
) -> &'ll DITemplateTypeParameter {
unsafe {
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(self),
None,
name.as_c_char_ptr(),
name.len(),
actual_type_metadata,
)
}
}
}

impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
Expand Down Expand Up @@ -471,46 +487,10 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
generics: &ty::Generics,
args: GenericArgsRef<'tcx>,
) -> &'ll DIArray {
if args.types().next().is_none() {
return create_DIArray(DIB(cx), &[]);
}

// Again, only create type information if full debuginfo is enabled
let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
let names = get_parameter_names(cx, generics);
iter::zip(args, names)
.filter_map(|(kind, name)| {
kind.as_type().map(|ty| {
let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
let actual_type_metadata = type_di_node(cx, actual_type);
let name = name.as_str();
unsafe {
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
None,
name.as_c_char_ptr(),
name.len(),
actual_type_metadata,
))
}
})
})
.collect()
} else {
vec![]
};

let template_params = metadata::get_template_parameters(cx, generics, args);
create_DIArray(DIB(cx), &template_params)
}

fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
get_parameter_names(cx, cx.tcx.generics_of(def_id))
});
names.extend(generics.own_params.iter().map(|param| param.name));
names
}

/// Returns a scope, plus `true` if that's a type scope for "class" methods,
/// otherwise `false` for plain namespace scopes.
fn get_containing_scope<'ll, 'tcx>(
Expand Down