1 use crate::back
::write
::{
2 compute_per_cgu_lto_type
, start_async_codegen
, submit_codegened_module_to_llvm
,
3 submit_post_lto_module_to_llvm
, submit_pre_lto_module_to_llvm
, ComputedLtoType
, OngoingCodegen
,
5 use crate::common
::{IntPredicate, RealPredicate, TypeKind}
;
8 use crate::mir
::operand
::OperandValue
;
9 use crate::mir
::place
::PlaceRef
;
11 use crate::{CachedModuleCodegen, CrateInfo, MemFlags, ModuleCodegen, ModuleKind}
;
13 use rustc_attr
as attr
;
14 use rustc_data_structures
::fx
::FxHashMap
;
15 use rustc_data_structures
::profiling
::{get_resident_set_size, print_time_passes_entry}
;
16 use rustc_data_structures
::sync
::{par_iter, ParallelIterator}
;
18 use rustc_hir
::def_id
::{DefId, LOCAL_CRATE}
;
19 use rustc_hir
::lang_items
::LangItem
;
20 use rustc_index
::vec
::Idx
;
21 use rustc_middle
::middle
::codegen_fn_attrs
::CodegenFnAttrs
;
22 use rustc_middle
::middle
::cstore
::EncodedMetadata
;
23 use rustc_middle
::middle
::cstore
::{self, LinkagePreference}
;
24 use rustc_middle
::middle
::lang_items
;
25 use rustc_middle
::mir
::mono
::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}
;
26 use rustc_middle
::ty
::layout
::{HasTyCtxt, TyAndLayout}
;
27 use rustc_middle
::ty
::layout
::{FAT_PTR_ADDR, FAT_PTR_EXTRA}
;
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}
;
32 use rustc_session
::Session
;
33 use rustc_target
::abi
::{Align, LayoutOf, VariantIdx}
;
35 use std
::ops
::{Deref, DerefMut}
;
36 use std
::time
::{Duration, Instant}
;
38 use itertools
::Itertools
;
40 pub fn bin_op_to_icmp_predicate(op
: hir
::BinOpKind
, signed
: bool
) -> IntPredicate
{
42 hir
::BinOpKind
::Eq
=> IntPredicate
::IntEQ
,
43 hir
::BinOpKind
::Ne
=> IntPredicate
::IntNE
,
44 hir
::BinOpKind
::Lt
=> {
51 hir
::BinOpKind
::Le
=> {
58 hir
::BinOpKind
::Gt
=> {
65 hir
::BinOpKind
::Ge
=> {
73 "comparison_op_to_icmp_predicate: expected comparison operator, \
80 pub fn bin_op_to_fcmp_predicate(op
: hir
::BinOpKind
) -> RealPredicate
{
82 hir
::BinOpKind
::Eq
=> RealPredicate
::RealOEQ
,
83 hir
::BinOpKind
::Ne
=> RealPredicate
::RealUNE
,
84 hir
::BinOpKind
::Lt
=> RealPredicate
::RealOLT
,
85 hir
::BinOpKind
::Le
=> RealPredicate
::RealOLE
,
86 hir
::BinOpKind
::Gt
=> RealPredicate
::RealOGT
,
87 hir
::BinOpKind
::Ge
=> RealPredicate
::RealOGE
,
90 "comparison_op_to_fcmp_predicate: expected comparison operator, \
98 pub fn compare_simd_types
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
106 let signed
= match t
.kind() {
108 let cmp
= bin_op_to_fcmp_predicate(op
);
109 let cmp
= bx
.fcmp(cmp
, lhs
, rhs
);
110 return bx
.sext(cmp
, ret_ty
);
112 ty
::Uint(_
) => false,
114 _
=> bug
!("compare_simd_types: invalid SIMD type"),
117 let cmp
= bin_op_to_icmp_predicate(op
, signed
);
118 let cmp
= bx
.icmp(cmp
, lhs
, rhs
);
119 // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
120 // to get the correctly sized type. This will compile to a single instruction
121 // once the IR is converted to assembly if the SIMD instruction is supported
122 // by the target architecture.
126 /// Retrieves the information we are losing (making dynamic) in an unsizing
129 /// The `old_info` argument is a bit odd. It is intended for use in an upcast,
130 /// where the new vtable for an object will be derived from the old one.
131 pub fn unsized_info
<'tcx
, Cx
: CodegenMethods
<'tcx
>>(
135 old_info
: Option
<Cx
::Value
>,
137 let (source
, target
) =
138 cx
.tcx().struct_lockstep_tails_erasing_lifetimes(source
, target
, cx
.param_env());
139 match (source
.kind(), target
.kind()) {
140 (&ty
::Array(_
, len
), &ty
::Slice(_
)) => {
141 cx
.const_usize(len
.eval_usize(cx
.tcx(), ty
::ParamEnv
::reveal_all()))
143 (&ty
::Dynamic(..), &ty
::Dynamic(..)) => {
144 // For now, upcasts are limited to changes in marker
145 // traits, and hence never actually require an actual
146 // change to the vtable.
147 old_info
.expect("unsized_info: missing old info for trait upcast")
149 (_
, &ty
::Dynamic(ref data
, ..)) => {
150 let vtable_ptr
= cx
.layout_of(cx
.tcx().mk_mut_ptr(target
)).field(cx
, FAT_PTR_EXTRA
);
152 meth
::get_vtable(cx
, source
, data
.principal()),
153 cx
.backend_type(vtable_ptr
),
156 _
=> bug
!("unsized_info: invalid unsizing {:?} -> {:?}", source
, target
),
160 /// Coerces `src` to `dst_ty`. `src_ty` must be a thin pointer.
161 pub fn unsize_thin_ptr
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
166 ) -> (Bx
::Value
, Bx
::Value
) {
167 debug
!("unsize_thin_ptr: {:?} => {:?}", src_ty
, dst_ty
);
168 match (src_ty
.kind(), dst_ty
.kind()) {
169 (&ty
::Ref(_
, a
, _
), &ty
::Ref(_
, b
, _
) | &ty
::RawPtr(ty
::TypeAndMut { ty: b, .. }
))
170 | (&ty
::RawPtr(ty
::TypeAndMut { ty: a, .. }
), &ty
::RawPtr(ty
::TypeAndMut { ty: b, .. }
)) => {
171 assert
!(bx
.cx().type_is_sized(a
));
172 let ptr_ty
= bx
.cx().type_ptr_to(bx
.cx().backend_type(bx
.cx().layout_of(b
)));
173 (bx
.pointercast(src
, ptr_ty
), unsized_info(bx
.cx(), a
, b
, None
))
175 (&ty
::Adt(def_a
, _
), &ty
::Adt(def_b
, _
)) => {
176 assert_eq
!(def_a
, def_b
);
178 let src_layout
= bx
.cx().layout_of(src_ty
);
179 let dst_layout
= bx
.cx().layout_of(dst_ty
);
180 let mut result
= None
;
181 for i
in 0..src_layout
.fields
.count() {
182 let src_f
= src_layout
.field(bx
.cx(), i
);
183 assert_eq
!(src_layout
.fields
.offset(i
).bytes(), 0);
184 assert_eq
!(dst_layout
.fields
.offset(i
).bytes(), 0);
188 assert_eq
!(src_layout
.size
, src_f
.size
);
190 let dst_f
= dst_layout
.field(bx
.cx(), i
);
191 assert_ne
!(src_f
.ty
, dst_f
.ty
);
192 assert_eq
!(result
, None
);
193 result
= Some(unsize_thin_ptr(bx
, src
, src_f
.ty
, dst_f
.ty
));
195 let (lldata
, llextra
) = result
.unwrap();
196 // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
197 // FIXME(eddyb) move these out of this `match` arm, so they're always
198 // applied, uniformly, no matter the source/destination types.
200 bx
.bitcast(lldata
, bx
.cx().scalar_pair_element_backend_type(dst_layout
, 0, true)),
201 bx
.bitcast(llextra
, bx
.cx().scalar_pair_element_backend_type(dst_layout
, 1, true)),
204 _
=> bug
!("unsize_thin_ptr: called on bad types"),
208 /// Coerces `src`, which is a reference to a value of type `src_ty`,
209 /// to a value of type `dst_ty`, and stores the result in `dst`.
210 pub fn coerce_unsized_into
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
212 src
: PlaceRef
<'tcx
, Bx
::Value
>,
213 dst
: PlaceRef
<'tcx
, Bx
::Value
>,
215 let src_ty
= src
.layout
.ty
;
216 let dst_ty
= dst
.layout
.ty
;
217 match (src_ty
.kind(), dst_ty
.kind()) {
218 (&ty
::Ref(..), &ty
::Ref(..) | &ty
::RawPtr(..)) | (&ty
::RawPtr(..), &ty
::RawPtr(..)) => {
219 let (base
, info
) = match bx
.load_operand(src
).val
{
220 OperandValue
::Pair(base
, info
) => {
221 // fat-ptr to fat-ptr unsize preserves the vtable
222 // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
223 // So we need to pointercast the base to ensure
224 // the types match up.
225 // FIXME(eddyb) use `scalar_pair_element_backend_type` here,
226 // like `unsize_thin_ptr` does.
227 let thin_ptr
= dst
.layout
.field(bx
.cx(), FAT_PTR_ADDR
);
228 (bx
.pointercast(base
, bx
.cx().backend_type(thin_ptr
)), info
)
230 OperandValue
::Immediate(base
) => unsize_thin_ptr(bx
, base
, src_ty
, dst_ty
),
231 OperandValue
::Ref(..) => bug
!(),
233 OperandValue
::Pair(base
, info
).store(bx
, dst
);
236 (&ty
::Adt(def_a
, _
), &ty
::Adt(def_b
, _
)) => {
237 assert_eq
!(def_a
, def_b
);
239 for i
in 0..def_a
.variants
[VariantIdx
::new(0)].fields
.len() {
240 let src_f
= src
.project_field(bx
, i
);
241 let dst_f
= dst
.project_field(bx
, i
);
243 if dst_f
.layout
.is_zst() {
247 if src_f
.layout
.ty
== dst_f
.layout
.ty
{
258 coerce_unsized_into(bx
, src_f
, dst_f
);
262 _
=> bug
!("coerce_unsized_into: invalid coercion {:?} -> {:?}", src_ty
, dst_ty
,),
266 pub fn cast_shift_expr_rhs
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
272 cast_shift_rhs(bx
, op
, lhs
, rhs
)
275 fn cast_shift_rhs
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
281 // Shifts may have any size int on the rhs
283 let mut rhs_llty
= bx
.cx().val_ty(rhs
);
284 let mut lhs_llty
= bx
.cx().val_ty(lhs
);
285 if bx
.cx().type_kind(rhs_llty
) == TypeKind
::Vector
{
286 rhs_llty
= bx
.cx().element_type(rhs_llty
)
288 if bx
.cx().type_kind(lhs_llty
) == TypeKind
::Vector
{
289 lhs_llty
= bx
.cx().element_type(lhs_llty
)
291 let rhs_sz
= bx
.cx().int_width(rhs_llty
);
292 let lhs_sz
= bx
.cx().int_width(lhs_llty
);
294 bx
.trunc(rhs
, lhs_llty
)
295 } else if lhs_sz
> rhs_sz
{
296 // FIXME (#1877: If in the future shifting by negative
297 // values is no longer undefined then this is wrong.
298 bx
.zext(rhs
, lhs_llty
)
307 /// Returns `true` if this session's target will use SEH-based unwinding.
309 /// This is only true for MSVC targets, and even then the 64-bit MSVC target
310 /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
311 /// 64-bit MinGW) instead of "full SEH".
312 pub fn wants_msvc_seh(sess
: &Session
) -> bool
{
313 sess
.target
.is_like_msvc
316 pub fn memcpy_ty
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
322 layout
: TyAndLayout
<'tcx
>,
325 let size
= layout
.size
.bytes();
330 bx
.memcpy(dst
, dst_align
, src
, src_align
, bx
.cx().const_usize(size
), flags
);
333 pub fn codegen_instance
<'a
, 'tcx
: 'a
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
334 cx
: &'a Bx
::CodegenCx
,
335 instance
: Instance
<'tcx
>,
337 // this is an info! to allow collecting monomorphization statistics
338 // and to allow finding the last function before LLVM aborts from
340 info
!("codegen_instance({})", instance
);
342 mir
::codegen_mir
::<Bx
>(cx
, instance
);
345 /// Creates the `main` function which will initialize the rust runtime and call
346 /// users main function.
347 pub fn maybe_create_entry_wrapper
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
348 cx
: &'a Bx
::CodegenCx
,
349 ) -> Option
<Bx
::Function
> {
350 let main_def_id
= cx
.tcx().entry_fn(LOCAL_CRATE
).map(|(def_id
, _
)| def_id
)?
;
351 let main_is_local
= main_def_id
.is_local();
352 let instance
= Instance
::mono(cx
.tcx(), main_def_id
);
355 // We want to create the wrapper in the same codegen unit as Rust's main
357 if !cx
.codegen_unit().contains_item(&MonoItem
::Fn(instance
)) {
361 // FIXME: Add support for non-local main fn codegen
362 let span
= cx
.tcx().main_def
.unwrap().span
;
365 .struct_span_err(span
, "entry symbol `main` from foreign crate is not yet supported.")
367 "see issue #{} <https://github.com/rust-lang/rust/issues/{}> \
368 for more information",
372 cx
.sess().abort_if_errors();
376 let main_llfn
= cx
.get_fn_addr(instance
);
378 return cx
.tcx().entry_fn(LOCAL_CRATE
).map(|(_
, et
)| {
379 let use_start_lang_item
= EntryFnType
::Start
!= et
;
380 create_entry_fn
::<Bx
>(cx
, main_llfn
, main_def_id
, use_start_lang_item
)
383 fn create_entry_fn
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
384 cx
: &'a Bx
::CodegenCx
,
385 rust_main
: Bx
::Value
,
386 rust_main_def_id
: DefId
,
387 use_start_lang_item
: bool
,
389 // The entry function is either `int main(void)` or `int main(int argc, char **argv)`,
390 // depending on whether the target needs `argc` and `argv` to be passed in.
391 let llfty
= if cx
.sess().target
.main_needs_argc_argv
{
392 cx
.type_func(&[cx
.type_int(), cx
.type_ptr_to(cx
.type_i8p())], cx
.type_int())
394 cx
.type_func(&[], cx
.type_int())
397 let main_ret_ty
= cx
.tcx().fn_sig(rust_main_def_id
).output();
398 // Given that `main()` has no arguments,
399 // then its return type cannot have
400 // late-bound regions, since late-bound
401 // regions must appear in the argument
403 let main_ret_ty
= cx
.tcx().erase_regions(main_ret_ty
.no_bound_vars().unwrap());
405 let llfn
= match cx
.declare_c_main(llfty
) {
408 // FIXME: We should be smart and show a better diagnostic here.
409 let span
= cx
.tcx().def_span(rust_main_def_id
);
411 .struct_span_err(span
, "entry symbol `main` declared multiple times")
412 .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead")
414 cx
.sess().abort_if_errors();
419 // `main` should respect same config for frame pointer elimination as rest of code
420 cx
.set_frame_pointer_elimination(llfn
);
421 cx
.apply_target_cpu_attr(llfn
);
423 let mut bx
= Bx
::new_block(&cx
, llfn
, "top");
425 bx
.insert_reference_to_gdb_debug_scripts_section_global();
427 let (arg_argc
, arg_argv
) = get_argc_argv(cx
, &mut bx
);
429 let (start_fn
, args
) = if use_start_lang_item
{
430 let start_def_id
= cx
.tcx().require_lang_item(LangItem
::Start
, None
);
431 let start_fn
= cx
.get_fn_addr(
432 ty
::Instance
::resolve(
434 ty
::ParamEnv
::reveal_all(),
436 cx
.tcx().intern_substs(&[main_ret_ty
.into()]),
443 vec
![bx
.pointercast(rust_main
, cx
.type_ptr_to(cx
.type_i8p())), arg_argc
, arg_argv
],
446 debug
!("using user-defined start fn");
447 (rust_main
, vec
![arg_argc
, arg_argv
])
450 let result
= bx
.call(start_fn
, &args
, None
);
451 let cast
= bx
.intcast(result
, cx
.type_int(), true);
458 /// Obtain the `argc` and `argv` values to pass to the rust start function.
459 fn get_argc_argv
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
460 cx
: &'a Bx
::CodegenCx
,
462 ) -> (Bx
::Value
, Bx
::Value
) {
463 if cx
.sess().target
.main_needs_argc_argv
{
464 // Params from native `main()` used as args for rust start function
465 let param_argc
= bx
.get_param(0);
466 let param_argv
= bx
.get_param(1);
467 let arg_argc
= bx
.intcast(param_argc
, cx
.type_isize(), true);
468 let arg_argv
= param_argv
;
471 // The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
472 let arg_argc
= bx
.const_int(cx
.type_int(), 0);
473 let arg_argv
= bx
.const_null(cx
.type_ptr_to(cx
.type_i8p()));
478 pub fn codegen_crate
<B
: ExtraBackendMethods
>(
481 metadata
: EncodedMetadata
,
482 need_metadata_module
: bool
,
483 ) -> OngoingCodegen
<B
> {
484 // Skip crate items and just output metadata in -Z no-codegen mode.
485 if tcx
.sess
.opts
.debugging_opts
.no_codegen
|| !tcx
.sess
.opts
.output_types
.should_codegen() {
486 let ongoing_codegen
= start_async_codegen(backend
, tcx
, metadata
, 1);
488 ongoing_codegen
.codegen_finished(tcx
);
490 ongoing_codegen
.check_for_errors(tcx
.sess
);
492 return ongoing_codegen
;
495 let cgu_name_builder
= &mut CodegenUnitNameBuilder
::new(tcx
);
497 // Run the monomorphization collector and partition the collected items into
499 let codegen_units
= tcx
.collect_and_partition_mono_items(LOCAL_CRATE
).1;
501 // Force all codegen_unit queries so they are already either red or green
502 // when compile_codegen_unit accesses them. We are not able to re-execute
503 // the codegen_unit query from just the DepNode, so an unknown color would
504 // lead to having to re-execute compile_codegen_unit, possibly
506 if tcx
.dep_graph
.is_fully_enabled() {
507 for cgu
in codegen_units
{
508 tcx
.ensure().codegen_unit(cgu
.name());
512 let ongoing_codegen
= start_async_codegen(backend
.clone(), tcx
, metadata
, codegen_units
.len());
513 let ongoing_codegen
= AbortCodegenOnDrop
::<B
>(Some(ongoing_codegen
));
515 // Codegen an allocator shim, if necessary.
517 // If the crate doesn't have an `allocator_kind` set then there's definitely
518 // no shim to generate. Otherwise we also check our dependency graph for all
519 // our output crate types. If anything there looks like its a `Dynamic`
520 // linkage, then it's already got an allocator shim and we'll be using that
521 // one instead. If nothing exists then it's our job to generate the
523 let any_dynamic_crate
= tcx
.dependency_formats(LOCAL_CRATE
).iter().any(|(_
, list
)| {
524 use rustc_middle
::middle
::dependency_format
::Linkage
;
525 list
.iter().any(|&linkage
| linkage
== Linkage
::Dynamic
)
527 let allocator_module
= if any_dynamic_crate
{
529 } else if let Some(kind
) = tcx
.allocator_kind() {
531 cgu_name_builder
.build_cgu_name(LOCAL_CRATE
, &["crate"], Some("allocator")).to_string();
532 let mut modules
= backend
.new_metadata(tcx
, &llmod_id
);
533 tcx
.sess
.time("write_allocator_module", || {
534 backend
.codegen_allocator(tcx
, &mut modules
, kind
, tcx
.lang_items().oom().is_some())
537 Some(ModuleCodegen { name: llmod_id, module_llvm: modules, kind: ModuleKind::Allocator }
)
542 if let Some(allocator_module
) = allocator_module
{
543 ongoing_codegen
.submit_pre_codegened_module_to_llvm(tcx
, allocator_module
);
546 if need_metadata_module
{
547 // Codegen the encoded metadata.
548 let metadata_cgu_name
=
549 cgu_name_builder
.build_cgu_name(LOCAL_CRATE
, &["crate"], Some("metadata")).to_string();
550 let mut metadata_llvm_module
= backend
.new_metadata(tcx
, &metadata_cgu_name
);
551 tcx
.sess
.time("write_compressed_metadata", || {
552 backend
.write_compressed_metadata(
554 &ongoing_codegen
.metadata
,
555 &mut metadata_llvm_module
,
559 let metadata_module
= ModuleCodegen
{
560 name
: metadata_cgu_name
,
561 module_llvm
: metadata_llvm_module
,
562 kind
: ModuleKind
::Metadata
,
564 ongoing_codegen
.submit_pre_codegened_module_to_llvm(tcx
, metadata_module
);
567 // For better throughput during parallel processing by LLVM, we used to sort
568 // CGUs largest to smallest. This would lead to better thread utilization
569 // by, for example, preventing a large CGU from being processed last and
570 // having only one LLVM thread working while the rest remained idle.
572 // However, this strategy would lead to high memory usage, as it meant the
573 // LLVM-IR for all of the largest CGUs would be resident in memory at once.
575 // Instead, we can compromise by ordering CGUs such that the largest and
576 // smallest are first, second largest and smallest are next, etc. If there
577 // are large size variations, this can reduce memory usage significantly.
578 let codegen_units
: Vec
<_
> = {
579 let mut sorted_cgus
= codegen_units
.iter().collect
::<Vec
<_
>>();
580 sorted_cgus
.sort_by_cached_key(|cgu
| cgu
.size_estimate());
582 let (first_half
, second_half
) = sorted_cgus
.split_at(sorted_cgus
.len() / 2);
583 second_half
.iter().rev().interleave(first_half
).copied().collect()
586 // The non-parallel compiler can only translate codegen units to LLVM IR
587 // on a single thread, leading to a staircase effect where the N LLVM
588 // threads have to wait on the single codegen threads to generate work
589 // for them. The parallel compiler does not have this restriction, so
590 // we can pre-load the LLVM queue in parallel before handing off
591 // coordination to the OnGoingCodegen scheduler.
593 // This likely is a temporary measure. Once we don't have to support the
594 // non-parallel compiler anymore, we can compile CGUs end-to-end in
595 // parallel and get rid of the complicated scheduling logic.
596 let pre_compile_cgus
= |cgu_reuse
: &[CguReuse
]| {
597 if cfg
!(parallel_compiler
) {
598 tcx
.sess
.time("compile_first_CGU_batch", || {
599 // Try to find one CGU to compile per thread.
600 let cgus
: Vec
<_
> = cgu_reuse
603 .filter(|&(_
, reuse
)| reuse
== &CguReuse
::No
)
604 .take(tcx
.sess
.threads())
607 // Compile the found CGUs in parallel.
608 let start_time
= Instant
::now();
610 let pre_compiled_cgus
= par_iter(cgus
)
612 let module
= backend
.compile_codegen_unit(tcx
, codegen_units
[i
].name());
617 (pre_compiled_cgus
, start_time
.elapsed())
620 (FxHashMap
::default(), Duration
::new(0, 0))
624 let mut cgu_reuse
= Vec
::new();
625 let mut pre_compiled_cgus
: Option
<FxHashMap
<usize, _
>> = None
;
626 let mut total_codegen_time
= Duration
::new(0, 0);
627 let start_rss
= tcx
.sess
.time_passes().then(|| get_resident_set_size());
629 for (i
, cgu
) in codegen_units
.iter().enumerate() {
630 ongoing_codegen
.wait_for_signal_to_codegen_item();
631 ongoing_codegen
.check_for_errors(tcx
.sess
);
633 // Do some setup work in the first iteration
634 if pre_compiled_cgus
.is_none() {
635 // Calculate the CGU reuse
636 cgu_reuse
= tcx
.sess
.time("find_cgu_reuse", || {
637 codegen_units
.iter().map(|cgu
| determine_cgu_reuse(tcx
, &cgu
)).collect()
639 // Pre compile some CGUs
640 let (compiled_cgus
, codegen_time
) = pre_compile_cgus(&cgu_reuse
);
641 pre_compiled_cgus
= Some(compiled_cgus
);
642 total_codegen_time
+= codegen_time
;
645 let cgu_reuse
= cgu_reuse
[i
];
646 tcx
.sess
.cgu_reuse_tracker
.set_actual_reuse(&cgu
.name().as_str(), cgu_reuse
);
651 if let Some(cgu
) = pre_compiled_cgus
.as_mut().unwrap().remove(&i
) {
654 let start_time
= Instant
::now();
655 let module
= backend
.compile_codegen_unit(tcx
, cgu
.name());
656 total_codegen_time
+= start_time
.elapsed();
659 // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
660 // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
661 // compilation hang on post-monomorphization errors.
662 tcx
.sess
.abort_if_errors();
664 submit_codegened_module_to_llvm(
666 &ongoing_codegen
.coordinator_send
,
672 CguReuse
::PreLto
=> {
673 submit_pre_lto_module_to_llvm(
676 &ongoing_codegen
.coordinator_send
,
677 CachedModuleCodegen
{
678 name
: cgu
.name().to_string(),
679 source
: cgu
.work_product(tcx
),
684 CguReuse
::PostLto
=> {
685 submit_post_lto_module_to_llvm(
687 &ongoing_codegen
.coordinator_send
,
688 CachedModuleCodegen
{
689 name
: cgu
.name().to_string(),
690 source
: cgu
.work_product(tcx
),
698 ongoing_codegen
.codegen_finished(tcx
);
700 // Since the main thread is sometimes blocked during codegen, we keep track
701 // -Ztime-passes output manually.
702 if tcx
.sess
.time_passes() {
703 let end_rss
= get_resident_set_size();
705 print_time_passes_entry(
706 "codegen_to_LLVM_IR",
713 ongoing_codegen
.check_for_errors(tcx
.sess
);
715 ongoing_codegen
.into_inner()
718 /// A curious wrapper structure whose only purpose is to call `codegen_aborted`
719 /// when it's dropped abnormally.
721 /// In the process of working on rust-lang/rust#55238 a mysterious segfault was
722 /// stumbled upon. The segfault was never reproduced locally, but it was
723 /// suspected to be related to the fact that codegen worker threads were
724 /// sticking around by the time the main thread was exiting, causing issues.
726 /// This structure is an attempt to fix that issue where the `codegen_aborted`
727 /// message will block until all workers have finished. This should ensure that
728 /// even if the main codegen thread panics we'll wait for pending work to
729 /// complete before returning from the main thread, hopefully avoiding
732 /// If you see this comment in the code, then it means that this workaround
733 /// worked! We may yet one day track down the mysterious cause of that
735 struct AbortCodegenOnDrop
<B
: ExtraBackendMethods
>(Option
<OngoingCodegen
<B
>>);
737 impl<B
: ExtraBackendMethods
> AbortCodegenOnDrop
<B
> {
738 fn into_inner(mut self) -> OngoingCodegen
<B
> {
739 self.0.take().unwrap()
743 impl<B
: ExtraBackendMethods
> Deref
for AbortCodegenOnDrop
<B
> {
744 type Target
= OngoingCodegen
<B
>;
746 fn deref(&self) -> &OngoingCodegen
<B
> {
747 self.0.as_ref().unwrap()
751 impl<B
: ExtraBackendMethods
> DerefMut
for AbortCodegenOnDrop
<B
> {
752 fn deref_mut(&mut self) -> &mut OngoingCodegen
<B
> {
753 self.0.as_mut().unwrap()
757 impl<B
: ExtraBackendMethods
> Drop
for AbortCodegenOnDrop
<B
> {
759 if let Some(codegen
) = self.0.take() {
760 codegen
.codegen_aborted();
766 pub fn new(tcx
: TyCtxt
<'_
>) -> CrateInfo
{
767 let mut info
= CrateInfo
{
769 compiler_builtins
: None
,
770 profiler_runtime
: None
,
771 is_no_builtins
: Default
::default(),
772 native_libraries
: Default
::default(),
773 used_libraries
: tcx
.native_libraries(LOCAL_CRATE
).iter().map(Into
::into
).collect(),
774 crate_name
: Default
::default(),
775 used_crates_dynamic
: cstore
::used_crates(tcx
, LinkagePreference
::RequireDynamic
),
776 used_crates_static
: cstore
::used_crates(tcx
, LinkagePreference
::RequireStatic
),
777 used_crate_source
: Default
::default(),
778 lang_item_to_crate
: Default
::default(),
779 missing_lang_items
: Default
::default(),
780 dependency_formats
: tcx
.dependency_formats(LOCAL_CRATE
),
782 let lang_items
= tcx
.lang_items();
784 let crates
= tcx
.crates();
786 let n_crates
= crates
.len();
787 info
.native_libraries
.reserve(n_crates
);
788 info
.crate_name
.reserve(n_crates
);
789 info
.used_crate_source
.reserve(n_crates
);
790 info
.missing_lang_items
.reserve(n_crates
);
792 for &cnum
in crates
.iter() {
793 info
.native_libraries
794 .insert(cnum
, tcx
.native_libraries(cnum
).iter().map(Into
::into
).collect());
795 info
.crate_name
.insert(cnum
, tcx
.crate_name(cnum
).to_string());
796 info
.used_crate_source
.insert(cnum
, tcx
.used_crate_source(cnum
));
797 if tcx
.is_panic_runtime(cnum
) {
798 info
.panic_runtime
= Some(cnum
);
800 if tcx
.is_compiler_builtins(cnum
) {
801 info
.compiler_builtins
= Some(cnum
);
803 if tcx
.is_profiler_runtime(cnum
) {
804 info
.profiler_runtime
= Some(cnum
);
806 if tcx
.is_no_builtins(cnum
) {
807 info
.is_no_builtins
.insert(cnum
);
809 let missing
= tcx
.missing_lang_items(cnum
);
810 for &item
in missing
.iter() {
811 if let Ok(id
) = lang_items
.require(item
) {
812 info
.lang_item_to_crate
.insert(item
, id
.krate
);
816 // No need to look for lang items that don't actually need to exist.
818 missing
.iter().cloned().filter(|&l
| lang_items
::required(tcx
, l
)).collect();
819 info
.missing_lang_items
.insert(cnum
, missing
);
826 pub fn provide(providers
: &mut Providers
) {
827 providers
.backend_optimization_level
= |tcx
, cratenum
| {
828 let for_speed
= match tcx
.sess
.opts
.optimize
{
829 // If globally no optimisation is done, #[optimize] has no effect.
831 // This is done because if we ended up "upgrading" to `-O2` here, we’d populate the
832 // pass manager and it is likely that some module-wide passes (such as inliner or
833 // cross-function constant propagation) would ignore the `optnone` annotation we put
834 // on the functions, thus necessarily involving these functions into optimisations.
835 config
::OptLevel
::No
=> return config
::OptLevel
::No
,
836 // If globally optimise-speed is already specified, just use that level.
837 config
::OptLevel
::Less
=> return config
::OptLevel
::Less
,
838 config
::OptLevel
::Default
=> return config
::OptLevel
::Default
,
839 config
::OptLevel
::Aggressive
=> return config
::OptLevel
::Aggressive
,
840 // If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
842 config
::OptLevel
::Size
=> config
::OptLevel
::Default
,
843 config
::OptLevel
::SizeMin
=> config
::OptLevel
::Default
,
846 let (defids
, _
) = tcx
.collect_and_partition_mono_items(cratenum
);
848 let CodegenFnAttrs { optimize, .. }
= tcx
.codegen_fn_attrs(*id
);
850 attr
::OptimizeAttr
::None
=> continue,
851 attr
::OptimizeAttr
::Size
=> continue,
852 attr
::OptimizeAttr
::Speed
=> {
857 tcx
.sess
.opts
.optimize
861 fn determine_cgu_reuse
<'tcx
>(tcx
: TyCtxt
<'tcx
>, cgu
: &CodegenUnit
<'tcx
>) -> CguReuse
{
862 if !tcx
.dep_graph
.is_fully_enabled() {
866 let work_product_id
= &cgu
.work_product_id();
867 if tcx
.dep_graph
.previous_work_product(work_product_id
).is_none() {
868 // We don't have anything cached for this CGU. This can happen
869 // if the CGU did not exist in the previous session.
873 // Try to mark the CGU as green. If it we can do so, it means that nothing
874 // affecting the LLVM module has changed and we can re-use a cached version.
875 // If we compile with any kind of LTO, this means we can re-use the bitcode
876 // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
877 // know that later). If we are not doing LTO, there is only one optimized
878 // version of each module, so we re-use that.
879 let dep_node
= cgu
.codegen_dep_node(tcx
);
881 !tcx
.dep_graph
.dep_node_exists(&dep_node
),
882 "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
886 if tcx
.try_mark_green(&dep_node
) {
887 // We can re-use either the pre- or the post-thinlto state. If no LTO is
888 // being performed then we can use post-LTO artifacts, otherwise we must
889 // reuse pre-LTO artifacts
890 match compute_per_cgu_lto_type(
893 &tcx
.sess
.crate_types(),
896 ComputedLtoType
::No
=> CguReuse
::PostLto
,
897 _
=> CguReuse
::PreLto
,