1
1
use std:: ffi:: { CStr , CString } ;
2
2
use std:: io:: { self , Write } ;
3
3
use std:: path:: { Path , PathBuf } ;
4
+ use std:: ptr:: null_mut;
4
5
use std:: sync:: Arc ;
5
6
use std:: { fs, slice, str} ;
6
7
@@ -15,7 +16,7 @@ use rustc_codegen_ssa::back::write::{
15
16
TargetMachineFactoryFn ,
16
17
} ;
17
18
use rustc_codegen_ssa:: traits:: * ;
18
- use rustc_codegen_ssa:: { CompiledModule , ModuleCodegen } ;
19
+ use rustc_codegen_ssa:: { CompiledModule , ModuleCodegen , ModuleKind } ;
19
20
use rustc_data_structures:: profiling:: SelfProfilerRef ;
20
21
use rustc_data_structures:: small_c_str:: SmallCStr ;
21
22
use rustc_errors:: { DiagCtxtHandle , FatalError , Level } ;
@@ -41,7 +42,7 @@ use crate::errors::{
41
42
WithLlvmError , WriteBytecode ,
42
43
} ;
43
44
use crate :: llvm:: diagnostic:: OptimizationDiagnosticKind :: * ;
44
- use crate :: llvm:: { self , DiagnosticInfo , PassManager } ;
45
+ use crate :: llvm:: { self , DiagnosticInfo , PassManager , ThinLTOBuffer } ;
45
46
use crate :: type_:: Type ;
46
47
use crate :: { LlvmCodegenBackend , ModuleLlvm , base, common, llvm_util} ;
47
48
@@ -516,13 +517,24 @@ pub(crate) unsafe fn llvm_optimize(
516
517
cgcx : & CodegenContext < LlvmCodegenBackend > ,
517
518
dcx : DiagCtxtHandle < ' _ > ,
518
519
module : & ModuleCodegen < ModuleLlvm > ,
520
+ thin_lto_buffer : Option < & mut * mut ThinLTOBuffer > ,
519
521
config : & ModuleConfig ,
520
522
opt_level : config:: OptLevel ,
521
523
opt_stage : llvm:: OptStage ,
522
524
) -> Result < ( ) , FatalError > {
525
+ if thin_lto_buffer. is_some ( ) {
526
+ assert ! (
527
+ matches!(
528
+ opt_stage,
529
+ llvm:: OptStage :: PreLinkNoLTO
530
+ | llvm:: OptStage :: PreLinkFatLTO
531
+ | llvm:: OptStage :: PreLinkThinLTO
532
+ ) ,
533
+ "the bitcode for LTO can only be obtained at the pre-link stage"
534
+ ) ;
535
+ }
523
536
let unroll_loops =
524
537
opt_level != config:: OptLevel :: Size && opt_level != config:: OptLevel :: SizeMin ;
525
- let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
526
538
let pgo_gen_path = get_pgo_gen_path ( config) ;
527
539
let pgo_use_path = get_pgo_use_path ( config) ;
528
540
let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -582,7 +594,9 @@ pub(crate) unsafe fn llvm_optimize(
582
594
config. no_prepopulate_passes ,
583
595
config. verify_llvm_ir ,
584
596
config. lint_llvm_ir ,
585
- using_thin_buffers,
597
+ thin_lto_buffer,
598
+ config. emit_thin_lto ,
599
+ config. emit_thin_lto_summary ,
586
600
config. merge_functions ,
587
601
unroll_loops,
588
602
config. vectorize_slp ,
@@ -637,7 +651,52 @@ pub(crate) unsafe fn optimize(
637
651
_ if cgcx. opts . cg . linker_plugin_lto . enabled ( ) => llvm:: OptStage :: PreLinkThinLTO ,
638
652
_ => llvm:: OptStage :: PreLinkNoLTO ,
639
653
} ;
640
- return unsafe { llvm_optimize ( cgcx, dcx, module, config, opt_level, opt_stage) } ;
654
+ // The embedded bitcode is used to run LTO/ThinLTO.
655
+ // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.
656
+ // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at
657
+ // this point.
658
+ let mut thin_lto_buffer = if ( module. kind == ModuleKind :: Regular
659
+ && config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) )
660
+ || config. emit_thin_lto_summary
661
+ {
662
+ Some ( null_mut ( ) )
663
+ } else {
664
+ None
665
+ } ;
666
+ unsafe {
667
+ llvm_optimize ( cgcx, dcx, module, thin_lto_buffer. as_mut ( ) , config, opt_level, opt_stage)
668
+ } ?;
669
+ if let Some ( thin_lto_buffer) = thin_lto_buffer {
670
+ let thin_lto_buffer = unsafe { ThinBuffer :: from_raw_ptr ( thin_lto_buffer) } ;
671
+ let thin_bc_out =
672
+ if let Some ( incr_comp_session_dir) = cgcx. incr_comp_session_dir . as_ref ( ) {
673
+ incr_comp_session_dir. join ( pre_lto_embed_bitcode_filename ( module_name. unwrap ( ) ) )
674
+ } else {
675
+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name)
676
+ } ;
677
+ if let Err ( err) = fs:: write ( & thin_bc_out, thin_lto_buffer. data ( ) ) {
678
+ dcx. emit_err ( WriteBytecode { path : & thin_bc_out, err } ) ;
679
+ }
680
+ let bc_summary_out =
681
+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
682
+ if config. emit_thin_lto_summary
683
+ && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
684
+ {
685
+ let summary_data = thin_lto_buffer. thin_link_data ( ) ;
686
+ cgcx. prof . artifact_size (
687
+ "llvm_bitcode_summary" ,
688
+ thin_link_bitcode_filename. to_string_lossy ( ) ,
689
+ summary_data. len ( ) as u64 ,
690
+ ) ;
691
+ let _timer = cgcx. prof . generic_activity_with_arg (
692
+ "LLVM_module_codegen_emit_bitcode_summary" ,
693
+ & * module. name ,
694
+ ) ;
695
+ if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
696
+ dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
697
+ }
698
+ }
699
+ }
641
700
}
642
701
Ok ( ( ) )
643
702
}
@@ -716,61 +775,60 @@ pub(crate) unsafe fn codegen(
716
775
// requested.
717
776
// - If we don't have the integrated assembler then we need to emit
718
777
// asm from LLVM and use `gcc` to create the object file.
719
-
720
778
let bc_out = cgcx. output_filenames . temp_path ( OutputType :: Bitcode , module_name) ;
721
- let bc_summary_out =
722
- cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
723
779
let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
724
780
725
781
if config. bitcode_needed ( ) {
726
- let _timer = cgcx
727
- . prof
728
- . generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
729
- let thin = ThinBuffer :: new ( llmod, config. emit_thin_lto , config. emit_thin_lto_summary ) ;
730
- let data = thin. data ( ) ;
731
-
732
- if let Some ( bitcode_filename) = bc_out. file_name ( ) {
733
- cgcx. prof . artifact_size (
734
- "llvm_bitcode" ,
735
- bitcode_filename. to_string_lossy ( ) ,
736
- data. len ( ) as u64 ,
737
- ) ;
738
- }
739
-
740
- if config. emit_thin_lto_summary
741
- && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
742
- {
743
- let summary_data = thin. thin_link_data ( ) ;
744
- cgcx. prof . artifact_size (
745
- "llvm_bitcode_summary" ,
746
- thin_link_bitcode_filename. to_string_lossy ( ) ,
747
- summary_data. len ( ) as u64 ,
748
- ) ;
749
-
750
- let _timer = cgcx. prof . generic_activity_with_arg (
751
- "LLVM_module_codegen_emit_bitcode_summary" ,
752
- & * module. name ,
753
- ) ;
754
- if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
755
- dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
756
- }
757
- }
758
-
782
+ // If the object file of the target spec is bitcode, what happens when performing LTO in Rust?
759
783
if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
784
+ let thin = {
785
+ let _timer = cgcx. prof . generic_activity_with_arg (
786
+ "LLVM_module_codegen_make_bitcode" ,
787
+ & * module. name ,
788
+ ) ;
789
+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
790
+ } ;
791
+ let data = thin. data ( ) ;
760
792
let _timer = cgcx
761
793
. prof
762
794
. generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
795
+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
796
+ cgcx. prof . artifact_size (
797
+ "llvm_bitcode" ,
798
+ bitcode_filename. to_string_lossy ( ) ,
799
+ data. len ( ) as u64 ,
800
+ ) ;
801
+ }
763
802
if let Err ( err) = fs:: write ( & bc_out, data) {
764
803
dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
765
804
}
766
805
}
767
806
768
- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
807
+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
808
+ && module. kind == ModuleKind :: Regular
809
+ {
769
810
let _timer = cgcx
770
811
. prof
771
812
. generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
813
+ let thin_bc_out = if let Some ( incr_comp_session_dir) =
814
+ cgcx. incr_comp_session_dir . as_ref ( )
815
+ {
816
+ incr_comp_session_dir. join ( pre_lto_embed_bitcode_filename ( module_name. unwrap ( ) ) )
817
+ } else {
818
+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name)
819
+ } ;
820
+ assert ! (
821
+ thin_bc_out. exists( ) ,
822
+ "cannot find {} as embedded bitcode" ,
823
+ thin_bc_out. display( )
824
+ ) ;
825
+ let data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
826
+ if cgcx. incr_comp_session_dir . is_none ( ) {
827
+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
828
+ ensure_removed ( dcx, & thin_bc_out) ;
829
+ }
772
830
unsafe {
773
- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
831
+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
774
832
}
775
833
}
776
834
}
@@ -1136,3 +1194,7 @@ fn record_llvm_cgu_instructions_stats(prof: &SelfProfilerRef, llmod: &llvm::Modu
1136
1194
serde_json:: from_str ( & raw_stats) . expect ( "cannot parse llvm cgu instructions stats" ) ;
1137
1195
prof. artifact_size ( "cgu_instructions" , module, total) ;
1138
1196
}
1197
+
1198
+ fn pre_lto_embed_bitcode_filename ( module_name : & str ) -> String {
1199
+ format ! ( "{module_name}.{}" , OutputType :: ThinBitcode . extension( ) )
1200
+ }
0 commit comments