@@ -16,13 +16,14 @@ use errors::{FatalError, Handler};
1616use llvm:: archive_ro:: ArchiveRO ;
1717use llvm:: { True , False } ;
1818use llvm;
19+ use memmap;
1920use rustc:: hir:: def_id:: LOCAL_CRATE ;
2021use rustc:: middle:: exported_symbols:: SymbolExportLevel ;
2122use rustc:: session:: config:: { self , Lto } ;
2223use rustc:: util:: common:: time_ext;
23- use rustc_data_structures:: fx:: FxHashMap ;
24+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
2425use time_graph:: Timeline ;
25- use { ModuleCodegen , ModuleLlvm , ModuleKind , ModuleSource } ;
26+ use { ModuleCodegen , ModuleLlvm , ModuleKind } ;
2627
2728use libc;
2829
@@ -82,8 +83,8 @@ impl LtoModuleCodegen {
8283 let module = module. take ( ) . unwrap ( ) ;
8384 {
8485 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 ;
8788 run_pass_manager ( cgcx, tm, llmod, config, false ) ;
8889 timeline. record ( "fat-done" ) ;
8990 }
@@ -106,6 +107,7 @@ impl LtoModuleCodegen {
106107
107108pub ( crate ) fn run ( cgcx : & CodegenContext ,
108109 modules : Vec < ModuleCodegen > ,
110+ import_only_modules : Vec < ( SerializedModule , CString ) > ,
109111 timeline : & mut Timeline )
110112 -> Result < Vec < LtoModuleCodegen > , FatalError >
111113{
@@ -194,19 +196,33 @@ pub(crate) fn run(cgcx: &CodegenContext,
194196 }
195197 }
196198
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 < _ > > ( ) ;
198202 match cgcx. lto {
199203 Lto :: Yes | // `-C lto` == fat LTO by default
200204 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)
202212 }
203213 Lto :: Thin |
204214 Lto :: ThinLocal => {
205215 if cgcx. opts . debugging_opts . cross_lang_lto . enabled ( ) {
206216 unreachable ! ( "We should never reach this case if the LTO step \
207217 is deferred to the linker") ;
208218 }
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)
210226 }
211227 Lto :: No => unreachable ! ( ) ,
212228 }
@@ -236,7 +252,7 @@ fn fat_lto(cgcx: &CodegenContext,
236252 . filter ( |& ( _, module) | module. kind == ModuleKind :: Regular )
237253 . map ( |( i, module) | {
238254 let cost = unsafe {
239- llvm:: LLVMRustModuleCost ( module. llvm ( ) . unwrap ( ) . llmod ( ) )
255+ llvm:: LLVMRustModuleCost ( module. module_llvm . llmod ( ) )
240256 } ;
241257 ( cost, i)
242258 } )
@@ -246,7 +262,7 @@ fn fat_lto(cgcx: &CodegenContext,
246262 let mut serialized_bitcode = Vec :: new ( ) ;
247263 {
248264 let ( llcx, llmod) = {
249- let llvm = module. llvm ( ) . expect ( "can't lto pre-codegened modules" ) ;
265+ let llvm = & module. module_llvm ;
250266 ( & llvm. llcx , llvm. llmod ( ) )
251267 } ;
252268 info ! ( "using {:?} as a base module" , module. name) ;
@@ -262,8 +278,7 @@ fn fat_lto(cgcx: &CodegenContext,
262278 // way we know of to do that is to serialize them to a string and them parse
263279 // them later. Not great but hey, that's why it's "fat" LTO, right?
264280 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 ( ) ) ;
267282 let llmod_id = CString :: new ( & module. name [ ..] ) . unwrap ( ) ;
268283 serialized_modules. push ( ( SerializedModule :: Local ( buffer) , llmod_id) ) ;
269284 }
@@ -373,6 +388,7 @@ fn thin_lto(cgcx: &CodegenContext,
373388 diag_handler : & Handler ,
374389 modules : Vec < ModuleCodegen > ,
375390 serialized_modules : Vec < ( SerializedModule , CString ) > ,
391+ import_only_modules : Vec < ( SerializedModule , CString ) > ,
376392 symbol_white_list : & [ * const libc:: c_char ] ,
377393 timeline : & mut Timeline )
378394 -> Result < Vec < LtoModuleCodegen > , FatalError >
@@ -393,9 +409,8 @@ fn thin_lto(cgcx: &CodegenContext,
393409 // analysis!
394410 for ( i, module) in modules. iter ( ) . enumerate ( ) {
395411 info ! ( "local module: {} - {}" , i, module. name) ;
396- let llvm = module. llvm ( ) . expect ( "can't lto precodegened module" ) ;
397412 let name = CString :: new ( module. name . clone ( ) ) . unwrap ( ) ;
398- let buffer = ThinBuffer :: new ( llvm . llmod ( ) ) ;
413+ let buffer = ThinBuffer :: new ( module . module_llvm . llmod ( ) ) ;
399414 thin_modules. push ( llvm:: ThinLTOModule {
400415 identifier : name. as_ptr ( ) ,
401416 data : buffer. data ( ) . as_ptr ( ) ,
@@ -434,6 +449,22 @@ fn thin_lto(cgcx: &CodegenContext,
434449 module_names. push ( name) ;
435450 }
436451
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+
437468 // Delegate to the C++ bindings to create some data here. Once this is a
438469 // tried-and-true interface we may wish to try to upstream some of this
439470 // to LLVM itself, right now we reimplement a lot of what they do
@@ -450,7 +481,21 @@ fn thin_lto(cgcx: &CodegenContext,
450481 // Save the ThinLTO import information for incremental compilation.
451482 if let Some ( ref incr_comp_session_dir) = cgcx. incr_comp_session_dir {
452483 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+
454499 if let Err ( err) = imports. save_to_file ( & path) {
455500 let msg = format ! ( "Error while writing ThinLTO import data: {}" ,
456501 err) ;
@@ -472,7 +517,7 @@ fn thin_lto(cgcx: &CodegenContext,
472517 serialized_modules : serialized,
473518 module_names,
474519 } ) ;
475- Ok ( ( 0 ..shared . module_names . len ( ) ) . map ( |i| {
520+ Ok ( ( 0 ..modules_to_optimize ) . map ( |i| {
476521 LtoModuleCodegen :: Thin ( ThinModule {
477522 shared : shared. clone ( ) ,
478523 idx : i,
@@ -546,13 +591,15 @@ fn run_pass_manager(cgcx: &CodegenContext,
546591pub enum SerializedModule {
547592 Local ( ModuleBuffer ) ,
548593 FromRlib ( Vec < u8 > ) ,
594+ FromUncompressedFile ( memmap:: Mmap , File ) ,
549595}
550596
551597impl SerializedModule {
552598 fn data ( & self ) -> & [ u8 ] {
553599 match * self {
554600 SerializedModule :: Local ( ref m) => m. data ( ) ,
555601 SerializedModule :: FromRlib ( ref m) => m,
602+ SerializedModule :: FromUncompressedFile ( ref m, _) => m,
556603 }
557604 }
558605}
@@ -682,16 +729,16 @@ impl ThinModule {
682729 write:: llvm_err ( & diag_handler, msg)
683730 } ) ? as * const _ ;
684731 let module = ModuleCodegen {
685- source : ModuleSource :: Codegened ( ModuleLlvm {
732+ module_llvm : ModuleLlvm {
686733 llmod_raw,
687734 llcx,
688735 tm,
689- } ) ,
736+ } ,
690737 name : self . name ( ) . to_string ( ) ,
691738 kind : ModuleKind :: Regular ,
692739 } ;
693740 {
694- let llmod = module. llvm ( ) . unwrap ( ) . llmod ( ) ;
741+ let llmod = module. module_llvm . llmod ( ) ;
695742 cgcx. save_temp_bitcode ( & module, "thin-lto-input" ) ;
696743
697744 // Before we do much else find the "main" `DICompileUnit` that we'll be
@@ -787,7 +834,7 @@ impl ThinModule {
787834 // little differently.
788835 info ! ( "running thin lto passes over {}" , module. name) ;
789836 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 ) ;
791838 cgcx. save_temp_bitcode ( & module, "thin-lto-after-pm" ) ;
792839 timeline. record ( "thin-done" ) ;
793840 }
@@ -809,6 +856,26 @@ impl ThinLTOImports {
809856 }
810857 }
811858
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+
812879 /// Load the ThinLTO import map from ThinLTOData.
813880 unsafe fn from_thin_lto_data ( data : * const llvm:: ThinLTOData ) -> ThinLTOImports {
814881 fn module_name_to_str ( c_str : & CStr ) -> & str {
@@ -832,6 +899,7 @@ impl ThinLTOImports {
832899 if !map. imports . contains_key ( importing_module_name) {
833900 map. imports . insert ( importing_module_name. to_owned ( ) , vec ! [ ] ) ;
834901 }
902+
835903 map. imports
836904 . get_mut ( importing_module_name)
837905 . unwrap ( )
@@ -888,4 +956,4 @@ impl ThinLTOImports {
888956 imports
889957 } )
890958 }
891- }
959+ }
0 commit comments