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 } ;
@@ -544,6 +545,7 @@ pub(crate) unsafe fn llvm_optimize(
544545 cgcx : & CodegenContext < LlvmCodegenBackend > ,
545546 dcx : DiagCtxtHandle < ' _ > ,
546547 module : & ModuleCodegen < ModuleLlvm > ,
548+ thin_lto_buffer : Option < & mut * mut llvm:: ThinLTOBuffer > ,
547549 config : & ModuleConfig ,
548550 opt_level : config:: OptLevel ,
549551 opt_stage : llvm:: OptStage ,
@@ -580,7 +582,17 @@ pub(crate) unsafe fn llvm_optimize(
580582 vectorize_loop = config. vectorize_loop ;
581583 }
582584 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+ }
584596 let pgo_gen_path = get_pgo_gen_path ( config) ;
585597 let pgo_use_path = get_pgo_use_path ( config) ;
586598 let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -640,7 +652,9 @@ pub(crate) unsafe fn llvm_optimize(
640652 config. no_prepopulate_passes ,
641653 config. verify_llvm_ir ,
642654 config. lint_llvm_ir ,
643- using_thin_buffers,
655+ thin_lto_buffer,
656+ config. emit_thin_lto ,
657+ config. emit_thin_lto_summary ,
644658 config. merge_functions ,
645659 unroll_loops,
646660 vectorize_slp,
@@ -705,9 +719,56 @@ pub(crate) unsafe fn optimize(
705719 // usages, not just if we build rustc with autodiff support.
706720 let autodiff_stage =
707721 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
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}
@@ -785,59 +846,47 @@ pub(crate) unsafe fn codegen(
785846 // otherwise requested.
786847
787848 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) ;
790849 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
791850
792851 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-
826852 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 ( ) ;
827861 let _timer = cgcx
828862 . prof
829863 . 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+ }
830871 if let Err ( err) = fs:: write ( & bc_out, data) {
831872 dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
832873 }
833874 }
834875
835- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
876+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
877+ && module. kind == ModuleKind :: Regular
878+ {
836879 let _timer = cgcx
837880 . prof
838881 . 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) ;
839888 unsafe {
840- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
889+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
841890 }
842891 }
843892 }
0 commit comments