Rollup merge of #155036 - bjorn3:lto_refactors16, r=TaKO8Ki

Store a PathBuf rather than SerializedModule for cached modules

In cg_gcc `ModuleBuffer` already only contains a path anyway. And for moving LTO into `-Zlink-only` we will need to serialize `MaybeLtoModules`. By storing a path cached modules we avoid writing them to the disk a second time during serialization of `MaybeLtoModules`.

Some further improvements will require changes to cg_gcc that I would prefer landing in the cg_gcc repo to actually test the LTO changes in CI.

Part of https://github.com/rust-lang/compiler-team/issues/908
This commit is contained in:
Jonathan Brouwer
2026-04-21 16:53:39 +02:00
committed by GitHub
4 changed files with 51 additions and 40 deletions
+5 -2
View File
@@ -144,9 +144,12 @@ fn fat_lto(
for module in modules { for module in modules {
match module { match module {
FatLtoInput::InMemory(m) => in_memory.push(m), FatLtoInput::InMemory(m) => in_memory.push(m),
FatLtoInput::Serialized { name, buffer } => { FatLtoInput::Serialized { name, bitcode_path } => {
info!("pushing serialized module {:?}", name); info!("pushing serialized module {:?}", name);
serialized_modules.push((buffer, CString::new(name).unwrap())); serialized_modules.push((
SerializedModule::from_file(&bitcode_path),
CString::new(name).unwrap(),
));
} }
} }
} }
+8 -3
View File
@@ -223,9 +223,12 @@ fn fat_lto(
for module in modules { for module in modules {
match module { match module {
FatLtoInput::InMemory(m) => in_memory.push(m), FatLtoInput::InMemory(m) => in_memory.push(m),
FatLtoInput::Serialized { name, buffer } => { FatLtoInput::Serialized { name, bitcode_path } => {
info!("pushing serialized module {:?}", name); info!("pushing serialized module {:?}", name);
serialized_modules.push((buffer, CString::new(name).unwrap())); serialized_modules.push((
SerializedModule::from_file(&bitcode_path),
CString::new(name).unwrap(),
));
} }
} }
} }
@@ -396,7 +399,9 @@ fn thin_lto(
for (i, module) in modules.into_iter().enumerate() { for (i, module) in modules.into_iter().enumerate() {
let (name, buffer) = match module { let (name, buffer) = match module {
ThinLtoInput::Red { name, buffer } => (name, buffer), ThinLtoInput::Red { name, buffer } => (name, buffer),
ThinLtoInput::Green { wp, buffer } => (wp.cgu_name, buffer), ThinLtoInput::Green { wp, bitcode_path } => {
(wp.cgu_name, SerializedModule::from_file(&bitcode_path))
}
}; };
info!("local module: {} - {}", i, name); info!("local module: {} - {}", i, name);
let cname = CString::new(name.as_bytes()).unwrap(); let cname = CString::new(name.as_bytes()).unwrap();
@@ -1,4 +1,6 @@
use std::ffi::CString; use std::ffi::CString;
use std::fs;
use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
use rustc_data_structures::memmap::Mmap; use rustc_data_structures::memmap::Mmap;
@@ -49,6 +51,19 @@ pub enum SerializedModule<M: ModuleBufferMethods> {
} }
impl<M: ModuleBufferMethods> SerializedModule<M> { impl<M: ModuleBufferMethods> SerializedModule<M> {
pub fn from_file(bc_path: &Path) -> Self {
let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
panic!("failed to open LTO bitcode file `{}`: {}", bc_path.display(), e)
});
let mmap = unsafe {
Mmap::map(file).unwrap_or_else(|e| {
panic!("failed to mmap LTO bitcode file `{}`: {}", bc_path.display(), e)
})
};
SerializedModule::FromUncompressedFile(mmap)
}
pub fn data(&self) -> &[u8] { pub fn data(&self) -> &[u8] {
match *self { match *self {
SerializedModule::Local(ref m) => m.data(), SerializedModule::Local(ref m) => m.data(),
+23 -35
View File
@@ -8,7 +8,6 @@
use rustc_abi::Size; use rustc_abi::Size;
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::jobserver::{self, Acquired};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
use rustc_errors::emitter::Emitter; use rustc_errors::emitter::Emitter;
use rustc_errors::{ use rustc_errors::{
@@ -35,9 +34,8 @@
use rustc_target::spec::{MergeFunctions, SanitizerSet}; use rustc_target::spec::{MergeFunctions, SanitizerSet};
use tracing::debug; use tracing::debug;
use super::link::{self, ensure_removed}; use crate::back::link::{self, ensure_removed};
use super::lto::{self, SerializedModule}; use crate::back::lto::{self, SerializedModule, check_lto_allowed};
use crate::back::lto::check_lto_allowed;
use crate::errors::ErrorCreatingRemarkDir; use crate::errors::ErrorCreatingRemarkDir;
use crate::traits::*; use crate::traits::*;
use crate::{ use crate::{
@@ -774,13 +772,13 @@ pub(crate) enum WorkItemResult<B: WriteBackendMethods> {
} }
pub enum FatLtoInput<B: WriteBackendMethods> { pub enum FatLtoInput<B: WriteBackendMethods> {
Serialized { name: String, buffer: SerializedModule<B::ModuleBuffer> }, Serialized { name: String, bitcode_path: PathBuf },
InMemory(ModuleCodegen<B::Module>), InMemory(ModuleCodegen<B::Module>),
} }
pub enum ThinLtoInput<B: WriteBackendMethods> { pub enum ThinLtoInput<B: WriteBackendMethods> {
Red { name: String, buffer: SerializedModule<B::ModuleBuffer> }, Red { name: String, buffer: SerializedModule<B::ModuleBuffer> },
Green { wp: WorkProduct, buffer: SerializedModule<B::ModuleBuffer> }, Green { wp: WorkProduct, bitcode_path: PathBuf },
} }
/// Actual LTO type we end up choosing based on multiple factors. /// Actual LTO type we end up choosing based on multiple factors.
@@ -866,7 +864,7 @@ fn execute_optimize_work_item<B: WriteBackendMethods>(
}); });
WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { WorkItemResult::NeedsFatLto(FatLtoInput::Serialized {
name: module.name, name: module.name,
buffer: SerializedModule::Local(buffer), bitcode_path: path,
}) })
} }
None => WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module)), None => WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module)),
@@ -1166,10 +1164,7 @@ pub(crate) enum Message<B: WriteBackendMethods> {
/// Similar to `CodegenDone`, but for reusing a pre-LTO artifact /// Similar to `CodegenDone`, but for reusing a pre-LTO artifact
/// Sent from the main thread. /// Sent from the main thread.
AddImportOnlyModule { AddImportOnlyModule { bitcode_path: PathBuf, work_product: WorkProduct },
module_data: SerializedModule<B::ModuleBuffer>,
work_product: WorkProduct,
},
/// The frontend has finished generating everything for all codegen units. /// The frontend has finished generating everything for all codegen units.
/// Sent from the main thread. /// Sent from the main thread.
@@ -1729,10 +1724,10 @@ enum CodegenState {
} }
} }
Message::AddImportOnlyModule { module_data, work_product } => { Message::AddImportOnlyModule { bitcode_path, work_product } => {
assert_eq!(codegen_state, Ongoing); assert_eq!(codegen_state, Ongoing);
assert_eq!(main_thread_state, MainThreadState::Codegenning); assert_eq!(main_thread_state, MainThreadState::Codegenning);
lto_import_only_modules.push((module_data, work_product)); lto_import_only_modules.push((bitcode_path, work_product));
main_thread_state = MainThreadState::Idle; main_thread_state = MainThreadState::Idle;
} }
} }
@@ -1758,8 +1753,8 @@ enum CodegenState {
needs_fat_lto.push(FatLtoInput::InMemory(allocator_module)); needs_fat_lto.push(FatLtoInput::InMemory(allocator_module));
} }
for (module, wp) in lto_import_only_modules { for (bitcode_path, wp) in lto_import_only_modules {
needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, buffer: module }) needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, bitcode_path })
} }
return Ok(MaybeLtoModules::FatLto { return Ok(MaybeLtoModules::FatLto {
@@ -1772,8 +1767,8 @@ enum CodegenState {
assert!(compiled_modules.is_empty()); assert!(compiled_modules.is_empty());
assert!(needs_fat_lto.is_empty()); assert!(needs_fat_lto.is_empty());
for (buffer, wp) in lto_import_only_modules { for (bitcode_path, wp) in lto_import_only_modules {
needs_thin_lto.push(ThinLtoInput::Green { wp, buffer }) needs_thin_lto.push(ThinLtoInput::Green { wp, bitcode_path })
} }
if cgcx.lto == Lto::ThinLocal { if cgcx.lto == Lto::ThinLocal {
@@ -2133,14 +2128,14 @@ fn drop(&mut self) {
} }
pub struct OngoingCodegen<B: WriteBackendMethods> { pub struct OngoingCodegen<B: WriteBackendMethods> {
pub backend: B, backend: B,
pub output_filenames: Arc<OutputFilenames>, output_filenames: Arc<OutputFilenames>,
// Field order below is intended to terminate the coordinator thread before two fields below // Field order below is intended to terminate the coordinator thread before two fields below
// drop and prematurely close channels used by coordinator thread. See `Coordinator`'s // drop and prematurely close channels used by coordinator thread. See `Coordinator`'s
// `Drop` implementation for more info. // `Drop` implementation for more info.
pub coordinator: Coordinator<B>, pub(crate) coordinator: Coordinator<B>,
pub codegen_worker_receive: Receiver<CguMessage>, codegen_worker_receive: Receiver<CguMessage>,
pub shared_emitter_main: SharedEmitterMain, shared_emitter_main: SharedEmitterMain,
} }
impl<B: WriteBackendMethods> OngoingCodegen<B> { impl<B: WriteBackendMethods> OngoingCodegen<B> {
@@ -2285,20 +2280,13 @@ pub(crate) fn submit_pre_lto_module_to_llvm<B: WriteBackendMethods>(
module: CachedModuleCodegen, module: CachedModuleCodegen,
) { ) {
let filename = pre_lto_bitcode_filename(&module.name); let filename = pre_lto_bitcode_filename(&module.name);
let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename); let bitcode_path = in_incr_comp_dir_sess(tcx.sess, &filename);
let file = fs::File::open(&bc_path)
.unwrap_or_else(|e| panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e));
let mmap = unsafe {
Mmap::map(file).unwrap_or_else(|e| {
panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e)
})
};
// Schedule the module to be loaded // Schedule the module to be loaded
drop(coordinator.sender.send(Message::AddImportOnlyModule::<B> { drop(
module_data: SerializedModule::FromUncompressedFile(mmap), coordinator
work_product: module.source, .sender
})); .send(Message::AddImportOnlyModule::<B> { bitcode_path, work_product: module.source }),
);
} }
fn pre_lto_bitcode_filename(module_name: &str) -> String { fn pre_lto_bitcode_filename(module_name: &str) -> String {