2020-09-23 13:13:49 +00:00
//! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
//! standalone executable.
2024-12-06 12:10:30 +00:00
use std ::env ;
2024-03-28 11:43:35 +00:00
use std ::fs ::{ self , File } ;
2024-11-09 13:48:06 +00:00
use std ::io ::BufWriter ;
2024-03-28 11:43:35 +00:00
use std ::path ::{ Path , PathBuf } ;
2022-08-24 16:40:58 +00:00
use std ::sync ::Arc ;
use std ::thread ::JoinHandle ;
2020-07-09 14:55:38 +00:00
2023-10-09 08:52:46 +00:00
use cranelift_object ::{ ObjectBuilder , ObjectModule } ;
2023-09-19 11:23:35 +00:00
use rustc_codegen_ssa ::assert_module_sources ::CguReuse ;
2024-03-28 11:43:35 +00:00
use rustc_codegen_ssa ::back ::link ::ensure_removed ;
2021-12-20 17:56:35 +00:00
use rustc_codegen_ssa ::back ::metadata ::create_compressed_metadata_file ;
2023-09-16 14:36:23 +00:00
use rustc_codegen_ssa ::base ::determine_cgu_reuse ;
2024-07-28 22:13:50 +00:00
use rustc_codegen_ssa ::{
2024-09-22 23:05:04 +00:00
CodegenResults , CompiledModule , CrateInfo , ModuleKind , errors as ssa_errors ,
2024-07-28 22:13:50 +00:00
} ;
2022-08-24 16:40:58 +00:00
use rustc_data_structures ::profiling ::SelfProfilerRef ;
2020-08-28 10:10:48 +00:00
use rustc_data_structures ::stable_hasher ::{ HashStable , StableHasher } ;
2024-09-22 23:05:04 +00:00
use rustc_data_structures ::sync ::{ IntoDynSyncSend , par_map } ;
2021-09-24 16:15:36 +00:00
use rustc_metadata ::EncodedMetadata ;
2024-09-22 23:05:04 +00:00
use rustc_metadata ::fs ::copy_to_stdout ;
2020-05-09 12:14:45 +00:00
use rustc_middle ::dep_graph ::{ WorkProduct , WorkProductId } ;
2024-12-12 20:31:20 +00:00
use rustc_middle ::middle ::codegen_fn_attrs ::CodegenFnAttrFlags ;
use rustc_middle ::mir ::mono ::{
CodegenUnit , Linkage as RLinkage , MonoItem , MonoItemData , Visibility ,
} ;
2021-09-19 11:56:58 +00:00
use rustc_session ::Session ;
2024-09-22 23:05:04 +00:00
use rustc_session ::config ::{ DebugInfo , OutFileName , OutputFilenames , OutputType } ;
2020-03-12 10:48:17 +00:00
2024-12-06 12:10:30 +00:00
use crate ::CodegenCx ;
use crate ::base ::CodegenedFunction ;
2022-08-24 16:40:58 +00:00
use crate ::concurrency_limiter ::{ ConcurrencyLimiter , ConcurrencyLimiterToken } ;
2024-03-28 11:43:35 +00:00
use crate ::debuginfo ::TypeDebugContext ;
2024-12-12 20:31:20 +00:00
use crate ::global_asm ::{ GlobalAsmConfig , GlobalAsmContext } ;
2024-07-28 22:13:50 +00:00
use crate ::prelude ::* ;
2024-06-30 11:28:14 +00:00
use crate ::unwind_module ::UnwindModule ;
2020-03-12 10:48:17 +00:00
2024-12-06 12:10:30 +00:00
fn disable_incr_cache ( ) -> bool {
env ::var ( " CG_CLIF_DISABLE_INCR_CACHE " ) . as_deref ( ) = = Ok ( " 1 " )
}
2022-08-24 16:40:58 +00:00
struct ModuleCodegenResult {
module_regular : CompiledModule ,
module_global_asm : Option < CompiledModule > ,
existing_work_product : Option < ( WorkProductId , WorkProduct ) > ,
}
enum OngoingModuleCodegen {
Sync ( Result < ModuleCodegenResult , String > ) ,
Async ( JoinHandle < Result < ModuleCodegenResult , String > > ) ,
}
2020-03-12 10:58:59 +00:00
2022-08-24 16:40:58 +00:00
impl < HCX > HashStable < HCX > for OngoingModuleCodegen {
2020-03-12 10:58:59 +00:00
fn hash_stable ( & self , _ : & mut HCX , _ : & mut StableHasher ) {
// do nothing
}
}
2022-08-24 16:40:58 +00:00
pub ( crate ) struct OngoingCodegen {
modules : Vec < OngoingModuleCodegen > ,
allocator_module : Option < CompiledModule > ,
metadata_module : Option < CompiledModule > ,
metadata : EncodedMetadata ,
crate_info : CrateInfo ,
concurrency_limiter : ConcurrencyLimiter ,
}
impl OngoingCodegen {
pub ( crate ) fn join (
self ,
sess : & Session ,
2024-03-28 11:43:35 +00:00
outputs : & OutputFilenames ,
2023-04-07 19:56:33 +00:00
) -> ( CodegenResults , FxIndexMap < WorkProductId , WorkProduct > ) {
let mut work_products = FxIndexMap ::default ( ) ;
2022-08-24 16:40:58 +00:00
let mut modules = vec! [ ] ;
2024-12-06 12:10:30 +00:00
let disable_incr_cache = disable_incr_cache ( ) ;
2022-08-24 16:40:58 +00:00
for module_codegen in self . modules {
let module_codegen_result = match module_codegen {
OngoingModuleCodegen ::Sync ( module_codegen_result ) = > module_codegen_result ,
OngoingModuleCodegen ::Async ( join_handle ) = > match join_handle . join ( ) {
Ok ( module_codegen_result ) = > module_codegen_result ,
Err ( panic ) = > std ::panic ::resume_unwind ( panic ) ,
} ,
} ;
let module_codegen_result = match module_codegen_result {
Ok ( module_codegen_result ) = > module_codegen_result ,
2023-12-18 11:21:37 +00:00
Err ( err ) = > sess . dcx ( ) . fatal ( err ) ,
2022-08-24 16:40:58 +00:00
} ;
let ModuleCodegenResult { module_regular , module_global_asm , existing_work_product } =
module_codegen_result ;
if let Some ( ( work_product_id , work_product ) ) = existing_work_product {
work_products . insert ( work_product_id , work_product ) ;
} else {
2024-12-06 12:10:30 +00:00
let work_product = if disable_incr_cache {
2022-08-24 16:40:58 +00:00
None
} else if let Some ( module_global_asm ) = & module_global_asm {
rustc_incremental ::copy_cgu_workproduct_to_incr_comp_cache_dir (
sess ,
& module_regular . name ,
& [
( " o " , & module_regular . object . as_ref ( ) . unwrap ( ) ) ,
( " asm.o " , & module_global_asm . object . as_ref ( ) . unwrap ( ) ) ,
] ,
2024-07-28 20:54:14 +00:00
& [ ] ,
2022-08-24 16:40:58 +00:00
)
} else {
rustc_incremental ::copy_cgu_workproduct_to_incr_comp_cache_dir (
sess ,
& module_regular . name ,
& [ ( " o " , & module_regular . object . as_ref ( ) . unwrap ( ) ) ] ,
2024-07-28 20:54:14 +00:00
& [ ] ,
2022-08-24 16:40:58 +00:00
)
} ;
if let Some ( ( work_product_id , work_product ) ) = work_product {
work_products . insert ( work_product_id , work_product ) ;
}
}
modules . push ( module_regular ) ;
if let Some ( module_global_asm ) = module_global_asm {
modules . push ( module_global_asm ) ;
}
}
2022-10-23 14:22:55 +00:00
self . concurrency_limiter . finished ( ) ;
2022-08-24 16:40:58 +00:00
2023-12-21 05:26:09 +00:00
sess . dcx ( ) . abort_if_errors ( ) ;
2023-01-24 17:56:42 +00:00
2024-03-28 11:43:35 +00:00
let codegen_results = CodegenResults {
modules ,
allocator_module : self . allocator_module ,
metadata_module : self . metadata_module ,
metadata : self . metadata ,
crate_info : self . crate_info ,
} ;
produce_final_output_artifacts ( sess , & codegen_results , outputs ) ;
( codegen_results , work_products )
}
}
// Adapted from https://github.com/rust-lang/rust/blob/73476d49904751f8d90ce904e16dfbc278083d2c/compiler/rustc_codegen_ssa/src/back/write.rs#L547C1-L706C2
fn produce_final_output_artifacts (
sess : & Session ,
codegen_results : & CodegenResults ,
crate_output : & OutputFilenames ,
) {
let user_wants_bitcode = false ;
let mut user_wants_objects = false ;
// Produce final compile outputs.
let copy_gracefully = | from : & Path , to : & OutFileName | match to {
OutFileName ::Stdout = > {
if let Err ( e ) = copy_to_stdout ( from ) {
sess . dcx ( ) . emit_err ( ssa_errors ::CopyPath ::new ( from , to . as_path ( ) , e ) ) ;
}
}
OutFileName ::Real ( path ) = > {
if let Err ( e ) = fs ::copy ( from , path ) {
sess . dcx ( ) . emit_err ( ssa_errors ::CopyPath ::new ( from , path , e ) ) ;
}
}
} ;
let copy_if_one_unit = | output_type : OutputType , keep_numbered : bool | {
if codegen_results . modules . len ( ) = = 1 {
// 1) Only one codegen unit. In this case it's no difficulty
// to copy `foo.0.x` to `foo.x`.
2025-04-06 23:50:16 +00:00
let path = crate_output . temp_path_for_cgu (
output_type ,
& codegen_results . modules [ 0 ] . name ,
sess . invocation_temp . as_deref ( ) ,
) ;
2024-03-28 11:43:35 +00:00
let output = crate_output . path ( output_type ) ;
if ! output_type . is_text_output ( ) & & output . is_tty ( ) {
sess . dcx ( )
. emit_err ( ssa_errors ::BinaryOutputToTty { shorthand : output_type . shorthand ( ) } ) ;
} else {
copy_gracefully ( & path , & output ) ;
}
if ! sess . opts . cg . save_temps & & ! keep_numbered {
// The user just wants `foo.x`, not `foo.#module-name#.x`.
ensure_removed ( sess . dcx ( ) , & path ) ;
}
} else {
if crate_output . outputs . contains_explicit_name ( & output_type ) {
// 2) Multiple codegen units, with `--emit foo=some_name`. We have
// no good solution for this case, so warn the user.
2025-04-06 23:37:30 +00:00
sess . dcx ( )
. emit_warn ( ssa_errors ::IgnoringEmitPath { extension : output_type . extension ( ) } ) ;
2024-03-28 11:43:35 +00:00
} else if crate_output . single_output_file . is_some ( ) {
// 3) Multiple codegen units, with `-o some_name`. We have
// no good solution for this case, so warn the user.
2025-04-06 23:37:30 +00:00
sess . dcx ( )
. emit_warn ( ssa_errors ::IgnoringOutput { extension : output_type . extension ( ) } ) ;
2024-03-28 11:43:35 +00:00
} else {
// 4) Multiple codegen units, but no explicit name. We
// just leave the `foo.0.x` files in place.
// (We don't have to do any work in this case.)
}
}
} ;
// Flag to indicate whether the user explicitly requested bitcode.
// Otherwise, we produced it only as a temporary output, and will need
// to get rid of it.
for output_type in crate_output . outputs . keys ( ) {
match * output_type {
2024-01-19 19:42:43 +00:00
OutputType ::Bitcode | OutputType ::ThinLinkBitcode = > {
2024-03-28 11:43:35 +00:00
// Cranelift doesn't have bitcode
// user_wants_bitcode = true;
// // Copy to .bc, but always keep the .0.bc. There is a later
// // check to figure out if we should delete .0.bc files, or keep
// // them for making an rlib.
// copy_if_one_unit(OutputType::Bitcode, true);
}
OutputType ::LlvmAssembly = > {
// Cranelift IR text already emitted during codegen
// copy_if_one_unit(OutputType::LlvmAssembly, false);
}
OutputType ::Assembly = > {
// Currently no support for emitting raw assembly files
// copy_if_one_unit(OutputType::Assembly, false);
}
OutputType ::Object = > {
user_wants_objects = true ;
copy_if_one_unit ( OutputType ::Object , true ) ;
}
OutputType ::Mir | OutputType ::Metadata | OutputType ::Exe | OutputType ::DepInfo = > { }
}
}
// Clean up unwanted temporary files.
// We create the following files by default:
// - #crate#.#module-name#.bc
// - #crate#.#module-name#.o
// - #crate#.crate.metadata.bc
// - #crate#.crate.metadata.o
// - #crate#.o (linked from crate.##.o)
// - #crate#.bc (copied from crate.##.bc)
// We may create additional files if requested by the user (through
// `-C save-temps` or `--emit=` flags).
if ! sess . opts . cg . save_temps {
// Remove the temporary .#module-name#.o objects. If the user didn't
// explicitly request bitcode (with --emit=bc), and the bitcode is not
// needed for building an rlib, then we must remove .#module-name#.bc as
// well.
// Specific rules for keeping .#module-name#.bc:
// - If the user requested bitcode (`user_wants_bitcode`), and
// codegen_units > 1, then keep it.
// - If the user requested bitcode but codegen_units == 1, then we
// can toss .#module-name#.bc because we copied it to .bc earlier.
// - If we're not building an rlib and the user didn't request
// bitcode, then delete .#module-name#.bc.
// If you change how this works, also update back::link::link_rlib,
// where .#module-name#.bc files are (maybe) deleted after making an
// rlib.
let needs_crate_object = crate_output . outputs . contains_key ( & OutputType ::Exe ) ;
let keep_numbered_bitcode = user_wants_bitcode & & sess . codegen_units ( ) . as_usize ( ) > 1 ;
let keep_numbered_objects =
needs_crate_object | | ( user_wants_objects & & sess . codegen_units ( ) . as_usize ( ) > 1 ) ;
for module in codegen_results . modules . iter ( ) {
if let Some ( ref path ) = module . object {
if ! keep_numbered_objects {
ensure_removed ( sess . dcx ( ) , path ) ;
}
}
if let Some ( ref path ) = module . dwarf_object {
if ! keep_numbered_objects {
ensure_removed ( sess . dcx ( ) , path ) ;
}
}
if let Some ( ref path ) = module . bytecode {
if ! keep_numbered_bitcode {
ensure_removed ( sess . dcx ( ) , path ) ;
}
}
}
if ! user_wants_bitcode {
if let Some ( ref allocator_module ) = codegen_results . allocator_module {
if let Some ( ref path ) = allocator_module . bytecode {
ensure_removed ( sess . dcx ( ) , path ) ;
}
}
}
2022-08-24 16:40:58 +00:00
}
2024-03-28 11:43:35 +00:00
2024-04-06 15:22:21 +00:00
if sess . opts . json_artifact_notifications {
if codegen_results . modules . len ( ) = = 1 {
codegen_results . modules [ 0 ] . for_each_output ( | _path , ty | {
if sess . opts . output_types . contains_key ( & ty ) {
let descr = ty . shorthand ( ) ;
// for single cgu file is renamed to drop cgu specific suffix
// so we regenerate it the same way
let path = crate_output . path ( ty ) ;
sess . dcx ( ) . emit_artifact_notification ( path . as_path ( ) , descr ) ;
}
} ) ;
} else {
for module in & codegen_results . modules {
module . for_each_output ( | path , ty | {
if sess . opts . output_types . contains_key ( & ty ) {
let descr = ty . shorthand ( ) ;
sess . dcx ( ) . emit_artifact_notification ( & path , descr ) ;
}
} ) ;
}
}
}
2024-03-28 11:43:35 +00:00
// We leave the following files around by default:
// - #crate#.o
// - #crate#.crate.metadata.o
// - #crate#.bc
// These are used in linking steps and will be cleaned up afterward.
2022-08-24 16:40:58 +00:00
}
2024-12-06 12:10:30 +00:00
fn make_module ( sess : & Session , name : String ) -> UnwindModule < ObjectModule > {
2025-03-06 15:02:29 +00:00
let isa = crate ::build_isa ( sess , false ) ;
2022-08-24 16:40:58 +00:00
2021-09-19 11:56:58 +00:00
let mut builder =
ObjectBuilder ::new ( isa , name + " .o " , cranelift_module ::default_libcall_names ( ) ) . unwrap ( ) ;
2025-01-20 15:30:04 +00:00
// Disable function sections by default on MSVC as it causes significant slowdowns with link.exe.
// Maybe link.exe has exponential behavior when there are many sections with the same name? Also
// explicitly disable it on MinGW as rustc already disables it by default on MinGW and as such
// isn't tested. If rustc enables it in the future on MinGW, we can re-enable it too once it has
// been on MinGW.
let default_function_sections = sess . target . function_sections & & ! sess . target . is_like_windows ;
2025-01-05 15:44:46 +00:00
builder . per_function_section (
2025-01-20 15:30:04 +00:00
sess . opts . unstable_opts . function_sections . unwrap_or ( default_function_sections ) ,
2025-01-05 15:44:46 +00:00
) ;
2025-01-20 15:30:04 +00:00
2024-06-30 11:28:14 +00:00
UnwindModule ::new ( ObjectModule ::new ( builder ) , true )
2021-09-19 11:56:58 +00:00
}
2022-08-24 16:40:58 +00:00
fn emit_cgu (
output_filenames : & OutputFilenames ,
2025-04-06 23:50:16 +00:00
invocation_temp : Option < & str > ,
2022-08-24 16:40:58 +00:00
prof : & SelfProfilerRef ,
2020-03-12 10:58:59 +00:00
name : String ,
2024-06-30 11:28:14 +00:00
module : UnwindModule < ObjectModule > ,
2022-08-24 16:40:58 +00:00
debug : Option < DebugContext > ,
global_asm_object_file : Option < PathBuf > ,
2024-01-26 18:33:45 +00:00
producer : & str ,
2022-08-24 16:40:58 +00:00
) -> Result < ModuleCodegenResult , String > {
2020-03-12 10:58:59 +00:00
let mut product = module . finish ( ) ;
if let Some ( mut debug ) = debug {
debug . emit ( & mut product ) ;
}
2024-01-26 18:33:45 +00:00
let module_regular = emit_module (
output_filenames ,
2025-04-06 23:50:16 +00:00
invocation_temp ,
2024-01-26 18:33:45 +00:00
prof ,
product . object ,
ModuleKind ::Regular ,
name . clone ( ) ,
producer ,
) ? ;
2022-08-24 16:40:58 +00:00
Ok ( ModuleCodegenResult {
module_regular ,
module_global_asm : global_asm_object_file . map ( | global_asm_object_file | CompiledModule {
name : format ! ( " {name}.asm " ) ,
kind : ModuleKind ::Regular ,
object : Some ( global_asm_object_file ) ,
dwarf_object : None ,
bytecode : None ,
2024-04-06 13:07:54 +00:00
assembly : None ,
llvm_ir : None ,
2024-07-28 20:54:14 +00:00
links_from_incr_cache : Vec ::new ( ) ,
2022-08-24 16:40:58 +00:00
} ) ,
existing_work_product : None ,
} )
}
2022-02-23 10:49:34 +00:00
2022-08-24 16:40:58 +00:00
fn emit_module (
output_filenames : & OutputFilenames ,
2025-04-06 23:50:16 +00:00
invocation_temp : Option < & str > ,
2022-08-24 16:40:58 +00:00
prof : & SelfProfilerRef ,
2023-01-24 17:56:42 +00:00
mut object : cranelift_object ::object ::write ::Object < '_ > ,
2022-08-24 16:40:58 +00:00
kind : ModuleKind ,
name : String ,
2024-01-26 18:33:45 +00:00
producer_str : & str ,
2022-08-24 16:40:58 +00:00
) -> Result < CompiledModule , String > {
2023-01-24 17:56:42 +00:00
if object . format ( ) = = cranelift_object ::object ::BinaryFormat ::Elf {
let comment_section = object . add_section (
Vec ::new ( ) ,
b " .comment " . to_vec ( ) ,
cranelift_object ::object ::SectionKind ::OtherString ,
) ;
let mut producer = vec! [ 0 ] ;
2024-01-26 18:33:45 +00:00
producer . extend ( producer_str . as_bytes ( ) ) ;
2023-01-24 17:56:42 +00:00
producer . push ( 0 ) ;
object . set_section_data ( comment_section , producer , 1 ) ;
}
2025-04-06 23:50:16 +00:00
let tmp_file = output_filenames . temp_path_for_cgu ( OutputType ::Object , & name , invocation_temp ) ;
2024-11-09 13:48:06 +00:00
let file = match File ::create ( & tmp_file ) {
2022-08-24 16:40:58 +00:00
Ok ( file ) = > file ,
Err ( err ) = > return Err ( format! ( " error creating object file: {} " , err ) ) ,
} ;
2022-02-23 10:49:34 +00:00
2024-11-09 13:48:06 +00:00
let mut file = BufWriter ::new ( file ) ;
2022-08-24 16:40:58 +00:00
if let Err ( err ) = object . write_stream ( & mut file ) {
return Err ( format! ( " error writing object file: {} " , err ) ) ;
2020-08-08 14:14:11 +00:00
}
2024-11-09 13:48:06 +00:00
let file = match file . into_inner ( ) {
Ok ( file ) = > file ,
Err ( err ) = > return Err ( format! ( " error writing object file: {} " , err ) ) ,
} ;
2020-03-12 10:48:17 +00:00
2024-12-06 12:10:30 +00:00
if prof . enabled ( ) {
prof . artifact_size (
" object_file " ,
tmp_file . file_name ( ) . unwrap ( ) . to_string_lossy ( ) ,
file . metadata ( ) . unwrap ( ) . len ( ) ,
) ;
}
2020-03-12 10:48:17 +00:00
2024-04-06 13:07:54 +00:00
Ok ( CompiledModule {
name ,
kind ,
object : Some ( tmp_file ) ,
dwarf_object : None ,
bytecode : None ,
assembly : None ,
llvm_ir : None ,
2024-07-28 20:54:14 +00:00
links_from_incr_cache : Vec ::new ( ) ,
2024-04-06 13:07:54 +00:00
} )
2020-03-12 10:58:59 +00:00
}
fn reuse_workproduct_for_cgu (
tcx : TyCtxt < '_ > ,
2020-04-05 11:48:26 +00:00
cgu : & CodegenUnit < '_ > ,
2022-08-24 16:40:58 +00:00
) -> Result < ModuleCodegenResult , String > {
2022-05-13 10:32:03 +00:00
let work_product = cgu . previous_work_product ( tcx ) ;
2025-04-06 23:50:16 +00:00
let obj_out_regular = tcx . output_filenames ( ( ) ) . temp_path_for_cgu (
OutputType ::Object ,
cgu . name ( ) . as_str ( ) ,
tcx . sess . invocation_temp . as_deref ( ) ,
) ;
2022-08-24 16:40:58 +00:00
let source_file_regular = rustc_incremental ::in_incr_comp_dir_sess (
2022-07-04 13:38:42 +00:00
& tcx . sess ,
& work_product . saved_files . get ( " o " ) . expect ( " no saved object file in work product " ) ,
) ;
2022-08-24 16:40:58 +00:00
if let Err ( err ) = rustc_fs_util ::link_or_copy ( & source_file_regular , & obj_out_regular ) {
return Err ( format! (
2022-05-15 11:31:28 +00:00
" unable to copy {} to {}: {} " ,
2022-08-24 16:40:58 +00:00
source_file_regular . display ( ) ,
obj_out_regular . display ( ) ,
2022-05-15 11:31:28 +00:00
err
) ) ;
2020-03-12 10:58:59 +00:00
}
2025-02-25 23:41:49 +00:00
2022-08-24 16:40:58 +00:00
let obj_out_global_asm =
crate ::global_asm ::add_file_stem_postfix ( obj_out_regular . clone ( ) , " .asm " ) ;
2025-02-25 23:41:49 +00:00
let source_file_global_asm = if let Some ( asm_o ) = work_product . saved_files . get ( " asm.o " ) {
2022-08-24 16:40:58 +00:00
let source_file_global_asm = rustc_incremental ::in_incr_comp_dir_sess ( & tcx . sess , asm_o ) ;
if let Err ( err ) = rustc_fs_util ::link_or_copy ( & source_file_global_asm , & obj_out_global_asm )
{
return Err ( format! (
" unable to copy {} to {}: {} " ,
2025-02-25 23:41:49 +00:00
source_file_global_asm . display ( ) ,
obj_out_global_asm . display ( ) ,
2022-08-24 16:40:58 +00:00
err
) ) ;
}
2025-02-25 23:41:49 +00:00
Some ( source_file_global_asm )
2022-08-24 16:40:58 +00:00
} else {
2025-02-25 23:41:49 +00:00
None
2022-08-24 16:40:58 +00:00
} ;
2020-03-12 10:48:17 +00:00
2022-08-24 16:40:58 +00:00
Ok ( ModuleCodegenResult {
module_regular : CompiledModule {
name : cgu . name ( ) . to_string ( ) ,
kind : ModuleKind ::Regular ,
object : Some ( obj_out_regular ) ,
dwarf_object : None ,
bytecode : None ,
2024-04-06 13:07:54 +00:00
assembly : None ,
llvm_ir : None ,
2025-02-25 23:41:49 +00:00
links_from_incr_cache : vec ! [ source_file_regular ] ,
2022-08-24 16:40:58 +00:00
} ,
2025-02-25 23:41:49 +00:00
module_global_asm : source_file_global_asm . map ( | source_file | CompiledModule {
2023-02-15 11:43:41 +00:00
name : cgu . name ( ) . to_string ( ) ,
kind : ModuleKind ::Regular ,
object : Some ( obj_out_global_asm ) ,
dwarf_object : None ,
bytecode : None ,
2024-04-06 13:07:54 +00:00
assembly : None ,
llvm_ir : None ,
2025-02-25 23:41:49 +00:00
links_from_incr_cache : vec ! [ source_file ] ,
2023-02-15 11:43:41 +00:00
} ) ,
2022-08-24 16:40:58 +00:00
existing_work_product : Some ( ( cgu . work_product_id ( ) , work_product ) ) ,
} )
2020-03-12 10:58:59 +00:00
}
2020-03-12 10:48:17 +00:00
2024-12-06 12:10:30 +00:00
fn codegen_cgu_content (
tcx : TyCtxt < '_ > ,
module : & mut dyn Module ,
cgu_name : rustc_span ::Symbol ,
) -> ( CodegenCx , Vec < CodegenedFunction > ) {
let _timer = tcx . prof . generic_activity_with_arg ( " codegen cgu " , cgu_name . as_str ( ) ) ;
let cgu = tcx . codegen_unit ( cgu_name ) ;
let mono_items = cgu . items_in_deterministic_order ( tcx ) ;
let mut cx = crate ::CodegenCx ::new (
tcx ,
module . isa ( ) ,
tcx . sess . opts . debuginfo ! = DebugInfo ::None ,
cgu_name ,
) ;
let mut type_dbg = TypeDebugContext ::default ( ) ;
super ::predefine_mono_items ( tcx , module , & mono_items ) ;
let mut codegened_functions = vec! [ ] ;
2024-12-12 20:31:20 +00:00
for ( mono_item , item_data ) in mono_items {
2024-12-06 12:10:30 +00:00
match mono_item {
2024-12-12 20:31:20 +00:00
MonoItem ::Fn ( instance ) = > {
if tcx . codegen_fn_attrs ( instance . def_id ( ) ) . flags . contains ( CodegenFnAttrFlags ::NAKED )
{
rustc_codegen_ssa ::mir ::naked_asm ::codegen_naked_asm (
& mut GlobalAsmContext { tcx , global_asm : & mut cx . global_asm } ,
instance ,
MonoItemData {
linkage : RLinkage ::External ,
visibility : if item_data . linkage = = RLinkage ::Internal {
Visibility ::Hidden
} else {
item_data . visibility
} ,
.. item_data
} ,
) ;
continue ;
}
let codegened_function = crate ::base ::codegen_fn (
2024-12-06 12:10:30 +00:00
tcx ,
& mut cx ,
& mut type_dbg ,
Function ::new ( ) ,
module ,
2024-12-12 20:31:20 +00:00
instance ,
) ;
codegened_functions . push ( codegened_function ) ;
2024-12-06 12:10:30 +00:00
}
MonoItem ::Static ( def_id ) = > {
let data_id = crate ::constant ::codegen_static ( tcx , module , def_id ) ;
if let Some ( debug_context ) = & mut cx . debug_context {
debug_context . define_static ( tcx , & mut type_dbg , def_id , data_id ) ;
}
}
MonoItem ::GlobalAsm ( item_id ) = > {
2024-12-13 10:01:09 +00:00
rustc_codegen_ssa ::base ::codegen_global_asm (
& mut GlobalAsmContext { tcx , global_asm : & mut cx . global_asm } ,
item_id ,
) ;
2024-12-06 12:10:30 +00:00
}
}
}
crate ::main_shim ::maybe_create_entry_wrapper ( tcx , module , false , cgu . is_primary ( ) ) ;
( cx , codegened_functions )
}
2021-03-05 18:12:59 +00:00
fn module_codegen (
tcx : TyCtxt < '_ > ,
2024-12-06 12:10:30 +00:00
( global_asm_config , cgu_name , token ) : (
2022-08-24 16:40:58 +00:00
Arc < GlobalAsmConfig > ,
rustc_span ::Symbol ,
ConcurrencyLimiterToken ,
) ,
) -> OngoingModuleCodegen {
2024-12-06 12:10:30 +00:00
let mut module = make_module ( tcx . sess , cgu_name . as_str ( ) . to_string ( ) ) ;
2022-08-24 16:40:58 +00:00
2024-12-06 12:10:30 +00:00
let ( mut cx , codegened_functions ) = codegen_cgu_content ( tcx , & mut module , cgu_name ) ;
2022-08-24 16:40:58 +00:00
2024-12-06 12:10:30 +00:00
let cgu_name = cgu_name . as_str ( ) . to_owned ( ) ;
2020-07-09 14:55:38 +00:00
2024-01-26 18:33:45 +00:00
let producer = crate ::debuginfo ::producer ( tcx . sess ) ;
2024-12-06 12:10:30 +00:00
let profiler = tcx . prof . clone ( ) ;
2022-08-24 16:40:58 +00:00
OngoingModuleCodegen ::Async ( std ::thread ::spawn ( move | | {
2024-12-06 12:10:30 +00:00
profiler . clone ( ) . generic_activity_with_arg ( " compile functions " , & * cgu_name ) . run ( | | {
2023-09-10 11:15:46 +00:00
cranelift_codegen ::timing ::set_thread_profiler ( Box ::new ( super ::MeasuremeProfiler (
2024-12-06 12:10:30 +00:00
profiler . clone ( ) ,
2023-09-10 11:15:46 +00:00
) ) ) ;
let mut cached_context = Context ::new ( ) ;
for codegened_func in codegened_functions {
2024-12-06 12:10:30 +00:00
crate ::base ::compile_fn (
& mut cx ,
& profiler ,
& mut cached_context ,
& mut module ,
codegened_func ,
) ;
2023-09-10 11:15:46 +00:00
}
} ) ;
2020-07-09 14:55:38 +00:00
2023-09-10 11:15:46 +00:00
let global_asm_object_file =
2024-12-06 12:10:30 +00:00
profiler . generic_activity_with_arg ( " compile assembly " , & * cgu_name ) . run ( | | {
2025-04-06 23:50:16 +00:00
crate ::global_asm ::compile_global_asm (
& global_asm_config ,
& cgu_name ,
& cx . global_asm ,
cx . invocation_temp . as_deref ( ) ,
)
2022-08-24 16:40:58 +00:00
} ) ? ;
2023-09-10 11:15:46 +00:00
let codegen_result =
2024-12-06 12:10:30 +00:00
profiler . generic_activity_with_arg ( " write object file " , & * cgu_name ) . run ( | | {
2023-02-09 11:38:16 +00:00
emit_cgu (
& global_asm_config . output_filenames ,
2025-04-06 23:50:16 +00:00
cx . invocation_temp . as_deref ( ) ,
2024-12-06 12:10:30 +00:00
& profiler ,
2023-02-09 11:38:16 +00:00
cgu_name ,
module ,
cx . debug_context ,
global_asm_object_file ,
2024-01-26 18:33:45 +00:00
& producer ,
2023-02-09 11:38:16 +00:00
)
} ) ;
2022-08-24 16:40:58 +00:00
std ::mem ::drop ( token ) ;
codegen_result
} ) )
2020-03-12 10:58:59 +00:00
}
2024-12-06 12:10:30 +00:00
fn emit_metadata_module ( tcx : TyCtxt < '_ > , metadata : & EncodedMetadata ) -> CompiledModule {
use rustc_middle ::mir ::mono ::CodegenUnitNameBuilder ;
let _timer = tcx . sess . timer ( " write compressed metadata " ) ;
let cgu_name_builder = & mut CodegenUnitNameBuilder ::new ( tcx ) ;
let metadata_cgu_name = cgu_name_builder
. build_cgu_name ( LOCAL_CRATE , [ " crate " ] , Some ( " metadata " ) )
. as_str ( )
. to_string ( ) ;
2025-04-06 23:50:16 +00:00
let tmp_file = tcx . output_filenames ( ( ) ) . temp_path_for_cgu (
OutputType ::Metadata ,
& metadata_cgu_name ,
tcx . sess . invocation_temp . as_deref ( ) ,
) ;
2024-12-06 12:10:30 +00:00
let symbol_name = rustc_middle ::middle ::exported_symbols ::metadata_symbol_name ( tcx ) ;
let obj = create_compressed_metadata_file ( tcx . sess , metadata , & symbol_name ) ;
if let Err ( err ) = std ::fs ::write ( & tmp_file , obj ) {
tcx . dcx ( ) . fatal ( format! ( " error writing metadata object file: {} " , err ) ) ;
}
CompiledModule {
name : metadata_cgu_name ,
kind : ModuleKind ::Metadata ,
object : Some ( tmp_file ) ,
dwarf_object : None ,
bytecode : None ,
assembly : None ,
llvm_ir : None ,
2024-07-28 20:54:14 +00:00
links_from_incr_cache : Vec ::new ( ) ,
2024-12-06 12:10:30 +00:00
}
}
fn emit_allocator_module ( tcx : TyCtxt < '_ > ) -> Option < CompiledModule > {
let mut allocator_module = make_module ( tcx . sess , " allocator_shim " . to_string ( ) ) ;
let created_alloc_shim = crate ::allocator ::codegen ( tcx , & mut allocator_module ) ;
if created_alloc_shim {
let product = allocator_module . finish ( ) ;
match emit_module (
tcx . output_filenames ( ( ) ) ,
2025-04-06 23:50:16 +00:00
tcx . sess . invocation_temp . as_deref ( ) ,
2024-12-06 12:10:30 +00:00
& tcx . sess . prof ,
product . object ,
ModuleKind ::Allocator ,
" allocator_shim " . to_owned ( ) ,
& crate ::debuginfo ::producer ( tcx . sess ) ,
) {
Ok ( allocator_module ) = > Some ( allocator_module ) ,
Err ( err ) = > tcx . dcx ( ) . fatal ( err ) ,
}
} else {
None
}
}
2021-04-30 12:49:58 +00:00
pub ( crate ) fn run_aot (
2020-03-12 10:58:59 +00:00
tcx : TyCtxt < '_ > ,
metadata : EncodedMetadata ,
need_metadata_module : bool ,
2022-08-24 16:40:58 +00:00
) -> Box < OngoingCodegen > {
2023-10-24 12:22:23 +00:00
// FIXME handle `-Ctarget-cpu=native`
let target_cpu = match tcx . sess . opts . cg . target_cpu {
Some ( ref name ) = > name ,
None = > tcx . sess . target . cpu . as_ref ( ) ,
}
. to_owned ( ) ;
2020-04-18 19:13:09 +00:00
let cgus = if tcx . sess . opts . output_types . should_codegen ( ) {
2025-01-27 08:11:02 +00:00
tcx . collect_and_partition_mono_items ( ( ) ) . codegen_units
2020-04-18 19:13:09 +00:00
} else {
// If only `--emit metadata` is used, we shouldn't perform any codegen.
// Also `tcx.collect_and_partition_mono_items` may panic in that case.
2023-10-24 12:22:23 +00:00
return Box ::new ( OngoingCodegen {
modules : vec ! [ ] ,
allocator_module : None ,
metadata_module : None ,
metadata ,
crate_info : CrateInfo ::new ( tcx , target_cpu ) ,
2024-12-12 11:40:36 +00:00
concurrency_limiter : ConcurrencyLimiter ::new ( 0 ) ,
2023-10-24 12:22:23 +00:00
} ) ;
2020-04-18 19:13:09 +00:00
} ;
2020-03-12 10:48:17 +00:00
if tcx . dep_graph . is_fully_enabled ( ) {
2023-03-15 14:41:48 +00:00
for cgu in cgus {
2025-01-30 05:20:09 +00:00
tcx . ensure_ok ( ) . codegen_unit ( cgu . name ( ) ) ;
2020-03-12 10:48:17 +00:00
}
}
2023-09-19 11:23:35 +00:00
// Calculate the CGU reuse
let cgu_reuse = tcx . sess . time ( " find_cgu_reuse " , | | {
cgus . iter ( ) . map ( | cgu | determine_cgu_reuse ( tcx , & cgu ) ) . collect ::< Vec < _ > > ( )
} ) ;
rustc_codegen_ssa ::assert_module_sources ::assert_module_sources ( tcx , & | cgu_reuse_tracker | {
for ( i , cgu ) in cgus . iter ( ) . enumerate ( ) {
let cgu_reuse = cgu_reuse [ i ] ;
cgu_reuse_tracker . set_actual_reuse ( cgu . name ( ) . as_str ( ) , cgu_reuse ) ;
}
} ) ;
2022-08-24 16:40:58 +00:00
let global_asm_config = Arc ::new ( crate ::global_asm ::GlobalAsmConfig ::new ( tcx ) ) ;
2024-12-06 12:10:30 +00:00
let disable_incr_cache = disable_incr_cache ( ) ;
2024-05-13 13:26:33 +00:00
let ( todo_cgus , done_cgus ) =
cgus . into_iter ( ) . enumerate ( ) . partition ::< Vec < _ > , _ > ( | & ( i , _ ) | match cgu_reuse [ i ] {
2024-12-06 12:10:30 +00:00
_ if disable_incr_cache = > true ,
2024-05-13 13:26:33 +00:00
CguReuse ::No = > true ,
CguReuse ::PreLto | CguReuse ::PostLto = > false ,
} ) ;
2024-12-12 11:40:36 +00:00
let concurrency_limiter = IntoDynSyncSend ( ConcurrencyLimiter ::new ( todo_cgus . len ( ) ) ) ;
2022-08-24 16:40:58 +00:00
2025-03-26 23:19:52 +00:00
let modules : Vec < _ > =
tcx . sess . time ( " codegen mono items " , | | {
let modules : Vec < _ > = par_map ( todo_cgus , | ( _ , cgu ) | {
let dep_node = cgu . codegen_dep_node ( tcx ) ;
let ( module , _ ) = tcx . dep_graph . with_task (
2024-05-13 13:26:33 +00:00
dep_node ,
tcx ,
2024-12-06 12:10:30 +00:00
( global_asm_config . clone ( ) , cgu . name ( ) , concurrency_limiter . acquire ( tcx . dcx ( ) ) ) ,
2024-05-13 13:26:33 +00:00
module_codegen ,
Some ( rustc_middle ::dep_graph ::hash_result ) ,
2025-03-26 23:19:52 +00:00
) ;
IntoDynSyncSend ( module )
} ) ;
modules
2024-05-13 13:26:33 +00:00
. into_iter ( )
2025-03-26 23:19:52 +00:00
. map ( | module | module . 0 )
. chain ( done_cgus . into_iter ( ) . map ( | ( _ , cgu ) | {
OngoingModuleCodegen ::Sync ( reuse_workproduct_for_cgu ( tcx , cgu ) )
} ) )
. collect ( )
} ) ;
2020-03-12 10:48:17 +00:00
2024-12-06 12:10:30 +00:00
let allocator_module = emit_allocator_module ( tcx ) ;
2022-08-24 16:40:58 +00:00
2024-12-06 12:10:30 +00:00
let metadata_module =
if need_metadata_module { Some ( emit_metadata_module ( tcx , & metadata ) ) } else { None } ;
2020-03-12 10:48:17 +00:00
2022-08-24 16:40:58 +00:00
Box ::new ( OngoingCodegen {
modules ,
allocator_module ,
metadata_module ,
metadata ,
crate_info : CrateInfo ::new ( tcx , target_cpu ) ,
2024-05-13 13:26:33 +00:00
concurrency_limiter : concurrency_limiter . 0 ,
2022-08-24 16:40:58 +00:00
} )
2020-07-09 14:55:38 +00:00
}