diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/lto.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/write.rs | 76 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/lib.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/link.rs | 100 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/back/write.rs | 24 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/lib.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_session/src/config.rs | 28 |
8 files changed, 228 insertions, 46 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 64ca7efb486..834fc02c48a 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -6,7 +6,9 @@ use crate::llvm::{self, build_string, False, True}; use crate::{LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; -use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_data_structures::fx::FxHashMap; @@ -728,7 +730,14 @@ pub unsafe fn optimize_thin_module( cgcx: &CodegenContext<LlvmCodegenBackend>, ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { let diag_handler = cgcx.create_diag_handler(); - let tm = (cgcx.tm_factory)().map_err(|e| write::llvm_err(&diag_handler, &e))?; + + let module_name = &thin_module.shared.module_names[thin_module.idx]; + let split_dwarf_file = cgcx + .output_filenames + .split_dwarf_file(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap())); + let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; + let tm = + (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?; // Right now the implementation we've got only works over serialized // modules, so we create a fresh new LLVM context and parse the module @@ -736,12 +745,8 @@ pub unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = parse_module( - llcx, - &thin_module.shared.module_names[thin_module.idx], - thin_module.data(), - &diag_handler, - )? as *const _; + let llmod_raw = + parse_module(llcx, &module_name, thin_module.data(), &diag_handler)? as *const _; let module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, llcx, tm }, name: thin_module.name().to_string(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 612ed4405bb..ef99c87053c 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -12,7 +12,8 @@ use crate::type_::Type; use crate::LlvmCodegenBackend; use crate::ModuleLlvm; use rustc_codegen_ssa::back::write::{ - BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryFn, + BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig, + TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; @@ -22,7 +23,9 @@ use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; -use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath}; +use rustc_session::config::{ + self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath, +}; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::InnerSpan; @@ -51,18 +54,31 @@ pub fn write_output_file( pm: &llvm::PassManager<'ll>, m: &'ll llvm::Module, output: &Path, + dwo_output: Option<&Path>, file_type: llvm::FileType, ) -> Result<(), FatalError> { unsafe { let output_c = path_to_c_string(output); - let result = llvm::LLVMRustWriteOutputFile( - target, - pm, - m, - output_c.as_ptr(), - std::ptr::null(), - file_type, - ); + let result = if let Some(dwo_output) = dwo_output { + let dwo_output_c = path_to_c_string(dwo_output); + llvm::LLVMRustWriteOutputFile( + target, + pm, + m, + output_c.as_ptr(), + dwo_output_c.as_ptr(), + file_type, + ) + } else { + llvm::LLVMRustWriteOutputFile( + target, + pm, + m, + output_c.as_ptr(), + std::ptr::null(), + file_type, + ) + }; result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); llvm_err(handler, &msg) @@ -71,12 +87,17 @@ pub fn write_output_file( } pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine { - target_machine_factory(sess, config::OptLevel::No)() + let config = TargetMachineFactoryConfig { split_dwarf_file: None }; + target_machine_factory(sess, config::OptLevel::No)(config) .unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise()) } -pub fn create_target_machine(tcx: TyCtxt<'_>) -> &'static mut llvm::TargetMachine { - target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))() +pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine { + let split_dwarf_file = tcx + .output_filenames(LOCAL_CRATE) + .split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name)); + let config = TargetMachineFactoryConfig { split_dwarf_file }; + target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) } @@ -172,8 +193,10 @@ pub fn target_machine_factory( let use_init_array = !sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); - Arc::new(move || { - let split_dwarf_file = std::ptr::null(); + Arc::new(move |config: TargetMachineFactoryConfig| { + let split_dwarf_file = config.split_dwarf_file.unwrap_or_default(); + let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap(); + let tm = unsafe { llvm::LLVMRustCreateTargetMachine( triple.as_ptr(), @@ -192,7 +215,7 @@ pub fn target_machine_factory( emit_stack_size_section, relax_elf_relocations, use_init_array, - split_dwarf_file, + split_dwarf_file.as_ptr(), ) }; @@ -796,7 +819,15 @@ pub(crate) unsafe fn codegen( llmod }; with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) + write_output_file( + diag_handler, + tm, + cpm, + llmod, + &path, + None, + llvm::FileType::AssemblyFile, + ) })?; } @@ -805,6 +836,15 @@ pub(crate) unsafe fn codegen( let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]); + + let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name); + let dwo_out = match cgcx.split_dwarf_kind { + // Don't change how DWARF is emitted in single mode (or when disabled). + SplitDwarfKind::None | SplitDwarfKind::Single => None, + // Emit (a subset of the) DWARF into a separate file in split mode. + SplitDwarfKind::Split => Some(dwo_out.as_path()), + }; + with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file( diag_handler, @@ -812,6 +852,7 @@ pub(crate) unsafe fn codegen( cpm, llmod, &obj_out, + dwo_out, llvm::FileType::ObjectFile, ) })?; @@ -839,6 +880,7 @@ pub(crate) unsafe fn codegen( Ok(module.into_compiled_module( config.emit_obj != EmitObj::None, + cgcx.split_dwarf_kind == SplitDwarfKind::Split, config.emit_bc, &cgcx.output_filenames, )) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 41c8a5e5705..a9eff59b6af 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -995,7 +995,11 @@ pub fn compile_unit_metadata( let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); let work_dir = tcx.sess.working_dir.0.to_string_lossy(); let flags = "\0"; - let split_name = ""; + let split_name = tcx + .output_filenames(LOCAL_CRATE) + .split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name)) + .unwrap_or_default(); + let split_name = split_name.to_str().unwrap(); // FIXME(#60020): // @@ -1040,7 +1044,7 @@ pub fn compile_unit_metadata( split_name.len(), kind, 0, - true, + tcx.sess.opts.debugging_opts.split_dwarf_inlining, ); if tcx.sess.opts.debugging_opts.profile { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4fe0384b369..a5f125d114d 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -20,7 +20,7 @@ pub use llvm_util::target_features; use rustc_ast::expand::allocator::AllocatorKind; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::back::write::{ - CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn, + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; @@ -332,7 +332,7 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; - ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx) } + ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) } } } @@ -353,7 +353,13 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; - let tm = match (cgcx.tm_factory)() { + + let split_dwarf_file = cgcx + .output_filenames + .split_dwarf_file(cgcx.split_dwarf_kind, Some(name.to_str().unwrap())); + let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file }; + + let tm = match (cgcx.tm_factory)(tm_factory_config) { Ok(m) => m, Err(e) => { handler.struct_err(&e).emit(); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5001e97016c..123d1ae55fb 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -21,7 +21,9 @@ use super::archive::ArchiveBuilder; use super::command::Command; use super::linker::{self, Linker}; use super::rpath::{self, RPathConfig}; -use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME}; +use crate::{ + looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME, +}; use cc::windows_registry; use tempfile::Builder as TempFileBuilder; @@ -96,6 +98,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( path.as_ref(), target_cpu, ); + if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split { + link_dwarf_object(sess, &out_filename); + } } } if sess.opts.json_artifact_notifications { @@ -107,22 +112,30 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>( // Remove the temporary object file and metadata if we aren't saving temps sess.time("link_binary_remove_temps", || { if !sess.opts.cg.save_temps { + let remove_temps_from_module = |module: &CompiledModule| { + if let Some(ref obj) = module.object { + remove(sess, obj); + } + + if let Some(ref obj) = module.dwarf_object { + remove(sess, obj); + } + }; + if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) { - for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { - remove(sess, obj); + for module in &codegen_results.modules { + remove_temps_from_module(module); } } + if let Some(ref metadata_module) = codegen_results.metadata_module { - if let Some(ref obj) = metadata_module.object { - remove(sess, obj); - } + remove_temps_from_module(metadata_module); } + if let Some(ref allocator_module) = codegen_results.allocator_module { - if let Some(ref obj) = allocator_module.object { - remove(sess, obj); - } + remove_temps_from_module(allocator_module); } } }); @@ -446,6 +459,69 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( } } +fn escape_stdout_stderr_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from)); + x + }) +} + +const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp"; + +/// Invoke `llvm-dwp` (shipped alongside rustc) to link `dwo` files from Split DWARF into a `dwp` +/// file. +fn link_dwarf_object<'a>(sess: &'a Session, executable_out_filename: &Path) { + info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap()); + + let dwp_out_filename = executable_out_filename.with_extension("dwp"); + let mut cmd = Command::new(LLVM_DWP_EXECUTABLE); + cmd.arg("-e"); + cmd.arg(executable_out_filename); + cmd.arg("-o"); + cmd.arg(&dwp_out_filename); + + let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(false); + if let Some(path) = env::var_os("PATH") { + new_path.extend(env::split_paths(&path)); + } + let new_path = env::join_paths(new_path).unwrap(); + cmd.env("PATH", new_path); + + info!("{:?}", &cmd); + match sess.time("run_dwp", || cmd.output()) { + Ok(prog) if !prog.status.success() => { + sess.struct_err(&format!( + "linking dwarf objects with `{}` failed: {}", + LLVM_DWP_EXECUTABLE, prog.status + )) + .note(&format!("{:?}", &cmd)) + .note(&escape_stdout_stderr_string(&prog.stdout)) + .note(&escape_stdout_stderr_string(&prog.stderr)) + .emit(); + info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); + } + Ok(_) => {} + Err(e) => { + let dwp_not_found = e.kind() == io::ErrorKind::NotFound; + let mut err = if dwp_not_found { + sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE)) + } else { + sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE)) + }; + + err.note(&e.to_string()); + + if !dwp_not_found { + err.note(&format!("{:?}", &cmd)); + } + + err.emit(); + } + } +} + /// Create a dynamic library or executable. /// /// This will invoke the system linker/cc to create the resulting file. This links to all upstream @@ -661,7 +737,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( prog.status )) .note(&format!("{:?}", &cmd)) - .note(&escape_string(&output)) + .note(&escape_stdout_stderr_string(&output)) .emit(); // If MSVC's `link.exe` was expected but the return code @@ -714,8 +790,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( sess.abort_if_errors(); } - info!("linker stderr:\n{}", escape_string(&prog.stderr)); - info!("linker stdout:\n{}", escape_string(&prog.stdout)); + info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr)); + info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout)); } Err(e) => { let linker_not_found = e.kind() == io::ErrorKind::NotFound; diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 615eeecf54e..c84b87964b8 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -274,8 +274,19 @@ impl ModuleConfig { } } -pub type TargetMachineFactoryFn<B> = - Arc<dyn Fn() -> Result<<B as WriteBackendMethods>::TargetMachine, String> + Send + Sync>; +/// Configuration passed to the function returned by the `target_machine_factory`. +pub struct TargetMachineFactoryConfig { + /// Split DWARF is enabled in LLVM by checking that `TM.MCOptions.SplitDwarfFile` isn't empty, + /// so the path to the dwarf object has to be provided when we create the target machine. + /// This can be ignored by backends which do not need it for their Split DWARF support. + pub split_dwarf_file: Option<PathBuf>, +} + +pub type TargetMachineFactoryFn<B> = Arc< + dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String> + + Send + + Sync, +>; pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportLevel)>>>; @@ -303,6 +314,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub target_pointer_width: u32, pub target_arch: String, pub debuginfo: config::DebugInfo, + pub split_dwarf_kind: config::SplitDwarfKind, // Number of cgus excluding the allocator/metadata modules pub total_cgus: usize, @@ -619,6 +631,12 @@ fn produce_final_output_artifacts( } } + if let Some(ref path) = module.dwarf_object { + if !keep_numbered_objects { + remove(sess, path); + } + } + if let Some(ref path) = module.bytecode { if !keep_numbered_bitcode { remove(sess, path); @@ -841,6 +859,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( name: module.name, kind: ModuleKind::Regular, object, + dwarf_object: None, bytecode: None, })) } @@ -1019,6 +1038,7 @@ fn start_executing_work<B: ExtraBackendMethods>( target_pointer_width: tcx.sess.target.pointer_width, target_arch: tcx.sess.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, + split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf, }; // This is the "main loop" of parallel work happening for parallel codegen. diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8ec1eed4404..ee889d55241 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -64,13 +64,15 @@ impl<M> ModuleCodegen<M> { pub fn into_compiled_module( self, emit_obj: bool, + emit_dwarf_obj: bool, emit_bc: bool, outputs: &OutputFilenames, ) -> CompiledModule { let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); + let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name))); let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); - CompiledModule { name: self.name.clone(), kind: self.kind, object, bytecode } + CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode } } } @@ -79,6 +81,7 @@ pub struct CompiledModule { pub name: String, pub kind: ModuleKind, pub object: Option<PathBuf>, + pub dwarf_object: Option<PathBuf>, pub bytecode: Option<PathBuf>, } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b5354513dc2..b3d4c6e3ec7 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -550,6 +550,7 @@ impl_stable_hash_via_hash!(OutputFilenames); pub const RLINK_EXT: &str = "rlink"; pub const RUST_CGU_EXT: &str = "rcgu"; +pub const DWARF_OBJECT_EXT: &str = "dwo"; impl OutputFilenames { pub fn new( @@ -583,7 +584,12 @@ impl OutputFilenames { self.temp_path_ext(extension, codegen_unit_name) } - /// Like temp_path, but also supports things where there is no corresponding + /// Like `temp_path`, but specifically for dwarf objects. + pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf { + self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name) + } + + /// Like `temp_path`, but also supports things where there is no corresponding /// OutputType, like noopt-bitcode or lto-bitcode. pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { let mut extension = String::new(); @@ -610,6 +616,26 @@ impl OutputFilenames { path.set_extension(extension); path } + + /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF + /// mode is being used, which is the logic that this function is intended to encapsulate. + pub fn split_dwarf_file( + &self, + split_dwarf_kind: SplitDwarfKind, + cgu_name: Option<&str>, + ) -> Option<PathBuf> { + let obj_out = self.temp_path(OutputType::Object, cgu_name); + let dwo_out = self.temp_path_dwo(cgu_name); + match split_dwarf_kind { + SplitDwarfKind::None => None, + // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes + // (pointing at the path which is being determined here). Use the path to the current + // object file. + SplitDwarfKind::Single => Some(obj_out), + // Split mode emits the DWARF into a different file, use that path. + SplitDwarfKind::Split => Some(dwo_out), + } + } } pub fn host_triple() -> &'static str { |
