1
1
use back:: bytecode:: { DecodedBytecode , RLIB_BYTECODE_EXTENSION } ;
2
2
use rustc_codegen_ssa:: back:: symbol_export;
3
- use rustc_codegen_ssa:: back:: write:: { ModuleConfig , CodegenContext , pre_lto_bitcode_filename } ;
3
+ use rustc_codegen_ssa:: back:: write:: { ModuleConfig , CodegenContext , FatLTOInput } ;
4
4
use rustc_codegen_ssa:: back:: lto:: { SerializedModule , LtoModuleCodegen , ThinShared , ThinModule } ;
5
5
use rustc_codegen_ssa:: traits:: * ;
6
6
use back:: write:: { self , DiagnosticHandlers , with_llvm_pmb, save_temp_bitcode, to_llvm_opt_settings} ;
@@ -21,7 +21,6 @@ use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
21
21
use libc;
22
22
23
23
use std:: ffi:: { CStr , CString } ;
24
- use std:: fs;
25
24
use std:: ptr;
26
25
use std:: slice;
27
26
use std:: sync:: Arc ;
@@ -133,7 +132,8 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
133
132
/// Performs fat LTO by merging all modules into a single one and returning it
134
133
/// for further optimization.
135
134
pub ( crate ) fn run_fat ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
136
- modules : Vec < ModuleCodegen < ModuleLlvm > > ,
135
+ modules : Vec < FatLTOInput < LlvmCodegenBackend > > ,
136
+ cached_modules : Vec < ( SerializedModule < ModuleBuffer > , WorkProduct ) > ,
137
137
timeline : & mut Timeline )
138
138
-> Result < LtoModuleCodegen < LlvmCodegenBackend > , FatalError >
139
139
{
@@ -142,7 +142,15 @@ pub(crate) fn run_fat(cgcx: &CodegenContext<LlvmCodegenBackend>,
142
142
let symbol_white_list = symbol_white_list. iter ( )
143
143
. map ( |c| c. as_ptr ( ) )
144
144
. collect :: < Vec < _ > > ( ) ;
145
- fat_lto ( cgcx, & diag_handler, modules, upstream_modules, & symbol_white_list, timeline)
145
+ fat_lto (
146
+ cgcx,
147
+ & diag_handler,
148
+ modules,
149
+ cached_modules,
150
+ upstream_modules,
151
+ & symbol_white_list,
152
+ timeline,
153
+ )
146
154
}
147
155
148
156
/// Performs thin LTO by performing necessary global analysis and returning two
@@ -173,33 +181,17 @@ pub(crate) fn run_thin(cgcx: &CodegenContext<LlvmCodegenBackend>,
173
181
}
174
182
175
183
pub ( crate ) fn prepare_thin (
176
- cgcx : & CodegenContext < LlvmCodegenBackend > ,
177
184
module : ModuleCodegen < ModuleLlvm >
178
185
) -> ( String , ThinBuffer ) {
179
186
let name = module. name . clone ( ) ;
180
187
let buffer = ThinBuffer :: new ( module. module_llvm . llmod ( ) ) ;
181
-
182
- // We emit the module after having serialized it into a ThinBuffer
183
- // because only then it will contain the ThinLTO module summary.
184
- if let Some ( ref incr_comp_session_dir) = cgcx. incr_comp_session_dir {
185
- if cgcx. config ( module. kind ) . emit_pre_thin_lto_bc {
186
- let path = incr_comp_session_dir
187
- . join ( pre_lto_bitcode_filename ( & name) ) ;
188
-
189
- fs:: write ( & path, buffer. data ( ) ) . unwrap_or_else ( |e| {
190
- panic ! ( "Error writing pre-lto-bitcode file `{}`: {}" ,
191
- path. display( ) ,
192
- e) ;
193
- } ) ;
194
- }
195
- }
196
-
197
188
( name, buffer)
198
189
}
199
190
200
191
fn fat_lto ( cgcx : & CodegenContext < LlvmCodegenBackend > ,
201
192
diag_handler : & Handler ,
202
- mut modules : Vec < ModuleCodegen < ModuleLlvm > > ,
193
+ mut modules : Vec < FatLTOInput < LlvmCodegenBackend > > ,
194
+ cached_modules : Vec < ( SerializedModule < ModuleBuffer > , WorkProduct ) > ,
203
195
mut serialized_modules : Vec < ( SerializedModule < ModuleBuffer > , CString ) > ,
204
196
symbol_white_list : & [ * const libc:: c_char ] ,
205
197
timeline : & mut Timeline )
@@ -216,18 +208,53 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
216
208
// file copy operations in the backend work correctly. The only other kind
217
209
// of module here should be an allocator one, and if your crate is smaller
218
210
// than the allocator module then the size doesn't really matter anyway.
219
- let ( _ , costliest_module) = modules. iter ( )
211
+ let costliest_module = modules. iter ( )
220
212
. enumerate ( )
213
+ . filter_map ( |( i, module) | {
214
+ match module {
215
+ FatLTOInput :: InMemory ( m) => Some ( ( i, m) ) ,
216
+ FatLTOInput :: Serialized { .. } => None ,
217
+ }
218
+ } )
221
219
. filter ( |& ( _, module) | module. kind == ModuleKind :: Regular )
222
220
. map ( |( i, module) | {
223
221
let cost = unsafe {
224
222
llvm:: LLVMRustModuleCost ( module. module_llvm . llmod ( ) )
225
223
} ;
226
224
( cost, i)
227
225
} )
228
- . max ( )
229
- . expect ( "must be codegen'ing at least one module" ) ;
230
- let module = modules. remove ( costliest_module) ;
226
+ . max ( ) ;
227
+
228
+ // If we found a costliest module, we're good to go. Otherwise all our
229
+ // inputs were serialized which could happen in the case, for example, that
230
+ // all our inputs were incrementally reread from the cache and we're just
231
+ // re-executing the LTO passes. If that's the case deserialize the first
232
+ // module and create a linker with it.
233
+ let module: ModuleCodegen < ModuleLlvm > = match costliest_module {
234
+ Some ( ( _cost, i) ) => {
235
+ match modules. remove ( i) {
236
+ FatLTOInput :: InMemory ( m) => m,
237
+ FatLTOInput :: Serialized { .. } => unreachable ! ( ) ,
238
+ }
239
+ }
240
+ None => {
241
+ let pos = modules. iter ( ) . position ( |m| {
242
+ match m {
243
+ FatLTOInput :: InMemory ( _) => false ,
244
+ FatLTOInput :: Serialized { .. } => true ,
245
+ }
246
+ } ) . expect ( "must have at least one serialized module" ) ;
247
+ let ( name, buffer) = match modules. remove ( pos) {
248
+ FatLTOInput :: Serialized { name, buffer } => ( name, buffer) ,
249
+ FatLTOInput :: InMemory ( _) => unreachable ! ( ) ,
250
+ } ;
251
+ ModuleCodegen {
252
+ module_llvm : ModuleLlvm :: parse ( cgcx, & name, & buffer, diag_handler) ?,
253
+ name,
254
+ kind : ModuleKind :: Regular ,
255
+ }
256
+ }
257
+ } ;
231
258
let mut serialized_bitcode = Vec :: new ( ) ;
232
259
{
233
260
let ( llcx, llmod) = {
@@ -247,10 +274,20 @@ fn fat_lto(cgcx: &CodegenContext<LlvmCodegenBackend>,
247
274
// way we know of to do that is to serialize them to a string and them parse
248
275
// them later. Not great but hey, that's why it's "fat" LTO, right?
249
276
serialized_modules. extend ( modules. into_iter ( ) . map ( |module| {
250
- let buffer = ModuleBuffer :: new ( module. module_llvm . llmod ( ) ) ;
251
- let llmod_id = CString :: new ( & module. name [ ..] ) . unwrap ( ) ;
252
-
253
- ( SerializedModule :: Local ( buffer) , llmod_id)
277
+ match module {
278
+ FatLTOInput :: InMemory ( module) => {
279
+ let buffer = ModuleBuffer :: new ( module. module_llvm . llmod ( ) ) ;
280
+ let llmod_id = CString :: new ( & module. name [ ..] ) . unwrap ( ) ;
281
+ ( SerializedModule :: Local ( buffer) , llmod_id)
282
+ }
283
+ FatLTOInput :: Serialized { name, buffer } => {
284
+ let llmod_id = CString :: new ( name) . unwrap ( ) ;
285
+ ( SerializedModule :: Local ( buffer) , llmod_id)
286
+ }
287
+ }
288
+ } ) ) ;
289
+ serialized_modules. extend ( cached_modules. into_iter ( ) . map ( |( buffer, wp) | {
290
+ ( buffer, CString :: new ( wp. cgu_name . clone ( ) ) . unwrap ( ) )
254
291
} ) ) ;
255
292
256
293
// For all serialized bitcode files we parse them and link them in as we did
@@ -579,6 +616,16 @@ impl ModuleBuffer {
579
616
llvm:: LLVMRustModuleBufferCreate ( m)
580
617
} )
581
618
}
619
+
620
+ pub fn parse < ' a > (
621
+ & self ,
622
+ name : & str ,
623
+ cx : & ' a llvm:: Context ,
624
+ handler : & Handler ,
625
+ ) -> Result < & ' a llvm:: Module , FatalError > {
626
+ let name = CString :: new ( name) . unwrap ( ) ;
627
+ parse_module ( cx, & name, self . data ( ) , handler)
628
+ }
582
629
}
583
630
584
631
impl ModuleBufferMethods for ModuleBuffer {
@@ -658,15 +705,12 @@ pub unsafe fn optimize_thin_module(
658
705
// crates but for locally codegened modules we may be able to reuse
659
706
// that LLVM Context and Module.
660
707
let llcx = llvm:: LLVMRustContextCreate ( cgcx. fewer_names ) ;
661
- let llmod_raw = llvm :: LLVMRustParseBitcodeForThinLTO (
708
+ let llmod_raw = parse_module (
662
709
llcx,
663
- thin_module. data ( ) . as_ptr ( ) ,
664
- thin_module. data ( ) . len ( ) ,
665
- thin_module. shared . module_names [ thin_module. idx ] . as_ptr ( ) ,
666
- ) . ok_or_else ( || {
667
- let msg = "failed to parse bitcode for thin LTO module" ;
668
- write:: llvm_err ( & diag_handler, msg)
669
- } ) ? as * const _ ;
710
+ & thin_module. shared . module_names [ thin_module. idx ] ,
711
+ thin_module. data ( ) ,
712
+ & diag_handler,
713
+ ) ? as * const _ ;
670
714
let module = ModuleCodegen {
671
715
module_llvm : ModuleLlvm {
672
716
llmod_raw,
@@ -823,3 +867,22 @@ fn module_name_to_str(c_str: &CStr) -> &str {
823
867
c_str. to_str ( ) . unwrap_or_else ( |e|
824
868
bug ! ( "Encountered non-utf8 LLVM module name `{}`: {}" , c_str. to_string_lossy( ) , e) )
825
869
}
870
+
871
+ fn parse_module < ' a > (
872
+ cx : & ' a llvm:: Context ,
873
+ name : & CStr ,
874
+ data : & [ u8 ] ,
875
+ diag_handler : & Handler ,
876
+ ) -> Result < & ' a llvm:: Module , FatalError > {
877
+ unsafe {
878
+ llvm:: LLVMRustParseBitcodeForLTO (
879
+ cx,
880
+ data. as_ptr ( ) ,
881
+ data. len ( ) ,
882
+ name. as_ptr ( ) ,
883
+ ) . ok_or_else ( || {
884
+ let msg = "failed to parse bitcode for LTO module" ;
885
+ write:: llvm_err ( & diag_handler, msg)
886
+ } )
887
+ }
888
+ }
0 commit comments