@@ -513,7 +513,8 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
513513pub ( crate ) unsafe fn llvm_optimize (
514514 cgcx : & CodegenContext < LlvmCodegenBackend > ,
515515 dcx : DiagCtxtHandle < ' _ > ,
516- module : & ModuleCodegen < ModuleLlvm > ,
516+ llmod : & llvm:: Module ,
517+ tm : & llvm:: TargetMachine ,
517518 config : & ModuleConfig ,
518519 opt_level : config:: OptLevel ,
519520 opt_stage : llvm:: OptStage ,
@@ -572,8 +573,8 @@ pub(crate) unsafe fn llvm_optimize(
572573
573574 let result = unsafe {
574575 llvm:: LLVMRustOptimize (
575- module . module_llvm . llmod ( ) ,
576- & * module . module_llvm . tm ,
576+ llmod,
577+ tm,
577578 to_pass_builder_opt_level ( opt_level) ,
578579 opt_stage,
579580 cgcx. opts . cg . linker_plugin_lto . enabled ( ) ,
@@ -635,8 +636,51 @@ pub(crate) unsafe fn optimize(
635636 _ if cgcx. opts . cg . linker_plugin_lto . enabled ( ) => llvm:: OptStage :: PreLinkThinLTO ,
636637 _ => llvm:: OptStage :: PreLinkNoLTO ,
637638 } ;
638- return unsafe { llvm_optimize ( cgcx, dcx, module, config, opt_level, opt_stage) } ;
639+ if opt_stage == llvm:: OptStage :: PreLinkNoLTO
640+ && config. emit_obj == EmitObj :: ObjectCode ( BitcodeSection :: Full )
641+ {
642+ let _timer = cgcx. prof . generic_activity_with_arg (
643+ "LLVM_module_codegen_prepare_embed_bitcode" ,
644+ & * module. name ,
645+ ) ;
646+ // The embedded bitcode is used to run LTO/ThinLTO.
647+ // `OptStage::PreLinkNoLTO` is not suitable as input for LTO,
648+ // as it may run certain passes that cannot be executed multiple times,
649+ // such as LLVM's Call Graph Profile pass. So, we create a copy to
650+ // run `OptStage::PreLinkThinLTO` for the subsequent LTO process.
651+ let llmod = unsafe { llvm:: LLVMCloneModule ( module. module_llvm . llmod ( ) ) } ;
652+ unsafe {
653+ llvm_optimize (
654+ cgcx,
655+ dcx,
656+ llmod,
657+ & * module. module_llvm . tm ,
658+ config,
659+ opt_level,
660+ llvm:: OptStage :: PreLinkThinLTO ,
661+ )
662+ } ?;
663+ let embed_thin =
664+ ThinBuffer :: new ( llmod, config. emit_thin_lto , config. emit_thin_lto_summary ) ;
665+ let thin_bc_out = cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
666+ if let Err ( err) = fs:: write ( & thin_bc_out, embed_thin. data ( ) ) {
667+ dcx. emit_err ( WriteBytecode { path : & thin_bc_out, err } ) ;
668+ }
669+ unsafe { llvm:: LLVMDisposeModule ( llmod) } ;
670+ }
671+ unsafe {
672+ llvm_optimize (
673+ cgcx,
674+ dcx,
675+ module. module_llvm . llmod ( ) ,
676+ & * module. module_llvm . tm ,
677+ config,
678+ opt_level,
679+ opt_stage,
680+ )
681+ } ?;
639682 }
683+
640684 Ok ( ( ) )
641685}
642686
@@ -716,11 +760,54 @@ pub(crate) unsafe fn codegen(
716760 // asm from LLVM and use `gcc` to create the object file.
717761
718762 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) ;
721763 let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
722764
765+ if config. emit_ir {
766+ let _timer =
767+ cgcx. prof . generic_activity_with_arg ( "LLVM_module_codegen_emit_ir" , & * module. name ) ;
768+ let out = cgcx. output_filenames . temp_path ( OutputType :: LlvmAssembly , module_name) ;
769+ let out_c = path_to_c_string ( & out) ;
770+
771+ extern "C" fn demangle_callback (
772+ input_ptr : * const c_char ,
773+ input_len : size_t ,
774+ output_ptr : * mut c_char ,
775+ output_len : size_t ,
776+ ) -> size_t {
777+ let input =
778+ unsafe { slice:: from_raw_parts ( input_ptr as * const u8 , input_len as usize ) } ;
779+
780+ let Ok ( input) = str:: from_utf8 ( input) else { return 0 } ;
781+
782+ let output = unsafe {
783+ slice:: from_raw_parts_mut ( output_ptr as * mut u8 , output_len as usize )
784+ } ;
785+ let mut cursor = io:: Cursor :: new ( output) ;
786+
787+ let Ok ( demangled) = rustc_demangle:: try_demangle ( input) else { return 0 } ;
788+
789+ if write ! ( cursor, "{demangled:#}" ) . is_err ( ) {
790+ // Possible only if provided buffer is not big enough
791+ return 0 ;
792+ }
793+
794+ cursor. position ( ) as size_t
795+ }
796+
797+ let result =
798+ unsafe { llvm:: LLVMRustPrintModule ( llmod, out_c. as_ptr ( ) , demangle_callback) } ;
799+
800+ if result == llvm:: LLVMRustResult :: Success {
801+ record_artifact_size ( & cgcx. prof , "llvm_ir" , & out) ;
802+ }
803+
804+ result. into_result ( ) . map_err ( |( ) | llvm_err ( dcx, LlvmError :: WriteIr { path : & out } ) ) ?;
805+ }
806+
723807 if config. bitcode_needed ( ) {
808+ let bc_out = cgcx. output_filenames . temp_path ( OutputType :: Bitcode , module_name) ;
809+ let bc_summary_out =
810+ cgcx. output_filenames . temp_path ( OutputType :: ThinLinkBitcode , module_name) ;
724811 let _timer = cgcx
725812 . prof
726813 . generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
@@ -767,54 +854,22 @@ pub(crate) unsafe fn codegen(
767854 let _timer = cgcx
768855 . prof
769856 . generic_activity_with_arg ( "LLVM_module_codegen_embed_bitcode" , & * module. name ) ;
857+ let thin_bc_out =
858+ cgcx. output_filenames . temp_path ( OutputType :: ThinBitcode , module_name) ;
859+ let thin_data;
860+ let mut data = data;
861+ if thin_bc_out. exists ( ) {
862+ thin_data = fs:: read ( & thin_bc_out) . unwrap ( ) ;
863+ debug ! ( "removing embed bitcode file {:?}" , thin_bc_out) ;
864+ ensure_removed ( dcx, & thin_bc_out) ;
865+ data = thin_data. as_slice ( ) ;
866+ }
770867 unsafe {
771868 embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
772869 }
773870 }
774871 }
775872
776- if config. emit_ir {
777- let _timer =
778- cgcx. prof . generic_activity_with_arg ( "LLVM_module_codegen_emit_ir" , & * module. name ) ;
779- let out = cgcx. output_filenames . temp_path ( OutputType :: LlvmAssembly , module_name) ;
780- let out_c = path_to_c_string ( & out) ;
781-
782- extern "C" fn demangle_callback (
783- input_ptr : * const c_char ,
784- input_len : size_t ,
785- output_ptr : * mut c_char ,
786- output_len : size_t ,
787- ) -> size_t {
788- let input =
789- unsafe { slice:: from_raw_parts ( input_ptr as * const u8 , input_len as usize ) } ;
790-
791- let Ok ( input) = str:: from_utf8 ( input) else { return 0 } ;
792-
793- let output = unsafe {
794- slice:: from_raw_parts_mut ( output_ptr as * mut u8 , output_len as usize )
795- } ;
796- let mut cursor = io:: Cursor :: new ( output) ;
797-
798- let Ok ( demangled) = rustc_demangle:: try_demangle ( input) else { return 0 } ;
799-
800- if write ! ( cursor, "{demangled:#}" ) . is_err ( ) {
801- // Possible only if provided buffer is not big enough
802- return 0 ;
803- }
804-
805- cursor. position ( ) as size_t
806- }
807-
808- let result =
809- unsafe { llvm:: LLVMRustPrintModule ( llmod, out_c. as_ptr ( ) , demangle_callback) } ;
810-
811- if result == llvm:: LLVMRustResult :: Success {
812- record_artifact_size ( & cgcx. prof , "llvm_ir" , & out) ;
813- }
814-
815- result. into_result ( ) . map_err ( |( ) | llvm_err ( dcx, LlvmError :: WriteIr { path : & out } ) ) ?;
816- }
817-
818873 if config. emit_asm {
819874 let _timer =
820875 cgcx. prof . generic_activity_with_arg ( "LLVM_module_codegen_emit_asm" , & * module. name ) ;
0 commit comments