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 } ;
@@ -41,7 +42,7 @@ use crate::errors::{
4142 WithLlvmError , WriteBytecode ,
4243} ;
4344use crate :: llvm:: diagnostic:: OptimizationDiagnosticKind :: * ;
44- use crate :: llvm:: { self , DiagnosticInfo , PassManager } ;
45+ use crate :: llvm:: { self , DiagnosticInfo , PassManager , ThinLTOBuffer } ;
4546use crate :: type_:: Type ;
4647use crate :: { LlvmCodegenBackend , ModuleLlvm , base, common, llvm_util} ;
4748
@@ -514,13 +515,24 @@ pub(crate) unsafe fn llvm_optimize(
514515 cgcx : & CodegenContext < LlvmCodegenBackend > ,
515516 dcx : DiagCtxtHandle < ' _ > ,
516517 module : & ModuleCodegen < ModuleLlvm > ,
518+ thin_lto_buffer : Option < & mut * mut ThinLTOBuffer > ,
517519 config : & ModuleConfig ,
518520 opt_level : config:: OptLevel ,
519521 opt_stage : llvm:: OptStage ,
520522) -> Result < ( ) , FatalError > {
523+ if thin_lto_buffer. is_some ( ) {
524+ assert ! (
525+ matches!(
526+ opt_stage,
527+ llvm:: OptStage :: PreLinkNoLTO
528+ | llvm:: OptStage :: PreLinkFatLTO
529+ | llvm:: OptStage :: PreLinkThinLTO
530+ ) ,
531+ "the bitcode for LTO can only be obtained at the pre-link stage"
532+ ) ;
533+ }
521534 let unroll_loops =
522535 opt_level != config:: OptLevel :: Size && opt_level != config:: OptLevel :: SizeMin ;
523- let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
524536 let pgo_gen_path = get_pgo_gen_path ( config) ;
525537 let pgo_use_path = get_pgo_use_path ( config) ;
526538 let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -580,7 +592,9 @@ pub(crate) unsafe fn llvm_optimize(
580592 config. no_prepopulate_passes ,
581593 config. verify_llvm_ir ,
582594 config. lint_llvm_ir ,
583- using_thin_buffers,
595+ thin_lto_buffer,
596+ config. emit_thin_lto ,
597+ config. emit_thin_lto_summary ,
584598 config. merge_functions ,
585599 unroll_loops,
586600 config. vectorize_slp ,
@@ -635,7 +649,47 @@ pub(crate) unsafe fn optimize(
635649 _ if cgcx. opts . cg . linker_plugin_lto . enabled ( ) => llvm:: OptStage :: PreLinkThinLTO ,
636650 _ => llvm:: OptStage :: PreLinkNoLTO ,
637651 } ;
638- return unsafe { llvm_optimize ( cgcx, dcx, module, config, opt_level, opt_stage) } ;
652+ // The embedded bitcode is used to run LTO/ThinLTO.
653+ // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.
654+ // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at
655+ // this point.
656+ let mut thin_lto_buffer = if ( module. kind == ModuleKind :: Regular
657+ && config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) )
658+ || config. emit_thin_lto_summary
659+ {
660+ Some ( null_mut ( ) )
661+ } else {
662+ None
663+ } ;
664+ unsafe {
665+ llvm_optimize ( cgcx, dcx, module, thin_lto_buffer. as_mut ( ) , config, opt_level, opt_stage)
666+ } ?;
667+ if let Some ( thin_lto_buffer) = thin_lto_buffer {
668+ let thin_lto_buffer = unsafe { ThinBuffer :: from_raw_ptr ( thin_lto_buffer) } ;
669+ let thin_bc_out = cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
670+ if let Err ( err) = fs:: write ( & thin_bc_out, thin_lto_buffer. data ( ) ) {
671+ dcx. emit_err ( WriteBytecode { path : & thin_bc_out, err } ) ;
672+ }
673+ let bc_summary_out =
674+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
675+ if config. emit_thin_lto_summary
676+ && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
677+ {
678+ let summary_data = thin_lto_buffer. thin_link_data ( ) ;
679+ cgcx. prof . artifact_size (
680+ "llvm_bitcode_summary" ,
681+ thin_link_bitcode_filename. to_string_lossy ( ) ,
682+ summary_data. len ( ) as u64 ,
683+ ) ;
684+ let _timer = cgcx. prof . generic_activity_with_arg (
685+ "LLVM_module_codegen_emit_bitcode_summary" ,
686+ & * module. name ,
687+ ) ;
688+ if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
689+ dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
690+ }
691+ }
692+ }
639693 }
640694 Ok ( ( ) )
641695}
@@ -714,61 +768,49 @@ pub(crate) unsafe fn codegen(
714768 // requested.
715769 // - If we don't have the integrated assembler then we need to emit
716770 // asm from LLVM and use `gcc` to create the object file.
717-
718771 let bc_out = cgcx. output_filenames . temp_path ( OutputType :: Bitcode , module_name) ;
719- let bc_summary_out =
720- cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
721772 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
722773
723774 if config. bitcode_needed ( ) {
724- let _timer = cgcx
725- . prof
726- . generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
727- let thin = ThinBuffer :: new ( llmod, config. emit_thin_lto , config. emit_thin_lto_summary ) ;
728- let data = thin. data ( ) ;
729-
730- if let Some ( bitcode_filename) = bc_out. file_name ( ) {
731- cgcx. prof . artifact_size (
732- "llvm_bitcode" ,
733- bitcode_filename. to_string_lossy ( ) ,
734- data. len ( ) as u64 ,
735- ) ;
736- }
737-
738- if config. emit_thin_lto_summary
739- && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
740- {
741- let summary_data = thin. thin_link_data ( ) ;
742- cgcx. prof . artifact_size (
743- "llvm_bitcode_summary" ,
744- thin_link_bitcode_filename. to_string_lossy ( ) ,
745- summary_data. len ( ) as u64 ,
746- ) ;
747-
748- let _timer = cgcx. prof . generic_activity_with_arg (
749- "LLVM_module_codegen_emit_bitcode_summary" ,
750- & * module. name ,
751- ) ;
752- if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
753- dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
754- }
755- }
756-
775+ // If the object file of the target spec is bitcode, what happens when performing LTO in Rust?
757776 if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
777+ let thin = {
778+ let _timer = cgcx. prof . generic_activity_with_arg (
779+ "LLVM_module_codegen_make_bitcode" ,
780+ & * module. name ,
781+ ) ;
782+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
783+ } ;
784+ let data = thin. data ( ) ;
758785 let _timer = cgcx
759786 . prof
760787 . generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
788+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
789+ cgcx. prof . artifact_size (
790+ "llvm_bitcode" ,
791+ bitcode_filename. to_string_lossy ( ) ,
792+ data. len ( ) as u64 ,
793+ ) ;
794+ }
761795 if let Err ( err) = fs:: write ( & bc_out, data) {
762796 dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
763797 }
764798 }
765799
766- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
800+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
801+ && module. kind == ModuleKind :: Regular
802+ {
767803 let _timer = cgcx
768804 . prof
769805 . generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
806+ let thin_bc_out =
807+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
808+ assert ! ( thin_bc_out. exists( ) , "cannot find {:?} as embedded bitcode" , thin_bc_out) ;
809+ let data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
810+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
811+ ensure_removed ( dcx, & thin_bc_out) ;
770812 unsafe {
771- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
813+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
772814 }
773815 }
774816 }
0 commit comments