Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 26 additions & 33 deletions compiler/rustc_codegen_gcc/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_errors::{DiagCtxt, DiagCtxtHandle};
use rustc_log::tracing::info;
use rustc_session::config::Lto;
use tempfile::{TempDir, tempdir};

use crate::back::write::{codegen, save_temp_bitcode};
Expand All @@ -45,11 +44,7 @@ struct LtoData {
tmp_path: TempDir,
}

fn prepare_lto(
cgcx: &CodegenContext,
each_linked_rlib_for_lto: &[PathBuf],
dcx: DiagCtxtHandle<'_>,
) -> LtoData {
fn prepare_lto(each_linked_rlib_for_lto: &[PathBuf], dcx: DiagCtxtHandle<'_>) -> LtoData {
let tmp_path = match tempdir() {
Ok(tmp_path) => tmp_path,
Err(error) => {
Expand All @@ -64,32 +59,30 @@ fn prepare_lto(
// We save off all the bytecode and GCC module file path for later processing
// with either fat or thin LTO
let mut upstream_modules = Vec::new();
if cgcx.lto != Lto::ThinLocal {
for path in each_linked_rlib_for_lto {
let archive_data = unsafe {
Mmap::map(File::open(path).expect("couldn't open rlib")).expect("couldn't map rlib")
};
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
let obj_files = archive
.members()
.filter_map(|child| {
child.ok().and_then(|c| {
std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c))
})
})
.filter(|&(name, _)| looks_like_rust_object_file(name));
for (name, child) in obj_files {
info!("adding bitcode from {}", name);
let path = tmp_path.path().join(name);
match save_as_file(child.data(&*archive_data).expect("corrupt rlib"), &path) {
Ok(()) => {
let buffer = ModuleBuffer::new(path);
let module = SerializedModule::Local(buffer);
upstream_modules.push((module, CString::new(name).unwrap()));
}
Err(e) => {
dcx.emit_fatal(e);
}
for path in each_linked_rlib_for_lto {
let archive_data = unsafe {
Mmap::map(File::open(path).expect("couldn't open rlib")).expect("couldn't map rlib")
};
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
let obj_files = archive
.members()
.filter_map(|child| {
child
.ok()
.and_then(|c| std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)))
})
.filter(|&(name, _)| looks_like_rust_object_file(name));
for (name, child) in obj_files {
info!("adding bitcode from {}", name);
let path = tmp_path.path().join(name);
match save_as_file(child.data(&*archive_data).expect("corrupt rlib"), &path) {
Ok(()) => {
let buffer = ModuleBuffer::new(path);
let module = SerializedModule::Local(buffer);
upstream_modules.push((module, CString::new(name).unwrap()));
}
Err(e) => {
dcx.emit_fatal(e);
}
}
}
Expand All @@ -115,7 +108,7 @@ pub(crate) fn run_fat(
) -> CompiledModule {
let dcx = DiagCtxt::new(Box::new(shared_emitter.clone()));
let dcx = dcx.handle();
let lto_data = prepare_lto(cgcx, each_linked_rlib_for_lto, dcx);
let lto_data = prepare_lto(each_linked_rlib_for_lto, dcx);
/*let symbols_below_threshold =
lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
fat_lto(
Expand Down
7 changes: 3 additions & 4 deletions compiler/rustc_codegen_gcc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ use gccjit::{CType, Context, OptimizationLevel};
#[cfg(feature = "master")]
use gccjit::{TargetInfo, Version};
use rustc_ast::expand::allocator::AllocatorMethod;
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
use rustc_codegen_ssa::back::lto::ThinModule;
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn,
CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryFn, ThinLtoInput,
};
use rustc_codegen_ssa::base::codegen_crate;
use rustc_codegen_ssa::target_features::cfg_target_feature;
Expand Down Expand Up @@ -449,8 +449,7 @@ impl WriteBackendMethods for GccCodegenBackend {
// FIXME(bjorn3): Limit LTO exports to these symbols
_exported_symbols_for_lto: &[String],
_each_linked_rlib_for_lto: &[PathBuf],
_modules: Vec<(String, Self::ModuleBuffer)>,
_cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
_modules: Vec<ThinLtoInput<Self>>,
) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {
unreachable!()
}
Expand Down
147 changes: 62 additions & 85 deletions compiler/rustc_codegen_llvm/src/back/lto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use object::read::archive::ArchiveFile;
use object::{Object, ObjectSection};
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, SharedEmitter, TargetMachineFactoryFn,
CodegenContext, FatLtoInput, SharedEmitter, TargetMachineFactoryFn, ThinLtoInput,
};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind, looks_like_rust_object_file};
Expand All @@ -20,7 +20,7 @@ use rustc_errors::{DiagCtxt, DiagCtxtHandle};
use rustc_hir::attrs::SanitizerSet;
use rustc_middle::bug;
use rustc_middle::dep_graph::WorkProduct;
use rustc_session::config::{self, Lto};
use rustc_session::config;
use tracing::{debug, info};

use crate::back::write::{
Expand Down Expand Up @@ -90,33 +90,31 @@ fn prepare_lto(
// We save off all the bytecode and LLVM module ids for later processing
// with either fat or thin LTO
let mut upstream_modules = Vec::new();
if cgcx.lto != Lto::ThinLocal {
for path in each_linked_rlib_for_lto {
let archive_data = unsafe {
Mmap::map(std::fs::File::open(&path).expect("couldn't open rlib"))
.expect("couldn't map rlib")
};
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
let obj_files = archive
.members()
.filter_map(|child| {
child.ok().and_then(|c| {
std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c))
})
})
.filter(|&(name, _)| looks_like_rust_object_file(name));
for (name, child) in obj_files {
info!("adding bitcode from {}", name);
match get_bitcode_slice_from_object_data(
child.data(&*archive_data).expect("corrupt rlib"),
cgcx,
) {
Ok(data) => {
let module = SerializedModule::FromRlib(data.to_vec());
upstream_modules.push((module, CString::new(name).unwrap()));
}
Err(e) => dcx.emit_fatal(e),
for path in each_linked_rlib_for_lto {
let archive_data = unsafe {
Mmap::map(std::fs::File::open(&path).expect("couldn't open rlib"))
.expect("couldn't map rlib")
};
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
let obj_files = archive
.members()
.filter_map(|child| {
child
.ok()
.and_then(|c| std::str::from_utf8(c.name()).ok().map(|name| (name.trim(), c)))
})
.filter(|&(name, _)| looks_like_rust_object_file(name));
for (name, child) in obj_files {
info!("adding bitcode from {}", name);
match get_bitcode_slice_from_object_data(
child.data(&*archive_data).expect("corrupt rlib"),
cgcx,
) {
Ok(data) => {
let module = SerializedModule::FromRlib(data.to_vec());
upstream_modules.push((module, CString::new(name).unwrap()));
}
Err(e) => dcx.emit_fatal(e),
}
}
}
Expand Down Expand Up @@ -187,8 +185,7 @@ pub(crate) fn run_thin(
dcx: DiagCtxtHandle<'_>,
exported_symbols_for_lto: &[String],
each_linked_rlib_for_lto: &[PathBuf],
modules: Vec<(String, ModuleBuffer)>,
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
modules: Vec<ThinLtoInput<LlvmCodegenBackend>>,
) -> (Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>) {
let (symbols_below_threshold, upstream_modules) =
prepare_lto(cgcx, exported_symbols_for_lto, each_linked_rlib_for_lto, dcx);
Expand All @@ -200,7 +197,7 @@ pub(crate) fn run_thin(
is deferred to the linker"
);
}
thin_lto(cgcx, prof, dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold)
thin_lto(cgcx, prof, dcx, modules, upstream_modules, &symbols_below_threshold)
}

fn fat_lto(
Expand Down Expand Up @@ -300,19 +297,27 @@ fn fat_lto(

// For all serialized bitcode files we parse them and link them in as we did
// above, this is all mostly handled in C++.
let mut linker = Linker::new(llmod);
let linker = unsafe { llvm::LLVMRustLinkerNew(llmod) };
for (bc_decoded, name) in serialized_modules {
let _timer = prof
.generic_activity_with_arg_recorder("LLVM_fat_lto_link_module", |recorder| {
recorder.record_arg(format!("{name:?}"))
});
info!("linking {:?}", name);
let data = bc_decoded.data();
linker
.add(data)
.unwrap_or_else(|()| write::llvm_err(dcx, LlvmError::LoadBitcode { name }));

unsafe {
if !llvm::LLVMRustLinkerAdd(
linker,
data.as_ptr() as *const libc::c_char,
data.len(),
) {
llvm::LLVMRustLinkerFree(linker);
write::llvm_err(dcx, LlvmError::LoadBitcode { name })
}
}
}
drop(linker);
unsafe { llvm::LLVMRustLinkerFree(linker) };
save_temp_bitcode(cgcx, &module, "lto.input");

// Internalize everything below threshold to help strip out more modules and such.
Expand All @@ -330,36 +335,6 @@ fn fat_lto(
module
}

pub(crate) struct Linker<'a>(&'a mut llvm::Linker<'a>);

impl<'a> Linker<'a> {
pub(crate) fn new(llmod: &'a llvm::Module) -> Self {
unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) }
}

pub(crate) fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> {
unsafe {
if llvm::LLVMRustLinkerAdd(
self.0,
bytecode.as_ptr() as *const libc::c_char,
bytecode.len(),
) {
Ok(())
} else {
Err(())
}
}
}
}

impl Drop for Linker<'_> {
fn drop(&mut self) {
unsafe {
llvm::LLVMRustLinkerFree(&mut *(self.0 as *mut _));
}
}
}

/// Prepare "thin" LTO to get run on these modules.
///
/// The general structure of ThinLTO is quite different from the structure of
Expand Down Expand Up @@ -394,24 +369,35 @@ fn thin_lto(
cgcx: &CodegenContext,
prof: &SelfProfilerRef,
dcx: DiagCtxtHandle<'_>,
modules: Vec<(String, ModuleBuffer)>,
modules: Vec<ThinLtoInput<LlvmCodegenBackend>>,
serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
symbols_below_threshold: &[*const libc::c_char],
) -> (Vec<ThinModule<LlvmCodegenBackend>>, Vec<WorkProduct>) {
let _timer = prof.generic_activity("LLVM_thin_lto_global_analysis");
unsafe {
info!("going for that thin, thin LTO");

let green_modules: FxHashMap<_, _> =
cached_modules.iter().map(|(_, wp)| (wp.cgu_name.clone(), wp.clone())).collect();
let green_modules: FxHashMap<_, _> = modules
.iter()
.filter_map(|module| {
if let ThinLtoInput::Green { wp, .. } = module {
Some((wp.cgu_name.clone(), wp.clone()))
} else {
None
}
})
.collect();

let full_scope_len = modules.len() + serialized_modules.len() + cached_modules.len();
let full_scope_len = modules.len();
let mut thin_buffers = Vec::with_capacity(modules.len());
let mut module_names = Vec::with_capacity(full_scope_len);
let mut thin_modules = Vec::with_capacity(full_scope_len);

for (i, (name, buffer)) in modules.into_iter().enumerate() {
for (i, module) in modules.into_iter().enumerate() {
let (name, buffer) = match module {
ThinLtoInput::Red { name, buffer } => (name, buffer),
ThinLtoInput::Green { wp, buffer } => (wp.cgu_name, buffer),
};
info!("local module: {} - {}", i, name);
let cname = CString::new(name.as_bytes()).unwrap();
thin_modules.push(llvm::ThinLTOModule {
Expand Down Expand Up @@ -439,19 +425,15 @@ fn thin_lto(
// incremental ThinLTO first where we could actually avoid
// looking at upstream modules entirely sometimes (the contents,
// we must always unconditionally look at the index).
let mut serialized = Vec::with_capacity(serialized_modules.len() + cached_modules.len());

let cached_modules =
cached_modules.into_iter().map(|(sm, wp)| (sm, CString::new(wp.cgu_name).unwrap()));

for (module, name) in serialized_modules.into_iter().chain(cached_modules) {
info!("upstream or cached module {:?}", name);
for (module, name) in serialized_modules {
info!("upstream module {:?}", name);
thin_modules.push(llvm::ThinLTOModule {
identifier: name.as_ptr(),
data: module.data().as_ptr(),
len: module.data().len(),
});
serialized.push(module);
thin_buffers.push(module);
module_names.push(name);
}

Expand Down Expand Up @@ -500,12 +482,7 @@ fn thin_lto(
// also put all memory referenced by the C++ data (buffers, ids, etc)
// into the arc as well. After this we'll create a thin module
// codegen per module in this data.
let shared = Arc::new(ThinShared {
data,
thin_buffers,
serialized_modules: serialized,
module_names,
});
let shared = Arc::new(ThinShared { data, modules: thin_buffers, module_names });

let mut copy_jobs = vec![];
let mut opt_jobs = vec![];
Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_codegen_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ use back::write::{create_informational_target_machine, create_target_machine};
use context::SimpleCx;
use llvm_util::target_config;
use rustc_ast::expand::allocator::AllocatorMethod;
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
use rustc_codegen_ssa::back::lto::ThinModule;
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, ModuleConfig, SharedEmitter, TargetMachineFactoryConfig,
TargetMachineFactoryFn,
TargetMachineFactoryFn, ThinLtoInput,
};
use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{CompiledModule, CompiledModules, CrateInfo, ModuleCodegen, TargetConfig};
Expand Down Expand Up @@ -165,8 +165,7 @@ impl WriteBackendMethods for LlvmCodegenBackend {
dcx: DiagCtxtHandle<'_>,
exported_symbols_for_lto: &[String],
each_linked_rlib_for_lto: &[PathBuf],
modules: Vec<(String, Self::ModuleBuffer)>,
cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>,
modules: Vec<ThinLtoInput<Self>>,
) -> (Vec<ThinModule<Self>>, Vec<WorkProduct>) {
back::lto::run_thin(
cgcx,
Expand All @@ -175,7 +174,6 @@ impl WriteBackendMethods for LlvmCodegenBackend {
exported_symbols_for_lto,
each_linked_rlib_for_lto,
modules,
cached_modules,
)
}
fn optimize(
Expand Down
Loading
Loading