Skip to content

Various codegen_llvm cleanups #138674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Mar 19, 2025
125 changes: 61 additions & 64 deletions compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::borrow::Cow;
use std::fmt::{self, Write};
use std::hash::{Hash, Hasher};
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::{iter, ptr};

use libc::{c_char, c_longlong, c_uint};
Expand Down Expand Up @@ -38,8 +39,8 @@ use crate::debuginfo::metadata::type_map::build_type_with_children;
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
use crate::llvm;
use crate::llvm::debuginfo::{
DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind,
DebugNameTableKind,
DIBuilder, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType,
DebugEmissionKind, DebugNameTableKind,
};
use crate::value::Value;

Expand Down Expand Up @@ -68,7 +69,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 @@ -311,12 +313,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(

debug_context(cx).type_map.unique_id_to_di_node.borrow_mut().remove(&unique_type_id);

let fn_di_node = unsafe {
llvm::LLVMRustDIBuilderCreateSubroutineType(
DIB(cx),
create_DIArray(DIB(cx), &signature_di_nodes[..]),
)
};
let fn_di_node = create_subroutine_type(cx, create_DIArray(DIB(cx), &signature_di_nodes[..]));

// This is actually a function pointer, so wrap it in pointer DI.
let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false);
Expand All @@ -340,6 +337,13 @@ fn build_subroutine_type_di_node<'ll, 'tcx>(
DINodeCreationResult::new(di_node, false)
}

pub(super) fn create_subroutine_type<'ll>(
cx: &CodegenCx<'ll, '_>,
signature: &'ll DICompositeType,
) -> &'ll DICompositeType {
unsafe { llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), signature) }
}

/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
/// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
fn build_dyn_type_di_node<'ll, 'tcx>(
Expand Down Expand Up @@ -620,42 +624,38 @@ pub(crate) fn file_metadata<'ll>(cx: &CodegenCx<'ll, '_>, source_file: &SourceFi
let source =
cx.sess().opts.unstable_opts.embed_source.then_some(()).and(source_file.src.as_ref());

unsafe {
llvm::LLVMRustDIBuilderCreateFile(
DIB(cx),
file_name.as_c_char_ptr(),
file_name.len(),
directory.as_c_char_ptr(),
directory.len(),
hash_kind,
hash_value.as_c_char_ptr(),
hash_value.len(),
source.map_or(ptr::null(), |x| x.as_c_char_ptr()),
source.map_or(0, |x| x.len()),
)
}
create_file(DIB(cx), &file_name, &directory, &hash_value, hash_kind, source)
}
}

fn unknown_file_metadata<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll DIFile {
debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| unsafe {
let file_name = "<unknown>";
let directory = "";
let hash_value = "";
debug_context(cx).created_files.borrow_mut().entry(None).or_insert_with(|| {
create_file(DIB(cx), "<unknown>", "", "", llvm::ChecksumKind::None, None)
})
}

fn create_file<'ll>(
builder: &DIBuilder<'ll>,
file_name: &str,
directory: &str,
hash_value: &str,
hash_kind: llvm::ChecksumKind,
source: Option<&Arc<String>>,
) -> &'ll DIFile {
unsafe {
llvm::LLVMRustDIBuilderCreateFile(
DIB(cx),
builder,
file_name.as_c_char_ptr(),
file_name.len(),
directory.as_c_char_ptr(),
directory.len(),
llvm::ChecksumKind::None,
hash_kind,
hash_value.as_c_char_ptr(),
hash_value.len(),
ptr::null(),
0,
source.map_or(ptr::null(), |x| x.as_c_char_ptr()),
source.map_or(0, |x| x.len()),
)
})
}
}

trait MsvcBasicName {
Expand Down Expand Up @@ -929,17 +929,13 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
};

unsafe {
let compile_unit_file = llvm::LLVMRustDIBuilderCreateFile(
let compile_unit_file = create_file(
debug_context.builder.as_ref(),
name_in_debuginfo.as_c_char_ptr(),
name_in_debuginfo.len(),
work_dir.as_c_char_ptr(),
work_dir.len(),
&name_in_debuginfo,
&work_dir,
"",
llvm::ChecksumKind::None,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe this. Empty string now, null pointer before

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But that wouldn't explain the query count changes

ptr::null(),
0,
ptr::null(),
0,
None,
);

let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
Expand Down Expand Up @@ -1287,32 +1283,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
69 changes: 24 additions & 45 deletions compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

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 metadata::create_subroutine_type;
use rustc_abi::Size;
use rustc_codegen_ssa::debuginfo::type_names;
use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
Expand Down Expand Up @@ -34,8 +35,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 +252,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 +280,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 @@ -325,10 +342,8 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
let loc = self.lookup_debug_loc(span.lo());
let file_metadata = file_metadata(self, &loc.file);

let function_type_metadata = unsafe {
let fn_signature = get_function_signature(self, fn_abi);
llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature)
};
let function_type_metadata =
create_subroutine_type(self, get_function_signature(self, fn_abi));

let mut name = String::with_capacity(64);
type_names::push_item_name(tcx, def_id, false, &mut name);
Expand Down Expand Up @@ -471,46 +486,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