11use std:: ffi:: { CStr , CString } ;
22use std:: io:: { self , Write } ;
33use std:: path:: { Path , PathBuf } ;
4+ use std:: ptr:: null_mut;
45use std:: sync:: Arc ;
56use std:: { fs, slice, str} ;
67
@@ -15,7 +16,7 @@ use rustc_codegen_ssa::back::write::{
1516 TargetMachineFactoryFn ,
1617} ;
1718use rustc_codegen_ssa:: traits:: * ;
18- use rustc_codegen_ssa:: { CompiledModule , ModuleCodegen } ;
19+ use rustc_codegen_ssa:: { CompiledModule , ModuleCodegen , ModuleKind } ;
1920use rustc_data_structures:: profiling:: SelfProfilerRef ;
2021use rustc_data_structures:: small_c_str:: SmallCStr ;
2122use rustc_errors:: { DiagCtxtHandle , FatalError , Level } ;
@@ -551,6 +552,7 @@ pub(crate) unsafe fn llvm_optimize(
551552 cgcx : & CodegenContext < LlvmCodegenBackend > ,
552553 dcx : DiagCtxtHandle < ' _ > ,
553554 module : & ModuleCodegen < ModuleLlvm > ,
555+ thin_lto_buffer : Option < & mut * mut llvm:: ThinLTOBuffer > ,
554556 config : & ModuleConfig ,
555557 opt_level : config:: OptLevel ,
556558 opt_stage : llvm:: OptStage ,
@@ -584,7 +586,17 @@ pub(crate) unsafe fn llvm_optimize(
584586 vectorize_loop = config. vectorize_loop ;
585587 }
586588 trace ! ( ?unroll_loops, ?vectorize_slp, ?vectorize_loop, ?run_enzyme) ;
587- let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
589+ if thin_lto_buffer. is_some ( ) {
590+ assert ! (
591+ matches!(
592+ opt_stage,
593+ llvm:: OptStage :: PreLinkNoLTO
594+ | llvm:: OptStage :: PreLinkFatLTO
595+ | llvm:: OptStage :: PreLinkThinLTO
596+ ) ,
597+ "the bitcode for LTO can only be obtained at the pre-link stage"
598+ ) ;
599+ }
588600 let pgo_gen_path = get_pgo_gen_path ( config) ;
589601 let pgo_use_path = get_pgo_use_path ( config) ;
590602 let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -644,7 +656,9 @@ pub(crate) unsafe fn llvm_optimize(
644656 config. no_prepopulate_passes ,
645657 config. verify_llvm_ir ,
646658 config. lint_llvm_ir ,
647- using_thin_buffers,
659+ thin_lto_buffer,
660+ config. emit_thin_lto ,
661+ config. emit_thin_lto_summary ,
648662 config. merge_functions ,
649663 unroll_loops,
650664 vectorize_slp,
@@ -705,9 +719,56 @@ pub(crate) unsafe fn optimize(
705719 // Otherwise we pretend AD is already done and run the normal opt pipeline (=PostAD).
706720 let consider_ad = cfg ! ( llvm_enzyme) && config. autodiff . contains ( & config:: AutoDiff :: Enable ) ;
707721 let autodiff_stage = if consider_ad { 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
710733 } ;
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+ }
711772 }
712773 Ok ( ( ) )
713774}
@@ -760,59 +821,47 @@ pub(crate) unsafe fn codegen(
760821 // otherwise requested.
761822
762823 let bc_out = cgcx. output_filenames . temp_path ( OutputType :: Bitcode , module_name) ;
763- let bc_summary_out =
764- cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
765824 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
766825
767826 if config. bitcode_needed ( ) {
768- let _timer = cgcx
769- . prof
770- . generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
771- let thin = ThinBuffer :: new ( llmod, config. emit_thin_lto , config. emit_thin_lto_summary ) ;
772- let data = thin. data ( ) ;
773-
774- if let Some ( bitcode_filename) = bc_out. file_name ( ) {
775- cgcx. prof . artifact_size (
776- "llvm_bitcode" ,
777- bitcode_filename. to_string_lossy ( ) ,
778- data. len ( ) as u64 ,
779- ) ;
780- }
781-
782- if config. emit_thin_lto_summary
783- && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
784- {
785- let summary_data = thin. thin_link_data ( ) ;
786- cgcx. prof . artifact_size (
787- "llvm_bitcode_summary" ,
788- thin_link_bitcode_filename. to_string_lossy ( ) ,
789- summary_data. len ( ) as u64 ,
790- ) ;
791-
792- let _timer = cgcx. prof . generic_activity_with_arg (
793- "LLVM_module_codegen_emit_bitcode_summary" ,
794- & * module. name ,
795- ) ;
796- if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
797- dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
798- }
799- }
800-
801827 if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
828+ let thin = {
829+ let _timer = cgcx. prof . generic_activity_with_arg (
830+ "LLVM_module_codegen_make_bitcode" ,
831+ & * module. name ,
832+ ) ;
833+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
834+ } ;
835+ let data = thin. data ( ) ;
802836 let _timer = cgcx
803837 . prof
804838 . generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
839+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
840+ cgcx. prof . artifact_size (
841+ "llvm_bitcode" ,
842+ bitcode_filename. to_string_lossy ( ) ,
843+ data. len ( ) as u64 ,
844+ ) ;
845+ }
805846 if let Err ( err) = fs:: write ( & bc_out, data) {
806847 dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
807848 }
808849 }
809850
810- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
851+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
852+ && module. kind == ModuleKind :: Regular
853+ {
811854 let _timer = cgcx
812855 . prof
813856 . generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
857+ let thin_bc_out =
858+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
859+ assert ! ( thin_bc_out. exists( ) , "cannot find {:?} as embedded bitcode" , thin_bc_out) ;
860+ let data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
861+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
862+ ensure_removed ( dcx, & thin_bc_out) ;
814863 unsafe {
815- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
864+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
816865 }
817866 }
818867 }
0 commit comments