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,21 @@ 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 ! ( matches!(
525+ opt_stage,
526+ llvm:: OptStage :: PreLinkNoLTO
527+ | llvm:: OptStage :: PreLinkFatLTO
528+ | llvm:: OptStage :: PreLinkThinLTO
529+ ) ) ;
530+ }
521531 let unroll_loops =
522532 opt_level != config:: OptLevel :: Size && opt_level != config:: OptLevel :: SizeMin ;
523- let using_thin_buffers = opt_stage == llvm:: OptStage :: PreLinkThinLTO || config. bitcode_needed ( ) ;
524533 let pgo_gen_path = get_pgo_gen_path ( config) ;
525534 let pgo_use_path = get_pgo_use_path ( config) ;
526535 let pgo_sample_use_path = get_pgo_sample_use_path ( config) ;
@@ -580,7 +589,9 @@ pub(crate) unsafe fn llvm_optimize(
580589 config. no_prepopulate_passes ,
581590 config. verify_llvm_ir ,
582591 config. lint_llvm_ir ,
583- using_thin_buffers,
592+ thin_lto_buffer,
593+ config. emit_thin_lto ,
594+ config. emit_thin_lto_summary ,
584595 config. merge_functions ,
585596 unroll_loops,
586597 config. vectorize_slp ,
@@ -635,7 +646,47 @@ pub(crate) unsafe fn optimize(
635646 _ if cgcx. opts . cg . linker_plugin_lto . enabled ( ) => llvm:: OptStage :: PreLinkThinLTO ,
636647 _ => llvm:: OptStage :: PreLinkNoLTO ,
637648 } ;
638- return unsafe { llvm_optimize ( cgcx, dcx, module, config, opt_level, opt_stage) } ;
649+ // The embedded bitcode is used to run LTO/ThinLTO.
650+ // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO.
651+ // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at
652+ // this point.
653+ let mut thin_lto_buffer = if ( module. kind == ModuleKind :: Regular
654+ && config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) )
655+ || config. emit_thin_lto_summary
656+ {
657+ Some ( null_mut ( ) )
658+ } else {
659+ None
660+ } ;
661+ unsafe {
662+ llvm_optimize ( cgcx, dcx, module, thin_lto_buffer. as_mut ( ) , config, opt_level, opt_stage)
663+ } ?;
664+ if let Some ( thin_lto_buffer) = thin_lto_buffer {
665+ let thin_lto_buffer = unsafe { ThinBuffer :: from_raw_ptr ( thin_lto_buffer) } ;
666+ let thin_bc_out = cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
667+ if let Err ( err) = fs:: write ( & thin_bc_out, thin_lto_buffer. data ( ) ) {
668+ dcx. emit_err ( WriteBytecode { path : & thin_bc_out, err } ) ;
669+ }
670+ let bc_summary_out =
671+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
672+ if config. emit_thin_lto_summary
673+ && let Some ( thin_link_bitcode_filename) = bc_summary_out. file_name ( )
674+ {
675+ let summary_data = thin_lto_buffer. thin_link_data ( ) ;
676+ cgcx. prof . artifact_size (
677+ "llvm_bitcode_summary" ,
678+ thin_link_bitcode_filename. to_string_lossy ( ) ,
679+ summary_data. len ( ) as u64 ,
680+ ) ;
681+ let _timer = cgcx. prof . generic_activity_with_arg (
682+ "LLVM_module_codegen_emit_bitcode_summary" ,
683+ & * module. name ,
684+ ) ;
685+ if let Err ( err) = fs:: write ( & bc_summary_out, summary_data) {
686+ dcx. emit_err ( WriteBytecode { path : & bc_summary_out, err } ) ;
687+ }
688+ }
689+ }
639690 }
640691 Ok ( ( ) )
641692}
@@ -714,61 +765,49 @@ pub(crate) unsafe fn codegen(
714765 // requested.
715766 // - If we don't have the integrated assembler then we need to emit
716767 // asm from LLVM and use `gcc` to create the object file.
717-
718768 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) ;
721769 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
722770
723771 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-
772+ // If the object file of the target spec is bitcode, what happens when performing LTO in Rust?
757773 if config. emit_bc || config. emit_obj == EmitObj :: Bitcode {
774+ let thin = {
775+ let _timer = cgcx. prof . generic_activity_with_arg (
776+ "LLVM_module_codegen_make_bitcode" ,
777+ & * module. name ,
778+ ) ;
779+ ThinBuffer :: new ( llmod, config. emit_thin_lto , false )
780+ } ;
781+ let data = thin. data ( ) ;
758782 let _timer = cgcx
759783 . prof
760784 . generic_activity_with_arg ( "LLVM_module_codegen_emit_bitcode" , & * module. name ) ;
785+ if let Some ( bitcode_filename) = bc_out. file_name ( ) {
786+ cgcx. prof . artifact_size (
787+ "llvm_bitcode" ,
788+ bitcode_filename. to_string_lossy ( ) ,
789+ data. len ( ) as u64 ,
790+ ) ;
791+ }
761792 if let Err ( err) = fs:: write ( & bc_out, data) {
762793 dcx. emit_err ( WriteBytecode { path : & bc_out, err } ) ;
763794 }
764795 }
765796
766- if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full ) {
797+ if config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
798+ && module. kind == ModuleKind :: Regular
799+ {
767800 let _timer = cgcx
768801 . prof
769802 . generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
803+ let thin_bc_out =
804+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
805+ assert ! ( thin_bc_out. exists( ) , "cannot find {:?} as embedded bitcode" , thin_bc_out) ;
806+ let data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
807+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
808+ ensure_removed ( dcx, & thin_bc_out) ;
770809 unsafe {
771- embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
810+ embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , & data) ;
772811 }
773812 }
774813 }
0 commit comments