Rollup merge of #131876 - workingjubilee:llvm-c-c-c-comdat, r=Zalathar

compiler: Use LLVM's Comdat support

Acting on these long-ago issues:
- https://github.com/rust-lang/rust/issues/46437
- https://github.com/rust-lang/rust/issues/68955
This commit is contained in:
Stuart Cook 2024-10-20 14:06:03 +11:00 committed by GitHub
commit 0bfc49b053
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 40 additions and 27 deletions

View File

@ -132,7 +132,7 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
.collect::<Vec<_>>();
let initializer = cx.const_array(cx.type_ptr(), &name_globals);
let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), "__llvm_coverage_names");
let array = llvm::add_global(cx.llmod, cx.val_ty(initializer), c"__llvm_coverage_names");
llvm::set_global_constant(array, true);
llvm::set_linkage(array, llvm::Linkage::InternalLinkage);
llvm::set_initializer(array, initializer);

View File

@ -1,4 +1,5 @@
use std::cell::RefCell;
use std::ffi::CString;
use libc::c_uint;
use rustc_codegen_ssa::traits::{
@ -12,6 +13,7 @@
use rustc_middle::ty::Instance;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_target::abi::{Align, Size};
use rustc_target::spec::HasTargetSpec;
use tracing::{debug, instrument};
use crate::builder::Builder;
@ -284,10 +286,10 @@ pub(crate) fn save_cov_data_to_mod<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
cov_data_val: &'ll llvm::Value,
) {
let covmap_var_name = llvm::build_string(|s| unsafe {
let covmap_var_name = CString::new(llvm::build_byte_buffer(|s| unsafe {
llvm::LLVMRustCoverageWriteMappingVarNameToString(s);
})
.expect("Rust Coverage Mapping var name failed UTF-8 conversion");
}))
.unwrap();
debug!("covmap var name: {:?}", covmap_var_name);
let covmap_section_name = llvm::build_string(|s| unsafe {
@ -322,7 +324,8 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
// of descriptions play distinct roles in LLVM IR; therefore, assign them different names (by
// appending "u" to the end of the function record var name, to prevent `linkonce_odr` merging.
let func_record_var_name =
format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" });
CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" }))
.unwrap();
debug!("function record var name: {:?}", func_record_var_name);
debug!("function record section name: {:?}", covfun_section_name);
@ -334,7 +337,9 @@ pub(crate) fn save_func_record_to_mod<'ll, 'tcx>(
llvm::set_section(llglobal, covfun_section_name);
// LLVM's coverage mapping format specifies 8-byte alignment for items in this section.
llvm::set_alignment(llglobal, Align::EIGHT);
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
if cx.target_spec().supports_comdat() {
llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name);
}
cx.add_used_global(llglobal);
}

View File

@ -787,7 +787,9 @@ fn codegen_msvc_try<'ll>(
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
unsafe {
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
llvm::SetUniqueComdat(bx.llmod, tydesc);
if bx.cx.tcx.sess.target.supports_comdat() {
llvm::SetUniqueComdat(bx.llmod, tydesc);
}
llvm::LLVMSetInitializer(tydesc, type_info);
}

View File

@ -646,6 +646,7 @@ struct InvariantOpaque<'a> {
pub type Attribute;
pub type Metadata;
pub type BasicBlock;
pub type Comdat;
}
#[repr(C)]
pub struct Builder<'a>(InvariantOpaque<'a>);
@ -1490,6 +1491,9 @@ pub fn LLVMStructSetBody<'a>(
pub fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr);
pub fn LLVMIsAConstantInt(value_ref: &Value) -> Option<&ConstantInt>;
pub fn LLVMGetOrInsertComdat(M: &Module, Name: *const c_char) -> &Comdat;
pub fn LLVMSetComdat(V: &Value, C: &Comdat);
}
#[link(name = "llvm-wrapper", kind = "static")]
@ -2320,7 +2324,6 @@ pub fn LLVMRustBuildOperandBundleDef(
pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
pub fn LLVMRustSetComdat<'a>(M: &'a Module, V: &'a Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMRustSetModulePICLevel(M: &Module);
pub fn LLVMRustSetModulePIELevel(M: &Module);
pub fn LLVMRustSetModuleCodeModel(M: &Module, Model: CodeModel);

View File

@ -178,10 +178,10 @@ pub fn SetFunctionCallConv(fn_: &Value, cc: CallConv) {
// function.
// For more details on COMDAT sections see e.g., https://www.airs.com/blog/archives/52
pub fn SetUniqueComdat(llmod: &Module, val: &Value) {
unsafe {
let name = get_value_name(val);
LLVMRustSetComdat(llmod, val, name.as_ptr().cast(), name.len());
}
let name_buf = get_value_name(val).to_vec();
let name =
CString::from_vec_with_nul(name_buf).or_else(|buf| CString::new(buf.into_bytes())).unwrap();
set_comdat(llmod, val, &name);
}
pub fn SetUnnamedAddress(global: &Value, unnamed: UnnamedAddr) {
@ -217,8 +217,7 @@ pub fn set_section(llglobal: &Value, section_name: &str) {
}
}
pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name: &str) -> &'a Value {
let name_cstr = CString::new(name).expect("unexpected CString error");
pub fn add_global<'a>(llmod: &'a Module, ty: &'a Type, name_cstr: &CStr) -> &'a Value {
unsafe { LLVMAddGlobal(llmod, ty, name_cstr.as_ptr()) }
}
@ -252,9 +251,14 @@ pub fn set_alignment(llglobal: &Value, align: Align) {
}
}
pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &str) {
/// Get the `name`d comdat from `llmod` and assign it to `llglobal`.
///
/// Inserts the comdat into `llmod` if it does not exist.
/// It is an error to call this if the target does not support comdat.
pub fn set_comdat(llmod: &Module, llglobal: &Value, name: &CStr) {
unsafe {
LLVMRustSetComdat(llmod, llglobal, name.as_ptr().cast(), name.len());
let comdat = LLVMGetOrInsertComdat(llmod, name.as_ptr());
LLVMSetComdat(llglobal, comdat);
}
}

View File

@ -64,7 +64,9 @@ fn predefine_fn(
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
base::set_link_section(lldecl, attrs);
if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR {
if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
&& self.tcx.sess.target.supports_comdat()
{
llvm::SetUniqueComdat(self.llmod, lldecl);
}

View File

@ -1658,16 +1658,6 @@ extern "C" void LLVMRustPositionBuilderAtStart(LLVMBuilderRef B,
unwrap(B)->SetInsertPoint(unwrap(BB), Point);
}
extern "C" void LLVMRustSetComdat(LLVMModuleRef M, LLVMValueRef V,
const char *Name, size_t NameLen) {
Triple TargetTriple = Triple(unwrap(M)->getTargetTriple());
GlobalObject *GV = unwrap<GlobalObject>(V);
if (TargetTriple.supportsCOMDAT()) {
StringRef NameRef(Name, NameLen);
GV->setComdat(unwrap(M)->getOrInsertComdat(NameRef));
}
}
enum class LLVMRustLinkage {
ExternalLinkage = 0,
AvailableExternallyLinkage = 1,

View File

@ -2514,6 +2514,13 @@ fn add_link_args(link_args: &mut LinkArgs, flavor: LinkerFlavor, args: &[&'stati
add_link_args_iter(link_args, flavor, args.iter().copied().map(Cow::Borrowed))
}
impl TargetOptions {
pub fn supports_comdat(&self) -> bool {
// XCOFF and MachO don't support COMDAT.
!self.is_like_aix && !self.is_like_osx
}
}
impl TargetOptions {
fn link_args(flavor: LinkerFlavor, args: &[&'static str]) -> LinkArgs {
let mut link_args = LinkArgs::new();