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 } ;
@@ -534,6 +535,7 @@ pub(crate) unsafe fn llvm_optimize(
534535 cgcx : & CodegenContext < LlvmCodegenBackend > ,
535536 dcx : DiagCtxtHandle < ' _ > ,
536537 module : & ModuleCodegen < ModuleLlvm > ,
538+ thin_lto_buffer : Option < & mut * mut llvm:: ThinLTOBuffer > ,
537539 config : & ModuleConfig ,
538540 opt_level : config:: OptLevel ,
539541 opt_stage : llvm:: OptStage ,
@@ -566,7 +568,17 @@ pub(crate) unsafe fn llvm_optimize(
566568 vectorize_loop = config. vectorize_loop ;
567569 }
568570 trace ! ( ?unroll_loops, ?vectorize_slp, ?vectorize_loop) ;
569- let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
571+ if thin_lto_buffer. is_some ( ) {
572+ assert ! (
573+ matches!(
574+ opt_stage,
575+ llvm:: OptStage :: PreLinkNoLTO
576+ | llvm:: OptStage :: PreLinkFatLTO
577+ | llvm:: OptStage :: PreLinkThinLTO
578+ ) ,
579+ "the bitcode for LTO can only be obtained at the pre-link stage"
580+ ) ;
581+ }
570582 let pgo_gen_path = get_pgo_gen_path ( config) ;
571583 let pgo_use_path = get_pgo_use_path ( config) ;
572584 let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -626,7 +638,9 @@ pub(crate) unsafe fn llvm_optimize(
626638 config. no_prepopulate_passes ,
627639 config. verify_llvm_ir ,
628640 config. lint_llvm_ir ,
629- using_thin_buffers,
641+ thin_lto_buffer,
642+ config. emit_thin_lto ,
643+ config. emit_thin_lto_summary ,
630644 config. merge_functions ,
631645 unroll_loops,
632646 vectorize_slp,
@@ -686,17 +700,56 @@ pub(crate) unsafe fn optimize(
686700
687701 // If we know that we will later run AD, then we disable vectorization and loop unrolling
688702 let skip_size_increasing_opts = cfg ! ( llvm_enzyme) ;
689- return unsafe {
703+ // The embedded bitcode is used to run LTO/ThinLTO.
704+ // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.
705+ // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at
706+ // this point.
707+ let mut thin_lto_buffer = if ( module. kind == ModuleKind :: Regular
708+ && config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) )
709+ || config. emit_thin_lto_summary
710+ {
711+ Some ( null_mut ( ) )
712+ } else {
713+ None
714+ } ;
715+ unsafe {
690716 llvm_optimize (
691717 cgcx,
692718 dcx,
693719 module,
720+ thin_lto_buffer. as_mut ( ) ,
694721 config,
695722 opt_level,
696723 opt_stage,
697724 skip_size_increasing_opts,
698725 )
699- } ;
726+ } ?;
727+ if let Some ( thin_lto_buffer) = thin_lto_buffer {
728+ let thin_lto_buffer = unsafe { ThinBuffer :: from_raw_ptr ( thin_lto_buffer) } ;
729+ let thin_bc_out = cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
730+ if let Err ( err) = fs:: write ( & thin_bc_out, thin_lto_buffer. data ( ) ) {
731+ dcx. emit_err ( WriteBytecode { path : & thin_bc_out, err } ) ;
732+ }
733+ let bc_summary_out =
734+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
735+ if config. emit_thin_lto_summary
736+ && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
737+ {
738+ let summary_data = thin_lto_buffer. thin_link_data ( ) ;
739+ cgcx. prof . artifact_size (
740+ "llvm_bitcode_summary" ,
741+ thin_link_bitcode_filename. to_string_lossy ( ) ,
742+ summary_data. len ( ) as u64 ,
743+ ) ;
744+ let _timer = cgcx. prof . generic_activity_with_arg (
745+ "LLVM_module_codegen_emit_bitcode_summary" ,
746+ & * module. name ,
747+ ) ;
748+ if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
749+ dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
750+ }
751+ }
752+ }
700753 }
701754 Ok ( ( ) )
702755}
@@ -777,59 +830,47 @@ pub(crate) unsafe fn codegen(
777830 // asm from LLVM and use `gcc` to create the object file.
778831
779832 let bc_out = cgcx. output_filenames . temp_path ( OutputType :: Bitcode , module_name) ;
780- let bc_summary_out =
781- cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
782833 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
783834
784835 if config. bitcode_needed ( ) {
785- let _timer = cgcx
786- . prof
787- . generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
788- let thin = ThinBuffer :: new ( llmod, config. emit_thin_lto , config. emit_thin_lto_summary ) ;
789- let data = thin. data ( ) ;
790-
791- if let Some ( bitcode_filename) = bc_out. file_name ( ) {
792- cgcx. prof . artifact_size (
793- "llvm_bitcode" ,
794- bitcode_filename. to_string_lossy ( ) ,
795- data. len ( ) as u64 ,
796- ) ;
797- }
798-
799- if config. emit_thin_lto_summary
800- && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
801- {
802- let summary_data = thin. thin_link_data ( ) ;
803- cgcx. prof . artifact_size (
804- "llvm_bitcode_summary" ,
805- thin_link_bitcode_filename. to_string_lossy ( ) ,
806- summary_data. len ( ) as u64 ,
807- ) ;
808-
809- let _timer = cgcx. prof . generic_activity_with_arg (
810- "LLVM_module_codegen_emit_bitcode_summary" ,
811- & * module. name ,
812- ) ;
813- if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
814- dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
815- }
816- }
817-
818836 if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
837+ let thin = {
838+ let _timer = cgcx. prof . generic_activity_with_arg (
839+ "LLVM_module_codegen_make_bitcode" ,
840+ & * module. name ,
841+ ) ;
842+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
843+ } ;
844+ let data = thin. data ( ) ;
819845 let _timer = cgcx
820846 . prof
821847 . generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
848+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
849+ cgcx. prof . artifact_size (
850+ "llvm_bitcode" ,
851+ bitcode_filename. to_string_lossy ( ) ,
852+ data. len ( ) as u64 ,
853+ ) ;
854+ }
822855 if let Err ( err) = fs:: write ( & bc_out, data) {
823856 dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
824857 }
825858 }
826859
827- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
860+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
861+ && module. kind == ModuleKind :: Regular
862+ {
828863 let _timer = cgcx
829864 . prof
830865 . generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
866+ let thin_bc_out =
867+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
868+ assert ! ( thin_bc_out. exists( ) , "cannot find {:?} as embedded bitcode" , thin_bc_out) ;
869+ let data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
870+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
871+ ensure_removed ( dcx, & thin_bc_out) ;
831872 unsafe {
832- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
873+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
833874 }
834875 }
835876 }
0 commit comments