Skip to content

Commit 07dbe49

Browse files
authored
Rollup merge of rust-lang#75094 - 0dvictor:cgu, r=oli-obk
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 rust-lang#64191
2 parents e2be5f5 + c81b43d commit 07dbe49

File tree

6 files changed

+90
-15
lines changed

6 files changed

+90
-15
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -346,14 +346,14 @@ fn fat_lto(
346346
Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
347347
}
348348

349-
struct Linker<'a>(&'a mut llvm::Linker<'a>);
349+
crate struct Linker<'a>(&'a mut llvm::Linker<'a>);
350350

351351
impl Linker<'a> {
352-
fn new(llmod: &'a llvm::Module) -> Self {
352+
crate fn new(llmod: &'a llvm::Module) -> Self {
353353
unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
354354
}
355355

356-
fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
356+
crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
357357
unsafe {
358358
if llvm::LLVMRustLinkerAdd(
359359
self.0,

compiler/rustc_codegen_llvm/src/back/write.rs

+25
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,31 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static
617617
}
618618
}
619619

620+
pub(crate) fn link(
621+
cgcx: &CodegenContext<LlvmCodegenBackend>,
622+
diag_handler: &Handler,
623+
mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
624+
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
625+
use super::lto::{Linker, ModuleBuffer};
626+
// Sort the modules by name to ensure to ensure deterministic behavior.
627+
modules.sort_by(|a, b| a.name.cmp(&b.name));
628+
let (first, elements) =
629+
modules.split_first().expect("Bug! modules must contain at least one module.");
630+
631+
let mut linker = Linker::new(first.module_llvm.llmod());
632+
for module in elements {
633+
let _timer =
634+
cgcx.prof.generic_activity_with_arg("LLVM_link_module", format!("{:?}", module.name));
635+
let buffer = ModuleBuffer::new(module.module_llvm.llmod());
636+
linker.add(&buffer.data()).map_err(|()| {
637+
let msg = format!("failed to serialize module {:?}", module.name);
638+
llvm_err(&diag_handler, &msg)
639+
})?;
640+
}
641+
drop(linker);
642+
Ok(modules.remove(0))
643+
}
644+
620645
pub(crate) unsafe fn codegen(
621646
cgcx: &CodegenContext<LlvmCodegenBackend>,
622647
diag_handler: &Handler,

compiler/rustc_codegen_llvm/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ impl WriteBackendMethods for LlvmCodegenBackend {
130130
llvm::LLVMRustPrintPassTimings();
131131
}
132132
}
133+
fn run_link(
134+
cgcx: &CodegenContext<Self>,
135+
diag_handler: &Handler,
136+
modules: Vec<ModuleCodegen<Self::Module>>,
137+
) -> Result<ModuleCodegen<Self::Module>, FatalError> {
138+
back::write::link(cgcx, diag_handler, modules)
139+
}
133140
fn run_fat_lto(
134141
cgcx: &CodegenContext<Self>,
135142
modules: Vec<FatLTOInput<Self>>,

compiler/rustc_codegen_ssa/src/back/write.rs

+47-12
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,7 @@ impl<B: WriteBackendMethods> WorkItem<B> {
702702

703703
enum WorkItemResult<B: WriteBackendMethods> {
704704
Compiled(CompiledModule),
705+
NeedsLink(ModuleCodegen<B::Module>),
705706
NeedsFatLTO(FatLTOInput<B>),
706707
NeedsThinLTO(String, B::ThinBuffer),
707708
}
@@ -801,31 +802,28 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
801802
None
802803
};
803804

804-
Ok(match lto_type {
805-
ComputedLtoType::No => {
806-
let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
807-
WorkItemResult::Compiled(module)
808-
}
805+
match lto_type {
806+
ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config),
809807
ComputedLtoType::Thin => {
810808
let (name, thin_buffer) = B::prepare_thin(module);
811809
if let Some(path) = bitcode {
812810
fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| {
813811
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
814812
});
815813
}
816-
WorkItemResult::NeedsThinLTO(name, thin_buffer)
814+
Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))
817815
}
818816
ComputedLtoType::Fat => match bitcode {
819817
Some(path) => {
820818
let (name, buffer) = B::serialize_module(module);
821819
fs::write(&path, buffer.data()).unwrap_or_else(|e| {
822820
panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
823821
});
824-
WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer })
822+
Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }))
825823
}
826-
None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)),
824+
None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))),
827825
},
828-
})
826+
}
829827
}
830828

