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 } ;
@@ -544,6 +545,7 @@ pub(crate) unsafe fn llvm_optimize(
544
545
cgcx : & CodegenContext < LlvmCodegenBackend > ,
545
546
dcx : DiagCtxtHandle < ' _ > ,
546
547
module : & ModuleCodegen < ModuleLlvm > ,
548
+ thin_lto_buffer : Option < & mut * mut llvm:: ThinLTOBuffer > ,
547
549
config : & ModuleConfig ,
548
550
opt_level : config:: OptLevel ,
549
551
opt_stage : llvm:: OptStage ,
@@ -580,7 +582,17 @@ pub(crate) unsafe fn llvm_optimize(
580
582
vectorize_loop = config. vectorize_loop ;
581
583
}
582
584
trace ! ( ?unroll_loops, ?vectorize_slp, ?vectorize_loop, ?run_enzyme) ;
583
- let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
585
+ if thin_lto_buffer. is_some ( ) {
586
+ assert ! (
587
+ matches!(
588
+ opt_stage,
589
+ llvm:: OptStage :: PreLinkNoLTO
590
+ | llvm:: OptStage :: PreLinkFatLTO
591
+ | llvm:: OptStage :: PreLinkThinLTO
592
+ ) ,
593
+ "the bitcode for LTO can only be obtained at the pre-link stage"
594
+ ) ;
595
+ }
584
596
let pgo_gen_path = get_pgo_gen_path ( config) ;
585
597
let pgo_use_path = get_pgo_use_path ( config) ;
586
598
let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -640,7 +652,9 @@ pub(crate) unsafe fn llvm_optimize(
640
652
config. no_prepopulate_passes ,
641
653
config. verify_llvm_ir ,
642
654
config. lint_llvm_ir ,
643
- using_thin_buffers,
655
+ thin_lto_buffer,
656
+ config. emit_thin_lto ,
657
+ config. emit_thin_lto_summary ,
644
658
config. merge_functions ,
645
659
unroll_loops,
646
660
vectorize_slp,
@@ -705,9 +719,56 @@ pub(crate) unsafe fn optimize(
705
719
// usages, not just if we build rustc with autodiff support.
706
720
let autodiff_stage =
707
721
if cfg ! ( llvm_enzyme) { AutodiffStage :: PreAD } else { AutodiffStage :: PostAD } ;
708
- return unsafe {
709
- llvm_optimize ( cgcx, dcx, module, config, opt_level, opt_stage, autodiff_stage)
722
+ // The embedded bitcode is used to run LTO/ThinLTO.
723
+ // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.
724
+ // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at
725
+ // this point.
726
+ let mut thin_lto_buffer = if ( module. kind == ModuleKind :: Regular
727
+ && config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) )
728
+ || config. emit_thin_lto_summary
729
+ {
730
+ Some ( null_mut ( ) )
731
+ } else {
732
+ None
710
733
} ;
734
+ unsafe {
735
+ llvm_optimize (
736
+ cgcx,
737
+ dcx,
738
+ module,
739
+ thin_lto_buffer. as_mut ( ) ,
740
+ config,
741
+ opt_level,
742
+ opt_stage,
743
+ autodiff_stage,
744
+ )
745
+ } ?;
746
+ if let Some ( thin_lto_buffer) = thin_lto_buffer {
747
+ let thin_lto_buffer = unsafe { ThinBuffer :: from_raw_ptr ( thin_lto_buffer) } ;
748
+ let thin_bc_out = cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
749
+ if let Err ( err) = fs:: write ( & thin_bc_out, thin_lto_buffer. data ( ) ) {
750
+ dcx. emit_err ( WriteBytecode { path : & thin_bc_out, err } ) ;
751
+ }
752
+ let bc_summary_out =
753
+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
754
+ if config. emit_thin_lto_summary
755
+ && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
756
+ {
757
+ let summary_data = thin_lto_buffer. thin_link_data ( ) ;
758
+ cgcx. prof . artifact_size (
759
+ "llvm_bitcode_summary" ,
760
+ thin_link_bitcode_filename. to_string_lossy ( ) ,
761
+ summary_data. len ( ) as u64 ,
762
+ ) ;
763
+ let _timer = cgcx. prof . generic_activity_with_arg (
764
+ "LLVM_module_codegen_emit_bitcode_summary" ,
765
+ & * module. name ,
766
+ ) ;
767
+ if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
768
+ dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
769
+ }
770
+ }
771
+ }
711
772
}
712
773
Ok ( ( ) )
713
774
}
@@ -785,59 +846,47 @@ pub(crate) unsafe fn codegen(
785
846
// otherwise requested.
786
847
787
848
let bc_out = cgcx. output_filenames . temp_path ( OutputType :: Bitcode , module_name) ;
788
- let bc_summary_out =
789
- cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
790
849
let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
791
850
792
851
if config. bitcode_needed ( ) {
793
- let _timer = cgcx
794
- . prof
795
- . generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
796
- let thin = ThinBuffer :: new ( llmod, config. emit_thin_lto , config. emit_thin_lto_summary ) ;
797
- let data = thin. data ( ) ;
798
-
799
- if let Some ( bitcode_filename) = bc_out. file_name ( ) {
800
- cgcx. prof . artifact_size (
801
- "llvm_bitcode" ,
802
- bitcode_filename. to_string_lossy ( ) ,
803
- data. len ( ) as u64 ,
804
- ) ;
805
- }
806
-
807
- if config. emit_thin_lto_summary
808
- && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
809
- {
810
- let summary_data = thin. thin_link_data ( ) ;
811
- cgcx. prof . artifact_size (
812
- "llvm_bitcode_summary" ,
813
- thin_link_bitcode_filename. to_string_lossy ( ) ,
814
- summary_data. len ( ) as u64 ,
815
- ) ;
816
-
817
- let _timer = cgcx. prof . generic_activity_with_arg (
818
- "LLVM_module_codegen_emit_bitcode_summary" ,
819
- & * module. name ,
820
- ) ;
821
- if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
822
- dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
823
- }
824
- }
825
-
826
852
if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
853
+ let thin = {
854
+ let _timer = cgcx. prof . generic_activity_with_arg (
855
+ "LLVM_module_codegen_make_bitcode" ,
856
+ & * module. name ,
857
+ ) ;
858
+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
859
+ } ;
860
+ let data = thin. data ( ) ;
827
861
let _timer = cgcx
828
862
. prof
829
863
. generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
864
+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
865
+ cgcx. prof . artifact_size (
866
+ "llvm_bitcode" ,
867
+ bitcode_filename. to_string_lossy ( ) ,
868
+ data. len ( ) as u64 ,
869
+ ) ;
870
+ }
830
871
if let Err ( err) = fs:: write ( & bc_out, data) {
831
872
dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
832
873
}
833
874
}
834
875
835
- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
876
+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
877
+ && module. kind == ModuleKind :: Regular
878
+ {
836
879
let _timer = cgcx
837
880
. prof
838
881
. generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
882
+ let thin_bc_out =
883
+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
884
+ assert ! ( thin_bc_out. exists( ) , "cannot find {:?} as embedded bitcode" , thin_bc_out) ;
885
+ let data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
886
+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
887
+ ensure_removed ( dcx, & thin_bc_out) ;
839
888
unsafe {
840
- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
889
+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
841
890
}
842
891
}
843
892
}
0 commit comments