@@ -513,7 +513,8 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
513
513
pub ( crate ) unsafe fn llvm_optimize (
514
514
cgcx : & CodegenContext < LlvmCodegenBackend > ,
515
515
dcx : DiagCtxtHandle < ' _ > ,
516
- module : & ModuleCodegen < ModuleLlvm > ,
516
+ llmod : & llvm:: Module ,
517
+ tm : & llvm:: TargetMachine ,
517
518
config : & ModuleConfig ,
518
519
opt_level : config:: OptLevel ,
519
520
opt_stage : llvm:: OptStage ,
@@ -572,8 +573,8 @@ pub(crate) unsafe fn llvm_optimize(
572
573
573
574
let result = unsafe {
574
575
llvm:: LLVMRustOptimize (
575
- module . module_llvm . llmod ( ) ,
576
- & * module . module_llvm . tm ,
576
+ llmod,
577
+ tm,
577
578
to_pass_builder_opt_level ( opt_level) ,
578
579
opt_stage,
579
580
cgcx. opts . cg . linker_plugin_lto . enabled ( ) ,
@@ -635,8 +636,51 @@ pub(crate) unsafe fn optimize(
635
636
_ if cgcx. opts . cg . linker_plugin_lto . enabled ( ) => llvm:: OptStage :: PreLinkThinLTO ,
636
637
_ => llvm:: OptStage :: PreLinkNoLTO ,
637
638
} ;
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
+ } ?;
639
682
}
683
+
640
684
Ok ( ( ) )
641
685
}
642
686
@@ -716,11 +760,54 @@ pub(crate) unsafe fn codegen(
716
760
// asm from LLVM and use `gcc` to create the object file.
717
761
718
762
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) ;
721
763
let obj_out = cgcx. output_filenames . temp_path ( OutputType :: Object , module_name) ;
722
764
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
+
723
807
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) ;
724
811
let _timer = cgcx
725
812
. prof
726
813
. generic_activity_with_arg ( "LLVM_module_codegen_make_bitcode" , & * module. name ) ;
@@ -767,54 +854,22 @@ pub(crate) unsafe fn codegen(
767
854
let _timer = cgcx
768
855
. prof
769
856
. 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
+ }
770
867
unsafe {
771
868
embed_bitcode ( cgcx, llcx, llmod, & config. bc_cmdline , data) ;
772
869
}
773
870
}
774
871
}
775
872
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
-
818
873
if config. emit_asm {
819
874
let _timer =
820
875
cgcx. prof . generic_activity_with_arg ( "LLVM_module_codegen_emit_asm" , & * module. name ) ;
0 commit comments