summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_codegen_llvm/src/back
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_codegen_llvm/src/back
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz
rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_codegen_llvm/src/back')
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs52
-rw-r--r--compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs103
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs146
4 files changed, 248 insertions, 55 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index a82d2c577..f33075a88 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -367,7 +367,7 @@ impl<'a> LlvmArchiveBuilder<'a> {
match addition {
Addition::File { path, name_in_archive } => {
let path = CString::new(path.to_str().unwrap())?;
- let name = CString::new(name_in_archive.clone())?;
+ let name = CString::new(name_in_archive.as_bytes())?;
members.push(llvm::LLVMRustArchiveMemberNew(
path.as_ptr(),
name.as_ptr(),
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index b2d28cef8..a3b0dc6b6 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -1,6 +1,8 @@
-use crate::back::write::{self, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers};
+use crate::back::write::{
+ self, bitcode_section_name, save_temp_bitcode, CodegenDiagnosticsStage, DiagnosticHandlers,
+};
use crate::errors::{
- DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib,
+ DynamicLinkingWithLTO, LlvmError, LtoBitcodeFromRlib, LtoDisallowed, LtoDylib, LtoProcMacro,
};
use crate::llvm::{self, build_string};
use crate::{LlvmCodegenBackend, ModuleLlvm};
@@ -24,6 +26,7 @@ use std::ffi::{CStr, CString};
use std::fs::File;
use std::io;
use std::iter;
+use std::mem::ManuallyDrop;
use std::path::Path;
use std::slice;
use std::sync::Arc;
@@ -34,8 +37,12 @@ pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin";
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
match crate_type {
- CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
- CrateType::Rlib | CrateType::ProcMacro => false,
+ CrateType::Executable
+ | CrateType::Dylib
+ | CrateType::Staticlib
+ | CrateType::Cdylib
+ | CrateType::ProcMacro => true,
+ CrateType::Rlib => false,
}
}
@@ -85,6 +92,11 @@ fn prepare_lto(
diag_handler.emit_err(LtoDylib);
return Err(FatalError);
}
+ } else if *crate_type == CrateType::ProcMacro {
+ if !cgcx.opts.unstable_opts.dylib_lto {
+ diag_handler.emit_err(LtoProcMacro);
+ return Err(FatalError);
+ }
}
}
@@ -120,6 +132,7 @@ fn prepare_lto(
info!("adding bitcode from {}", name);
match get_bitcode_slice_from_object_data(
child.data(&*archive_data).expect("corrupt rlib"),
+ cgcx,
) {
Ok(data) => {
let module = SerializedModule::FromRlib(data.to_vec());
@@ -141,10 +154,29 @@ fn prepare_lto(
Ok((symbols_below_threshold, upstream_modules))
}
-fn get_bitcode_slice_from_object_data(obj: &[u8]) -> Result<&[u8], LtoBitcodeFromRlib> {
+fn get_bitcode_slice_from_object_data<'a>(
+ obj: &'a [u8],
+ cgcx: &CodegenContext<LlvmCodegenBackend>,
+) -> Result<&'a [u8], LtoBitcodeFromRlib> {
+ // We're about to assume the data here is an object file with sections, but if it's raw LLVM IR that
+ // won't work. Fortunately, if that's what we have we can just return the object directly, so we sniff
+ // the relevant magic strings here and return.
+ if obj.starts_with(b"\xDE\xC0\x17\x0B") || obj.starts_with(b"BC\xC0\xDE") {
+ return Ok(obj);
+ }
+ // We drop the "__LLVM," prefix here because on Apple platforms there's a notion of "segment name"
+ // which in the public API for sections gets treated as part of the section name, but internally
+ // in MachOObjectFile.cpp gets treated separately.
+ let section_name = bitcode_section_name(cgcx).trim_start_matches("__LLVM,");
let mut len = 0;
- let data =
- unsafe { llvm::LLVMRustGetBitcodeSliceFromObjectData(obj.as_ptr(), obj.len(), &mut len) };
+ let data = unsafe {
+ llvm::LLVMRustGetSliceFromObjectDataByName(
+ obj.as_ptr(),
+ obj.len(),
+ section_name.as_ptr(),
+ &mut len,
+ )
+ };
if !data.is_null() {
assert!(len != 0);
let bc = unsafe { slice::from_raw_parts(data, len) };
@@ -441,7 +473,7 @@ fn thin_lto(
for (i, (name, buffer)) in modules.into_iter().enumerate() {
info!("local module: {} - {}", i, name);
- let cname = CString::new(name.clone()).unwrap();
+ let cname = CString::new(name.as_bytes()).unwrap();
thin_modules.push(llvm::ThinLTOModule {
identifier: cname.as_ptr(),
data: buffer.data().as_ptr(),
@@ -583,7 +615,7 @@ pub(crate) fn run_pass_manager(
module: &mut ModuleCodegen<ModuleLlvm>,
thin: bool,
) -> Result<(), FatalError> {
- let _timer = cgcx.prof.verbose_generic_activity_with_arg("LLVM_lto_optimize", &*module.name);
+ let _timer = cgcx.prof.generic_activity_with_arg("LLVM_lto_optimize", &*module.name);
let config = cgcx.config(module.kind);
// Now we have one massive module inside of llmod. Time to run the
@@ -705,7 +737,7 @@ pub unsafe fn optimize_thin_module(
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _;
let mut module = ModuleCodegen {
- module_llvm: ModuleLlvm { llmod_raw, llcx, tm },
+ module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) },
name: thin_module.name().to_string(),
kind: ModuleKind::Regular,
};
diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
new file mode 100644
index 000000000..36484c3c3
--- /dev/null
+++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs
@@ -0,0 +1,103 @@
+use std::{
+ ffi::{c_char, CStr},
+ marker::PhantomData,
+ ops::Deref,
+ ptr::NonNull,
+};
+
+use rustc_data_structures::small_c_str::SmallCStr;
+
+use crate::{errors::LlvmError, llvm};
+
+/// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions.
+/// Not cloneable as there is no clone function for llvm::TargetMachine.
+#[repr(transparent)]
+pub struct OwnedTargetMachine {
+ tm_unique: NonNull<llvm::TargetMachine>,
+ phantom: PhantomData<llvm::TargetMachine>,
+}
+
+impl OwnedTargetMachine {
+ pub fn new(
+ triple: &CStr,
+ cpu: &CStr,
+ features: &CStr,
+ abi: &CStr,
+ model: llvm::CodeModel,
+ reloc: llvm::RelocModel,
+ level: llvm::CodeGenOptLevel,
+ use_soft_fp: bool,
+ function_sections: bool,
+ data_sections: bool,
+ unique_section_names: bool,
+ trap_unreachable: bool,
+ singletree: bool,
+ asm_comments: bool,
+ emit_stack_size_section: bool,
+ relax_elf_relocations: bool,
+ use_init_array: bool,
+ split_dwarf_file: &CStr,
+ output_obj_file: &CStr,
+ debug_info_compression: &CStr,
+ force_emulated_tls: bool,
+ args_cstr_buff: &[u8],
+ ) -> Result<Self, LlvmError<'static>> {
+ assert!(args_cstr_buff.len() > 0);
+ assert!(
+ *args_cstr_buff.last().unwrap() == 0,
+ "The last character must be a null terminator."
+ );
+
+ // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
+ let tm_ptr = unsafe {
+ llvm::LLVMRustCreateTargetMachine(
+ triple.as_ptr(),
+ cpu.as_ptr(),
+ features.as_ptr(),
+ abi.as_ptr(),
+ model,
+ reloc,
+ level,
+ use_soft_fp,
+ function_sections,
+ data_sections,
+ unique_section_names,
+ trap_unreachable,
+ singletree,
+ asm_comments,
+ emit_stack_size_section,
+ relax_elf_relocations,
+ use_init_array,
+ split_dwarf_file.as_ptr(),
+ output_obj_file.as_ptr(),
+ debug_info_compression.as_ptr(),
+ force_emulated_tls,
+ args_cstr_buff.as_ptr() as *const c_char,
+ args_cstr_buff.len(),
+ )
+ };
+
+ NonNull::new(tm_ptr)
+ .map(|tm_unique| Self { tm_unique, phantom: PhantomData })
+ .ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) })
+ }
+}
+
+impl Deref for OwnedTargetMachine {
+ type Target = llvm::TargetMachine;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
+ unsafe { self.tm_unique.as_ref() }
+ }
+}
+
+impl Drop for OwnedTargetMachine {
+ fn drop(&mut self) {
+ // SAFETY: constructing ensures we have a valid pointer created by llvm::LLVMRustCreateTargetMachine
+ // OwnedTargetMachine is not copyable so there is no double free or use after free
+ unsafe {
+ llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_mut());
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 47cc5bd52..c778a6e01 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -1,17 +1,22 @@
use crate::back::lto::ThinBuffer;
+use crate::back::owned_target_machine::OwnedTargetMachine;
use crate::back::profiling::{
selfprofile_after_pass_callback, selfprofile_before_pass_callback, LlvmSelfProfiler,
};
use crate::base;
use crate::common;
use crate::errors::{
- CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, WithLlvmError, WriteBytecode,
+ CopyBitcode, FromLlvmDiag, FromLlvmOptimizationDiag, LlvmError, UnknownCompression,
+ WithLlvmError, WriteBytecode,
};
use crate::llvm::{self, DiagnosticInfo, PassManager};
use crate::llvm_util;
use crate::type_::Type;
use crate::LlvmCodegenBackend;
use crate::ModuleLlvm;
+use llvm::{
+ LLVMRustLLVMHasZlibCompressionForDebugSymbols, LLVMRustLLVMHasZstdCompressionForDebugSymbols,
+};
use rustc_codegen_ssa::back::link::ensure_removed;
use rustc_codegen_ssa::back::write::{
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
@@ -94,8 +99,8 @@ pub fn write_output_file<'ll>(
}
}
-pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine {
- let config = TargetMachineFactoryConfig { split_dwarf_file: None };
+pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine {
+ let config = TargetMachineFactoryConfig { split_dwarf_file: None, output_obj_file: None };
// Can't use query system here quite yet because this function is invoked before the query
// system/tcx is set up.
let features = llvm_util::global_llvm_features(sess, false);
@@ -103,7 +108,7 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
.unwrap_or_else(|err| llvm_err(sess.diagnostic(), err).raise())
}
-pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
+pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMachine {
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
tcx.output_filenames(()).split_dwarf_path(
tcx.sess.split_debuginfo(),
@@ -113,7 +118,11 @@ pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut ll
} else {
None
};
- let config = TargetMachineFactoryConfig { split_dwarf_file };
+
+ let output_obj_file =
+ Some(tcx.output_filenames(()).temp_path(OutputType::Object, Some(mod_name)));
+ let config = TargetMachineFactoryConfig { split_dwarf_file, output_obj_file };
+
target_machine_factory(
&tcx.sess,
tcx.backend_optimization_level(()),
@@ -216,36 +225,73 @@ pub fn target_machine_factory(
let force_emulated_tls = sess.target.force_emulated_tls;
+ // copy the exe path, followed by path all into one buffer
+ // null terminating them so we can use them as null terminated strings
+ let args_cstr_buff = {
+ let mut args_cstr_buff: Vec<u8> = Vec::new();
+ let exe_path = std::env::current_exe().unwrap_or_default();
+ let exe_path_str = exe_path.into_os_string().into_string().unwrap_or_default();
+
+ args_cstr_buff.extend_from_slice(exe_path_str.as_bytes());
+ args_cstr_buff.push(0);
+
+ for arg in sess.expanded_args.iter() {
+ args_cstr_buff.extend_from_slice(arg.as_bytes());
+ args_cstr_buff.push(0);
+ }
+
+ args_cstr_buff
+ };
+
+ let debuginfo_compression = sess.opts.debuginfo_compression.to_string();
+ match sess.opts.debuginfo_compression {
+ rustc_session::config::DebugInfoCompression::Zlib => {
+ if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } {
+ sess.emit_warning(UnknownCompression { algorithm: "zlib" });
+ }
+ }
+ rustc_session::config::DebugInfoCompression::Zstd => {
+ if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } {
+ sess.emit_warning(UnknownCompression { algorithm: "zstd" });
+ }
+ }
+ rustc_session::config::DebugInfoCompression::None => {}
+ };
+ let debuginfo_compression = SmallCStr::new(&debuginfo_compression);
+
Arc::new(move |config: TargetMachineFactoryConfig| {
- let split_dwarf_file =
- path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
- let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap();
-
- let tm = unsafe {
- llvm::LLVMRustCreateTargetMachine(
- triple.as_ptr(),
- cpu.as_ptr(),
- features.as_ptr(),
- abi.as_ptr(),
- code_model,
- reloc_model,
- opt_level,
- use_softfp,
- ffunction_sections,
- fdata_sections,
- funique_section_names,
- trap_unreachable,
- singlethread,
- asm_comments,
- emit_stack_size_section,
- relax_elf_relocations,
- use_init_array,
- split_dwarf_file.as_ptr(),
- force_emulated_tls,
- )
+ let path_to_cstring_helper = |path: Option<PathBuf>| -> CString {
+ let path = path_mapping.map_prefix(path.unwrap_or_default()).0;
+ CString::new(path.to_str().unwrap()).unwrap()
};
- tm.ok_or_else(|| LlvmError::CreateTargetMachine { triple: triple.clone() })
+ let split_dwarf_file = path_to_cstring_helper(config.split_dwarf_file);
+ let output_obj_file = path_to_cstring_helper(config.output_obj_file);
+
+ OwnedTargetMachine::new(
+ &triple,
+ &cpu,
+ &features,
+ &abi,
+ code_model,
+ reloc_model,
+ opt_level,
+ use_softfp,
+ ffunction_sections,
+ fdata_sections,
+ funique_section_names,
+ trap_unreachable,
+ singlethread,
+ asm_comments,
+ emit_stack_size_section,
+ relax_elf_relocations,
+ use_init_array,
+ &split_dwarf_file,
+ &output_obj_file,
+ &debuginfo_compression,
+ force_emulated_tls,
+ &args_cstr_buff,
+ )
})
}
@@ -853,6 +899,27 @@ fn create_section_with_flags_asm(section_name: &str, section_flags: &str, data:
asm
}
+fn target_is_apple(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
+ cgcx.opts.target_triple.triple().contains("-ios")
+ || cgcx.opts.target_triple.triple().contains("-darwin")
+ || cgcx.opts.target_triple.triple().contains("-tvos")
+ || cgcx.opts.target_triple.triple().contains("-watchos")
+}
+
+fn target_is_aix(cgcx: &CodegenContext<LlvmCodegenBackend>) -> bool {
+ cgcx.opts.target_triple.triple().contains("-aix")
+}
+
+pub(crate) fn bitcode_section_name(cgcx: &CodegenContext<LlvmCodegenBackend>) -> &'static str {
+ if target_is_apple(cgcx) {
+ "__LLVM,__bitcode\0"
+ } else if target_is_aix(cgcx) {
+ ".ipa\0"
+ } else {
+ ".llvmbc\0"
+ }
+}
+
/// Embed the bitcode of an LLVM module in the LLVM module itself.
///
/// This is done primarily for iOS where it appears to be standard to compile C
@@ -913,11 +980,8 @@ unsafe fn embed_bitcode(
// Unfortunately, LLVM provides no way to set custom section flags. For ELF
// and COFF we emit the sections using module level inline assembly for that
// reason (see issue #90326 for historical background).
- let is_aix = cgcx.opts.target_triple.triple().contains("-aix");
- let is_apple = cgcx.opts.target_triple.triple().contains("-ios")
- || cgcx.opts.target_triple.triple().contains("-darwin")
- || cgcx.opts.target_triple.triple().contains("-tvos")
- || cgcx.opts.target_triple.triple().contains("-watchos");
+ let is_aix = target_is_aix(cgcx);
+ let is_apple = target_is_apple(cgcx);
if is_apple
|| is_aix
|| cgcx.opts.target_triple.triple().starts_with("wasm")
@@ -932,13 +996,7 @@ unsafe fn embed_bitcode(
);
llvm::LLVMSetInitializer(llglobal, llconst);
- let section = if is_apple {
- "__LLVM,__bitcode\0"
- } else if is_aix {
- ".ipa\0"
- } else {
- ".llvmbc\0"
- };
+ let section = bitcode_section_name(cgcx);
llvm::LLVMSetSection(llglobal, section.as_ptr().cast());
llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage);
llvm::LLVMSetGlobalConstant(llglobal, llvm::True);