rustc_codegen_ssa/back/
lto.rs

1use std::ffi::CString;
2use std::sync::Arc;
3
4use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
5use rustc_data_structures::memmap::Mmap;
6use rustc_errors::FatalError;
7
8use super::write::CodegenContext;
9use crate::ModuleCodegen;
10use crate::back::write::ModuleConfig;
11use crate::traits::*;
12
13pub struct ThinModule<B: WriteBackendMethods> {
14    pub shared: Arc<ThinShared<B>>,
15    pub idx: usize,
16}
17
18impl<B: WriteBackendMethods> ThinModule<B> {
19    pub fn name(&self) -> &str {
20        self.shared.module_names[self.idx].to_str().unwrap()
21    }
22
23    pub fn cost(&self) -> u64 {
24        // Yes, that's correct, we're using the size of the bytecode as an
25        // indicator for how costly this codegen unit is.
26        self.data().len() as u64
27    }
28
29    pub fn data(&self) -> &[u8] {
30        let a = self.shared.thin_buffers.get(self.idx).map(|b| b.data());
31        a.unwrap_or_else(|| {
32            let len = self.shared.thin_buffers.len();
33            self.shared.serialized_modules[self.idx - len].data()
34        })
35    }
36}
37
38pub struct ThinShared<B: WriteBackendMethods> {
39    pub data: B::ThinData,
40    pub thin_buffers: Vec<B::ThinBuffer>,
41    pub serialized_modules: Vec<SerializedModule<B::ModuleBuffer>>,
42    pub module_names: Vec<CString>,
43}
44
45pub enum LtoModuleCodegen<B: WriteBackendMethods> {
46    Fat(ModuleCodegen<B::Module>),
47    Thin(ThinModule<B>),
48}
49
50impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
51    pub fn name(&self) -> &str {
52        match *self {
53            LtoModuleCodegen::Fat(_) => "everything",
54            LtoModuleCodegen::Thin(ref m) => m.name(),
55        }
56    }
57
58    /// Optimize this module within the given codegen context.
59    ///
60    /// This function is unsafe as it'll return a `ModuleCodegen` still
61    /// points to LLVM data structures owned by this `LtoModuleCodegen`.
62    /// It's intended that the module returned is immediately code generated and
63    /// dropped, and then this LTO module is dropped.
64    pub unsafe fn optimize(
65        self,
66        cgcx: &CodegenContext<B>,
67    ) -> Result<ModuleCodegen<B::Module>, FatalError> {
68        match self {
69            LtoModuleCodegen::Fat(mut module) => {
70                B::optimize_fat(cgcx, &mut module)?;
71                Ok(module)
72            }
73            LtoModuleCodegen::Thin(thin) => unsafe { B::optimize_thin(cgcx, thin) },
74        }
75    }
76
77    /// A "gauge" of how costly it is to optimize this module, used to sort
78    /// biggest modules first.
79    pub fn cost(&self) -> u64 {
80        match *self {
81            // Only one module with fat LTO, so the cost doesn't matter.
82            LtoModuleCodegen::Fat(_) => 0,
83            LtoModuleCodegen::Thin(ref m) => m.cost(),
84        }
85    }
86
87    /// Run autodiff on Fat LTO module
88    pub unsafe fn autodiff(
89        self,
90        cgcx: &CodegenContext<B>,
91        diff_fncs: Vec<AutoDiffItem>,
92        config: &ModuleConfig,
93    ) -> Result<LtoModuleCodegen<B>, FatalError> {
94        match &self {
95            LtoModuleCodegen::Fat(module) => {
96                B::autodiff(cgcx, &module, diff_fncs, config)?;
97            }
98            _ => panic!("autodiff called with non-fat LTO module"),
99        }
100
101        Ok(self)
102    }
103}
104
105pub enum SerializedModule<M: ModuleBufferMethods> {
106    Local(M),
107    FromRlib(Vec<u8>),
108    FromUncompressedFile(Mmap),
109}
110
111impl<M: ModuleBufferMethods> SerializedModule<M> {
112    pub fn data(&self) -> &[u8] {
113        match *self {
114            SerializedModule::Local(ref m) => m.data(),
115            SerializedModule::FromRlib(ref m) => m,
116            SerializedModule::FromUncompressedFile(ref m) => m,
117        }
118    }
119}