rustc_codegen_ssa/
base.rs

1use std::cmp;
2use std::collections::BTreeSet;
3use std::sync::Arc;
4use std::time::{Duration, Instant};
5
6use itertools::Itertools;
7use rustc_abi::FIRST_VARIANT;
8use rustc_ast as ast;
9use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name};
10use rustc_attr_data_structures::OptimizeAttr;
11use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
12use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
13use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
14use rustc_data_structures::unord::UnordMap;
15use rustc_hir::ItemId;
16use rustc_hir::def_id::{DefId, LOCAL_CRATE};
17use rustc_hir::lang_items::LangItem;
18use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
19use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
20use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
21use rustc_middle::middle::lang_items;
22use rustc_middle::mir::BinOp;
23use rustc_middle::mir::interpret::ErrorHandled;
24use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
25use rustc_middle::query::Providers;
26use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
27use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
28use rustc_middle::{bug, span_bug};
29use rustc_session::Session;
30use rustc_session::config::{self, CrateType, EntryFnType};
31use rustc_span::{DUMMY_SP, Symbol, sym};
32use rustc_symbol_mangling::mangle_internal_symbol;
33use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
34use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
35use tracing::{debug, info};
36
37use crate::assert_module_sources::CguReuse;
38use crate::back::link::are_upstream_rust_objects_already_included;
39use crate::back::write::{
40    ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen,
41    submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
42};
43use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
44use crate::meth::load_vtable;
45use crate::mir::operand::OperandValue;
46use crate::mir::place::PlaceRef;
47use crate::traits::*;
48use crate::{
49    CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
50};
51
52pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
53    match (op, signed) {
54        (BinOp::Eq, _) => IntPredicate::IntEQ,
55        (BinOp::Ne, _) => IntPredicate::IntNE,
56        (BinOp::Lt, true) => IntPredicate::IntSLT,
57        (BinOp::Lt, false) => IntPredicate::IntULT,
58        (BinOp::Le, true) => IntPredicate::IntSLE,
59        (BinOp::Le, false) => IntPredicate::IntULE,
60        (BinOp::Gt, true) => IntPredicate::IntSGT,
61        (BinOp::Gt, false) => IntPredicate::IntUGT,
62        (BinOp::Ge, true) => IntPredicate::IntSGE,
63        (BinOp::Ge, false) => IntPredicate::IntUGE,
64        op => bug!("bin_op_to_icmp_predicate: expected comparison operator, found {:?}", op),
65    }
66}
67
68pub(crate) fn bin_op_to_fcmp_predicate(op: BinOp) -> RealPredicate {
69    match op {
70        BinOp::Eq => RealPredicate::RealOEQ,
71        BinOp::Ne => RealPredicate::RealUNE,
72        BinOp::Lt => RealPredicate::RealOLT,
73        BinOp::Le => RealPredicate::RealOLE,
74        BinOp::Gt => RealPredicate::RealOGT,
75        BinOp::Ge => RealPredicate::RealOGE,
76        op => bug!("bin_op_to_fcmp_predicate: expected comparison operator, found {:?}", op),
77    }
78}
79
80pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
81    bx: &mut Bx,
82    lhs: Bx::Value,
83    rhs: Bx::Value,
84    t: Ty<'tcx>,
85    ret_ty: Bx::Type,
86    op: BinOp,
87) -> Bx::Value {
88    let signed = match t.kind() {
89        ty::Float(_) => {
90            let cmp = bin_op_to_fcmp_predicate(op);
91            let cmp = bx.fcmp(cmp, lhs, rhs);
92            return bx.sext(cmp, ret_ty);
93        }
94        ty::Uint(_) => false,
95        ty::Int(_) => true,
96        _ => bug!("compare_simd_types: invalid SIMD type"),
97    };
98
99    let cmp = bin_op_to_icmp_predicate(op, signed);
100    let cmp = bx.icmp(cmp, lhs, rhs);
101    // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
102    // to get the correctly sized type. This will compile to a single instruction
103    // once the IR is converted to assembly if the SIMD instruction is supported
104    // by the target architecture.
105    bx.sext(cmp, ret_ty)
106}
107
108/// Codegen takes advantage of the additional assumption, where if the
109/// principal trait def id of what's being casted doesn't change,
110/// then we don't need to adjust the vtable at all. This
111/// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
112/// requires that `A = B`; we don't allow *upcasting* objects
113/// between the same trait with different args. If we, for
114/// some reason, were to relax the `Unsize` trait, it could become
115/// unsound, so let's validate here that the trait refs are subtypes.
116pub fn validate_trivial_unsize<'tcx>(
117    tcx: TyCtxt<'tcx>,
118    source_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
119    target_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
120) -> bool {
121    match (source_data.principal(), target_data.principal()) {
122        (Some(hr_source_principal), Some(hr_target_principal)) => {
123            let (infcx, param_env) =
124                tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
125            let universe = infcx.universe();
126            let ocx = ObligationCtxt::new(&infcx);
127            infcx.enter_forall(hr_target_principal, |target_principal| {
128                let source_principal = infcx.instantiate_binder_with_fresh_vars(
129                    DUMMY_SP,
130                    BoundRegionConversionTime::HigherRankedType,
131                    hr_source_principal,
132                );
133                let Ok(()) = ocx.eq(
134                    &ObligationCause::dummy(),
135                    param_env,
136                    target_principal,
137                    source_principal,
138                ) else {
139                    return false;
140                };
141                if !ocx.select_all_or_error().is_empty() {
142                    return false;
143                }
144                infcx.leak_check(universe, None).is_ok()
145            })
146        }
147        (_, None) => true,
148        _ => false,
149    }
150}
151
152/// Retrieves the information we are losing (making dynamic) in an unsizing
153/// adjustment.
154///
155/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
156/// where the new vtable for an object will be derived from the old one.
157fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
158    bx: &mut Bx,
159    source: Ty<'tcx>,
160    target: Ty<'tcx>,
161    old_info: Option<Bx::Value>,
162) -> Bx::Value {
163    let cx = bx.cx();
164    let (source, target) =
165        cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.typing_env());
166    match (source.kind(), target.kind()) {
167        (&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize(
168            len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"),
169        ),
170        (&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
171            if src_dyn_kind == target_dyn_kind =>
172        {
173            let old_info =
174                old_info.expect("unsized_info: missing old info for trait upcasting coercion");
175            let b_principal_def_id = data_b.principal_def_id();
176            if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
177                // Codegen takes advantage of the additional assumption, where if the
178                // principal trait def id of what's being casted doesn't change,
179                // then we don't need to adjust the vtable at all. This
180                // corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
181                // requires that `A = B`; we don't allow *upcasting* objects
182                // between the same trait with different args. If we, for
183                // some reason, were to relax the `Unsize` trait, it could become
184                // unsound, so let's assert here that the trait refs are *equal*.
185                debug_assert!(
186                    validate_trivial_unsize(cx.tcx(), data_a, data_b),
187                    "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
188                );
189
190                // A NOP cast that doesn't actually change anything, let's avoid any
191                // unnecessary work. This relies on the assumption that if the principal
192                // traits are equal, then the associated type bounds (`dyn Trait<Assoc=T>`)
193                // are also equal, which is ensured by the fact that normalization is
194                // a function and we do not allow overlapping impls.
195                return old_info;
196            }
197
198            // trait upcasting coercion
199
200            let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target));
201
202            if let Some(entry_idx) = vptr_entry_idx {
203                let ptr_size = bx.data_layout().pointer_size;
204                let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes();
205                load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true)
206            } else {
207                old_info
208            }
209        }
210        (_, ty::Dynamic(data, _, _)) => meth::get_vtable(
211            cx,
212            source,
213            data.principal()
214                .map(|principal| bx.tcx().instantiate_bound_regions_with_erased(principal)),
215        ),
216        _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
217    }
218}
219
220/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
221pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
222    bx: &mut Bx,
223    src: Bx::Value,
224    src_ty: Ty<'tcx>,
225    dst_ty: Ty<'tcx>,
226    old_info: Option<Bx::Value>,
227) -> (Bx::Value, Bx::Value) {
228    debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
229    match (src_ty.kind(), dst_ty.kind()) {
230        (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
231        | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
232            assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
233            (src, unsized_info(bx, a, b, old_info))
234        }
235        (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
236            assert_eq!(def_a, def_b); // implies same number of fields
237            let src_layout = bx.cx().layout_of(src_ty);
238            let dst_layout = bx.cx().layout_of(dst_ty);
239            if src_ty == dst_ty {
240                return (src, old_info.unwrap());
241            }
242            let mut result = None;
243            for i in 0..src_layout.fields.count() {
244                let src_f = src_layout.field(bx.cx(), i);
245                if src_f.is_1zst() {
246                    // We are looking for the one non-1-ZST field; this is not it.
247                    continue;
248                }
249
250                assert_eq!(src_layout.fields.offset(i).bytes(), 0);
251                assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
252                assert_eq!(src_layout.size, src_f.size);
253
254                let dst_f = dst_layout.field(bx.cx(), i);
255                assert_ne!(src_f.ty, dst_f.ty);
256                assert_eq!(result, None);
257                result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info));
258            }
259            result.unwrap()
260        }
261        _ => bug!("unsize_ptr: called on bad types"),
262    }
263}
264
265/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
266pub(crate) fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
267    bx: &mut Bx,
268    src: Bx::Value,
269    src_ty_and_layout: TyAndLayout<'tcx>,
270    dst_ty: Ty<'tcx>,
271    old_info: Option<Bx::Value>,
272) -> (Bx::Value, Bx::Value) {
273    debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty);
274    assert!(
275        matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
276        "destination type must be a dyn*"
277    );
278    let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) {
279        TypeKind::Pointer => src,
280        TypeKind::Integer => bx.inttoptr(src, bx.type_ptr()),
281        // FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr.
282        kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"),
283    };
284    (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
285}
286
287/// Coerces `src`, which is a reference to a value of type `src_ty`,
288/// to a value of type `dst_ty`, and stores the result in `dst`.
289pub(crate) fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
290    bx: &mut Bx,
291    src: PlaceRef<'tcx, Bx::Value>,
292    dst: PlaceRef<'tcx, Bx::Value>,
293) {
294    let src_ty = src.layout.ty;
295    let dst_ty = dst.layout.ty;
296    match (src_ty.kind(), dst_ty.kind()) {
297        (&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
298            let (base, info) = match bx.load_operand(src).val {
299                OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)),
300                OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None),
301                OperandValue::Ref(..) | OperandValue::ZeroSized => bug!(),
302            };
303            OperandValue::Pair(base, info).store(bx, dst);
304        }
305
306        (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
307            assert_eq!(def_a, def_b); // implies same number of fields
308
309            for i in def_a.variant(FIRST_VARIANT).fields.indices() {
310                let src_f = src.project_field(bx, i.as_usize());
311                let dst_f = dst.project_field(bx, i.as_usize());
312
313                if dst_f.layout.is_zst() {
314                    // No data here, nothing to copy/coerce.
315                    continue;
316                }
317
318                if src_f.layout.ty == dst_f.layout.ty {
319                    bx.typed_place_copy(dst_f.val, src_f.val, src_f.layout);
320                } else {
321                    coerce_unsized_into(bx, src_f, dst_f);
322                }
323            }
324        }
325        _ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}", src_ty, dst_ty,),
326    }
327}
328
329/// Returns `rhs` sufficiently masked, truncated, and/or extended so that it can be used to shift
330/// `lhs`: it has the same size as `lhs`, and the value, when interpreted unsigned (no matter its
331/// type), will not exceed the size of `lhs`.
332///
333/// Shifts in MIR are all allowed to have mismatched LHS & RHS types, and signed RHS.
334/// The shift methods in `BuilderMethods`, however, are fully homogeneous
335/// (both parameters and the return type are all the same size) and assume an unsigned RHS.
336///
337/// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds,
338/// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts.
339/// For 32- and 64-bit types, this matches the semantics
340/// of Java. (See related discussion on #1877 and #10183.)
341///
342/// If `is_unchecked` is true, this does no masking, and adds sufficient `assume`
343/// calls or operation flags to preserve as much freedom to optimize as possible.
344pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
345    bx: &mut Bx,
346    lhs: Bx::Value,
347    mut rhs: Bx::Value,
348    is_unchecked: bool,
349) -> Bx::Value {
350    // Shifts may have any size int on the rhs
351    let mut rhs_llty = bx.cx().val_ty(rhs);
352    let mut lhs_llty = bx.cx().val_ty(lhs);
353
354    let mask = common::shift_mask_val(bx, lhs_llty, rhs_llty, false);
355    if !is_unchecked {
356        rhs = bx.and(rhs, mask);
357    }
358
359    if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
360        rhs_llty = bx.cx().element_type(rhs_llty)
361    }
362    if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
363        lhs_llty = bx.cx().element_type(lhs_llty)
364    }
365    let rhs_sz = bx.cx().int_width(rhs_llty);
366    let lhs_sz = bx.cx().int_width(lhs_llty);
367    if lhs_sz < rhs_sz {
368        if is_unchecked { bx.unchecked_utrunc(rhs, lhs_llty) } else { bx.trunc(rhs, lhs_llty) }
369    } else if lhs_sz > rhs_sz {
370        // We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
371        // RHS to `255i32`. But then we mask the shift amount to be within the size of the LHS
372        // anyway so the result is `31` as it should be. All the extra bits introduced by zext
373        // are masked off so their value does not matter.
374        // FIXME: if we ever support 512bit integers, this will be wrong! For such large integers,
375        // the extra bits introduced by zext are *not* all masked away any more.
376        assert!(lhs_sz <= 256);
377        bx.zext(rhs, lhs_llty)
378    } else {
379        rhs
380    }
381}
382
383// Returns `true` if this session's target will use native wasm
384// exceptions. This means that the VM does the unwinding for
385// us
386pub fn wants_wasm_eh(sess: &Session) -> bool {
387    sess.target.is_like_wasm
388        && (sess.target.os != "emscripten" || sess.opts.unstable_opts.emscripten_wasm_eh)
389}
390
391/// Returns `true` if this session's target will use SEH-based unwinding.
392///
393/// This is only true for MSVC targets, and even then the 64-bit MSVC target
394/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
395/// 64-bit MinGW) instead of "full SEH".
396pub fn wants_msvc_seh(sess: &Session) -> bool {
397    sess.target.is_like_msvc
398}
399
400/// Returns `true` if this session's target requires the new exception
401/// handling LLVM IR instructions (catchpad / cleanuppad / ... instead
402/// of landingpad)
403pub(crate) fn wants_new_eh_instructions(sess: &Session) -> bool {
404    wants_wasm_eh(sess) || wants_msvc_seh(sess)
405}
406
407pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
408    cx: &'a Bx::CodegenCx,
409    instance: Instance<'tcx>,
410) {
411    // this is an info! to allow collecting monomorphization statistics
412    // and to allow finding the last function before LLVM aborts from
413    // release builds.
414    info!("codegen_instance({})", instance);
415
416    mir::codegen_mir::<Bx>(cx, instance);
417}
418
419pub fn codegen_global_asm<'tcx, Cx>(cx: &mut Cx, item_id: ItemId)
420where
421    Cx: LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + AsmCodegenMethods<'tcx>,
422{
423    let item = cx.tcx().hir_item(item_id);
424    if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind {
425        let operands: Vec<_> = asm
426            .operands
427            .iter()
428            .map(|(op, op_sp)| match *op {
429                rustc_hir::InlineAsmOperand::Const { ref anon_const } => {
430                    match cx.tcx().const_eval_poly(anon_const.def_id.to_def_id()) {
431                        Ok(const_value) => {
432                            let ty =
433                                cx.tcx().typeck_body(anon_const.body).node_type(anon_const.hir_id);
434                            let string = common::asm_const_to_str(
435                                cx.tcx(),
436                                *op_sp,
437                                const_value,
438                                cx.layout_of(ty),
439                            );
440                            GlobalAsmOperandRef::Const { string }
441                        }
442                        Err(ErrorHandled::Reported { .. }) => {
443                            // An error has already been reported and
444                            // compilation is guaranteed to fail if execution
445                            // hits this path. So an empty string instead of
446                            // a stringified constant value will suffice.
447                            GlobalAsmOperandRef::Const { string: String::new() }
448                        }
449                        Err(ErrorHandled::TooGeneric(_)) => {
450                            span_bug!(*op_sp, "asm const cannot be resolved; too generic")
451                        }
452                    }
453                }
454                rustc_hir::InlineAsmOperand::SymFn { expr } => {
455                    let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr);
456                    let instance = match ty.kind() {
457                        &ty::FnDef(def_id, args) => Instance::expect_resolve(
458                            cx.tcx(),
459                            ty::TypingEnv::fully_monomorphized(),
460                            def_id,
461                            args,
462                            expr.span,
463                        ),
464                        _ => span_bug!(*op_sp, "asm sym is not a function"),
465                    };
466
467                    GlobalAsmOperandRef::SymFn { instance }
468                }
469                rustc_hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
470                    GlobalAsmOperandRef::SymStatic { def_id }
471                }
472                rustc_hir::InlineAsmOperand::In { .. }
473                | rustc_hir::InlineAsmOperand::Out { .. }
474                | rustc_hir::InlineAsmOperand::InOut { .. }
475                | rustc_hir::InlineAsmOperand::SplitInOut { .. }
476                | rustc_hir::InlineAsmOperand::Label { .. } => {
477                    span_bug!(*op_sp, "invalid operand type for global_asm!")
478                }
479            })
480            .collect();
481
482        cx.codegen_global_asm(asm.template, &operands, asm.options, asm.line_spans);
483    } else {
484        span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type")
485    }
486}
487
488/// Creates the `main` function which will initialize the rust runtime and call
489/// users main function.
490pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
491    cx: &'a Bx::CodegenCx,
492    cgu: &CodegenUnit<'tcx>,
493) -> Option<Bx::Function> {
494    let (main_def_id, entry_type) = cx.tcx().entry_fn(())?;
495    let main_is_local = main_def_id.is_local();
496    let instance = Instance::mono(cx.tcx(), main_def_id);
497
498    if main_is_local {
499        // We want to create the wrapper in the same codegen unit as Rust's main
500        // function.
501        if !cgu.contains_item(&MonoItem::Fn(instance)) {
502            return None;
503        }
504    } else if !cgu.is_primary() {
505        // We want to create the wrapper only when the codegen unit is the primary one
506        return None;
507    }
508
509    let main_llfn = cx.get_fn_addr(instance);
510
511    let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
512    return Some(entry_fn);
513
514    fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
515        cx: &'a Bx::CodegenCx,
516        rust_main: Bx::Value,
517        rust_main_def_id: DefId,
518        entry_type: EntryFnType,
519    ) -> Bx::Function {
520        // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or
521        // `usize efi_main(void *handle, void *system_table)` depending on the target.
522        let llfty = if cx.sess().target.os.contains("uefi") {
523            cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize())
524        } else if cx.sess().target.main_needs_argc_argv {
525            cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int())
526        } else {
527            cx.type_func(&[], cx.type_int())
528        };
529
530        let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
531        // Given that `main()` has no arguments,
532        // then its return type cannot have
533        // late-bound regions, since late-bound
534        // regions must appear in the argument
535        // listing.
536        let main_ret_ty = cx
537            .tcx()
538            .normalize_erasing_regions(cx.typing_env(), main_ret_ty.no_bound_vars().unwrap());
539
540        let Some(llfn) = cx.declare_c_main(llfty) else {
541            // FIXME: We should be smart and show a better diagnostic here.
542            let span = cx.tcx().def_span(rust_main_def_id);
543            cx.tcx().dcx().emit_fatal(errors::MultipleMainFunctions { span });
544        };
545
546        // `main` should respect same config for frame pointer elimination as rest of code
547        cx.set_frame_pointer_type(llfn);
548        cx.apply_target_cpu_attr(llfn);
549
550        let llbb = Bx::append_block(cx, llfn, "top");
551        let mut bx = Bx::build(cx, llbb);
552
553        bx.insert_reference_to_gdb_debug_scripts_section_global();
554
555        let isize_ty = cx.type_isize();
556        let ptr_ty = cx.type_ptr();
557        let (arg_argc, arg_argv) = get_argc_argv(&mut bx);
558
559        let EntryFnType::Main { sigpipe } = entry_type;
560        let (start_fn, start_ty, args, instance) = {
561            let start_def_id = cx.tcx().require_lang_item(LangItem::Start, DUMMY_SP);
562            let start_instance = ty::Instance::expect_resolve(
563                cx.tcx(),
564                cx.typing_env(),
565                start_def_id,
566                cx.tcx().mk_args(&[main_ret_ty.into()]),
567                DUMMY_SP,
568            );
569            let start_fn = cx.get_fn_addr(start_instance);
570
571            let i8_ty = cx.type_i8();
572            let arg_sigpipe = bx.const_u8(sigpipe);
573
574            let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, ptr_ty, i8_ty], isize_ty);
575            (
576                start_fn,
577                start_ty,
578                vec![rust_main, arg_argc, arg_argv, arg_sigpipe],
579                Some(start_instance),
580            )
581        };
582
583        let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
584        if cx.sess().target.os.contains("uefi") {
585            bx.ret(result);
586        } else {
587            let cast = bx.intcast(result, cx.type_int(), true);
588            bx.ret(cast);
589        }
590
591        llfn
592    }
593}
594
595/// Obtain the `argc` and `argv` values to pass to the rust start function
596/// (i.e., the "start" lang item).
597fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) {
598    if bx.cx().sess().target.os.contains("uefi") {
599        // Params for UEFI
600        let param_handle = bx.get_param(0);
601        let param_system_table = bx.get_param(1);
602        let ptr_size = bx.tcx().data_layout.pointer_size;
603        let ptr_align = bx.tcx().data_layout.pointer_align.abi;
604        let arg_argc = bx.const_int(bx.cx().type_isize(), 2);
605        let arg_argv = bx.alloca(2 * ptr_size, ptr_align);
606        bx.store(param_handle, arg_argv, ptr_align);
607        let arg_argv_el1 = bx.inbounds_ptradd(arg_argv, bx.const_usize(ptr_size.bytes()));
608        bx.store(param_system_table, arg_argv_el1, ptr_align);
609        (arg_argc, arg_argv)
610    } else if bx.cx().sess().target.main_needs_argc_argv {
611        // Params from native `main()` used as args for rust start function
612        let param_argc = bx.get_param(0);
613        let param_argv = bx.get_param(1);
614        let arg_argc = bx.intcast(param_argc, bx.cx().type_isize(), true);
615        let arg_argv = param_argv;
616        (arg_argc, arg_argv)
617    } else {
618        // The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
619        let arg_argc = bx.const_int(bx.cx().type_int(), 0);
620        let arg_argv = bx.const_null(bx.cx().type_ptr());
621        (arg_argc, arg_argv)
622    }
623}
624
625/// This function returns all of the debugger visualizers specified for the
626/// current crate as well as all upstream crates transitively that match the
627/// `visualizer_type` specified.
628pub fn collect_debugger_visualizers_transitive(
629    tcx: TyCtxt<'_>,
630    visualizer_type: DebuggerVisualizerType,
631) -> BTreeSet<DebuggerVisualizerFile> {
632    tcx.debugger_visualizers(LOCAL_CRATE)
633        .iter()
634        .chain(
635            tcx.crates(())
636                .iter()
637                .filter(|&cnum| {
638                    let used_crate_source = tcx.used_crate_source(*cnum);
639                    used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some()
640                })
641                .flat_map(|&cnum| tcx.debugger_visualizers(cnum)),
642        )
643        .filter(|visualizer| visualizer.visualizer_type == visualizer_type)
644        .cloned()
645        .collect::<BTreeSet<_>>()
646}
647
648/// Decide allocator kind to codegen. If `Some(_)` this will be the same as
649/// `tcx.allocator_kind`, but it may be `None` in more cases (e.g. if using
650/// allocator definitions from a dylib dependency).
651pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
652    // If the crate doesn't have an `allocator_kind` set then there's definitely
653    // no shim to generate. Otherwise we also check our dependency graph for all
654    // our output crate types. If anything there looks like its a `Dynamic`
655    // linkage, then it's already got an allocator shim and we'll be using that
656    // one instead. If nothing exists then it's our job to generate the
657    // allocator!
658    let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
659        use rustc_middle::middle::dependency_format::Linkage;
660        list.iter().any(|&linkage| linkage == Linkage::Dynamic)
661    });
662    if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
663}
664
665pub fn codegen_crate<B: ExtraBackendMethods>(
666    backend: B,
667    tcx: TyCtxt<'_>,
668    target_cpu: String,
669) -> OngoingCodegen<B> {
670    // Skip crate items and just output metadata in -Z no-codegen mode.
671    if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
672        let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu);
673
674        ongoing_codegen.codegen_finished(tcx);
675
676        ongoing_codegen.check_for_errors(tcx.sess);
677
678        return ongoing_codegen;
679    }
680
681    if tcx.sess.target.need_explicit_cpu && tcx.sess.opts.cg.target_cpu.is_none() {
682        // The target has no default cpu, but none is set explicitly
683        tcx.dcx().emit_fatal(errors::CpuRequired);
684    }
685
686    let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
687
688    // Run the monomorphization collector and partition the collected items into
689    // codegen units.
690    let MonoItemPartitions { codegen_units, autodiff_items, .. } =
691        tcx.collect_and_partition_mono_items(());
692    let autodiff_fncs = autodiff_items.to_vec();
693
694    // Force all codegen_unit queries so they are already either red or green
695    // when compile_codegen_unit accesses them. We are not able to re-execute
696    // the codegen_unit query from just the DepNode, so an unknown color would
697    // lead to having to re-execute compile_codegen_unit, possibly
698    // unnecessarily.
699    if tcx.dep_graph.is_fully_enabled() {
700        for cgu in codegen_units {
701            tcx.ensure_ok().codegen_unit(cgu.name());
702        }
703    }
704
705    let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu);
706
707    // Codegen an allocator shim, if necessary.
708    if let Some(kind) = allocator_kind_for_codegen(tcx) {
709        let llmod_id =
710            cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
711        let module_llvm = tcx.sess.time("write_allocator_module", || {
712            backend.codegen_allocator(
713                tcx,
714                &llmod_id,
715                kind,
716                // If allocator_kind is Some then alloc_error_handler_kind must
717                // also be Some.
718                tcx.alloc_error_handler_kind(()).unwrap(),
719            )
720        });
721
722        ongoing_codegen.wait_for_signal_to_codegen_item();
723        ongoing_codegen.check_for_errors(tcx.sess);
724
725        // These modules are generally cheap and won't throw off scheduling.
726        let cost = 0;
727        submit_codegened_module_to_llvm(
728            &backend,
729            &ongoing_codegen.coordinator.sender,
730            ModuleCodegen::new_allocator(llmod_id, module_llvm),
731            cost,
732        );
733    }
734
735    if !autodiff_fncs.is_empty() {
736        ongoing_codegen.submit_autodiff_items(autodiff_fncs);
737    }
738
739    // For better throughput during parallel processing by LLVM, we used to sort
740    // CGUs largest to smallest. This would lead to better thread utilization
741    // by, for example, preventing a large CGU from being processed last and
742    // having only one LLVM thread working while the rest remained idle.
743    //
744    // However, this strategy would lead to high memory usage, as it meant the
745    // LLVM-IR for all of the largest CGUs would be resident in memory at once.
746    //
747    // Instead, we can compromise by ordering CGUs such that the largest and
748    // smallest are first, second largest and smallest are next, etc. If there
749    // are large size variations, this can reduce memory usage significantly.
750    let codegen_units: Vec<_> = {
751        let mut sorted_cgus = codegen_units.iter().collect::<Vec<_>>();
752        sorted_cgus.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate()));
753
754        let (first_half, second_half) = sorted_cgus.split_at(sorted_cgus.len() / 2);
755        first_half.iter().interleave(second_half.iter().rev()).copied().collect()
756    };
757
758    // Calculate the CGU reuse
759    let cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
760        codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, cgu)).collect::<Vec<_>>()
761    });
762
763    crate::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| {
764        for (i, cgu) in codegen_units.iter().enumerate() {
765            let cgu_reuse = cgu_reuse[i];
766            cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
767        }
768    });
769
770    let mut total_codegen_time = Duration::new(0, 0);
771    let start_rss = tcx.sess.opts.unstable_opts.time_passes.then(|| get_resident_set_size());
772
773    // The non-parallel compiler can only translate codegen units to LLVM IR
774    // on a single thread, leading to a staircase effect where the N LLVM
775    // threads have to wait on the single codegen threads to generate work
776    // for them. The parallel compiler does not have this restriction, so
777    // we can pre-load the LLVM queue in parallel before handing off
778    // coordination to the OnGoingCodegen scheduler.
779    //
780    // This likely is a temporary measure. Once we don't have to support the
781    // non-parallel compiler anymore, we can compile CGUs end-to-end in
782    // parallel and get rid of the complicated scheduling logic.
783    let mut pre_compiled_cgus = if tcx.sess.threads() > 1 {
784        tcx.sess.time("compile_first_CGU_batch", || {
785            // Try to find one CGU to compile per thread.
786            let cgus: Vec<_> = cgu_reuse
787                .iter()
788                .enumerate()
789                .filter(|&(_, reuse)| reuse == &CguReuse::No)
790                .take(tcx.sess.threads())
791                .collect();
792
793            // Compile the found CGUs in parallel.
794            let start_time = Instant::now();
795
796            let pre_compiled_cgus = par_map(cgus, |(i, _)| {
797                let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
798                (i, IntoDynSyncSend(module))
799            });
800
801            total_codegen_time += start_time.elapsed();
802
803            pre_compiled_cgus
804        })
805    } else {
806        FxHashMap::default()
807    };
808
809    for (i, cgu) in codegen_units.iter().enumerate() {
810        ongoing_codegen.wait_for_signal_to_codegen_item();
811        ongoing_codegen.check_for_errors(tcx.sess);
812
813        let cgu_reuse = cgu_reuse[i];
814
815        match cgu_reuse {
816            CguReuse::No => {
817                let (module, cost) = if let Some(cgu) = pre_compiled_cgus.remove(&i) {
818                    cgu.0
819                } else {
820                    let start_time = Instant::now();
821                    let module = backend.compile_codegen_unit(tcx, cgu.name());
822                    total_codegen_time += start_time.elapsed();
823                    module
824                };
825                // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
826                // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
827                // compilation hang on post-monomorphization errors.
828                tcx.dcx().abort_if_errors();
829
830                submit_codegened_module_to_llvm(
831                    &backend,
832                    &ongoing_codegen.coordinator.sender,
833                    module,
834                    cost,
835                );
836            }
837            CguReuse::PreLto => {
838                submit_pre_lto_module_to_llvm(
839                    &backend,
840                    tcx,
841                    &ongoing_codegen.coordinator.sender,
842                    CachedModuleCodegen {
843                        name: cgu.name().to_string(),
844                        source: cgu.previous_work_product(tcx),
845                    },
846                );
847            }
848            CguReuse::PostLto => {
849                submit_post_lto_module_to_llvm(
850                    &backend,
851                    &ongoing_codegen.coordinator.sender,
852                    CachedModuleCodegen {
853                        name: cgu.name().to_string(),
854                        source: cgu.previous_work_product(tcx),
855                    },
856                );
857            }
858        }
859    }
860
861    ongoing_codegen.codegen_finished(tcx);
862
863    // Since the main thread is sometimes blocked during codegen, we keep track
864    // -Ztime-passes output manually.
865    if tcx.sess.opts.unstable_opts.time_passes {
866        let end_rss = get_resident_set_size();
867
868        print_time_passes_entry(
869            "codegen_to_LLVM_IR",
870            total_codegen_time,
871            start_rss.unwrap(),
872            end_rss,
873            tcx.sess.opts.unstable_opts.time_passes_format,
874        );
875    }
876
877    ongoing_codegen.check_for_errors(tcx.sess);
878    ongoing_codegen
879}
880
881/// Returns whether a call from the current crate to the [`Instance`] would produce a call
882/// from `compiler_builtins` to a symbol the linker must resolve.
883///
884/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
885/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
886/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
887/// unlinkable calls.
888///
889/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
890pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
891    tcx: TyCtxt<'tcx>,
892    instance: Instance<'tcx>,
893) -> bool {
894    fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
895        if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
896            name.as_str().starts_with("llvm.")
897        } else {
898            false
899        }
900    }
901
902    let def_id = instance.def_id();
903    !def_id.is_local()
904        && tcx.is_compiler_builtins(LOCAL_CRATE)
905        && !is_llvm_intrinsic(tcx, def_id)
906        && !tcx.should_codegen_locally(instance)
907}
908
909impl CrateInfo {
910    pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
911        let crate_types = tcx.crate_types().to_vec();
912        let exported_symbols = crate_types
913            .iter()
914            .map(|&c| (c, crate::back::linker::exported_symbols(tcx, c)))
915            .collect();
916        let linked_symbols =
917            crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect();
918        let local_crate_name = tcx.crate_name(LOCAL_CRATE);
919        let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
920        let subsystem =
921            ast::attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
922        let windows_subsystem = subsystem.map(|subsystem| {
923            if subsystem != sym::windows && subsystem != sym::console {
924                tcx.dcx().emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
925            }
926            subsystem.to_string()
927        });
928
929        // This list is used when generating the command line to pass through to
930        // system linker. The linker expects undefined symbols on the left of the
931        // command line to be defined in libraries on the right, not the other way
932        // around. For more info, see some comments in the add_used_library function
933        // below.
934        //
935        // In order to get this left-to-right dependency ordering, we use the reverse
936        // postorder of all crates putting the leaves at the rightmost positions.
937        let mut compiler_builtins = None;
938        let mut used_crates: Vec<_> = tcx
939            .postorder_cnums(())
940            .iter()
941            .rev()
942            .copied()
943            .filter(|&cnum| {
944                let link = !tcx.dep_kind(cnum).macros_only();
945                if link && tcx.is_compiler_builtins(cnum) {
946                    compiler_builtins = Some(cnum);
947                    return false;
948                }
949                link
950            })
951            .collect();
952        // `compiler_builtins` are always placed last to ensure that they're linked correctly.
953        used_crates.extend(compiler_builtins);
954
955        let crates = tcx.crates(());
956        let n_crates = crates.len();
957        let mut info = CrateInfo {
958            target_cpu,
959            target_features: tcx.global_backend_features(()).clone(),
960            crate_types,
961            exported_symbols,
962            linked_symbols,
963            local_crate_name,
964            compiler_builtins,
965            profiler_runtime: None,
966            is_no_builtins: Default::default(),
967            native_libraries: Default::default(),
968            used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
969            crate_name: UnordMap::with_capacity(n_crates),
970            used_crates,
971            used_crate_source: UnordMap::with_capacity(n_crates),
972            dependency_formats: Arc::clone(tcx.dependency_formats(())),
973            windows_subsystem,
974            natvis_debugger_visualizers: Default::default(),
975            lint_levels: CodegenLintLevels::from_tcx(tcx),
976            metadata_symbol: exported_symbols::metadata_symbol_name(tcx),
977        };
978
979        info.native_libraries.reserve(n_crates);
980
981        for &cnum in crates.iter() {
982            info.native_libraries
983                .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
984            info.crate_name.insert(cnum, tcx.crate_name(cnum));
985
986            let used_crate_source = tcx.used_crate_source(cnum);
987            info.used_crate_source.insert(cnum, Arc::clone(used_crate_source));
988            if tcx.is_profiler_runtime(cnum) {
989                info.profiler_runtime = Some(cnum);
990            }
991            if tcx.is_no_builtins(cnum) {
992                info.is_no_builtins.insert(cnum);
993            }
994        }
995
996        // Handle circular dependencies in the standard library.
997        // See comment before `add_linked_symbol_object` function for the details.
998        // If global LTO is enabled then almost everything (*) is glued into a single object file,
999        // so this logic is not necessary and can cause issues on some targets (due to weak lang
1000        // item symbols being "privatized" to that object file), so we disable it.
1001        // (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued,
1002        // and we assume that they cannot define weak lang items. This is not currently enforced
1003        // by the compiler, but that's ok because all this stuff is unstable anyway.
1004        let target = &tcx.sess.target;
1005        if !are_upstream_rust_objects_already_included(tcx.sess) {
1006            let missing_weak_lang_items: FxIndexSet<Symbol> = info
1007                .used_crates
1008                .iter()
1009                .flat_map(|&cnum| tcx.missing_lang_items(cnum))
1010                .filter(|l| l.is_weak())
1011                .filter_map(|&l| {
1012                    let name = l.link_name()?;
1013                    lang_items::required(tcx, l).then_some(name)
1014                })
1015                .collect();
1016            let prefix = match (target.is_like_windows, target.arch.as_ref()) {
1017                (true, "x86") => "_",
1018                (true, "arm64ec") => "#",
1019                _ => "",
1020            };
1021
1022            // This loop only adds new items to values of the hash map, so the order in which we
1023            // iterate over the values is not important.
1024            #[allow(rustc::potential_query_instability)]
1025            info.linked_symbols
1026                .iter_mut()
1027                .filter(|(crate_type, _)| {
1028                    !matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
1029                })
1030                .for_each(|(_, linked_symbols)| {
1031                    let mut symbols = missing_weak_lang_items
1032                        .iter()
1033                        .map(|item| {
1034                            (
1035                                format!("{prefix}{}", mangle_internal_symbol(tcx, item.as_str())),
1036                                SymbolExportKind::Text,
1037                            )
1038                        })
1039                        .collect::<Vec<_>>();
1040                    symbols.sort_unstable_by(|a, b| a.0.cmp(&b.0));
1041                    linked_symbols.extend(symbols);
1042                    if tcx.allocator_kind(()).is_some() {
1043                        // At least one crate needs a global allocator. This crate may be placed
1044                        // after the crate that defines it in the linker order, in which case some
1045                        // linkers return an error. By adding the global allocator shim methods to
1046                        // the linked_symbols list, linking the generated symbols.o will ensure that
1047                        // circular dependencies involving the global allocator don't lead to linker
1048                        // errors.
1049                        linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
1050                            (
1051                                format!(
1052                                    "{prefix}{}",
1053                                    mangle_internal_symbol(
1054                                        tcx,
1055                                        global_fn_name(method.name).as_str()
1056                                    )
1057                                ),
1058                                SymbolExportKind::Text,
1059                            )
1060                        }));
1061                    }
1062                });
1063        }
1064
1065        let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
1066            CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
1067                // These are crate types for which we invoke the linker and can embed
1068                // NatVis visualizers.
1069                true
1070            }
1071            CrateType::ProcMacro => {
1072                // We could embed NatVis for proc macro crates too (to improve the debugging
1073                // experience for them) but it does not seem like a good default, since
1074                // this is a rare use case and we don't want to slow down the common case.
1075                false
1076            }
1077            CrateType::Staticlib | CrateType::Rlib => {
1078                // We don't invoke the linker for these, so we don't need to collect the NatVis for
1079                // them.
1080                false
1081            }
1082        });
1083
1084        if target.is_like_msvc && embed_visualizers {
1085            info.natvis_debugger_visualizers =
1086                collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis);
1087        }
1088
1089        info
1090    }
1091}
1092
1093pub(crate) fn provide(providers: &mut Providers) {
1094    providers.backend_optimization_level = |tcx, cratenum| {
1095        let for_speed = match tcx.sess.opts.optimize {
1096            // If globally no optimisation is done, #[optimize] has no effect.
1097            //
1098            // This is done because if we ended up "upgrading" to `-O2` here, we’d populate the
1099            // pass manager and it is likely that some module-wide passes (such as inliner or
1100            // cross-function constant propagation) would ignore the `optnone` annotation we put
1101            // on the functions, thus necessarily involving these functions into optimisations.
1102            config::OptLevel::No => return config::OptLevel::No,
1103            // If globally optimise-speed is already specified, just use that level.
1104            config::OptLevel::Less => return config::OptLevel::Less,
1105            config::OptLevel::More => return config::OptLevel::More,
1106            config::OptLevel::Aggressive => return config::OptLevel::Aggressive,
1107            // If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
1108            // are present).
1109            config::OptLevel::Size => config::OptLevel::More,
1110            config::OptLevel::SizeMin => config::OptLevel::More,
1111        };
1112
1113        let defids = tcx.collect_and_partition_mono_items(cratenum).all_mono_items;
1114
1115        let any_for_speed = defids.items().any(|id| {
1116            let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
1117            matches!(optimize, OptimizeAttr::Speed)
1118        });
1119
1120        if any_for_speed {
1121            return for_speed;
1122        }
1123
1124        tcx.sess.opts.optimize
1125    };
1126}
1127
1128pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
1129    if !tcx.dep_graph.is_fully_enabled() {
1130        return CguReuse::No;
1131    }
1132
1133    let work_product_id = &cgu.work_product_id();
1134    if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
1135        // We don't have anything cached for this CGU. This can happen
1136        // if the CGU did not exist in the previous session.
1137        return CguReuse::No;
1138    }
1139
1140    // Try to mark the CGU as green. If it we can do so, it means that nothing
1141    // affecting the LLVM module has changed and we can re-use a cached version.
1142    // If we compile with any kind of LTO, this means we can re-use the bitcode
1143    // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
1144    // know that later). If we are not doing LTO, there is only one optimized
1145    // version of each module, so we re-use that.
1146    let dep_node = cgu.codegen_dep_node(tcx);
1147    tcx.dep_graph.assert_dep_node_not_yet_allocated_in_current_session(&dep_node, || {
1148        format!(
1149            "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
1150            cgu.name()
1151        )
1152    });
1153
1154    if tcx.try_mark_green(&dep_node) {
1155        // We can re-use either the pre- or the post-thinlto state. If no LTO is
1156        // being performed then we can use post-LTO artifacts, otherwise we must
1157        // reuse pre-LTO artifacts
1158        match compute_per_cgu_lto_type(
1159            &tcx.sess.lto(),
1160            &tcx.sess.opts,
1161            tcx.crate_types(),
1162            ModuleKind::Regular,
1163        ) {
1164            ComputedLtoType::No => CguReuse::PostLto,
1165            _ => CguReuse::PreLto,
1166        }
1167    } else {
1168        CguReuse::No
1169    }
1170}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy