From: Victor Ding Date: Wed, 9 Sep 2020 04:51:16 +0000 (+1000) Subject: Add `-Z combine_cgu` flag X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=c81b43d8ac0dd68a49c4c65771c3c65a4ca61f93;p=rust.git Add `-Z combine_cgu` flag Introduce a compiler option to let rustc combines all regular CGUs into a single one at the end of compilation. Part of Issue #64191 --- diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 7c710a1cb3d..4b2d5907a02 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -346,14 +346,14 @@ fn fat_lto( Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode }) } -struct Linker<'a>(&'a mut llvm::Linker<'a>); +crate struct Linker<'a>(&'a mut llvm::Linker<'a>); impl Linker<'a> { - fn new(llmod: &'a llvm::Module) -> Self { + crate fn new(llmod: &'a llvm::Module) -> Self { unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } } - fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { unsafe { if llvm::LLVMRustLinkerAdd( self.0, diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6f386c1287c..937821e9d4f 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -617,6 +617,31 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static } } +pub(crate) fn link( + cgcx: &CodegenContext, + diag_handler: &Handler, + mut modules: Vec>, +) -> Result, FatalError> { + use super::lto::{Linker, ModuleBuffer}; + // Sort the modules by name to ensure to ensure deterministic behavior. + modules.sort_by(|a, b| a.name.cmp(&b.name)); + let (first, elements) = + modules.split_first().expect("Bug! modules must contain at least one module."); + + let mut linker = Linker::new(first.module_llvm.llmod()); + for module in elements { + let _timer = + cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name)); + let buffer = ModuleBuffer::new(module.module_llvm.llmod()); + linker.add(&buffer.data()).map_err(|()| { + let msg = format!("failed to serialize module {:?}", module.name); + llvm_err(&diag_handler, &msg) + })?; + } + drop(linker); + Ok(modules.remove(0)) +} + pub(crate) unsafe fn codegen( cgcx: &CodegenContext, diag_handler: &Handler, diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 67d4b2642c0..2e2abe9fb30 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -130,6 +130,13 @@ fn print_pass_timings(&self) { llvm::LLVMRustPrintPassTimings(); } } + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError> { + back::write::link(cgcx, diag_handler, modules) + } fn run_fat_lto( cgcx: &CodegenContext, modules: Vec>, diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 7d69bb983dd..0edf0fcd1a2 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -702,6 +702,7 @@ fn start_profiling<'a>(&self, cgcx: &'a CodegenContext) -> TimingGuard<'a> { enum WorkItemResult { Compiled(CompiledModule), + NeedsLink(ModuleCodegen), NeedsFatLTO(FatLTOInput), NeedsThinLTO(String, B::ThinBuffer), } @@ -801,11 +802,8 @@ fn execute_optimize_work_item( None }; - Ok(match lto_type { - ComputedLtoType::No => { - let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; - WorkItemResult::Compiled(module) - } + match lto_type { + ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config), ComputedLtoType::Thin => { let (name, thin_buffer) = B::prepare_thin(module); if let Some(path) = bitcode { @@ -813,7 +811,7 @@ fn execute_optimize_work_item( panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); } - WorkItemResult::NeedsThinLTO(name, thin_buffer) + Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) } ComputedLtoType::Fat => match bitcode { Some(path) => { @@ -821,11 +819,11 @@ fn execute_optimize_work_item( fs::write(&path, buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); - WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }) + Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer })) } - None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)), + None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))), }, - }) + } } fn execute_copy_from_cache_work_item( @@ -870,13 +868,26 @@ fn execute_lto_work_item( cgcx: &CodegenContext, mut module: lto::LtoModuleCodegen, module_config: &ModuleConfig, +) -> Result, FatalError> { + let module = unsafe { module.optimize(cgcx)? }; + finish_intra_module_work(cgcx, module, module_config) +} + +fn finish_intra_module_work( + cgcx: &CodegenContext, + module: ModuleCodegen, + module_config: &ModuleConfig, ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - unsafe { - let module = module.optimize(cgcx)?; - let module = B::codegen(cgcx, &diag_handler, module, module_config)?; + if !cgcx.opts.debugging_opts.combine_cgu + || module.kind == ModuleKind::Metadata + || module.kind == ModuleKind::Allocator + { + let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; Ok(WorkItemResult::Compiled(module)) + } else { + Ok(WorkItemResult::NeedsLink(module)) } } @@ -891,6 +902,10 @@ pub enum Message { thin_buffer: B::ThinBuffer, worker_id: usize, }, + NeedsLink { + module: ModuleCodegen, + worker_id: usize, + }, Done { result: Result>, worker_id: usize, @@ -1178,6 +1193,7 @@ fn start_executing_work( let mut compiled_modules = vec![]; let mut compiled_metadata_module = None; let mut compiled_allocator_module = None; + let mut needs_link = Vec::new(); let mut needs_fat_lto = Vec::new(); let mut needs_thin_lto = Vec::new(); let mut lto_import_only_modules = Vec::new(); @@ -1434,6 +1450,10 @@ fn start_executing_work( } } } + Message::NeedsLink { module, worker_id } => { + free_worker(worker_id); + needs_link.push(module); + } Message::NeedsFatLTO { result, worker_id } => { assert!(!started_lto); free_worker(worker_id); @@ -1462,6 +1482,18 @@ fn start_executing_work( } } + let needs_link = mem::take(&mut needs_link); + if !needs_link.is_empty() { + assert!(compiled_modules.is_empty()); + let diag_handler = cgcx.create_diag_handler(); + let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?; + let module = unsafe { + B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular)) + .map_err(|_| ())? + }; + compiled_modules.push(module); + } + // Drop to print timings drop(llvm_start_time); @@ -1521,6 +1553,9 @@ fn drop(&mut self) { Some(Ok(WorkItemResult::Compiled(m))) => { Message::Done:: { result: Ok(m), worker_id } } + Some(Ok(WorkItemResult::NeedsLink(m))) => { + Message::NeedsLink:: { module: m, worker_id } + } Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { Message::NeedsFatLTO:: { result: m, worker_id } } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index 27d52e9b9c5..264e7c2aa92 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -13,6 +13,12 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { type ThinData: Send + Sync; type ThinBuffer: ThinBufferMethods; + /// Merge all modules into main_module and returning it + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError>; /// Performs fat LTO by merging all modules into a single one and returning it /// for further optimization. fn run_fat_lto( diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ad36fa76986..848c7cb7d75 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -850,6 +850,8 @@ fn parse_target_feature(slot: &mut String, v: Option<&str>) -> bool { "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), + combine_cgu: bool = (false, parse_bool, [TRACKED], + "combine CGUs into a single one"), crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), debug_macros: bool = (false, parse_bool, [TRACKED],