rustc_codegen_ssa/back/
lto.rs1use std::ffi::CString;
2use std::sync::Arc;
3
4use rustc_data_structures::memmap::Mmap;
5use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
6use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportLevel};
7use rustc_middle::ty::TyCtxt;
8use rustc_session::config::{CrateType, Lto};
9use tracing::info;
10
11use crate::back::symbol_export::{self, allocator_shim_symbols, symbol_name_for_instance_in_crate};
12use crate::back::write::CodegenContext;
13use crate::base::allocator_kind_for_codegen;
14use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro};
15use crate::traits::*;
16
17pub struct ThinModule<B: WriteBackendMethods> {
18 pub shared: Arc<ThinShared<B>>,
19 pub idx: usize,
20}
21
22impl<B: WriteBackendMethods> ThinModule<B> {
23 pub fn name(&self) -> &str {
24 self.shared.module_names[self.idx].to_str().unwrap()
25 }
26
27 pub fn cost(&self) -> u64 {
28 self.data().len() as u64
31 }
32
33 pub fn data(&self) -> &[u8] {
34 let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
35 a.unwrap_or_else(|| {
36 let len = self.shared.thin_buffers.len();
37 self.shared.serialized_modules[self.idx - len].data()
38 })
39 }
40}
41
42pub struct ThinShared<B: WriteBackendMethods> {
43 pub data: B::ThinData,
44 pub thin_buffers: Vec<B::ThinBuffer>,
45 pub serialized_modules: Vec<SerializedModule<B::ModuleBuffer>>,
46 pub module_names: Vec<CString>,
47}
48
49pub enum SerializedModule<M: ModuleBufferMethods> {
50 Local(M),
51 FromRlib(Vec<u8>),
52 FromUncompressedFile(Mmap),
53}
54
55impl<M: ModuleBufferMethods> SerializedModule<M> {
56 pub fn data(&self) -> &[u8] {
57 match *self {
58 SerializedModule::Local(ref m) => m.data(),
59 SerializedModule::FromRlib(ref m) => m,
60 SerializedModule::FromUncompressedFile(ref m) => m,
61 }
62 }
63}
64
65fn crate_type_allows_lto(crate_type: CrateType) -> bool {
66 match crate_type {
67 CrateType::Executable
68 | CrateType::Dylib
69 | CrateType::Staticlib
70 | CrateType::Cdylib
71 | CrateType::ProcMacro
72 | CrateType::Sdylib => true,
73 CrateType::Rlib => false,
74 }
75}
76
77pub(super) fn exported_symbols_for_lto(
78 tcx: TyCtxt<'_>,
79 each_linked_rlib_for_lto: &[CrateNum],
80) -> Vec<String> {
81 let export_threshold = match tcx.sess.lto() {
82 Lto::ThinLocal => SymbolExportLevel::Rust,
84
85 Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&tcx.crate_types()),
87
88 Lto::No => return ::alloc::vec::Vec::new()vec![],
89 };
90
91 let copy_symbols = |cnum| {
92 tcx.exported_non_generic_symbols(cnum)
93 .iter()
94 .chain(tcx.exported_generic_symbols(cnum))
95 .filter_map(|&(s, info): &(ExportedSymbol<'_>, SymbolExportInfo)| {
96 if info.level.is_below_threshold(export_threshold) || info.used {
97 Some(symbol_name_for_instance_in_crate(tcx, s, cnum))
98 } else {
99 None
100 }
101 })
102 .collect::<Vec<_>>()
103 };
104 let mut symbols_below_threshold = {
105 let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
106 copy_symbols(LOCAL_CRATE)
107 };
108 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_ssa/src/back/lto.rs:108",
"rustc_codegen_ssa::back::lto", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_ssa/src/back/lto.rs"),
::tracing_core::__macro_support::Option::Some(108u32),
::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};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("{0} symbols to preserve in this crate",
symbols_below_threshold.len()) as &dyn Value))])
});
} else { ; }
};info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
109
110 if tcx.sess.lto() != Lto::ThinLocal {
113 for &cnum in each_linked_rlib_for_lto {
114 let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
115 symbols_below_threshold.extend(copy_symbols(cnum));
116 }
117 }
118
119 if export_threshold == SymbolExportLevel::Rust && allocator_kind_for_codegen(tcx).is_some() {
121 symbols_below_threshold.extend(allocator_shim_symbols(tcx).map(|(name, _kind)| name));
122 }
123
124 symbols_below_threshold
125}
126
127pub(super) fn check_lto_allowed<B: WriteBackendMethods>(cgcx: &CodegenContext<B>) {
128 if cgcx.lto == Lto::ThinLocal {
129 return;
131 }
132
133 let dcx = cgcx.create_dcx();
134
135 for crate_type in cgcx.crate_types.iter() {
137 if !crate_type_allows_lto(*crate_type) {
138 dcx.handle().emit_fatal(LtoDisallowed);
139 } else if *crate_type == CrateType::Dylib {
140 if !cgcx.opts.unstable_opts.dylib_lto {
141 dcx.handle().emit_fatal(LtoDylib);
142 }
143 } else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto {
144 dcx.handle().emit_fatal(LtoProcMacro);
145 }
146 }
147
148 if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
149 dcx.handle().emit_fatal(DynamicLinkingWithLTO);
150 }
151}