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
@@ -514,13 +515,24 @@ pub(crate) unsafe fn llvm_optimize(
514
515
cgcx : & CodegenContext < LlvmCodegenBackend > ,
515
516
dcx : DiagCtxtHandle < ' _ > ,
516
517
module : & ModuleCodegen < ModuleLlvm > ,
518
+ thin_lto_buffer : Option < & mut * mut ThinLTOBuffer > ,
517
519
config : & ModuleConfig ,
518
520
opt_level : config:: OptLevel ,
519
521
opt_stage : llvm:: OptStage ,
520
522
) -> Result < ( ) , FatalError > {
523
+ if thin_lto_buffer. is_some ( ) {
524
+ assert ! (
525
+ matches!(
526
+ opt_stage,
527
+ llvm:: OptStage :: PreLinkNoLTO
528
+ | llvm:: OptStage :: PreLinkFatLTO
529
+ | llvm:: OptStage :: PreLinkThinLTO
530
+ ) ,
531
+ "the bitcode for LTO can only be obtained at the pre-link stage"
532
+ ) ;
533
+ }
521
534
let unroll_loops =
522
535
opt_level != config:: OptLevel :: Size && opt_level != config:: OptLevel :: SizeMin ;
523
- let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
524
536
let pgo_gen_path = get_pgo_gen_path ( config) ;
525
537
let pgo_use_path = get_pgo_use_path ( config) ;
526
538
let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -580,7 +592,9 @@ pub(crate) unsafe fn llvm_optimize(
580
592
config. no_prepopulate_passes ,
581
593
config. verify_llvm_ir ,
582
594
config. lint_llvm_ir ,
583
- using_thin_buffers,
595
+ thin_lto_buffer,
596
+ config. emit_thin_lto ,
597
+ config. emit_thin_lto_summary ,
584
598
config. merge_functions ,
585
599
unroll_loops,
586
600
config. vectorize_slp ,
@@ -635,7 +649,47 @@ pub(crate) unsafe fn optimize(
635
649
_ if cgcx. opts . cg . linker_plugin_lto . enabled ( ) => llvm:: OptStage :: PreLinkThinLTO ,
636
650
_ => llvm:: OptStage :: PreLinkNoLTO ,
637
651
} ;
638
- return unsafe { llvm_optimize ( cgcx, dcx, module, config, opt_level, opt_stage) } ;
652
+ // The embedded bitcode is used to run LTO/ThinLTO.
653
+ // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.
654
+ // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at
655
+ // this point.
656
+ let mut thin_lto_buffer = if ( module. kind == ModuleKind :: Regular
657
+ && config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) )
658
+ || config. emit_thin_lto_summary
659
+ {
660
+ Some ( null_mut ( ) )
661
+ } else {
662
+ None
663
+ } ;
664
+ unsafe {
665
+ llvm_optimize ( cgcx, dcx, module, thin_lto_buffer. as_mut ( ) , config, opt_level, opt_stage)
666
+ } ?;
667
+ if let Some ( thin_lto_buffer) = thin_lto_buffer {
668
+ let thin_lto_buffer = unsafe { ThinBuffer :: from_raw_ptr ( thin_lto_buffer) } ;
669
+ let thin_bc_out = cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
670
+ if let Err ( err) = fs:: write ( & thin_bc_out, thin_lto_buffer. data ( ) ) {
671
+ dcx. emit_err ( WriteBytecode { path : & thin_bc_out, err } ) ;
672
+ }
673
+ let bc_summary_out =
674
+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
675
+ if config. emit_thin_lto_summary
676
+ && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
677
+ {
678
+ let summary_data = thin_lto_buffer. thin_link_data ( ) ;
679
+ cgcx. prof . artifact_size (
680
+ "llvm_bitcode_summary" ,
681
+ thin_link_bitcode_filename. to_string_lossy ( ) ,
682
+ summary_data. len ( ) as u64 ,
683
+ ) ;
684
+ let _timer = cgcx. prof . generic_activity_with_arg (
685
+ "LLVM_module_codegen_emit_bitcode_summary" ,
686
+ & * module. name ,
687
+ ) ;
688
+ if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
689
+ dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
690
+ }
691
+ }
692
+ }
639
693
}
640
694
Ok ( ( ) )
641
695
}
@@ -714,61 +768,49 @@ pub(crate) unsafe fn codegen(
714
768
// requested.
715
769
// - If we don't have the integrated assembler then we need to emit
716
770
// asm from LLVM and use `gcc` to create the object file.
717
-
718
771
let bc_out = cgcx. output_filenames . temp_path ( OutputType :: Bitcode , module_name) ;
719
- let bc_summary_out =
720
- cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
721
772
let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
722
773
723
774
if config. bitcode_needed ( ) {
724
- let _timer = cgcx
725
- . prof
726
- . generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
727
- let thin = ThinBuffer :: new ( llmod, config. emit_thin_lto , config. emit_thin_lto_summary ) ;
728
- let data = thin. data ( ) ;
729
-
730
- if let Some ( bitcode_filename) = bc_out. file_name ( ) {
731
- cgcx. prof . artifact_size (
732
- "llvm_bitcode" ,
733
- bitcode_filename. to_string_lossy ( ) ,
734
- data. len ( ) as u64 ,
735
- ) ;
736
- }
737
-
738
- if config. emit_thin_lto_summary
739
- && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
740
- {
741
- let summary_data = thin. thin_link_data ( ) ;
742
- cgcx. prof . artifact_size (
743
- "llvm_bitcode_summary" ,
744
- thin_link_bitcode_filename. to_string_lossy ( ) ,
745
- summary_data. len ( ) as u64 ,
746
- ) ;
747
-
748
- let _timer = cgcx. prof . generic_activity_with_arg (
749
- "LLVM_module_codegen_emit_bitcode_summary" ,
750
- & * module. name ,
751
- ) ;
752
- if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
753
- dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
754
- }
755
- }
756
-
775
+ // If the object file of the target spec is bitcode, what happens when performing LTO in Rust?
757
776
if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
777
+ let thin = {
778
+ let _timer = cgcx. prof . generic_activity_with_arg (
779
+ "LLVM_module_codegen_make_bitcode" ,
780
+ & * module. name ,
781
+ ) ;
782
+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
783
+ } ;
784
+ let data = thin. data ( ) ;
758
785
let _timer = cgcx
759
786
. prof
760
787
. generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
788
+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
789
+ cgcx. prof . artifact_size (
790
+ "llvm_bitcode" ,
791
+ bitcode_filename. to_string_lossy ( ) ,
792
+ data. len ( ) as u64 ,
793
+ ) ;
794
+ }
761
795
if let Err ( err) = fs:: write ( & bc_out, data) {
762
796
dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
763
797
}
764
798
}
765
799
766
- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
800
+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
801
+ && module. kind == ModuleKind :: Regular
802
+ {
767
803
let _timer = cgcx
768
804
. prof
769
805
. generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
806
+ let thin_bc_out =
807
+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
808
+ assert ! ( thin_bc_out. exists( ) , "cannot find {:?} as embedded bitcode" , thin_bc_out) ;
809
+ let data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
810
+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
811
+ ensure_removed ( dcx, & thin_bc_out) ;
770
812
unsafe {
771
- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
813
+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
772
814
}
773
815
}
774
816
}
0 commit comments