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,
@@ -675,7 +689,7 @@ pub(crate) unsafe fn llvm_optimize(
675689pub ( crate ) unsafe fn optimize (
676690 cgcx : & CodegenContext < LlvmCodegenBackend > ,
677691 dcx : DiagCtxtHandle < ' _ > ,
678- module : & ModuleCodegen < ModuleLlvm > ,
692+ module : & mut ModuleCodegen < ModuleLlvm > ,
679693 config : & ModuleConfig ,
680694) -> Result < ( ) , FatalError > {
681695 let _timer = cgcx. prof . generic_activity_with_arg ( "LLVM_module_optimize" , & * module. name ) ;
@@ -705,9 +719,53 @@ 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+ module. thin_lto_buffer = Some ( thin_lto_buffer. data ( ) . to_vec ( ) ) ;
749+ let bc_summary_out =
750+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
751+ if config. emit_thin_lto_summary
752+ && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
753+ {
754+ let summary_data = thin_lto_buffer. thin_link_data ( ) ;
755+ cgcx. prof . artifact_size (
756+ "llvm_bitcode_summary" ,
757+ thin_link_bitcode_filename. to_string_lossy ( ) ,
758+ summary_data. len ( ) as u64 ,
759+ ) ;
760+ let _timer = cgcx. prof . generic_activity_with_arg (
761+ "LLVM_module_codegen_emit_bitcode_summary" ,
762+ & * module. name ,
763+ ) ;
764+ if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
765+ dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
766+ }
767+ }
768+ }
711769 }
712770 Ok ( ( ) )
713771}
@@ -760,59 +818,41 @@ pub(crate) unsafe fn codegen(
760818 // otherwise requested.
761819
762820 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) ;
765821 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
766822
767823 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-
801824 if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
825+ let thin = {
826+ let _timer = cgcx. prof . generic_activity_with_arg (
827+ "LLVM_module_codegen_make_bitcode" ,
828+ & * module. name ,
829+ ) ;
830+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
831+ } ;
832+ let data = thin. data ( ) ;
802833 let _timer = cgcx
803834 . prof
804835 . generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
836+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
837+ cgcx. prof . artifact_size (
838+ "llvm_bitcode" ,
839+ bitcode_filename. to_string_lossy ( ) ,
840+ data. len ( ) as u64 ,
841+ ) ;
842+ }
805843 if let Err ( err) = fs:: write ( & bc_out, data) {
806844 dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
807845 }
808846 }
809847
810- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
848+ if config. embed_bitcode ( ) && module . kind == ModuleKind :: Regular {
811849 let _timer = cgcx
812850 . prof
813851 . generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
852+ let thin_bc =
853+ module. thin_lto_buffer . as_deref ( ) . expect ( "cannot find embedded bitcode" ) ;
814854 unsafe {
815- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data ) ;
855+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & thin_bc ) ;
816856 }
817857 }
818858 }
0 commit comments