@@ -20,16 +20,23 @@ use rustc::hir::def_id::LOCAL_CRATE;
20
20
use rustc:: middle:: exported_symbols:: SymbolExportLevel ;
21
21
use rustc:: session:: config:: { self , Lto } ;
22
22
use rustc:: util:: common:: time_ext;
23
+ use rustc_data_structures:: fx:: FxHashMap ;
23
24
use time_graph:: Timeline ;
24
25
use { ModuleCodegen , ModuleLlvm , ModuleKind , ModuleSource } ;
25
26
26
27
use libc;
27
28
28
- use std:: ffi:: CString ;
29
+ use std:: ffi:: { CStr , CString } ;
30
+ use std:: fs:: File ;
31
+ use std:: io;
32
+ use std:: mem;
33
+ use std:: path:: Path ;
29
34
use std:: ptr;
30
35
use std:: slice;
31
36
use std:: sync:: Arc ;
32
37
38
+ pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME : & str = "thin-lto-imports.bin" ;
39
+
33
40
pub fn crate_type_allows_lto ( crate_type : config:: CrateType ) -> bool {
34
41
match crate_type {
35
42
config:: CrateType :: Executable |
@@ -199,7 +206,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
199
206
unreachable ! ( "We should never reach this case if the LTO step \
200
207
is deferred to the linker") ;
201
208
}
202
- thin_lto ( & diag_handler, modules, upstream_modules, & arr, timeline)
209
+ thin_lto ( cgcx , & diag_handler, modules, upstream_modules, & arr, timeline)
203
210
}
204
211
Lto :: No => unreachable ! ( ) ,
205
212
}
@@ -362,7 +369,8 @@ impl Drop for Linker<'a> {
362
369
/// calculating the *index* for ThinLTO. This index will then be shared amongst
363
370
/// all of the `LtoModuleCodegen` units returned below and destroyed once
364
371
/// they all go out of scope.
365
- fn thin_lto ( diag_handler : & Handler ,
372
+ fn thin_lto ( cgcx : & CodegenContext ,
373
+ diag_handler : & Handler ,
366
374
modules : Vec < ModuleCodegen > ,
367
375
serialized_modules : Vec < ( SerializedModule , CString ) > ,
368
376
symbol_white_list : & [ * const libc:: c_char ] ,
@@ -439,6 +447,17 @@ fn thin_lto(diag_handler: &Handler,
439
447
write:: llvm_err ( & diag_handler, "failed to prepare thin LTO context" . to_string ( ) )
440
448
} ) ?;
441
449
450
+ // Save the ThinLTO import information for incremental compilation.
451
+ if let Some ( ref incr_comp_session_dir) = cgcx. incr_comp_session_dir {
452
+ let path = incr_comp_session_dir. join ( THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME ) ;
453
+ let imports = ThinLTOImports :: from_thin_lto_data ( data) ;
454
+ if let Err ( err) = imports. save_to_file ( & path) {
455
+ let msg = format ! ( "Error while writing ThinLTO import data: {}" ,
456
+ err) ;
457
+ return Err ( write:: llvm_err ( & diag_handler, msg) ) ;
458
+ }
459
+ }
460
+
442
461
let data = ThinData ( data) ;
443
462
info ! ( "thin LTO data created" ) ;
444
463
timeline. record ( "data" ) ;
@@ -776,3 +795,97 @@ impl ThinModule {
776
795
Ok ( module)
777
796
}
778
797
}
798
+
799
+ #[ derive( Debug ) ]
800
+ pub struct ThinLTOImports {
801
+ // key = llvm name of importing module, value = list of modules it imports from
802
+ imports : FxHashMap < String , Vec < String > > ,
803
+ }
804
+
805
+ impl ThinLTOImports {
806
+ pub fn new ( ) -> ThinLTOImports {
807
+ ThinLTOImports {
808
+ imports : FxHashMap ( ) ,
809
+ }
810
+ }
811
+
812
+ /// Load the ThinLTO import map from ThinLTOData.
813
+ unsafe fn from_thin_lto_data ( data : * const llvm:: ThinLTOData ) -> ThinLTOImports {
814
+ fn module_name_to_str ( c_str : & CStr ) -> & str {
815
+ match c_str. to_str ( ) {
816
+ Ok ( s) => s,
817
+ Err ( e) => {
818
+ bug ! ( "Encountered non-utf8 LLVM module name `{}`: {}" ,
819
+ c_str. to_string_lossy( ) ,
820
+ e)
821
+ }
822
+ }
823
+ }
824
+ unsafe extern "C" fn imported_module_callback ( payload : * mut libc:: c_void ,
825
+ importing_module_name : * const libc:: c_char ,
826
+ imported_module_name : * const libc:: c_char ) {
827
+ let map = & mut * ( payload as * mut ThinLTOImports ) ;
828
+ let importing_module_name = CStr :: from_ptr ( importing_module_name) ;
829
+ let importing_module_name = module_name_to_str ( & importing_module_name) ;
830
+ let imported_module_name = CStr :: from_ptr ( imported_module_name) ;
831
+ let imported_module_name = module_name_to_str ( & imported_module_name) ;
832
+ if !map. imports . contains_key ( importing_module_name) {
833
+ map. imports . insert ( importing_module_name. to_owned ( ) , vec ! [ ] ) ;
834
+ }
835
+ map. imports
836
+ . get_mut ( importing_module_name)
837
+ . unwrap ( )
838
+ . push ( imported_module_name. to_owned ( ) ) ;
839
+ }
840
+ let mut map = ThinLTOImports {
841
+ imports : FxHashMap ( ) ,
842
+ } ;
843
+ llvm:: LLVMRustGetThinLTOModuleImports ( data,
844
+ imported_module_callback,
845
+ & mut map as * mut _ as * mut libc:: c_void ) ;
846
+ map
847
+ }
848
+
849
+ pub fn save_to_file ( & self , path : & Path ) -> io:: Result < ( ) > {
850
+ use std:: io:: Write ;
851
+ let file = File :: create ( path) ?;
852
+ let mut writer = io:: BufWriter :: new ( file) ;
853
+ for ( importing_module_name, imported_modules) in & self . imports {
854
+ writeln ! ( writer, "{}" , importing_module_name) ?;
855
+ for imported_module in imported_modules {
856
+ writeln ! ( writer, " {}" , imported_module) ?;
857
+ }
858
+ writeln ! ( writer) ?;
859
+ }
860
+ Ok ( ( ) )
861
+ }
862
+
863
+ pub fn load_from_file ( path : & Path ) -> io:: Result < ThinLTOImports > {
864
+ use std:: io:: BufRead ;
865
+ let mut imports = FxHashMap ( ) ;
866
+ let mut current_module = None ;
867
+ let mut current_imports = vec ! [ ] ;
868
+ let file = File :: open ( path) ?;
869
+ for line in io:: BufReader :: new ( file) . lines ( ) {
870
+ let line = line?;
871
+ if line. is_empty ( ) {
872
+ let importing_module = current_module
873
+ . take ( )
874
+ . expect ( "Importing module not set" ) ;
875
+ imports. insert ( importing_module,
876
+ mem:: replace ( & mut current_imports, vec ! [ ] ) ) ;
877
+ } else if line. starts_with ( " " ) {
878
+ // This is an imported module
879
+ assert_ne ! ( current_module, None ) ;
880
+ current_imports. push ( line. trim ( ) . to_string ( ) ) ;
881
+ } else {
882
+ // This is the beginning of a new module
883
+ assert_eq ! ( current_module, None ) ;
884
+ current_module = Some ( line. trim ( ) . to_string ( ) ) ;
885
+ }
886
+ }
887
+ Ok ( ThinLTOImports {
888
+ imports
889
+ } )
890
+ }
891
+ }
0 commit comments