@@ -16,13 +16,14 @@ use errors::{FatalError, Handler};
16
16
use llvm:: archive_ro:: ArchiveRO ;
17
17
use llvm:: { True , False } ;
18
18
use llvm;
19
+ use memmap;
19
20
use rustc:: hir:: def_id:: LOCAL_CRATE ;
20
21
use rustc:: middle:: exported_symbols:: SymbolExportLevel ;
21
22
use rustc:: session:: config:: { self , Lto } ;
22
23
use rustc:: util:: common:: time_ext;
23
- use rustc_data_structures:: fx:: FxHashMap ;
24
+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
24
25
use time_graph:: Timeline ;
25
- use { ModuleCodegen , ModuleLlvm , ModuleKind , ModuleSource } ;
26
+ use { ModuleCodegen , ModuleLlvm , ModuleKind } ;
26
27
27
28
use libc;
28
29
@@ -82,8 +83,8 @@ impl LtoModuleCodegen {
82
83
let module = module. take ( ) . unwrap ( ) ;
83
84
{
84
85
let config = cgcx. config ( module. kind ) ;
85
- let llmod = module. llvm ( ) . unwrap ( ) . llmod ( ) ;
86
- let tm = & * module. llvm ( ) . unwrap ( ) . tm ;
86
+ let llmod = module. module_llvm . llmod ( ) ;
87
+ let tm = & * module. module_llvm . tm ;
87
88
run_pass_manager ( cgcx, tm, llmod, config, false ) ;
88
89
timeline. record ( "fat-done" ) ;
89
90
}
@@ -106,6 +107,7 @@ impl LtoModuleCodegen {
106
107
107
108
pub ( crate ) fn run ( cgcx : & CodegenContext ,
108
109
modules : Vec < ModuleCodegen > ,
110
+ import_only_modules : Vec < ( SerializedModule , CString ) > ,
109
111
timeline : & mut Timeline )
110
112
-> Result < Vec < LtoModuleCodegen > , FatalError >
111
113
{
@@ -194,19 +196,33 @@ pub(crate) fn run(cgcx: &CodegenContext,
194
196
}
195
197
}
196
198
197
- let arr = symbol_white_list. iter ( ) . map ( |c| c. as_ptr ( ) ) . collect :: < Vec < _ > > ( ) ;
199
+ let symbol_white_list = symbol_white_list. iter ( )
200
+ . map ( |c| c. as_ptr ( ) )
201
+ . collect :: < Vec < _ > > ( ) ;
198
202
match cgcx. lto {
199
203
Lto :: Yes | // `-C lto` == fat LTO by default
200
204
Lto :: Fat => {
201
- fat_lto ( cgcx, & diag_handler, modules, upstream_modules, & arr, timeline)
205
+ assert ! ( import_only_modules. is_empty( ) ) ;
206
+ fat_lto ( cgcx,
207
+ & diag_handler,
208
+ modules,
209
+ upstream_modules,
210
+ & symbol_white_list,
211
+ timeline)
202
212
}
203
213
Lto :: Thin |
204
214
Lto :: ThinLocal => {
205
215
if cgcx. opts . debugging_opts . cross_lang_lto . enabled ( ) {
206
216
unreachable ! ( "We should never reach this case if the LTO step \
207
217
is deferred to the linker") ;
208
218
}
209
- thin_lto ( cgcx, & diag_handler, modules, upstream_modules, & arr, timeline)
219
+ thin_lto ( cgcx,
220
+ & diag_handler,
221
+ modules,
222
+ upstream_modules,
223
+ import_only_modules,
224
+ & symbol_white_list,
225
+ timeline)
210
226
}
211
227
Lto :: No => unreachable ! ( ) ,
212
228
}
@@ -236,7 +252,7 @@ fn fat_lto(cgcx: &CodegenContext,
236
252
. filter ( |& ( _, module) | module. kind == ModuleKind :: Regular )
237
253
. map ( |( i, module) | {
238
254
let cost = unsafe {
239
- llvm:: LLVMRustModuleCost ( module. llvm ( ) . unwrap ( ) . llmod ( ) )
255
+ llvm:: LLVMRustModuleCost ( module. module_llvm . llmod ( ) )
240
256
} ;
241
257
( cost, i)
242
258
} )
@@ -246,7 +262,7 @@ fn fat_lto(cgcx: &CodegenContext,
246
262
let mut serialized_bitcode = Vec :: new ( ) ;
247
263
{
248
264
let ( llcx, llmod) = {
249
- let llvm = module. llvm ( ) . expect ( "can't lto pre-codegened modules" ) ;
265
+ let llvm = & module. module_llvm ;
250
266
( & llvm. llcx , llvm. llmod ( ) )
251
267
} ;
252
268
info ! ( "using {:?} as a base module" , module. name) ;
@@ -262,8 +278,7 @@ fn fat_lto(cgcx: &CodegenContext,
262
278
// way we know of to do that is to serialize them to a string and them parse
263
279
// them later. Not great but hey, that's why it's "fat" LTO, right?
264
280
for module in modules {
265
- let llvm = module. llvm ( ) . expect ( "can't lto pre-codegened modules" ) ;
266
- let buffer = ModuleBuffer :: new ( llvm. llmod ( ) ) ;
281
+ let buffer = ModuleBuffer :: new ( module. module_llvm . llmod ( ) ) ;
267
282
let llmod_id = CString :: new ( & module. name [ ..] ) . unwrap ( ) ;
268
283
serialized_modules. push ( ( SerializedModule :: Local ( buffer) , llmod_id) ) ;
269
284
}
@@ -373,6 +388,7 @@ fn thin_lto(cgcx: &CodegenContext,
373
388
diag_handler : & Handler ,
374
389
modules : Vec < ModuleCodegen > ,
375
390
serialized_modules : Vec < ( SerializedModule , CString ) > ,
391
+ import_only_modules : Vec < ( SerializedModule , CString ) > ,
376
392
symbol_white_list : & [ * const libc:: c_char ] ,
377
393
timeline : & mut Timeline )
378
394
-> Result < Vec < LtoModuleCodegen > , FatalError >
@@ -393,9 +409,8 @@ fn thin_lto(cgcx: &CodegenContext,
393
409
// analysis!
394
410
for ( i, module) in modules. iter ( ) . enumerate ( ) {
395
411
info ! ( "local module: {} - {}" , i, module. name) ;
396
- let llvm = module. llvm ( ) . expect ( "can't lto precodegened module" ) ;
397
412
let name = CString :: new ( module. name . clone ( ) ) . unwrap ( ) ;
398
- let buffer = ThinBuffer :: new ( llvm . llmod ( ) ) ;
413
+ let buffer = ThinBuffer :: new ( module . module_llvm . llmod ( ) ) ;
399
414
thin_modules. push ( llvm:: ThinLTOModule {
400
415
identifier : name. as_ptr ( ) ,
401
416
data : buffer. data ( ) . as_ptr ( ) ,
@@ -434,6 +449,22 @@ fn thin_lto(cgcx: &CodegenContext,
434
449
module_names. push ( name) ;
435
450
}
436
451
452
+ // All the modules collected up to this point we actually want to
453
+ // optimize. The `import_only_modules` below need to be in the list of
454
+ // available modules but we don't need to run optimizations for them
455
+ // since we already have their optimized version cached.
456
+ let modules_to_optimize = module_names. len ( ) ;
457
+ for ( module, name) in import_only_modules {
458
+ info ! ( "foreign module {:?}" , name) ;
459
+ thin_modules. push ( llvm:: ThinLTOModule {
460
+ identifier : name. as_ptr ( ) ,
461
+ data : module. data ( ) . as_ptr ( ) ,
462
+ len : module. data ( ) . len ( ) ,
463
+ } ) ;
464
+ serialized. push ( module) ;
465
+ module_names. push ( name) ;
466
+ }
467
+
437
468
// Delegate to the C++ bindings to create some data here. Once this is a
438
469
// tried-and-true interface we may wish to try to upstream some of this
439
470
// to LLVM itself, right now we reimplement a lot of what they do
@@ -450,7 +481,21 @@ fn thin_lto(cgcx: &CodegenContext,
450
481
// Save the ThinLTO import information for incremental compilation.
451
482
if let Some ( ref incr_comp_session_dir) = cgcx. incr_comp_session_dir {
452
483
let path = incr_comp_session_dir. join ( THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME ) ;
453
- let imports = ThinLTOImports :: from_thin_lto_data ( data) ;
484
+
485
+ // The import information from the current compilation session. It
486
+ // does not contain info about modules that have been loaded from
487
+ // the cache instead of having been recompiled...
488
+ let current_imports = ThinLTOImports :: from_thin_lto_data ( data) ;
489
+
490
+ // ... so we load this additional information from the previous
491
+ // cache file if necessary.
492
+ let imports = if path. exists ( ) {
493
+ let prev_imports = ThinLTOImports :: load_from_file ( & path) . unwrap ( ) ;
494
+ prev_imports. update ( current_imports, & module_names)
495
+ } else {
496
+ current_imports
497
+ } ;
498
+
454
499
if let Err ( err) = imports. save_to_file ( & path) {
455
500
let msg = format ! ( "Error while writing ThinLTO import data: {}" ,
456
501
err) ;
@@ -472,7 +517,7 @@ fn thin_lto(cgcx: &CodegenContext,
472
517
serialized_modules : serialized,
473
518
module_names,
474
519
} ) ;
475
- Ok ( ( 0 ..shared . module_names . len ( ) ) . map ( |i| {
520
+ Ok ( ( 0 ..modules_to_optimize ) . map ( |i| {
476
521
LtoModuleCodegen :: Thin ( ThinModule {
477
522
shared : shared. clone ( ) ,
478
523
idx : i,
@@ -546,13 +591,15 @@ fn run_pass_manager(cgcx: &CodegenContext,
546
591
pub enum SerializedModule {
547
592
Local ( ModuleBuffer ) ,
548
593
FromRlib ( Vec < u8 > ) ,
594
+ FromUncompressedFile ( memmap:: Mmap , File ) ,
549
595
}
550
596
551
597
impl SerializedModule {
552
598
fn data ( & self ) -> & [ u8 ] {
553
599
match * self {
554
600
SerializedModule :: Local ( ref m) => m. data ( ) ,
555
601
SerializedModule :: FromRlib ( ref m) => m,
602
+ SerializedModule :: FromUncompressedFile ( ref m, _) => m,
556
603
}
557
604
}
558
605
}
@@ -682,16 +729,16 @@ impl ThinModule {
682
729
write:: llvm_err ( & diag_handler, msg)
683
730
} ) ? as * const _ ;
684
731
let module = ModuleCodegen {
685
- source : ModuleSource :: Codegened ( ModuleLlvm {
732
+ module_llvm : ModuleLlvm {
686
733
llmod_raw,
687
734
llcx,
688
735
tm,
689
- } ) ,
736
+ } ,
690
737
name : self . name ( ) . to_string ( ) ,
691
738
kind : ModuleKind :: Regular ,
692
739
} ;
693
740
{
694
- let llmod = module. llvm ( ) . unwrap ( ) . llmod ( ) ;
741
+ let llmod = module. module_llvm . llmod ( ) ;
695
742
cgcx. save_temp_bitcode ( & module, "thin-lto-input" ) ;
696
743
697
744
// Before we do much else find the "main" `DICompileUnit` that we'll be
@@ -787,7 +834,7 @@ impl ThinModule {
787
834
// little differently.
788
835
info ! ( "running thin lto passes over {}" , module. name) ;
789
836
let config = cgcx. config ( module. kind ) ;
790
- run_pass_manager ( cgcx, module. llvm ( ) . unwrap ( ) . tm , llmod, config, true ) ;
837
+ run_pass_manager ( cgcx, module. module_llvm . tm , llmod, config, true ) ;
791
838
cgcx. save_temp_bitcode ( & module, "thin-lto-after-pm" ) ;
792
839
timeline. record ( "thin-done" ) ;
793
840
}
@@ -809,6 +856,26 @@ impl ThinLTOImports {
809
856
}
810
857
}
811
858
859
+ pub fn modules_imported_by ( & self , llvm_module_name : & str ) -> & [ String ] {
860
+ self . imports . get ( llvm_module_name) . map ( |v| & v[ ..] ) . unwrap_or ( & [ ] )
861
+ }
862
+
863
+ pub fn update ( mut self , new : ThinLTOImports , module_names : & [ CString ] ) -> ThinLTOImports {
864
+ let module_names: FxHashSet < _ > = module_names. iter ( ) . map ( |name| {
865
+ name. clone ( ) . into_string ( ) . unwrap ( )
866
+ } ) . collect ( ) ;
867
+
868
+ // Remove all modules that don't exist anymore.
869
+ self . imports . retain ( |k, _| module_names. contains ( k) ) ;
870
+
871
+ // Overwrite old values
872
+ for ( importing_module, imported_modules) in new. imports {
873
+ self . imports . insert ( importing_module, imported_modules) ;
874
+ }
875
+
876
+ self
877
+ }
878
+
812
879
/// Load the ThinLTO import map from ThinLTOData.
813
880
unsafe fn from_thin_lto_data ( data : * const llvm:: ThinLTOData ) -> ThinLTOImports {
814
881
fn module_name_to_str ( c_str : & CStr ) -> & str {
@@ -832,6 +899,7 @@ impl ThinLTOImports {
832
899
if !map. imports . contains_key ( importing_module_name) {
833
900
map. imports . insert ( importing_module_name. to_owned ( ) , vec ! [ ] ) ;
834
901
}
902
+
835
903
map. imports
836
904
. get_mut ( importing_module_name)
837
905
. unwrap ( )
@@ -888,4 +956,4 @@ impl ThinLTOImports {
888
956
imports
889
957
} )
890
958
}
891
- }
959
+ }
0 commit comments