diff options
| author | bors <bors@rust-lang.org> | 2020-12-16 12:51:42 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-12-16 12:51:42 +0000 |
| commit | 2ba7ca2bbbff6cd424aebc654308febc00b9497a (patch) | |
| tree | 231959b03519aadce7c2e68becd08d620cad790e /compiler/rustc_codegen_llvm/src | |
| parent | 268cbfeb88b4c13425d47910d3424c85b4c96462 (diff) | |
| parent | ee073b5ec54a13b393071298acc54e1fd28cfcdf (diff) | |
| download | rust-2ba7ca2bbbff6cd424aebc654308febc00b9497a.tar.gz rust-2ba7ca2bbbff6cd424aebc654308febc00b9497a.zip | |
Auto merge of #77117 - davidtwco:issue-34651-split-dwarf, r=nagisa
cg_llvm: split dwarf support
cc #34651
This PR adds initial support for Split DWARF to rustc, based on the implementation in Clang.
##### Current Status
This PR currently has functioning split-dwarf, running rustc with `-Zsplit-dwarf=split` when compiling a binary will produce a `dwp` alongside the binary, which contains the linked dwarf objects.
```shell-session
$ rustc -Cdebuginfo=2 -Zsplit-dwarf=split -C save-temps ./foo.rs
$ ls foo*
foo
foo.belfx9afw9cmv8.rcgu.dwo
foo.belfx9afw9cmv8.rcgu.o
foo.foo.7rcbfp3g-cgu.0.rcgu.dwo
foo.foo.7rcbfp3g-cgu.0.rcgu.o
foo.foo.7rcbfp3g-cgu.1.rcgu.dwo
foo.foo.7rcbfp3g-cgu.1.rcgu.o
foo.foo.7rcbfp3g-cgu.2.rcgu.dwo
foo.foo.7rcbfp3g-cgu.2.rcgu.o
foo.foo.7rcbfp3g-cgu.3.rcgu.dwo
foo.foo.7rcbfp3g-cgu.3.rcgu.o
foo.foo.7rcbfp3g-cgu.4.rcgu.dwo
foo.foo.7rcbfp3g-cgu.4.rcgu.o
foo.foo.7rcbfp3g-cgu.5.rcgu.dwo
foo.foo.7rcbfp3g-cgu.5.rcgu.o
foo.foo.7rcbfp3g-cgu.6.rcgu.dwo
foo.foo.7rcbfp3g-cgu.6.rcgu.o
foo.foo.7rcbfp3g-cgu.7.rcgu.dwo
foo.foo.7rcbfp3g-cgu.7.rcgu.o
foo.dwp
foo.rs
$ readelf -wi foo.foo.7rcbfp3g-cgu.0.rcgu.o
# ...
Compilation Unit @ offset 0x90:
Length: 0x2c (32-bit)
Version: 4
Abbrev Offset: 0x5b
Pointer Size: 8
<0><9b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<9c> DW_AT_stmt_list : 0xe8
<a0> DW_AT_comp_dir : (indirect string, offset: 0x13b): /home/david/Projects/rust/rust0
<a4> DW_AT_GNU_dwo_name: (indirect string, offset: 0x15b): foo.foo.7rcbfp3g-cgu.0.rcgu.dwo
<a8> DW_AT_GNU_dwo_id : 0x357472a2b032d7b9
<b0> DW_AT_low_pc : 0x0
<b8> DW_AT_ranges : 0x40
<bc> DW_AT_GNU_addr_base: 0x0
# ...
```
##### To-Do
I've opened this PR as a draft to get feedback and work out how we'd expect rustc to work when Split DWARF is requested. It might be easier to read the PR commit-by-commit.
- [ ] Add error when Split DWARF is requested on platforms where it doesn't make sense.
- [x] Determine whether or not there should be a single `dwo` output from rustc, or one per codegen-unit as exists currently.
- [x] Add tests.
- [x] Fix `single` mode - currently single mode doesn't change the invocation of `addPassesToEmitFile`, which is correct, but it also needs to change the split dwarf path provided to `createCompileUnit` and `createTargetMachine` so that it's just the final binary (currently it is still a non-existent `dwo` file).
r? `@nagisa`
cc `@michaelwoerister` `@eddyb` `@alexcrichton` `@rust-lang/wg-incr-comp`
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/lto.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/write.rs | 71 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/lib.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 |
5 files changed, 103 insertions, 26 deletions
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 64fd1d09cc2..29415973ed0 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.0)().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_filename(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 7407dfc455d..3fda1e26dae 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -11,7 +11,10 @@ use crate::llvm_util; use crate::type_::Type; use crate::LlvmCodegenBackend; use crate::ModuleLlvm; -use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig}; +use rustc_codegen_ssa::back::write::{ + BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig, + TargetMachineFactoryFn, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::small_c_str::SmallCStr; @@ -20,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; @@ -49,11 +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(), 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) @@ -62,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_filename(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()) } @@ -122,7 +152,7 @@ fn to_llvm_code_model(code_model: Option<CodeModel>) -> llvm::CodeModel { pub fn target_machine_factory( sess: &Session, optlvl: config::OptLevel, -) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { +) -> TargetMachineFactoryFn<LlvmCodegenBackend> { let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let (opt_level, _) = to_llvm_opt_settings(optlvl); @@ -163,7 +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 || { + 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(), @@ -182,6 +215,7 @@ pub fn target_machine_factory( emit_stack_size_section, relax_elf_relocations, use_init_array, + split_dwarf_file.as_ptr(), ) }; @@ -785,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, + ) })?; } @@ -794,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, @@ -801,6 +852,7 @@ pub(crate) unsafe fn codegen( cpm, llmod, &obj_out, + dwo_out, llvm::FileType::ObjectFile, ) })?; @@ -828,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 31e43893ac8..fa285f3488f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -993,9 +993,15 @@ pub fn compile_unit_metadata( let producer = format!("clang LLVM ({})", rustc_producer); 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 out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory; + let split_name = tcx + .output_filenames(LOCAL_CRATE) + .split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name)) + .unwrap_or_default(); + let out_dir = out_dir.to_str().unwrap(); + let split_name = split_name.to_str().unwrap(); // FIXME(#60020): // @@ -1020,8 +1026,8 @@ pub fn compile_unit_metadata( debug_context.builder, name_in_debuginfo.as_ptr().cast(), name_in_debuginfo.len(), - work_dir.as_ptr().cast(), - work_dir.len(), + out_dir.as_ptr().cast(), + out_dir.len(), llvm::ChecksumKind::None, ptr::null(), 0, @@ -1039,6 +1045,8 @@ pub fn compile_unit_metadata( split_name.as_ptr().cast(), split_name.len(), kind, + 0, + 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 5974b59d39e..a58c2fbd8ab 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -19,7 +19,9 @@ use back::write::{create_informational_target_machine, create_target_machine}; 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}; +use rustc_codegen_ssa::back::write::{ + CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn, +}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; @@ -34,7 +36,6 @@ use rustc_span::symbol::Symbol; use std::any::Any; use std::ffi::CStr; -use std::sync::Arc; mod back { pub mod archive; @@ -109,7 +110,7 @@ impl ExtraBackendMethods for LlvmCodegenBackend { &self, sess: &Session, optlvl: OptLevel, - ) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { + ) -> TargetMachineFactoryFn<Self> { back::write::target_machine_factory(sess, optlvl) } fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str { @@ -331,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) } } } @@ -352,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.0)() { + + let split_dwarf_file = cgcx + .output_filenames + .split_dwarf_filename(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_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 41482d18946..707aaa2b53f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1830,6 +1830,8 @@ extern "C" { SplitName: *const c_char, SplitNameLen: size_t, kind: DebugEmissionKind, + DWOId: u64, + SplitDebugInlining: bool, ) -> &'a DIDescriptor; pub fn LLVMRustDIBuilderCreateFile( @@ -2151,6 +2153,7 @@ extern "C" { EmitStackSizeSection: bool, RelaxELFRelocations: bool, UseInitArray: bool, + SplitDwarfFile: *const c_char, ) -> Option<&'static mut TargetMachine>; pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine); pub fn LLVMRustAddBuilderLibraryInfo( @@ -2179,6 +2182,7 @@ extern "C" { PM: &PassManager<'a>, M: &'a Module, Output: *const c_char, + DwoOutput: *const c_char, FileType: FileType, ) -> LLVMRustResult; pub fn LLVMRustOptimizeWithNewPassManager( |
