Move LTO symbol export calculation from backends to cg_ssa

This commit is contained in:
bjorn3
2025-07-04 14:59:53 +00:00
parent 2ad7930b40
commit 1c8dc6f440
9 changed files with 132 additions and 191 deletions

View File

@@ -2,7 +2,15 @@ use std::ffi::CString;
use std::sync::Arc;
use rustc_data_structures::memmap::Mmap;
use rustc_errors::{DiagCtxtHandle, FatalError};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
use rustc_session::config::{CrateType, Lto};
use tracing::info;
use crate::back::symbol_export;
use crate::back::write::CodegenContext;
use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro};
use crate::traits::*;
pub struct ThinModule<B: WriteBackendMethods> {
@@ -52,3 +60,78 @@ impl<M: ModuleBufferMethods> SerializedModule<M> {
}
}
}
fn crate_type_allows_lto(crate_type: CrateType) -> bool {
match crate_type {
CrateType::Executable
| CrateType::Dylib
| CrateType::Staticlib
| CrateType::Cdylib
| CrateType::ProcMacro
| CrateType::Sdylib => true,
CrateType::Rlib => false,
}
}
pub fn exported_symbols_for_lto<'a, B: WriteBackendMethods>(
cgcx: &'a CodegenContext<B>,
dcx: DiagCtxtHandle<'_>,
) -> Result<Vec<&'a str>, FatalError> {
// FIXME move symbol filtering to cg_ssa
let export_threshold = match cgcx.lto {
// We're just doing LTO for our one crate
Lto::ThinLocal => SymbolExportLevel::Rust,
// We're doing LTO for the entire crate graph
Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&cgcx.crate_types),
Lto::No => panic!("didn't request LTO but we're doing LTO"),
};
let symbol_filter = &|&(ref name, info): &'a (String, SymbolExportInfo)| {
if info.level.is_below_threshold(export_threshold) || info.used {
Some(name.as_str())
} else {
None
}
};
let exported_symbols = cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
let mut symbols_below_threshold = {
let _timer = cgcx.prof.generic_activity("lto_generate_symbols_below_threshold");
exported_symbols[&LOCAL_CRATE].iter().filter_map(symbol_filter).collect::<Vec<&str>>()
};
info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
// If we're performing LTO for the entire crate graph, then for each of our
// upstream dependencies, include their exported symbols.
if cgcx.lto != Lto::ThinLocal {
// Make sure we actually can run LTO
for crate_type in cgcx.crate_types.iter() {
if !crate_type_allows_lto(*crate_type) {
return Err(dcx.emit_almost_fatal(LtoDisallowed));
} else if *crate_type == CrateType::Dylib {
if !cgcx.opts.unstable_opts.dylib_lto {
return Err(dcx.emit_almost_fatal(LtoDylib));
}
} else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto {
return Err(dcx.emit_almost_fatal(LtoProcMacro));
}
}
if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
return Err(dcx.emit_almost_fatal(DynamicLinkingWithLTO));
}
for &(cnum, ref _path) in cgcx.each_linked_rlib_for_lto.iter() {
let exported_symbols =
cgcx.exported_symbols.as_ref().expect("needs exported symbols for LTO");
{
let _timer = cgcx.prof.generic_activity("lto_generate_symbols_below_threshold");
symbols_below_threshold
.extend(exported_symbols[&cnum].iter().filter_map(symbol_filter));
}
}
}
Ok(symbols_below_threshold)
}

View File

@@ -1294,3 +1294,20 @@ pub(crate) struct FeatureNotValid<'a> {
#[help]
pub plus_hint: bool,
}
#[derive(Diagnostic)]
#[diag(codegen_ssa_lto_disallowed)]
pub(crate) struct LtoDisallowed;
#[derive(Diagnostic)]
#[diag(codegen_ssa_lto_dylib)]
pub(crate) struct LtoDylib;
#[derive(Diagnostic)]
#[diag(codegen_ssa_lto_proc_macro)]
pub(crate) struct LtoProcMacro;
#[derive(Diagnostic)]
#[diag(codegen_ssa_dynamic_linking_with_lto)]
#[note]
pub(crate) struct DynamicLinkingWithLTO;