1 use crate::back
::metadata
::create_compressed_metadata_file
;
2 use crate::back
::write
::{
3 compute_per_cgu_lto_type
, start_async_codegen
, submit_codegened_module_to_llvm
,
4 submit_post_lto_module_to_llvm
, submit_pre_lto_module_to_llvm
, ComputedLtoType
, OngoingCodegen
,
6 use crate::common
::{IntPredicate, RealPredicate, TypeKind}
;
9 use crate::mir
::operand
::OperandValue
;
10 use crate::mir
::place
::PlaceRef
;
12 use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}
;
14 use rustc_attr
as attr
;
15 use rustc_data_structures
::fx
::FxHashMap
;
16 use rustc_data_structures
::profiling
::{get_resident_set_size, print_time_passes_entry}
;
17 use rustc_data_structures
::sync
::{par_iter, ParallelIterator}
;
19 use rustc_hir
::def_id
::{DefId, LOCAL_CRATE}
;
20 use rustc_hir
::lang_items
::LangItem
;
21 use rustc_index
::vec
::Idx
;
22 use rustc_metadata
::EncodedMetadata
;
23 use rustc_middle
::middle
::codegen_fn_attrs
::CodegenFnAttrs
;
24 use rustc_middle
::middle
::exported_symbols
;
25 use rustc_middle
::middle
::lang_items
;
26 use rustc_middle
::mir
::mono
::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}
;
27 use rustc_middle
::ty
::layout
::{HasTyCtxt, LayoutOf, TyAndLayout}
;
28 use rustc_middle
::ty
::query
::Providers
;
29 use rustc_middle
::ty
::{self, Instance, Ty, TyCtxt}
;
30 use rustc_session
::cgu_reuse_tracker
::CguReuse
;
31 use rustc_session
::config
::{self, EntryFnType, OutputType}
;
32 use rustc_session
::Session
;
33 use rustc_span
::symbol
::sym
;
34 use rustc_target
::abi
::{Align, VariantIdx}
;
36 use std
::convert
::TryFrom
;
37 use std
::ops
::{Deref, DerefMut}
;
38 use std
::time
::{Duration, Instant}
;
40 use itertools
::Itertools
;
42 pub fn bin_op_to_icmp_predicate(op
: hir
::BinOpKind
, signed
: bool
) -> IntPredicate
{
44 hir
::BinOpKind
::Eq
=> IntPredicate
::IntEQ
,
45 hir
::BinOpKind
::Ne
=> IntPredicate
::IntNE
,
46 hir
::BinOpKind
::Lt
=> {
53 hir
::BinOpKind
::Le
=> {
60 hir
::BinOpKind
::Gt
=> {
67 hir
::BinOpKind
::Ge
=> {
75 "comparison_op_to_icmp_predicate: expected comparison operator, \
82 pub fn bin_op_to_fcmp_predicate(op
: hir
::BinOpKind
) -> RealPredicate
{
84 hir
::BinOpKind
::Eq
=> RealPredicate
::RealOEQ
,
85 hir
::BinOpKind
::Ne
=> RealPredicate
::RealUNE
,
86 hir
::BinOpKind
::Lt
=> RealPredicate
::RealOLT
,
87 hir
::BinOpKind
::Le
=> RealPredicate
::RealOLE
,
88 hir
::BinOpKind
::Gt
=> RealPredicate
::RealOGT
,
89 hir
::BinOpKind
::Ge
=> RealPredicate
::RealOGE
,
92 "comparison_op_to_fcmp_predicate: expected comparison operator, \
100 pub fn compare_simd_types
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
108 let signed
= match t
.kind() {
110 let cmp
= bin_op_to_fcmp_predicate(op
);
111 let cmp
= bx
.fcmp(cmp
, lhs
, rhs
);
112 return bx
.sext(cmp
, ret_ty
);
114 ty
::Uint(_
) => false,
116 _
=> bug
!("compare_simd_types: invalid SIMD type"),
119 let cmp
= bin_op_to_icmp_predicate(op
, signed
);
120 let cmp
= bx
.icmp(cmp
, lhs
, rhs
);
121 // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
122 // to get the correctly sized type. This will compile to a single instruction
123 // once the IR is converted to assembly if the SIMD instruction is supported
124 // by the target architecture.
128 /// Retrieves the information we are losing (making dynamic) in an unsizing
131 /// The `old_info` argument is a bit odd. It is intended for use in an upcast,
132 /// where the new vtable for an object will be derived from the old one.
133 pub fn unsized_info
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
137 old_info
: Option
<Bx
::Value
>,
140 let (source
, target
) =
141 cx
.tcx().struct_lockstep_tails_erasing_lifetimes(source
, target
, bx
.param_env());
142 match (source
.kind(), target
.kind()) {
143 (&ty
::Array(_
, len
), &ty
::Slice(_
)) => {
144 cx
.const_usize(len
.eval_usize(cx
.tcx(), ty
::ParamEnv
::reveal_all()))
146 (&ty
::Dynamic(ref data_a
, ..), &ty
::Dynamic(ref data_b
, ..)) => {
148 old_info
.expect("unsized_info: missing old info for trait upcasting coercion");
149 if data_a
.principal_def_id() == data_b
.principal_def_id() {
153 // trait upcasting coercion
156 cx
.tcx().vtable_trait_upcasting_coercion_new_vptr_slot((source
, target
));
158 if let Some(entry_idx
) = vptr_entry_idx
{
159 let ptr_ty
= cx
.type_i8p();
160 let ptr_align
= cx
.tcx().data_layout
.pointer_align
.abi
;
161 let llvtable
= bx
.pointercast(old_info
, bx
.type_ptr_to(ptr_ty
));
162 let gep
= bx
.inbounds_gep(
165 &[bx
.const_usize(u64::try_from(entry_idx
).unwrap())],
167 let new_vptr
= bx
.load(ptr_ty
, gep
, ptr_align
);
168 bx
.nonnull_metadata(new_vptr
);
169 // Vtable loads are invariant.
170 bx
.set_invariant_load(new_vptr
);
176 (_
, &ty
::Dynamic(ref data
, ..)) => {
177 let vtable_ptr_ty
= cx
.scalar_pair_element_backend_type(
178 cx
.layout_of(cx
.tcx().mk_mut_ptr(target
)),
182 cx
.const_ptrcast(meth
::get_vtable(cx
, source
, data
.principal()), vtable_ptr_ty
)
184 _
=> bug
!("unsized_info: invalid unsizing {:?} -> {:?}", source
, target
),
188 /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
189 pub fn unsize_ptr
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
194 old_info
: Option
<Bx
::Value
>,
195 ) -> (Bx
::Value
, Bx
::Value
) {
196 debug
!("unsize_ptr: {:?} => {:?}", src_ty
, dst_ty
);
197 match (src_ty
.kind(), dst_ty
.kind()) {
198 (&ty
::Ref(_
, a
, _
), &ty
::Ref(_
, b
, _
) | &ty
::RawPtr(ty
::TypeAndMut { ty: b, .. }
))
199 | (&ty
::RawPtr(ty
::TypeAndMut { ty: a, .. }
), &ty
::RawPtr(ty
::TypeAndMut { ty: b, .. }
)) => {
200 assert_eq
!(bx
.cx().type_is_sized(a
), old_info
.is_none());
201 let ptr_ty
= bx
.cx().type_ptr_to(bx
.cx().backend_type(bx
.cx().layout_of(b
)));
202 (bx
.pointercast(src
, ptr_ty
), unsized_info(bx
, a
, b
, old_info
))
204 (&ty
::Adt(def_a
, _
), &ty
::Adt(def_b
, _
)) => {
205 assert_eq
!(def_a
, def_b
);
206 let src_layout
= bx
.cx().layout_of(src_ty
);
207 let dst_layout
= bx
.cx().layout_of(dst_ty
);
208 if src_ty
== dst_ty
{
209 return (src
, old_info
.unwrap());
211 let mut result
= None
;
212 for i
in 0..src_layout
.fields
.count() {
213 let src_f
= src_layout
.field(bx
.cx(), i
);
214 assert_eq
!(src_layout
.fields
.offset(i
).bytes(), 0);
215 assert_eq
!(dst_layout
.fields
.offset(i
).bytes(), 0);
219 assert_eq
!(src_layout
.size
, src_f
.size
);
221 let dst_f
= dst_layout
.field(bx
.cx(), i
);
222 assert_ne
!(src_f
.ty
, dst_f
.ty
);
223 assert_eq
!(result
, None
);
224 result
= Some(unsize_ptr(bx
, src
, src_f
.ty
, dst_f
.ty
, old_info
));
226 let (lldata
, llextra
) = result
.unwrap();
227 let lldata_ty
= bx
.cx().scalar_pair_element_backend_type(dst_layout
, 0, true);
228 let llextra_ty
= bx
.cx().scalar_pair_element_backend_type(dst_layout
, 1, true);
229 // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
230 (bx
.bitcast(lldata
, lldata_ty
), bx
.bitcast(llextra
, llextra_ty
))
232 _
=> bug
!("unsize_ptr: called on bad types"),
236 /// Coerces `src`, which is a reference to a value of type `src_ty`,
237 /// to a value of type `dst_ty`, and stores the result in `dst`.
238 pub fn coerce_unsized_into
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
240 src
: PlaceRef
<'tcx
, Bx
::Value
>,
241 dst
: PlaceRef
<'tcx
, Bx
::Value
>,
243 let src_ty
= src
.layout
.ty
;
244 let dst_ty
= dst
.layout
.ty
;
245 match (src_ty
.kind(), dst_ty
.kind()) {
246 (&ty
::Ref(..), &ty
::Ref(..) | &ty
::RawPtr(..)) | (&ty
::RawPtr(..), &ty
::RawPtr(..)) => {
247 let (base
, info
) = match bx
.load_operand(src
).val
{
248 OperandValue
::Pair(base
, info
) => unsize_ptr(bx
, base
, src_ty
, dst_ty
, Some(info
)),
249 OperandValue
::Immediate(base
) => unsize_ptr(bx
, base
, src_ty
, dst_ty
, None
),
250 OperandValue
::Ref(..) => bug
!(),
252 OperandValue
::Pair(base
, info
).store(bx
, dst
);
255 (&ty
::Adt(def_a
, _
), &ty
::Adt(def_b
, _
)) => {
256 assert_eq
!(def_a
, def_b
);
258 for i
in 0..def_a
.variants
[VariantIdx
::new(0)].fields
.len() {
259 let src_f
= src
.project_field(bx
, i
);
260 let dst_f
= dst
.project_field(bx
, i
);
262 if dst_f
.layout
.is_zst() {
266 if src_f
.layout
.ty
== dst_f
.layout
.ty
{
277 coerce_unsized_into(bx
, src_f
, dst_f
);
281 _
=> bug
!("coerce_unsized_into: invalid coercion {:?} -> {:?}", src_ty
, dst_ty
,),
285 pub fn cast_shift_expr_rhs
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
291 cast_shift_rhs(bx
, op
, lhs
, rhs
)
294 fn cast_shift_rhs
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
300 // Shifts may have any size int on the rhs
302 let mut rhs_llty
= bx
.cx().val_ty(rhs
);
303 let mut lhs_llty
= bx
.cx().val_ty(lhs
);
304 if bx
.cx().type_kind(rhs_llty
) == TypeKind
::Vector
{
305 rhs_llty
= bx
.cx().element_type(rhs_llty
)
307 if bx
.cx().type_kind(lhs_llty
) == TypeKind
::Vector
{
308 lhs_llty
= bx
.cx().element_type(lhs_llty
)
310 let rhs_sz
= bx
.cx().int_width(rhs_llty
);
311 let lhs_sz
= bx
.cx().int_width(lhs_llty
);
313 bx
.trunc(rhs
, lhs_llty
)
314 } else if lhs_sz
> rhs_sz
{
315 // FIXME (#1877: If in the future shifting by negative
316 // values is no longer undefined then this is wrong.
317 bx
.zext(rhs
, lhs_llty
)
326 /// Returns `true` if this session's target will use SEH-based unwinding.
328 /// This is only true for MSVC targets, and even then the 64-bit MSVC target
329 /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
330 /// 64-bit MinGW) instead of "full SEH".
331 pub fn wants_msvc_seh(sess
: &Session
) -> bool
{
332 sess
.target
.is_like_msvc
335 pub fn memcpy_ty
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
341 layout
: TyAndLayout
<'tcx
>,
344 let size
= layout
.size
.bytes();
349 bx
.memcpy(dst
, dst_align
, src
, src_align
, bx
.cx().const_usize(size
), flags
);
352 pub fn codegen_instance
<'a
, 'tcx
: 'a
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
353 cx
: &'a Bx
::CodegenCx
,
354 instance
: Instance
<'tcx
>,
356 // this is an info! to allow collecting monomorphization statistics
357 // and to allow finding the last function before LLVM aborts from
359 info
!("codegen_instance({})", instance
);
361 mir
::codegen_mir
::<Bx
>(cx
, instance
);
364 /// Creates the `main` function which will initialize the rust runtime and call
365 /// users main function.
366 pub fn maybe_create_entry_wrapper
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
367 cx
: &'a Bx
::CodegenCx
,
368 ) -> Option
<Bx
::Function
> {
369 let (main_def_id
, entry_type
) = cx
.tcx().entry_fn(())?
;
370 let main_is_local
= main_def_id
.is_local();
371 let instance
= Instance
::mono(cx
.tcx(), main_def_id
);
374 // We want to create the wrapper in the same codegen unit as Rust's main
376 if !cx
.codegen_unit().contains_item(&MonoItem
::Fn(instance
)) {
379 } else if !cx
.codegen_unit().is_primary() {
380 // We want to create the wrapper only when the codegen unit is the primary one
384 let main_llfn
= cx
.get_fn_addr(instance
);
386 let use_start_lang_item
= EntryFnType
::Start
!= entry_type
;
387 let entry_fn
= create_entry_fn
::<Bx
>(cx
, main_llfn
, main_def_id
, use_start_lang_item
);
388 return Some(entry_fn
);
390 fn create_entry_fn
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
391 cx
: &'a Bx
::CodegenCx
,
392 rust_main
: Bx
::Value
,
393 rust_main_def_id
: DefId
,
394 use_start_lang_item
: bool
,
396 // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
397 // depending on whether the target needs `argc` and `argv` to be passed in.
398 let llfty
= if cx
.sess().target
.main_needs_argc_argv
{
399 cx
.type_func(&[cx
.type_int(), cx
.type_ptr_to(cx
.type_i8p())], cx
.type_int())
401 cx
.type_func(&[], cx
.type_int())
404 let main_ret_ty
= cx
.tcx().fn_sig(rust_main_def_id
).output();
405 // Given that `main()` has no arguments,
406 // then its return type cannot have
407 // late-bound regions, since late-bound
408 // regions must appear in the argument
410 let main_ret_ty
= cx
.tcx().erase_regions(main_ret_ty
.no_bound_vars().unwrap());
412 let llfn
= match cx
.declare_c_main(llfty
) {
415 // FIXME: We should be smart and show a better diagnostic here.
416 let span
= cx
.tcx().def_span(rust_main_def_id
);
418 .struct_span_err(span
, "entry symbol `main` declared multiple times")
419 .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
421 cx
.sess().abort_if_errors();
426 // `main` should respect same config for frame pointer elimination as rest of code
427 cx
.set_frame_pointer_type(llfn
);
428 cx
.apply_target_cpu_attr(llfn
);
430 let llbb
= Bx
::append_block(&cx
, llfn
, "top");
431 let mut bx
= Bx
::build(&cx
, llbb
);
433 bx
.insert_reference_to_gdb_debug_scripts_section_global();
435 let isize_ty
= cx
.type_isize();
436 let i8pp_ty
= cx
.type_ptr_to(cx
.type_i8p());
437 let (arg_argc
, arg_argv
) = get_argc_argv(cx
, &mut bx
);
439 let (start_fn
, start_ty
, args
) = if use_start_lang_item
{
440 let start_def_id
= cx
.tcx().require_lang_item(LangItem
::Start
, None
);
441 let start_fn
= cx
.get_fn_addr(
442 ty
::Instance
::resolve(
444 ty
::ParamEnv
::reveal_all(),
446 cx
.tcx().intern_substs(&[main_ret_ty
.into()]),
451 let start_ty
= cx
.type_func(&[cx
.val_ty(rust_main
), isize_ty
, i8pp_ty
], isize_ty
);
452 (start_fn
, start_ty
, vec
![rust_main
, arg_argc
, arg_argv
])
454 debug
!("using user-defined start fn");
455 let start_ty
= cx
.type_func(&[isize_ty
, i8pp_ty
], isize_ty
);
456 (rust_main
, start_ty
, vec
![arg_argc
, arg_argv
])
459 let result
= bx
.call(start_ty
, start_fn
, &args
, None
);
460 let cast
= bx
.intcast(result
, cx
.type_int(), true);
467 /// Obtain the `argc` and `argv` values to pass to the rust start function.
468 fn get_argc_argv
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
469 cx
: &'a Bx
::CodegenCx
,
471 ) -> (Bx
::Value
, Bx
::Value
) {
472 if cx
.sess().target
.main_needs_argc_argv
{
473 // Params from native `main()` used as args for rust start function
474 let param_argc
= bx
.get_param(0);
475 let param_argv
= bx
.get_param(1);
476 let arg_argc
= bx
.intcast(param_argc
, cx
.type_isize(), true);
477 let arg_argv
= param_argv
;
480 // The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
481 let arg_argc
= bx
.const_int(cx
.type_int(), 0);
482 let arg_argv
= bx
.const_null(cx
.type_ptr_to(cx
.type_i8p()));
487 pub fn codegen_crate
<B
: ExtraBackendMethods
>(
491 metadata
: EncodedMetadata
,
492 need_metadata_module
: bool
,
493 ) -> OngoingCodegen
<B
> {
494 // Skip crate items and just output metadata in -Z no-codegen mode.
495 if tcx
.sess
.opts
.debugging_opts
.no_codegen
|| !tcx
.sess
.opts
.output_types
.should_codegen() {
496 let ongoing_codegen
= start_async_codegen(backend
, tcx
, target_cpu
, metadata
, None
, 1);
498 ongoing_codegen
.codegen_finished(tcx
);
500 ongoing_codegen
.check_for_errors(tcx
.sess
);
502 return ongoing_codegen
;
505 let cgu_name_builder
= &mut CodegenUnitNameBuilder
::new(tcx
);
507 // Run the monomorphization collector and partition the collected items into
509 let codegen_units
= tcx
.collect_and_partition_mono_items(()).1;
511 // Force all codegen_unit queries so they are already either red or green
512 // when compile_codegen_unit accesses them. We are not able to re-execute
513 // the codegen_unit query from just the DepNode, so an unknown color would
514 // lead to having to re-execute compile_codegen_unit, possibly
516 if tcx
.dep_graph
.is_fully_enabled() {
517 for cgu
in codegen_units
{
518 tcx
.ensure().codegen_unit(cgu
.name());
522 let metadata_module
= if need_metadata_module
{
523 // Emit compressed metadata object.
524 let metadata_cgu_name
=
525 cgu_name_builder
.build_cgu_name(LOCAL_CRATE
, &["crate"], Some("metadata")).to_string();
526 tcx
.sess
.time("write_compressed_metadata", || {
528 tcx
.output_filenames(()).temp_path(OutputType
::Metadata
, Some(&metadata_cgu_name
));
529 let data
= create_compressed_metadata_file(
532 &exported_symbols
::metadata_symbol_name(tcx
),
534 if let Err(err
) = std
::fs
::write(&file_name
, data
) {
535 tcx
.sess
.fatal(&format
!("error writing metadata object file: {}", err
));
537 Some(CompiledModule
{
538 name
: metadata_cgu_name
,
539 kind
: ModuleKind
::Metadata
,
540 object
: Some(file_name
),
549 let ongoing_codegen
= start_async_codegen(
557 let ongoing_codegen
= AbortCodegenOnDrop
::<B
>(Some(ongoing_codegen
));
559 // Codegen an allocator shim, if necessary.
561 // If the crate doesn't have an `allocator_kind` set then there's definitely
562 // no shim to generate. Otherwise we also check our dependency graph for all
563 // our output crate types. If anything there looks like its a `Dynamic`
564 // linkage, then it's already got an allocator shim and we'll be using that
565 // one instead. If nothing exists then it's our job to generate the
567 let any_dynamic_crate
= tcx
.dependency_formats(()).iter().any(|(_
, list
)| {
568 use rustc_middle
::middle
::dependency_format
::Linkage
;
569 list
.iter().any(|&linkage
| linkage
== Linkage
::Dynamic
)
571 let allocator_module
= if any_dynamic_crate
{
573 } else if let Some(kind
) = tcx
.allocator_kind(()) {
575 cgu_name_builder
.build_cgu_name(LOCAL_CRATE
, &["crate"], Some("allocator")).to_string();
576 let mut module_llvm
= backend
.new_metadata(tcx
, &llmod_id
);
577 tcx
.sess
.time("write_allocator_module", || {
578 backend
.codegen_allocator(
583 tcx
.lang_items().oom().is_some(),
587 Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }
)
592 if let Some(allocator_module
) = allocator_module
{
593 ongoing_codegen
.submit_pre_codegened_module_to_llvm(tcx
, allocator_module
);
596 // For better throughput during parallel processing by LLVM, we used to sort
597 // CGUs largest to smallest. This would lead to better thread utilization
598 // by, for example, preventing a large CGU from being processed last and
599 // having only one LLVM thread working while the rest remained idle.
601 // However, this strategy would lead to high memory usage, as it meant the
602 // LLVM-IR for all of the largest CGUs would be resident in memory at once.
604 // Instead, we can compromise by ordering CGUs such that the largest and
605 // smallest are first, second largest and smallest are next, etc. If there
606 // are large size variations, this can reduce memory usage significantly.
607 let codegen_units
: Vec
<_
> = {
608 let mut sorted_cgus
= codegen_units
.iter().collect
::<Vec
<_
>>();
609 sorted_cgus
.sort_by_cached_key(|cgu
| cgu
.size_estimate());
611 let (first_half
, second_half
) = sorted_cgus
.split_at(sorted_cgus
.len() / 2);
612 second_half
.iter().rev().interleave(first_half
).copied().collect()
615 // The non-parallel compiler can only translate codegen units to LLVM IR
616 // on a single thread, leading to a staircase effect where the N LLVM
617 // threads have to wait on the single codegen threads to generate work
618 // for them. The parallel compiler does not have this restriction, so
619 // we can pre-load the LLVM queue in parallel before handing off
620 // coordination to the OnGoingCodegen scheduler.
622 // This likely is a temporary measure. Once we don't have to support the
623 // non-parallel compiler anymore, we can compile CGUs end-to-end in
624 // parallel and get rid of the complicated scheduling logic.
625 let pre_compile_cgus
= |cgu_reuse
: &[CguReuse
]| {
626 if cfg
!(parallel_compiler
) {
627 tcx
.sess
.time("compile_first_CGU_batch", || {
628 // Try to find one CGU to compile per thread.
629 let cgus
: Vec
<_
> = cgu_reuse
632 .filter(|&(_
, reuse
)| reuse
== &CguReuse
::No
)
633 .take(tcx
.sess
.threads())
636 // Compile the found CGUs in parallel.
637 let start_time
= Instant
::now();
639 let pre_compiled_cgus
= par_iter(cgus
)
641 let module
= backend
.compile_codegen_unit(tcx
, codegen_units
[i
].name());
646 (pre_compiled_cgus
, start_time
.elapsed())
649 (FxHashMap
::default(), Duration
::new(0, 0))
653 let mut cgu_reuse
= Vec
::new();
654 let mut pre_compiled_cgus
: Option
<FxHashMap
<usize, _
>> = None
;
655 let mut total_codegen_time
= Duration
::new(0, 0);
656 let start_rss
= tcx
.sess
.time_passes().then(|| get_resident_set_size());
658 for (i
, cgu
) in codegen_units
.iter().enumerate() {
659 ongoing_codegen
.wait_for_signal_to_codegen_item();
660 ongoing_codegen
.check_for_errors(tcx
.sess
);
662 // Do some setup work in the first iteration
663 if pre_compiled_cgus
.is_none() {
664 // Calculate the CGU reuse
665 cgu_reuse
= tcx
.sess
.time("find_cgu_reuse", || {
666 codegen_units
.iter().map(|cgu
| determine_cgu_reuse(tcx
, &cgu
)).collect()
668 // Pre compile some CGUs
669 let (compiled_cgus
, codegen_time
) = pre_compile_cgus(&cgu_reuse
);
670 pre_compiled_cgus
= Some(compiled_cgus
);
671 total_codegen_time
+= codegen_time
;
674 let cgu_reuse
= cgu_reuse
[i
];
675 tcx
.sess
.cgu_reuse_tracker
.set_actual_reuse(cgu
.name().as_str(), cgu_reuse
);
680 if let Some(cgu
) = pre_compiled_cgus
.as_mut().unwrap().remove(&i
) {
683 let start_time
= Instant
::now();
684 let module
= backend
.compile_codegen_unit(tcx
, cgu
.name());
685 total_codegen_time
+= start_time
.elapsed();
688 // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
689 // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
690 // compilation hang on post-monomorphization errors.
691 tcx
.sess
.abort_if_errors();
693 submit_codegened_module_to_llvm(
695 &ongoing_codegen
.coordinator_send
,
701 CguReuse
::PreLto
=> {
702 submit_pre_lto_module_to_llvm(
705 &ongoing_codegen
.coordinator_send
,
706 CachedModuleCodegen
{
707 name
: cgu
.name().to_string(),
708 source
: cgu
.work_product(tcx
),
713 CguReuse
::PostLto
=> {
714 submit_post_lto_module_to_llvm(
716 &ongoing_codegen
.coordinator_send
,
717 CachedModuleCodegen
{
718 name
: cgu
.name().to_string(),
719 source
: cgu
.work_product(tcx
),
727 ongoing_codegen
.codegen_finished(tcx
);
729 // Since the main thread is sometimes blocked during codegen, we keep track
730 // -Ztime-passes output manually.
731 if tcx
.sess
.time_passes() {
732 let end_rss
= get_resident_set_size();
734 print_time_passes_entry(
735 "codegen_to_LLVM_IR",
742 ongoing_codegen
.check_for_errors(tcx
.sess
);
744 ongoing_codegen
.into_inner()
747 /// A curious wrapper structure whose only purpose is to call `codegen_aborted`
748 /// when it's dropped abnormally.
750 /// In the process of working on rust-lang/rust#55238 a mysterious segfault was
751 /// stumbled upon. The segfault was never reproduced locally, but it was
752 /// suspected to be related to the fact that codegen worker threads were
753 /// sticking around by the time the main thread was exiting, causing issues.
755 /// This structure is an attempt to fix that issue where the `codegen_aborted`
756 /// message will block until all workers have finished. This should ensure that
757 /// even if the main codegen thread panics we'll wait for pending work to
758 /// complete before returning from the main thread, hopefully avoiding
761 /// If you see this comment in the code, then it means that this workaround
762 /// worked! We may yet one day track down the mysterious cause of that
764 struct AbortCodegenOnDrop
<B
: ExtraBackendMethods
>(Option
<OngoingCodegen
<B
>>);
766 impl<B
: ExtraBackendMethods
> AbortCodegenOnDrop
<B
> {
767 fn into_inner(mut self) -> OngoingCodegen
<B
> {
768 self.0.take().unwrap()
772 impl<B
: ExtraBackendMethods
> Deref
for AbortCodegenOnDrop
<B
> {
773 type Target
= OngoingCodegen
<B
>;
775 fn deref(&self) -> &OngoingCodegen
<B
> {
776 self.0.as_ref().unwrap()
780 impl<B
: ExtraBackendMethods
> DerefMut
for AbortCodegenOnDrop
<B
> {
781 fn deref_mut(&mut self) -> &mut OngoingCodegen
<B
> {
782 self.0.as_mut().unwrap()
786 impl<B
: ExtraBackendMethods
> Drop
for AbortCodegenOnDrop
<B
> {
788 if let Some(codegen
) = self.0.take() {
789 codegen
.codegen_aborted();
795 pub fn new(tcx
: TyCtxt
<'_
>, target_cpu
: String
) -> CrateInfo
{
796 let exported_symbols
= tcx
800 .map(|&c
| (c
, crate::back
::linker
::exported_symbols(tcx
, c
)))
802 let local_crate_name
= tcx
.crate_name(LOCAL_CRATE
);
803 let crate_attrs
= tcx
.hir().attrs(rustc_hir
::CRATE_HIR_ID
);
804 let subsystem
= tcx
.sess
.first_attr_value_str_by_name(crate_attrs
, sym
::windows_subsystem
);
805 let windows_subsystem
= subsystem
.map(|subsystem
| {
806 if subsystem
!= sym
::windows
&& subsystem
!= sym
::console
{
807 tcx
.sess
.fatal(&format
!(
808 "invalid windows subsystem `{}`, only \
809 `windows` and `console` are allowed",
813 subsystem
.to_string()
816 // This list is used when generating the command line to pass through to
817 // system linker. The linker expects undefined symbols on the left of the
818 // command line to be defined in libraries on the right, not the other way
819 // around. For more info, see some comments in the add_used_library function
822 // In order to get this left-to-right dependency ordering, we use the reverse
823 // postorder of all crates putting the leaves at the right-most positions.
824 let used_crates
= tcx
829 .filter(|&cnum
| !tcx
.dep_kind(cnum
).macros_only())
832 let mut info
= CrateInfo
{
836 compiler_builtins
: None
,
837 profiler_runtime
: None
,
838 is_no_builtins
: Default
::default(),
839 native_libraries
: Default
::default(),
840 used_libraries
: tcx
.native_libraries(LOCAL_CRATE
).iter().map(Into
::into
).collect(),
841 crate_name
: Default
::default(),
843 used_crate_source
: Default
::default(),
844 lang_item_to_crate
: Default
::default(),
845 missing_lang_items
: Default
::default(),
846 dependency_formats
: tcx
.dependency_formats(()),
849 let lang_items
= tcx
.lang_items();
851 let crates
= tcx
.crates(());
853 let n_crates
= crates
.len();
854 info
.native_libraries
.reserve(n_crates
);
855 info
.crate_name
.reserve(n_crates
);
856 info
.used_crate_source
.reserve(n_crates
);
857 info
.missing_lang_items
.reserve(n_crates
);
859 for &cnum
in crates
.iter() {
860 info
.native_libraries
861 .insert(cnum
, tcx
.native_libraries(cnum
).iter().map(Into
::into
).collect());
862 info
.crate_name
.insert(cnum
, tcx
.crate_name(cnum
).to_string());
863 info
.used_crate_source
.insert(cnum
, tcx
.used_crate_source(cnum
));
864 if tcx
.is_compiler_builtins(cnum
) {
865 info
.compiler_builtins
= Some(cnum
);
867 if tcx
.is_profiler_runtime(cnum
) {
868 info
.profiler_runtime
= Some(cnum
);
870 if tcx
.is_no_builtins(cnum
) {
871 info
.is_no_builtins
.insert(cnum
);
873 let missing
= tcx
.missing_lang_items(cnum
);
874 for &item
in missing
.iter() {
875 if let Ok(id
) = lang_items
.require(item
) {
876 info
.lang_item_to_crate
.insert(item
, id
.krate
);
880 // No need to look for lang items that don't actually need to exist.
882 missing
.iter().cloned().filter(|&l
| lang_items
::required(tcx
, l
)).collect();
883 info
.missing_lang_items
.insert(cnum
, missing
);
890 pub fn provide(providers
: &mut Providers
) {
891 providers
.backend_optimization_level
= |tcx
, cratenum
| {
892 let for_speed
= match tcx
.sess
.opts
.optimize
{
893 // If globally no optimisation is done, #[optimize] has no effect.
895 // This is done because if we ended up "upgrading" to `-O2` here, we’d populate the
896 // pass manager and it is likely that some module-wide passes (such as inliner or
897 // cross-function constant propagation) would ignore the `optnone` annotation we put
898 // on the functions, thus necessarily involving these functions into optimisations.
899 config
::OptLevel
::No
=> return config
::OptLevel
::No
,
900 // If globally optimise-speed is already specified, just use that level.
901 config
::OptLevel
::Less
=> return config
::OptLevel
::Less
,
902 config
::OptLevel
::Default
=> return config
::OptLevel
::Default
,
903 config
::OptLevel
::Aggressive
=> return config
::OptLevel
::Aggressive
,
904 // If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
906 config
::OptLevel
::Size
=> config
::OptLevel
::Default
,
907 config
::OptLevel
::SizeMin
=> config
::OptLevel
::Default
,
910 let (defids
, _
) = tcx
.collect_and_partition_mono_items(cratenum
);
912 let CodegenFnAttrs { optimize, .. }
= tcx
.codegen_fn_attrs(*id
);
914 attr
::OptimizeAttr
::None
=> continue,
915 attr
::OptimizeAttr
::Size
=> continue,
916 attr
::OptimizeAttr
::Speed
=> {
921 tcx
.sess
.opts
.optimize
925 fn determine_cgu_reuse
<'tcx
>(tcx
: TyCtxt
<'tcx
>, cgu
: &CodegenUnit
<'tcx
>) -> CguReuse
{
926 if !tcx
.dep_graph
.is_fully_enabled() {
930 let work_product_id
= &cgu
.work_product_id();
931 if tcx
.dep_graph
.previous_work_product(work_product_id
).is_none() {
932 // We don't have anything cached for this CGU. This can happen
933 // if the CGU did not exist in the previous session.
937 // Try to mark the CGU as green. If it we can do so, it means that nothing
938 // affecting the LLVM module has changed and we can re-use a cached version.
939 // If we compile with any kind of LTO, this means we can re-use the bitcode
940 // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
941 // know that later). If we are not doing LTO, there is only one optimized
942 // version of each module, so we re-use that.
943 let dep_node
= cgu
.codegen_dep_node(tcx
);
945 !tcx
.dep_graph
.dep_node_exists(&dep_node
),
946 "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
950 if tcx
.try_mark_green(&dep_node
) {
951 // We can re-use either the pre- or the post-thinlto state. If no LTO is
952 // being performed then we can use post-LTO artifacts, otherwise we must
953 // reuse pre-LTO artifacts
954 match compute_per_cgu_lto_type(
957 &tcx
.sess
.crate_types(),
960 ComputedLtoType
::No
=> CguReuse
::PostLto
,
961 _
=> CguReuse
::PreLto
,