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, symbol_name_for_instance_in_crate};
12use crate::back::write::CodegenContext;
13use crate::errors::{DynamicLinkingWithLTO, LtoDisallowed, LtoDylib, LtoProcMacro};
14use crate::traits::*;
15
16pub struct ThinModule<B: WriteBackendMethods> {
17 pub shared: Arc<ThinShared<B>>,
18 pub idx: usize,
19}
20
21impl<B: WriteBackendMethods> ThinModule<B> {
22 pub fn name(&self) -> &str {
23 self.shared.module_names[self.idx].to_str().unwrap()
24 }
25
26 pub fn cost(&self) -> u64 {
27 self.data().len() as u64
30 }
31
32 pub fn data(&self) -> &[u8] {
33 let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
34 a.unwrap_or_else(|| {
35 let len = self.shared.thin_buffers.len();
36 self.shared.serialized_modules[self.idx - len].data()
37 })
38 }
39}
40
41pub struct ThinShared<B: WriteBackendMethods> {
42 pub data: B::ThinData,
43 pub thin_buffers: Vec<B::ThinBuffer>,
44 pub serialized_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 data(&self) -> &[u8] {
56 match *self {
57 SerializedModule::Local(ref m) => m.data(),
58 SerializedModule::FromRlib(ref m) => m,
59 SerializedModule::FromUncompressedFile(ref m) => m,
60 }
61 }
62}
63
64fn crate_type_allows_lto(crate_type: CrateType) -> bool {
65 match crate_type {
66 CrateType::Executable
67 | CrateType::Dylib
68 | CrateType::Staticlib
69 | CrateType::Cdylib
70 | CrateType::ProcMacro
71 | CrateType::Sdylib => true,
72 CrateType::Rlib => false,
73 }
74}
75
76pub(super) fn exported_symbols_for_lto(
77 tcx: TyCtxt<'_>,
78 each_linked_rlib_for_lto: &[CrateNum],
79) -> Vec<String> {
80 let export_threshold = match tcx.sess.lto() {
81 Lto::ThinLocal => SymbolExportLevel::Rust,
83
84 Lto::Fat | Lto::Thin => symbol_export::crates_export_threshold(&tcx.crate_types()),
86
87 Lto::No => return vec![],
88 };
89
90 let copy_symbols = |cnum| {
91 tcx.exported_non_generic_symbols(cnum)
92 .iter()
93 .chain(tcx.exported_generic_symbols(cnum))
94 .filter_map(|&(s, info): &(ExportedSymbol<'_>, SymbolExportInfo)| {
95 if info.level.is_below_threshold(export_threshold) || info.used {
96 Some(symbol_name_for_instance_in_crate(tcx, s, cnum))
97 } else {
98 None
99 }
100 })
101 .collect::<Vec<_>>()
102 };
103 let mut symbols_below_threshold = {
104 let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
105 copy_symbols(LOCAL_CRATE)
106 };
107 info!("{} symbols to preserve in this crate", symbols_below_threshold.len());
108
109 if tcx.sess.lto() != Lto::ThinLocal {
112 for &cnum in each_linked_rlib_for_lto {
113 let _timer = tcx.prof.generic_activity("lto_generate_symbols_below_threshold");
114 symbols_below_threshold.extend(copy_symbols(cnum));
115 }
116 }
117
118 symbols_below_threshold
119}
120
121pub(super) fn check_lto_allowed<B: WriteBackendMethods>(cgcx: &CodegenContext<B>) {
122 if cgcx.lto == Lto::ThinLocal {
123 return;
125 }
126
127 let dcx = cgcx.create_dcx();
128
129 for crate_type in cgcx.crate_types.iter() {
131 if !crate_type_allows_lto(*crate_type) {
132 dcx.handle().emit_fatal(LtoDisallowed);
133 } else if *crate_type == CrateType::Dylib {
134 if !cgcx.opts.unstable_opts.dylib_lto {
135 dcx.handle().emit_fatal(LtoDylib);
136 }
137 } else if *crate_type == CrateType::ProcMacro && !cgcx.opts.unstable_opts.dylib_lto {
138 dcx.handle().emit_fatal(LtoProcMacro);
139 }
140 }
141
142 if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
143 dcx.handle().emit_fatal(DynamicLinkingWithLTO);
144 }
145}