rustc_codegen_ssa/back/
lto.rs1use std::ffi::CString;
2use std::fs;
3use std::path::Path;
4use std::sync::Arc;
5
6use rustc_data_structures::memmap::Mmap;
7use rustc_errors::DiagCtxtHandle;
8use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
9use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportLevel};
10use rustc_middle::ty::TyCtxt;
11use rustc_session::config::Lto;
12use rustc_structures::CrateType;
13use tracing::info;
14
15use crate::back::symbol_export::{self, allocator_shim_symbols, symbol_name_for_instance_in_crate};
16use crate::back::write::CodegenContext;
17use crate::base::allocator_kind_for_codegen;
18use crate::diagnostics::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro};
19use crate::traits::*;
20
21pub struct ThinModule<B: WriteBackendMethods> {
22 pub shared: Arc<ThinShared<B>>,
23 pub idx: usize,
24}
25
26impl<B: WriteBackendMethods> ThinModule<B> {
27 pub fn name(&self) -> &str {
28 self.shared.module_names[self.idx].to_str().unwrap()
29 }
30
31 pub fn cost(&self) -> u64 {
32 self.data().len() as u64
35 }
36
37 pub fn data(&self) -> &[u8] {
38 self.shared.modules[self.idx].data()
39 }
40}
41
42pub struct ThinShared<B: WriteBackendMethods> {
43 pub data: B::ThinData,
44 pub modules: Vec<SerializedModule<B::ModuleBuffer>>,
45 pub module_names: Vec<CString>,
46}
47
48pub enum SerializedModule<M: ModuleBufferMethods> {
49 Local(M),
50 FromRlib(Vec<u8>),
51 FromUncompressedFile(Mmap),
52}
53
54impl<M: ModuleBufferMethods> SerializedModule<M> {
55 pub fn from_file(bc_path: &Path) -> Self {
56 let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
57 {
::core::panicking::panic_fmt(format_args!("failed to open LTO bitcode file `{0}`: {1}",
bc_path.display(), e));
}panic!("failed to open LTO bitcode file `{}`: {}", bc_path.display(), e)
58 });
59
60 let mmap = unsafe {
61 Mmap::map(file).unwrap_or_else(|e| {
62 {
::core::panicking::panic_fmt(format_args!("failed to mmap LTO bitcode file `{0}`: {1}",
bc_path.display(), e));
}panic!("failed to mmap LTO bitcode file `{}`: {}", bc_path.display(), e)
63 })
64 };
65 SerializedModule::FromUncompressedFile(mmap)
66 }
67
68 pub fn data(&self) -> &[u8] {
69 match *self {
70 SerializedModule::Local(ref m) => m.data(),
71 SerializedModule::FromRlib(ref m) => m,
72 SerializedModule::FromUncompressedFile(ref m) => m,
73 }
74 }
75}
76
77fn crate_type_allows_lto(crate_type: CrateType) -> bool {
78 match crate_type {
79 CrateType::Executable
80 | CrateType::Dylib
81 | CrateType::StaticLib
82 | CrateType::Cdylib
83 | CrateType::ProcMacro
84 | CrateType::Sdylib => true,
85 CrateType::Rlib => false,
86 }
87}
88
89pub(crate) fn exported_symbols_for_lto(
90 tcx: TyCtxt<'_>,
91 each_linked_rlib_for_lto: &[CrateNum],
92) -> Vec<String> {
93 let export_threshold = match tcx.sess.lto() {
94 Lto::ThinLocal => SymbolExportLevel::Rust,
96
97 Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&tcx.crate_types()),
99
100 Lto::No => return ::alloc::vec::Vec::new()vec![],
101 };
102
103 let copy_symbols = |cnum| {
104 tcx.exported_non_generic_symbols(cnum)
105 .iter()
106 .chain(tcx.exported_generic_symbols(cnum))
107 .filter_map(|&(s, info): &(ExportedSymbol<'_>, SymbolExportInfo)| {
108 if info.level.is_below_threshold(export_threshold) || info.used {
109 Some(symbol_name_for_instance_in_crate(tcx, s, cnum))
110 } else {
111 None
112 }
113 })
114 .collect::<Vec<_>>()
115 };
116 let mut symbols_below_threshold = {
117 let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
118 copy_symbols(LOCAL_CRATE)
119 };
120 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/f248f4038796913873f11ca65b1b901e311c8dae/compiler/rustc_codegen_ssa/src/back/lto.rs:120",
"rustc_codegen_ssa::back::lto", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("/rustc-dev/f248f4038796913873f11ca65b1b901e311c8dae/compiler/rustc_codegen_ssa/src/back/lto.rs"),
::tracing_core::__macro_support::Option::Some(120u32),
::tracing_core::__macro_support::Option::Some("rustc_codegen_ssa::back::lto"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0} symbols to preserve in this crate",
symbols_below_threshold.len()) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
121
122 for &cnum in each_linked_rlib_for_lto {
125 let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
126 symbols_below_threshold.extend(copy_symbols(cnum));
127 }
128
129 if export_threshold == SymbolExportLevel::Rust
131 && let Some(kind) = allocator_kind_for_codegen(tcx)
132 {
133 symbols_below_threshold.extend(allocator_shim_symbols(tcx, kind).map(|(name, _kind)| name));
134 }
135
136 symbols_below_threshold
137}
138
139pub(super) fn check_lto_allowed(cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>) {
140 if cgcx.lto == Lto::ThinLocal {
141 return;
143 }
144
145 for crate_type in cgcx.crate_types.iter() {
147 if !crate_type_allows_lto(*crate_type) {
148 dcx.handle().emit_fatal(LtoDisallowed);
149 } else if *crate_type == CrateType::Dylib {
150 if !cgcx.dylib_lto {
151 dcx.handle().emit_fatal(LtoDylib);
152 }
153 } else if *crate_type == CrateType::ProcMacro && !cgcx.dylib_lto {
154 dcx.handle().emit_fatal(LtoProcMacro);
155 }
156 }
157
158 if cgcx.prefer_dynamic && !cgcx.dylib_lto {
159 dcx.handle().emit_fatal(DynamicLinkingWithLTO);
160 }
161}