831829
fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
@@ -870,13 +868,26 @@ fn execute_lto_work_item<B: ExtraBackendMethods>(
870868
cgcx: &CodegenContext<B>,
871869
mut module: lto::LtoModuleCodegen<B>,
872870
module_config: &ModuleConfig,
871+
) -> Result<WorkItemResult<B>, FatalError> {
872+
let module = unsafe { module.optimize(cgcx)? };
873+
finish_intra_module_work(cgcx, module, module_config)
874+
}
875+
876+
fn finish_intra_module_work<B: ExtraBackendMethods>(
877+
cgcx: &CodegenContext<B>,
878+
module: ModuleCodegen<B::Module>,
879+
module_config: &ModuleConfig,
873880
) -> Result<WorkItemResult<B>, FatalError> {
874881
let diag_handler = cgcx.create_diag_handler();
875882

876-
unsafe {
877-
let module = module.optimize(cgcx)?;
878-
let module = B::codegen(cgcx, &diag_handler, module, module_config)?;
883+
if !cgcx.opts.debugging_opts.combine_cgu
884+
|| module.kind == ModuleKind::Metadata
885+
|| module.kind == ModuleKind::Allocator
886+
{
887+
let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
879888
Ok(WorkItemResult::Compiled(module))
889+
} else {
890+
Ok(WorkItemResult::NeedsLink(module))
880891
}
881892
}
882893

@@ -891,6 +902,10 @@ pub enum Message<B: WriteBackendMethods> {
891902
thin_buffer: B::ThinBuffer,
892903
worker_id: usize,
893904
},
905+
NeedsLink {
906+
module: ModuleCodegen<B::Module>,
907+
worker_id: usize,
908+
},
894909
Done {
895910
result: Result<CompiledModule, Option<WorkerFatalError>>,
896911
worker_id: usize,
@@ -1178,6 +1193,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
11781193
let mut compiled_modules = vec![];
11791194
let mut compiled_metadata_module = None;
11801195
let mut compiled_allocator_module = None;
1196+
let mut needs_link = Vec::new();
11811197
let mut needs_fat_lto = Vec::new();
11821198
let mut needs_thin_lto = Vec::new();
11831199
let mut lto_import_only_modules = Vec::new();
@@ -1434,6 +1450,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
14341450
}
14351451
}
14361452
}
1453+
Message::NeedsLink { module, worker_id } => {
1454+
free_worker(worker_id);
1455+
needs_link.push(module);
1456+
}
14371457
Message::NeedsFatLTO { result, worker_id } => {
14381458
assert!(!started_lto);
14391459
free_worker(worker_id);
@@ -1462,6 +1482,18 @@ fn start_executing_work<B: ExtraBackendMethods>(
14621482
}
14631483
}
14641484

1485+
let needs_link = mem::take(&mut needs_link);
1486+
if !needs_link.is_empty() {
1487+
assert!(compiled_modules.is_empty());
1488+
let diag_handler = cgcx.create_diag_handler();
1489+
let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?;
1490+
let module = unsafe {
1491+
B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular))
1492+
.map_err(|_| ())?
1493+
};
1494+
compiled_modules.push(module);
1495+
}
1496+
14651497
// Drop to print timings
14661498
drop(llvm_start_time);
14671499

@@ -1521,6 +1553,9 @@ fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>
15211553
Some(Ok(WorkItemResult::Compiled(m))) => {
15221554
Message::Done::<B> { result: Ok(m), worker_id }
15231555
}
1556+
Some(Ok(WorkItemResult::NeedsLink(m))) => {
1557+
Message::NeedsLink::<B> { module: m, worker_id }
1558+
}
15241559
Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
15251560
Message::NeedsFatLTO::<B> { result: m, worker_id }
15261561
}

compiler/rustc_codegen_ssa/src/traits/write.rs

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
1313
type ThinData: Send + Sync;
1414
type ThinBuffer: ThinBufferMethods;
1515

16+
/// Merge all modules into main_module and returning it
17+
fn run_link(
18+
cgcx: &CodegenContext<Self>,
19+
diag_handler: &Handler,
20+
modules: Vec<ModuleCodegen<Self::Module>>,
21+
) -> Result<ModuleCodegen<Self::Module>, FatalError>;
1622
/// Performs fat LTO by merging all modules into a single one and returning it
1723
/// for further optimization.
1824
fn run_fat_lto(

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
850850
"enable the experimental Chalk-based trait solving engine"),
851851
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
852852
"the backend to use"),
853+
combine_cgu: bool = (false, parse_bool, [TRACKED],
854+
"combine CGUs into a single one"),
853855
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
854856
"inject the given attribute in the crate"),
855857
debug_macros: bool = (false, parse_bool, [TRACKED],

0 commit comments

Comments
 (0)