2022-10-15 22:01:28 +04:00
|
|
|
|
use std::cmp;
|
Use object crate for .rustc metadata generation
We already use the object crate for generating uncompressed .rmeta
metadata object files. This switches the generation of compressed
.rustc object files to use the object crate as well. These have
slightly different requirements in that .rmeta should be completely
excluded from any final compilation artifacts, while .rustc should
be part of shared objects, but not loaded into memory.
The primary motivation for this change is #90326: In LLVM 14, the
current way of setting section flags (and in particular, preventing
the setting of SHF_ALLOC) will no longer work. There are other ways
we could work around this, but switching to the object crate seems
like the most elegant, as we already use it for .rmeta, and as it
makes this independent of the codegen backend. In particular, we
don't need separate handling in codegen_llvm and codegen_gcc.
codegen_cranelift should be able to reuse the implementation as
well, though I have omitted that here, as it is not based on
codegen_ssa.
This change mostly extracts the existing code for .rmeta handling
to allow using it for .rustc as well, and adjust the codegen
infrastructure to handle the metadata object file separately: We
no longer create a backend-specific module for it, and directly
produce the compiled module instead.
This does not fix #90326 by itself yet, as .llvmbc will need to be
handled separately.
2021-12-02 12:24:25 +01:00
|
|
|
|
use std::collections::BTreeSet;
|
2024-03-30 00:36:45 -07:00
|
|
|
|
use std::time::{Duration, Instant};
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2021-02-03 18:41:30 -08:00
|
|
|
|
use itertools::Itertools;
|
2024-11-02 19:32:52 -07:00
|
|
|
|
use rustc_abi::FIRST_VARIANT;
|
2023-06-19 13:39:17 +00:00
|
|
|
|
use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name};
|
2024-02-11 19:50:50 +08:00
|
|
|
|
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
|
2021-01-25 12:56:21 -08:00
|
|
|
|
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
|
2024-10-07 22:22:51 +03:00
|
|
|
|
use rustc_data_structures::sync::{Lrc, par_map};
|
2024-02-11 19:50:50 +08:00
|
|
|
|
use rustc_data_structures::unord::UnordMap;
|
2021-04-26 01:09:35 +08:00
|
|
|
|
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
2020-08-18 11:47:27 +01:00
|
|
|
|
use rustc_hir::lang_items::LangItem;
|
2021-09-24 18:15:36 +02:00
|
|
|
|
use rustc_metadata::EncodedMetadata;
|
2024-04-29 13:56:41 +10:00
|
|
|
|
use rustc_middle::bug;
|
2020-03-29 16:41:09 +02:00
|
|
|
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
2023-05-16 21:03:28 +02:00
|
|
|
|
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
2022-08-15 13:15:01 +03:00
|
|
|
|
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
2020-03-29 16:41:09 +02:00
|
|
|
|
use rustc_middle::middle::{exported_symbols, lang_items};
|
2024-05-24 15:08:18 +10:00
|
|
|
|
use rustc_middle::mir::BinOp;
|
2020-03-29 16:41:09 +02:00
|
|
|
|
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
|
2023-05-15 06:24:45 +02:00
|
|
|
|
use rustc_middle::query::Providers;
|
2024-11-15 13:53:31 +01:00
|
|
|
|
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
|
2024-11-19 21:11:55 +01:00
|
|
|
|
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
2020-03-11 12:49:08 +01:00
|
|
|
|
use rustc_session::Session;
|
2024-03-30 00:36:45 -07:00
|
|
|
|
use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
|
2021-05-29 17:08:46 +02:00
|
|
|
|
use rustc_span::symbol::sym;
|
2024-07-01 16:32:32 -04:00
|
|
|
|
use rustc_span::{DUMMY_SP, Symbol};
|
2024-09-30 12:42:29 -04:00
|
|
|
|
use rustc_trait_selection::infer::at::ToTrace;
|
|
|
|
|
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
2024-09-28 14:16:05 -04:00
|
|
|
|
use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
|
2024-05-22 15:08:26 +10:00
|
|
|
|
use tracing::{debug, info};
|
2024-12-13 14:47:11 +01:00
|
|
|
|
use {rustc_ast as ast, rustc_attr_parsing as attr};
|
2021-02-03 18:41:30 -08:00
|
|
|
|
|
2023-09-19 11:23:35 +00:00
|
|
|
|
use crate::assert_module_sources::CguReuse;
|
2022-10-15 22:01:28 +04:00
|
|
|
|
use crate::back::link::are_upstream_rust_objects_already_included;
|
Use object crate for .rustc metadata generation
We already use the object crate for generating uncompressed .rmeta
metadata object files. This switches the generation of compressed
.rustc object files to use the object crate as well. These have
slightly different requirements in that .rmeta should be completely
excluded from any final compilation artifacts, while .rustc should
be part of shared objects, but not loaded into memory.
The primary motivation for this change is #90326: In LLVM 14, the
current way of setting section flags (and in particular, preventing
the setting of SHF_ALLOC) will no longer work. There are other ways
we could work around this, but switching to the object crate seems
like the most elegant, as we already use it for .rmeta, and as it
makes this independent of the codegen backend. In particular, we
don't need separate handling in codegen_llvm and codegen_gcc.
codegen_cranelift should be able to reuse the implementation as
well, though I have omitted that here, as it is not based on
codegen_ssa.
This change mostly extracts the existing code for .rmeta handling
to allow using it for .rustc as well, and adjust the codegen
infrastructure to handle the metadata object file separately: We
no longer create a backend-specific module for it, and directly
produce the compiled module instead.
This does not fix #90326 by itself yet, as .llvmbc will need to be
handled separately.
2021-12-02 12:24:25 +01:00
|
|
|
|
use crate::back::metadata::create_compressed_metadata_file;
|
2019-05-17 02:20:14 +01:00
|
|
|
|
use crate::back::write::{
|
2020-05-08 09:27:59 -07:00
|
|
|
|
ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen,
|
|
|
|
|
submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
|
2024-07-29 08:13:50 +10:00
|
|
|
|
};
|
2024-03-30 00:36:45 -07:00
|
|
|
|
use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
|
2024-09-23 15:25:52 +08:00
|
|
|
|
use crate::meth::load_vtable;
|
2019-05-17 02:20:14 +01:00
|
|
|
|
use crate::mir::operand::OperandValue;
|
|
|
|
|
use crate::mir::place::PlaceRef;
|
|
|
|
|
use crate::traits::*;
|
|
|
|
|
use crate::{
|
2024-03-29 00:00:24 -07:00
|
|
|
|
CachedModuleCodegen, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
|
2024-07-29 08:13:50 +10:00
|
|
|
|
};
|
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
2024-09-11 09:55:04 +10:00
|
|
|
|
match (op, signed) {
|
|
|
|
|
(BinOp::Eq, _) => IntPredicate::IntEQ,
|
|
|
|
|
(BinOp::Ne, _) => IntPredicate::IntNE,
|
|
|
|
|
(BinOp::Lt, true) => IntPredicate::IntSLT,
|
|
|
|
|
(BinOp::Lt, false) => IntPredicate::IntULT,
|
|
|
|
|
(BinOp::Le, true) => IntPredicate::IntSLE,
|
|
|
|
|
(BinOp::Le, false) => IntPredicate::IntULE,
|
|
|
|
|
(BinOp::Gt, true) => IntPredicate::IntSGT,
|
|
|
|
|
(BinOp::Gt, false) => IntPredicate::IntUGT,
|
|
|
|
|
(BinOp::Ge, true) => IntPredicate::IntSGE,
|
|
|
|
|
(BinOp::Ge, false) => IntPredicate::IntUGE,
|
|
|
|
|
op => bug!("bin_op_to_icmp_predicate: expected comparison operator, found {:?}", op),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn bin_op_to_fcmp_predicate(op: BinOp) -> RealPredicate {
|
2018-10-03 13:49:57 +02:00
|
|
|
|
match op {
|
2024-05-22 00:56:57 -07:00
|
|
|
|
BinOp::Eq => RealPredicate::RealOEQ,
|
|
|
|
|
BinOp::Ne => RealPredicate::RealUNE,
|
|
|
|
|
BinOp::Lt => RealPredicate::RealOLT,
|
|
|
|
|
BinOp::Le => RealPredicate::RealOLE,
|
|
|
|
|
BinOp::Gt => RealPredicate::RealOGT,
|
|
|
|
|
BinOp::Ge => RealPredicate::RealOGE,
|
2024-09-11 09:55:04 +10:00
|
|
|
|
op => bug!("bin_op_to_fcmp_predicate: expected comparison operator, found {:?}", op),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
|
pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
2018-10-05 15:08:49 +02:00
|
|
|
|
bx: &mut Bx,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
lhs: Bx::Value,
|
|
|
|
|
rhs: Bx::Value,
|
|
|
|
|
t: Ty<'tcx>,
|
|
|
|
|
ret_ty: Bx::Type,
|
2024-05-22 00:56:57 -07:00
|
|
|
|
op: BinOp,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
) -> Bx::Value {
|
2020-08-03 00:49:11 +02:00
|
|
|
|
let signed = match t.kind() {
|
2018-10-03 13:49:57 +02:00
|
|
|
|
ty::Float(_) => {
|
|
|
|
|
let cmp = bin_op_to_fcmp_predicate(op);
|
2018-10-05 15:08:49 +02:00
|
|
|
|
let cmp = bx.fcmp(cmp, lhs, rhs);
|
|
|
|
|
return bx.sext(cmp, ret_ty);
|
2019-12-24 17:38:22 -05:00
|
|
|
|
}
|
2018-10-03 13:49:57 +02:00
|
|
|
|
ty::Uint(_) => false,
|
|
|
|
|
ty::Int(_) => true,
|
|
|
|
|
_ => bug!("compare_simd_types: invalid SIMD type"),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let cmp = bin_op_to_icmp_predicate(op, signed);
|
2018-10-05 15:08:49 +02:00
|
|
|
|
let cmp = bx.icmp(cmp, lhs, rhs);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
// LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
|
|
|
|
|
// to get the correctly sized type. This will compile to a single instruction
|
|
|
|
|
// once the IR is converted to assembly if the SIMD instruction is supported
|
|
|
|
|
// by the target architecture.
|
2018-10-05 15:08:49 +02:00
|
|
|
|
bx.sext(cmp, ret_ty)
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-09-28 14:16:05 -04:00
|
|
|
|
/// Codegen takes advantage of the additional assumption, where if the
|
|
|
|
|
/// principal trait def id of what's being casted doesn't change,
|
|
|
|
|
/// then we don't need to adjust the vtable at all. This
|
|
|
|
|
/// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
|
|
|
|
|
/// requires that `A = B`; we don't allow *upcasting* objects
|
|
|
|
|
/// between the same trait with different args. If we, for
|
|
|
|
|
/// some reason, were to relax the `Unsize` trait, it could become
|
|
|
|
|
/// unsound, so let's validate here that the trait refs are subtypes.
|
|
|
|
|
pub fn validate_trivial_unsize<'tcx>(
|
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2024-09-30 12:42:29 -04:00
|
|
|
|
source_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
|
|
|
|
target_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
|
2024-09-28 14:16:05 -04:00
|
|
|
|
) -> bool {
|
2024-09-30 12:42:29 -04:00
|
|
|
|
match (source_data.principal(), target_data.principal()) {
|
|
|
|
|
(Some(hr_source_principal), Some(hr_target_principal)) => {
|
2024-11-19 21:11:55 +01:00
|
|
|
|
let (infcx, param_env) =
|
|
|
|
|
tcx.infer_ctxt().build_with_typing_env(ty::TypingEnv::fully_monomorphized());
|
2024-09-30 12:42:29 -04:00
|
|
|
|
let universe = infcx.universe();
|
2024-09-28 14:16:05 -04:00
|
|
|
|
let ocx = ObligationCtxt::new(&infcx);
|
2024-09-30 12:42:29 -04:00
|
|
|
|
infcx.enter_forall(hr_target_principal, |target_principal| {
|
|
|
|
|
let source_principal = infcx.instantiate_binder_with_fresh_vars(
|
|
|
|
|
DUMMY_SP,
|
|
|
|
|
BoundRegionConversionTime::HigherRankedType,
|
|
|
|
|
hr_source_principal,
|
|
|
|
|
);
|
|
|
|
|
let Ok(()) = ocx.eq_trace(
|
|
|
|
|
&ObligationCause::dummy(),
|
2024-11-19 21:11:55 +01:00
|
|
|
|
param_env,
|
2024-09-30 12:42:29 -04:00
|
|
|
|
ToTrace::to_trace(
|
|
|
|
|
&ObligationCause::dummy(),
|
|
|
|
|
hr_target_principal,
|
|
|
|
|
hr_source_principal,
|
|
|
|
|
),
|
|
|
|
|
target_principal,
|
|
|
|
|
source_principal,
|
|
|
|
|
) else {
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
if !ocx.select_all_or_error().is_empty() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
infcx.leak_check(universe, None).is_ok()
|
|
|
|
|
})
|
2024-09-28 14:16:05 -04:00
|
|
|
|
}
|
2023-08-09 00:31:26 +00:00
|
|
|
|
(_, None) => true,
|
2024-09-28 14:16:05 -04:00
|
|
|
|
_ => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
|
/// Retrieves the information we are losing (making dynamic) in an unsizing
|
2018-10-03 13:49:57 +02:00
|
|
|
|
/// adjustment.
|
|
|
|
|
///
|
2019-05-17 02:20:14 +01:00
|
|
|
|
/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
|
|
|
|
|
/// where the new vtable for an object will be derived from the old one.
|
2024-09-05 15:16:55 +10:00
|
|
|
|
fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
2021-07-31 22:46:23 +08:00
|
|
|
|
bx: &mut Bx,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
source: Ty<'tcx>,
|
|
|
|
|
target: Ty<'tcx>,
|
2021-07-31 22:46:23 +08:00
|
|
|
|
old_info: Option<Bx::Value>,
|
|
|
|
|
) -> Bx::Value {
|
|
|
|
|
let cx = bx.cx();
|
2019-07-11 13:27:41 +02:00
|
|
|
|
let (source, target) =
|
2024-11-15 13:53:31 +01:00
|
|
|
|
cx.tcx().struct_lockstep_tails_for_codegen(source, target, bx.typing_env());
|
2020-08-03 00:49:11 +02:00
|
|
|
|
match (source.kind(), target.kind()) {
|
2024-09-20 20:38:11 -04:00
|
|
|
|
(&ty::Array(_, len), &ty::Slice(_)) => cx.const_usize(
|
|
|
|
|
len.try_to_target_usize(cx.tcx()).expect("expected monomorphic const in codegen"),
|
|
|
|
|
),
|
2023-11-21 20:07:32 +01:00
|
|
|
|
(&ty::Dynamic(data_a, _, src_dyn_kind), &ty::Dynamic(data_b, _, target_dyn_kind))
|
|
|
|
|
if src_dyn_kind == target_dyn_kind =>
|
|
|
|
|
{
|
2021-07-31 22:46:23 +08:00
|
|
|
|
let old_info =
|
|
|
|
|
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
2023-08-09 00:31:26 +00:00
|
|
|
|
let b_principal_def_id = data_b.principal_def_id();
|
|
|
|
|
if data_a.principal_def_id() == b_principal_def_id || b_principal_def_id.is_none() {
|
2024-09-23 13:52:02 -04:00
|
|
|
|
// Codegen takes advantage of the additional assumption, where if the
|
|
|
|
|
// principal trait def id of what's being casted doesn't change,
|
|
|
|
|
// then we don't need to adjust the vtable at all. This
|
|
|
|
|
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
|
|
|
|
|
// requires that `A = B`; we don't allow *upcasting* objects
|
|
|
|
|
// between the same trait with different args. If we, for
|
|
|
|
|
// some reason, were to relax the `Unsize` trait, it could become
|
|
|
|
|
// unsound, so let's assert here that the trait refs are *equal*.
|
2024-09-28 14:16:05 -04:00
|
|
|
|
debug_assert!(
|
|
|
|
|
validate_trivial_unsize(cx.tcx(), data_a, data_b),
|
2024-09-23 13:52:02 -04:00
|
|
|
|
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// A NOP cast that doesn't actually change anything, let's avoid any
|
|
|
|
|
// unnecessary work. This relies on the assumption that if the principal
|
|
|
|
|
// traits are equal, then the associated type bounds (`dyn Trait<Assoc=T>`)
|
|
|
|
|
// are also equal, which is ensured by the fact that normalization is
|
|
|
|
|
// a function and we do not allow overlapping impls.
|
2021-07-31 22:46:23 +08:00
|
|
|
|
return old_info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// trait upcasting coercion
|
|
|
|
|
|
2024-06-14 20:35:45 -04:00
|
|
|
|
let vptr_entry_idx = cx.tcx().supertrait_vtable_slot((source, target));
|
2021-07-31 22:46:23 +08:00
|
|
|
|
|
|
|
|
|
if let Some(entry_idx) = vptr_entry_idx {
|
2024-03-10 22:38:53 -04:00
|
|
|
|
let ptr_size = bx.data_layout().pointer_size;
|
|
|
|
|
let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes();
|
2024-09-23 15:25:52 +08:00
|
|
|
|
load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true)
|
2021-07-31 22:46:23 +08:00
|
|
|
|
} else {
|
|
|
|
|
old_info
|
|
|
|
|
}
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
2023-09-27 23:48:47 +02:00
|
|
|
|
(_, ty::Dynamic(data, _, _)) => meth::get_vtable(cx, source, data.principal()),
|
2019-12-24 17:38:22 -05:00
|
|
|
|
_ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-31 22:46:23 +08:00
|
|
|
|
/// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
2018-10-05 15:08:49 +02:00
|
|
|
|
bx: &mut Bx,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
src: Bx::Value,
|
|
|
|
|
src_ty: Ty<'tcx>,
|
2019-06-16 12:41:24 +03:00
|
|
|
|
dst_ty: Ty<'tcx>,
|
2021-07-31 22:46:23 +08:00
|
|
|
|
old_info: Option<Bx::Value>,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
) -> (Bx::Value, Bx::Value) {
|
2021-07-31 22:46:23 +08:00
|
|
|
|
debug!("unsize_ptr: {:?} => {:?}", src_ty, dst_ty);
|
2020-08-03 00:49:11 +02:00
|
|
|
|
match (src_ty.kind(), dst_ty.kind()) {
|
2024-03-21 17:11:06 -04:00
|
|
|
|
(&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
|
|
|
|
|
| (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => {
|
2021-07-31 22:46:23 +08:00
|
|
|
|
assert_eq!(bx.cx().type_is_sized(a), old_info.is_none());
|
2023-07-28 20:24:33 -04:00
|
|
|
|
(src, unsized_info(bx, a, b, old_info))
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
2023-08-27 18:12:34 +02:00
|
|
|
|
assert_eq!(def_a, def_b); // implies same number of fields
|
2018-10-03 13:49:57 +02:00
|
|
|
|
let src_layout = bx.cx().layout_of(src_ty);
|
|
|
|
|
let dst_layout = bx.cx().layout_of(dst_ty);
|
2021-07-31 22:46:23 +08:00
|
|
|
|
if src_ty == dst_ty {
|
|
|
|
|
return (src, old_info.unwrap());
|
|
|
|
|
}
|
2018-10-03 13:49:57 +02:00
|
|
|
|
let mut result = None;
|
|
|
|
|
for i in 0..src_layout.fields.count() {
|
|
|
|
|
let src_f = src_layout.field(bx.cx(), i);
|
2023-08-27 18:12:34 +02:00
|
|
|
|
if src_f.is_1zst() {
|
|
|
|
|
// We are looking for the one non-1-ZST field; this is not it.
|
2018-10-03 13:49:57 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2022-06-04 12:33:01 -05:00
|
|
|
|
|
|
|
|
|
assert_eq!(src_layout.fields.offset(i).bytes(), 0);
|
|
|
|
|
assert_eq!(dst_layout.fields.offset(i).bytes(), 0);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
assert_eq!(src_layout.size, src_f.size);
|
|
|
|
|
|
|
|
|
|
let dst_f = dst_layout.field(bx.cx(), i);
|
|
|
|
|
assert_ne!(src_f.ty, dst_f.ty);
|
|
|
|
|
assert_eq!(result, None);
|
2021-07-31 22:46:23 +08:00
|
|
|
|
result = Some(unsize_ptr(bx, src, src_f.ty, dst_f.ty, old_info));
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
2023-07-28 20:24:33 -04:00
|
|
|
|
result.unwrap()
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
2021-07-31 22:46:23 +08:00
|
|
|
|
_ => bug!("unsize_ptr: called on bad types"),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-14 23:28:14 +00:00
|
|
|
|
/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type.
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
2022-09-14 23:28:14 +00:00
|
|
|
|
bx: &mut Bx,
|
|
|
|
|
src: Bx::Value,
|
|
|
|
|
src_ty_and_layout: TyAndLayout<'tcx>,
|
|
|
|
|
dst_ty: Ty<'tcx>,
|
|
|
|
|
old_info: Option<Bx::Value>,
|
|
|
|
|
) -> (Bx::Value, Bx::Value) {
|
2022-10-14 04:55:07 +00:00
|
|
|
|
debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty);
|
|
|
|
|
assert!(
|
|
|
|
|
matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
|
|
|
|
|
"destination type must be a dyn*"
|
|
|
|
|
);
|
2023-02-07 19:17:04 +00:00
|
|
|
|
let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) {
|
2023-07-28 20:24:33 -04:00
|
|
|
|
TypeKind::Pointer => src,
|
|
|
|
|
TypeKind::Integer => bx.inttoptr(src, bx.type_ptr()),
|
2023-02-07 19:17:04 +00:00
|
|
|
|
// FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr.
|
|
|
|
|
kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"),
|
|
|
|
|
};
|
2022-09-14 23:28:14 +00:00
|
|
|
|
(src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-17 02:20:14 +01:00
|
|
|
|
/// Coerces `src`, which is a reference to a value of type `src_ty`,
|
|
|
|
|
/// to a value of type `dst_ty`, and stores the result in `dst`.
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
2018-10-05 15:08:49 +02:00
|
|
|
|
bx: &mut Bx,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
src: PlaceRef<'tcx, Bx::Value>,
|
2019-06-16 12:41:24 +03:00
|
|
|
|
dst: PlaceRef<'tcx, Bx::Value>,
|
|
|
|
|
) {
|
2018-10-03 13:49:57 +02:00
|
|
|
|
let src_ty = src.layout.ty;
|
|
|
|
|
let dst_ty = dst.layout.ty;
|
2020-08-03 00:49:11 +02:00
|
|
|
|
match (src_ty.kind(), dst_ty.kind()) {
|
2020-04-16 17:38:52 -07:00
|
|
|
|
(&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => {
|
2019-10-15 22:11:39 +03:00
|
|
|
|
let (base, info) = match bx.load_operand(src).val {
|
2021-07-31 22:46:23 +08:00
|
|
|
|
OperandValue::Pair(base, info) => unsize_ptr(bx, base, src_ty, dst_ty, Some(info)),
|
|
|
|
|
OperandValue::Immediate(base) => unsize_ptr(bx, base, src_ty, dst_ty, None),
|
2023-05-07 03:00:41 -07:00
|
|
|
|
OperandValue::Ref(..) | OperandValue::ZeroSized => bug!(),
|
2019-10-15 22:11:39 +03:00
|
|
|
|
};
|
|
|
|
|
OperandValue::Pair(base, info).store(bx, dst);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
|
2023-08-27 18:12:34 +02:00
|
|
|
|
assert_eq!(def_a, def_b); // implies same number of fields
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2023-04-01 20:11:38 -07:00
|
|
|
|
for i in def_a.variant(FIRST_VARIANT).fields.indices() {
|
|
|
|
|
let src_f = src.project_field(bx, i.as_usize());
|
|
|
|
|
let dst_f = dst.project_field(bx, i.as_usize());
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
if dst_f.layout.is_zst() {
|
2023-08-27 18:12:34 +02:00
|
|
|
|
// No data here, nothing to copy/coerce.
|
2018-10-03 13:49:57 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if src_f.layout.ty == dst_f.layout.ty {
|
2024-04-12 19:11:21 -07:00
|
|
|
|
bx.typed_place_copy(dst_f.val, src_f.val, src_f.layout);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
} else {
|
|
|
|
|
coerce_unsized_into(bx, src_f, dst_f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-24 17:38:22 -05:00
|
|
|
|
_ => bug!("coerce_unsized_into: invalid coercion {:?} -> {:?}", src_ty, dst_ty,),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-15 17:33:26 +02:00
|
|
|
|
/// Returns `rhs` sufficiently masked, truncated, and/or extended so that it can be used to shift
|
|
|
|
|
/// `lhs`: it has the same size as `lhs`, and the value, when interpreted unsigned (no matter its
|
|
|
|
|
/// type), will not exceed the size of `lhs`.
|
2024-03-30 00:36:45 -07:00
|
|
|
|
///
|
2024-05-15 17:33:26 +02:00
|
|
|
|
/// Shifts in MIR are all allowed to have mismatched LHS & RHS types, and signed RHS.
|
2024-04-02 10:17:21 -07:00
|
|
|
|
/// The shift methods in `BuilderMethods`, however, are fully homogeneous
|
2024-05-15 17:33:26 +02:00
|
|
|
|
/// (both parameters and the return type are all the same size) and assume an unsigned RHS.
|
2024-03-30 00:36:45 -07:00
|
|
|
|
///
|
2024-04-02 10:17:21 -07:00
|
|
|
|
/// If `is_unchecked` is false, this masks the RHS to ensure it stays in-bounds,
|
|
|
|
|
/// as the `BuilderMethods` shifts are UB for out-of-bounds shift amounts.
|
2024-03-30 00:36:45 -07:00
|
|
|
|
/// For 32- and 64-bit types, this matches the semantics
|
|
|
|
|
/// of Java. (See related discussion on #1877 and #10183.)
|
|
|
|
|
///
|
|
|
|
|
/// If `is_unchecked` is true, this does no masking, and adds sufficient `assume`
|
|
|
|
|
/// calls or operation flags to preserve as much freedom to optimize as possible.
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
2018-10-05 15:08:49 +02:00
|
|
|
|
bx: &mut Bx,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
lhs: Bx::Value,
|
2024-03-30 00:36:45 -07:00
|
|
|
|
mut rhs: Bx::Value,
|
|
|
|
|
is_unchecked: bool,
|
2018-10-05 15:08:49 +02:00
|
|
|
|
) -> Bx::Value {
|
2018-10-03 13:49:57 +02:00
|
|
|
|
// Shifts may have any size int on the rhs
|
2022-10-25 14:39:20 +11:00
|
|
|
|
let mut rhs_llty = bx.cx().val_ty(rhs);
|
|
|
|
|
let mut lhs_llty = bx.cx().val_ty(lhs);
|
2024-03-30 00:36:45 -07:00
|
|
|
|
|
|
|
|
|
let mask = common::shift_mask_val(bx, lhs_llty, rhs_llty, false);
|
|
|
|
|
if !is_unchecked {
|
|
|
|
|
rhs = bx.and(rhs, mask);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 14:39:20 +11:00
|
|
|
|
if bx.cx().type_kind(rhs_llty) == TypeKind::Vector {
|
|
|
|
|
rhs_llty = bx.cx().element_type(rhs_llty)
|
|
|
|
|
}
|
|
|
|
|
if bx.cx().type_kind(lhs_llty) == TypeKind::Vector {
|
|
|
|
|
lhs_llty = bx.cx().element_type(lhs_llty)
|
|
|
|
|
}
|
|
|
|
|
let rhs_sz = bx.cx().int_width(rhs_llty);
|
|
|
|
|
let lhs_sz = bx.cx().int_width(lhs_llty);
|
|
|
|
|
if lhs_sz < rhs_sz {
|
2024-03-30 00:36:45 -07:00
|
|
|
|
if is_unchecked && bx.sess().opts.optimize != OptLevel::No {
|
|
|
|
|
// FIXME: Use `trunc nuw` once that's available
|
|
|
|
|
let inrange = bx.icmp(IntPredicate::IntULE, rhs, mask);
|
|
|
|
|
bx.assume(inrange);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 14:39:20 +11:00
|
|
|
|
bx.trunc(rhs, lhs_llty)
|
|
|
|
|
} else if lhs_sz > rhs_sz {
|
2023-11-12 12:16:41 +01:00
|
|
|
|
// We zero-extend even if the RHS is signed. So e.g. `(x: i32) << -1i8` will zero-extend the
|
|
|
|
|
// RHS to `255i32`. But then we mask the shift amount to be within the size of the LHS
|
|
|
|
|
// anyway so the result is `31` as it should be. All the extra bits introduced by zext
|
|
|
|
|
// are masked off so their value does not matter.
|
|
|
|
|
// FIXME: if we ever support 512bit integers, this will be wrong! For such large integers,
|
|
|
|
|
// the extra bits introduced by zext are *not* all masked away any more.
|
|
|
|
|
assert!(lhs_sz <= 256);
|
2022-10-25 14:39:20 +11:00
|
|
|
|
bx.zext(rhs, lhs_llty)
|
2018-10-03 13:49:57 +02:00
|
|
|
|
} else {
|
|
|
|
|
rhs
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-01 19:24:21 +00:00
|
|
|
|
// Returns `true` if this session's target will use native wasm
|
|
|
|
|
// exceptions. This means that the VM does the unwinding for
|
|
|
|
|
// us
|
|
|
|
|
pub fn wants_wasm_eh(sess: &Session) -> bool {
|
|
|
|
|
sess.target.is_like_wasm && sess.target.os != "emscripten"
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
|
/// Returns `true` if this session's target will use SEH-based unwinding.
|
2018-10-03 13:49:57 +02:00
|
|
|
|
///
|
|
|
|
|
/// This is only true for MSVC targets, and even then the 64-bit MSVC target
|
|
|
|
|
/// currently uses SEH-ish unwinding with DWARF info tables to the side (same as
|
|
|
|
|
/// 64-bit MinGW) instead of "full SEH".
|
|
|
|
|
pub fn wants_msvc_seh(sess: &Session) -> bool {
|
2020-11-08 14:27:51 +03:00
|
|
|
|
sess.target.is_like_msvc
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-05-01 19:24:21 +00:00
|
|
|
|
/// Returns `true` if this session's target requires the new exception
|
|
|
|
|
/// handling LLVM IR instructions (catchpad / cleanuppad / ... instead
|
|
|
|
|
/// of landingpad)
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn wants_new_eh_instructions(sess: &Session) -> bool {
|
2023-05-01 19:24:21 +00:00
|
|
|
|
wants_wasm_eh(sess) || wants_msvc_seh(sess)
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
|
2018-10-03 13:49:57 +02:00
|
|
|
|
cx: &'a Bx::CodegenCx,
|
|
|
|
|
instance: Instance<'tcx>,
|
|
|
|
|
) {
|
|
|
|
|
// this is an info! to allow collecting monomorphization statistics
|
|
|
|
|
// and to allow finding the last function before LLVM aborts from
|
|
|
|
|
// release builds.
|
|
|
|
|
info!("codegen_instance({})", instance);
|
|
|
|
|
|
2019-10-29 16:26:25 +02:00
|
|
|
|
mir::codegen_mir::<Bx>(cx, instance);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
|
/// Creates the `main` function which will initialize the rust runtime and call
|
2018-10-03 13:49:57 +02:00
|
|
|
|
/// users main function.
|
2020-01-16 00:00:00 +00:00
|
|
|
|
pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|
|
|
|
cx: &'a Bx::CodegenCx,
|
|
|
|
|
) -> Option<Bx::Function> {
|
2021-05-11 12:00:59 +02:00
|
|
|
|
let (main_def_id, entry_type) = cx.tcx().entry_fn(())?;
|
2021-04-26 01:09:35 +08:00
|
|
|
|
let main_is_local = main_def_id.is_local();
|
|
|
|
|
let instance = Instance::mono(cx.tcx(), main_def_id);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2021-04-26 01:09:35 +08:00
|
|
|
|
if main_is_local {
|
2018-10-03 13:49:57 +02:00
|
|
|
|
// We want to create the wrapper in the same codegen unit as Rust's main
|
|
|
|
|
// function.
|
2021-04-26 01:09:35 +08:00
|
|
|
|
if !cx.codegen_unit().contains_item(&MonoItem::Fn(instance)) {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
2021-04-24 13:16:34 +08:00
|
|
|
|
} else if !cx.codegen_unit().is_primary() {
|
|
|
|
|
// We want to create the wrapper only when the codegen unit is the primary one
|
|
|
|
|
return None;
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-13 12:05:40 +02:00
|
|
|
|
let main_llfn = cx.get_fn_addr(instance);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2022-07-05 19:56:22 +02:00
|
|
|
|
let entry_fn = create_entry_fn::<Bx>(cx, main_llfn, main_def_id, entry_type);
|
2021-05-11 12:00:59 +02:00
|
|
|
|
return Some(entry_fn);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
|
fn create_entry_fn<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
2018-10-03 13:49:57 +02:00
|
|
|
|
cx: &'a Bx::CodegenCx,
|
|
|
|
|
rust_main: Bx::Value,
|
2021-04-26 01:09:35 +08:00
|
|
|
|
rust_main_def_id: DefId,
|
2022-07-05 19:56:22 +02:00
|
|
|
|
entry_type: EntryFnType,
|
2020-01-16 00:00:00 +00:00
|
|
|
|
) -> Bx::Function {
|
2022-12-18 09:54:54 +05:30
|
|
|
|
// The entry function is either `int main(void)` or `int main(int argc, char **argv)`, or
|
2023-05-21 14:26:59 +05:30
|
|
|
|
// `usize efi_main(void *handle, void *system_table)` depending on the target.
|
2022-12-18 09:54:54 +05:30
|
|
|
|
let llfty = if cx.sess().target.os.contains("uefi") {
|
|
|
|
|
cx.type_func(&[cx.type_ptr(), cx.type_ptr()], cx.type_isize())
|
|
|
|
|
} else if cx.sess().target.main_needs_argc_argv {
|
2023-07-28 20:24:33 -04:00
|
|
|
|
cx.type_func(&[cx.type_int(), cx.type_ptr()], cx.type_int())
|
2019-10-17 16:09:32 -07:00
|
|
|
|
} else {
|
|
|
|
|
cx.type_func(&[], cx.type_int())
|
|
|
|
|
};
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2023-01-19 12:09:01 -07:00
|
|
|
|
let main_ret_ty = cx.tcx().fn_sig(rust_main_def_id).no_bound_vars().unwrap().output();
|
2018-10-03 13:49:57 +02:00
|
|
|
|
// Given that `main()` has no arguments,
|
|
|
|
|
// then its return type cannot have
|
|
|
|
|
// late-bound regions, since late-bound
|
|
|
|
|
// regions must appear in the argument
|
|
|
|
|
// listing.
|
2024-11-15 13:53:31 +01:00
|
|
|
|
let main_ret_ty = cx
|
|
|
|
|
.tcx()
|
|
|
|
|
.normalize_erasing_regions(cx.typing_env(), main_ret_ty.no_bound_vars().unwrap());
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2022-02-19 00:48:49 +01:00
|
|
|
|
let Some(llfn) = cx.declare_c_main(llfty) else {
|
|
|
|
|
// FIXME: We should be smart and show a better diagnostic here.
|
|
|
|
|
let span = cx.tcx().def_span(rust_main_def_id);
|
2024-02-19 10:23:58 +11:00
|
|
|
|
cx.tcx().dcx().emit_fatal(errors::MultipleMainFunctions { span });
|
2020-09-18 13:06:53 +02:00
|
|
|
|
};
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
// `main` should respect same config for frame pointer elimination as rest of code
|
2021-06-26 23:53:35 +03:00
|
|
|
|
cx.set_frame_pointer_type(llfn);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
cx.apply_target_cpu_attr(llfn);
|
|
|
|
|
|
2023-11-21 20:07:32 +01:00
|
|
|
|
let llbb = Bx::append_block(cx, llfn, "top");
|
|
|
|
|
let mut bx = Bx::build(cx, llbb);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
bx.insert_reference_to_gdb_debug_scripts_section_global();
|
|
|
|
|
|
2021-08-03 15:09:57 -07:00
|
|
|
|
let isize_ty = cx.type_isize();
|
2023-07-28 20:24:33 -04:00
|
|
|
|
let ptr_ty = cx.type_ptr();
|
2024-09-11 10:22:06 +10:00
|
|
|
|
let (arg_argc, arg_argv) = get_argc_argv(&mut bx);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2024-03-15 19:45:46 +00:00
|
|
|
|
let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type
|
|
|
|
|
{
|
2020-08-18 11:47:27 +01:00
|
|
|
|
let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None);
|
2024-03-15 19:45:46 +00:00
|
|
|
|
let start_instance = ty::Instance::expect_resolve(
|
2024-03-10 11:49:27 +01:00
|
|
|
|
cx.tcx(),
|
2024-11-15 13:53:31 +01:00
|
|
|
|
cx.typing_env(),
|
2024-03-10 11:49:27 +01:00
|
|
|
|
start_def_id,
|
|
|
|
|
cx.tcx().mk_args(&[main_ret_ty.into()]),
|
2024-07-01 16:32:32 -04:00
|
|
|
|
DUMMY_SP,
|
2024-03-15 19:45:46 +00:00
|
|
|
|
);
|
|
|
|
|
let start_fn = cx.get_fn_addr(start_instance);
|
2022-07-05 19:56:22 +02:00
|
|
|
|
|
|
|
|
|
let i8_ty = cx.type_i8();
|
|
|
|
|
let arg_sigpipe = bx.const_u8(sigpipe);
|
|
|
|
|
|
2023-07-28 20:24:33 -04:00
|
|
|
|
let start_ty = cx.type_func(&[cx.val_ty(rust_main), isize_ty, ptr_ty, i8_ty], isize_ty);
|
2024-03-15 19:45:46 +00:00
|
|
|
|
(
|
|
|
|
|
start_fn,
|
|
|
|
|
start_ty,
|
|
|
|
|
vec![rust_main, arg_argc, arg_argv, arg_sigpipe],
|
|
|
|
|
Some(start_instance),
|
|
|
|
|
)
|
2018-10-03 13:49:57 +02:00
|
|
|
|
} else {
|
|
|
|
|
debug!("using user-defined start fn");
|
2023-07-28 20:24:33 -04:00
|
|
|
|
let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty);
|
2024-03-15 19:45:46 +00:00
|
|
|
|
(rust_main, start_ty, vec![arg_argc, arg_argv], None)
|
2018-10-03 13:49:57 +02:00
|
|
|
|
};
|
|
|
|
|
|
2024-03-15 19:45:46 +00:00
|
|
|
|
let result = bx.call(start_ty, None, None, start_fn, &args, None, instance);
|
2022-12-18 09:54:54 +05:30
|
|
|
|
if cx.sess().target.os.contains("uefi") {
|
|
|
|
|
bx.ret(result);
|
|
|
|
|
} else {
|
|
|
|
|
let cast = bx.intcast(result, cx.type_int(), true);
|
|
|
|
|
bx.ret(cast);
|
|
|
|
|
}
|
2020-01-16 00:00:00 +00:00
|
|
|
|
|
|
|
|
|
llfn
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-21 17:29:40 -07:00
|
|
|
|
/// Obtain the `argc` and `argv` values to pass to the rust start function.
|
2024-09-11 10:22:06 +10:00
|
|
|
|
fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) {
|
|
|
|
|
if bx.cx().sess().target.os.contains("uefi") {
|
2022-12-18 09:54:54 +05:30
|
|
|
|
// Params for UEFI
|
|
|
|
|
let param_handle = bx.get_param(0);
|
|
|
|
|
let param_system_table = bx.get_param(1);
|
2024-03-08 00:54:48 +00:00
|
|
|
|
let ptr_size = bx.tcx().data_layout.pointer_size;
|
|
|
|
|
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
|
2024-09-11 10:22:06 +10:00
|
|
|
|
let arg_argc = bx.const_int(bx.cx().type_isize(), 2);
|
2024-02-24 00:48:20 -05:00
|
|
|
|
let arg_argv = bx.alloca(2 * ptr_size, ptr_align);
|
2024-03-08 00:54:48 +00:00
|
|
|
|
bx.store(param_handle, arg_argv, ptr_align);
|
|
|
|
|
let arg_argv_el1 = bx.inbounds_ptradd(arg_argv, bx.const_usize(ptr_size.bytes()));
|
|
|
|
|
bx.store(param_system_table, arg_argv_el1, ptr_align);
|
2022-12-18 09:54:54 +05:30
|
|
|
|
(arg_argc, arg_argv)
|
2024-09-11 10:22:06 +10:00
|
|
|
|
} else if bx.cx().sess().target.main_needs_argc_argv {
|
2019-10-21 17:29:40 -07:00
|
|
|
|
// Params from native `main()` used as args for rust start function
|
|
|
|
|
let param_argc = bx.get_param(0);
|
|
|
|
|
let param_argv = bx.get_param(1);
|
2024-09-11 10:22:06 +10:00
|
|
|
|
let arg_argc = bx.intcast(param_argc, bx.cx().type_isize(), true);
|
2019-10-21 17:29:40 -07:00
|
|
|
|
let arg_argv = param_argv;
|
|
|
|
|
(arg_argc, arg_argv)
|
|
|
|
|
} else {
|
|
|
|
|
// The Rust start function doesn't need `argc` and `argv`, so just pass zeros.
|
2024-09-11 10:22:06 +10:00
|
|
|
|
let arg_argc = bx.const_int(bx.cx().type_int(), 0);
|
|
|
|
|
let arg_argv = bx.const_null(bx.cx().type_ptr());
|
2019-10-21 17:29:40 -07:00
|
|
|
|
(arg_argc, arg_argv)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-24 11:14:48 -07:00
|
|
|
|
/// This function returns all of the debugger visualizers specified for the
|
|
|
|
|
/// current crate as well as all upstream crates transitively that match the
|
|
|
|
|
/// `visualizer_type` specified.
|
|
|
|
|
pub fn collect_debugger_visualizers_transitive(
|
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
|
visualizer_type: DebuggerVisualizerType,
|
|
|
|
|
) -> BTreeSet<DebuggerVisualizerFile> {
|
|
|
|
|
tcx.debugger_visualizers(LOCAL_CRATE)
|
|
|
|
|
.iter()
|
|
|
|
|
.chain(
|
2024-06-06 09:45:50 +00:00
|
|
|
|
tcx.crates(())
|
2022-05-24 11:14:48 -07:00
|
|
|
|
.iter()
|
|
|
|
|
.filter(|&cnum| {
|
|
|
|
|
let used_crate_source = tcx.used_crate_source(*cnum);
|
|
|
|
|
used_crate_source.rlib.is_some() || used_crate_source.rmeta.is_some()
|
|
|
|
|
})
|
|
|
|
|
.flat_map(|&cnum| tcx.debugger_visualizers(cnum)),
|
|
|
|
|
)
|
|
|
|
|
.filter(|visualizer| visualizer.visualizer_type == visualizer_type)
|
|
|
|
|
.cloned()
|
|
|
|
|
.collect::<BTreeSet<_>>()
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-13 18:48:06 -05:00
|
|
|
|
/// Decide allocator kind to codegen. If `Some(_)` this will be the same as
|
|
|
|
|
/// `tcx.allocator_kind`, but it may be `None` in more cases (e.g. if using
|
|
|
|
|
/// allocator definitions from a dylib dependency).
|
|
|
|
|
pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
|
|
|
|
|
// If the crate doesn't have an `allocator_kind` set then there's definitely
|
|
|
|
|
// no shim to generate. Otherwise we also check our dependency graph for all
|
|
|
|
|
// our output crate types. If anything there looks like its a `Dynamic`
|
|
|
|
|
// linkage, then it's already got an allocator shim and we'll be using that
|
|
|
|
|
// one instead. If nothing exists then it's our job to generate the
|
|
|
|
|
// allocator!
|
|
|
|
|
let any_dynamic_crate = tcx.dependency_formats(()).iter().any(|(_, list)| {
|
|
|
|
|
use rustc_middle::middle::dependency_format::Linkage;
|
|
|
|
|
list.iter().any(|&linkage| linkage == Linkage::Dynamic)
|
|
|
|
|
});
|
2023-05-21 14:26:59 +05:30
|
|
|
|
if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
|
2023-02-13 18:48:06 -05:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-04 15:23:10 +02:00
|
|
|
|
pub fn codegen_crate<B: ExtraBackendMethods>(
|
2018-10-03 13:49:57 +02:00
|
|
|
|
backend: B,
|
2021-12-13 21:52:35 -05:00
|
|
|
|
tcx: TyCtxt<'_>,
|
2021-03-28 22:14:09 +02:00
|
|
|
|
target_cpu: String,
|
2019-04-26 17:22:36 +10:00
|
|
|
|
metadata: EncodedMetadata,
|
|
|
|
|
need_metadata_module: bool,
|
2018-10-23 17:01:35 +02:00
|
|
|
|
) -> OngoingCodegen<B> {
|
2018-10-03 13:49:57 +02:00
|
|
|
|
// Skip crate items and just output metadata in -Z no-codegen mode.
|
2022-07-06 07:44:47 -05:00
|
|
|
|
if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
|
2023-06-20 15:08:49 +10:00
|
|
|
|
let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2018-10-23 17:01:35 +02:00
|
|
|
|
ongoing_codegen.codegen_finished(tcx);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2018-10-23 17:01:35 +02:00
|
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
return ongoing_codegen;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-26 17:22:36 +10:00
|
|
|
|
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
|
|
|
|
|
2018-10-03 13:49:57 +02:00
|
|
|
|
// Run the monomorphization collector and partition the collected items into
|
|
|
|
|
// codegen units.
|
2021-05-11 14:39:04 +02:00
|
|
|
|
let codegen_units = tcx.collect_and_partition_mono_items(()).1;
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
// Force all codegen_unit queries so they are already either red or green
|
|
|
|
|
// when compile_codegen_unit accesses them. We are not able to re-execute
|
|
|
|
|
// the codegen_unit query from just the DepNode, so an unknown color would
|
|
|
|
|
// lead to having to re-execute compile_codegen_unit, possibly
|
|
|
|
|
// unnecessarily.
|
|
|
|
|
if tcx.dep_graph.is_fully_enabled() {
|
2020-03-14 12:41:32 +01:00
|
|
|
|
for cgu in codegen_units {
|
2020-05-01 11:32:20 +02:00
|
|
|
|
tcx.ensure().codegen_unit(cgu.name());
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-15 11:43:41 +00:00
|
|
|
|
let metadata_module = need_metadata_module.then(|| {
|
Use object crate for .rustc metadata generation
We already use the object crate for generating uncompressed .rmeta
metadata object files. This switches the generation of compressed
.rustc object files to use the object crate as well. These have
slightly different requirements in that .rmeta should be completely
excluded from any final compilation artifacts, while .rustc should
be part of shared objects, but not loaded into memory.
The primary motivation for this change is #90326: In LLVM 14, the
current way of setting section flags (and in particular, preventing
the setting of SHF_ALLOC) will no longer work. There are other ways
we could work around this, but switching to the object crate seems
like the most elegant, as we already use it for .rmeta, and as it
makes this independent of the codegen backend. In particular, we
don't need separate handling in codegen_llvm and codegen_gcc.
codegen_cranelift should be able to reuse the implementation as
well, though I have omitted that here, as it is not based on
codegen_ssa.
This change mostly extracts the existing code for .rmeta handling
to allow using it for .rustc as well, and adjust the codegen
infrastructure to handle the metadata object file separately: We
no longer create a backend-specific module for it, and directly
produce the compiled module instead.
This does not fix #90326 by itself yet, as .llvmbc will need to be
handled separately.
2021-12-02 12:24:25 +01:00
|
|
|
|
// Emit compressed metadata object.
|
|
|
|
|
let metadata_cgu_name =
|
|
|
|
|
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string();
|
|
|
|
|
tcx.sess.time("write_compressed_metadata", || {
|
|
|
|
|
let file_name =
|
|
|
|
|
tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
|
|
|
|
|
let data = create_compressed_metadata_file(
|
|
|
|
|
tcx.sess,
|
|
|
|
|
&metadata,
|
|
|
|
|
&exported_symbols::metadata_symbol_name(tcx),
|
|
|
|
|
);
|
2022-11-16 20:08:14 -05:00
|
|
|
|
if let Err(error) = std::fs::write(&file_name, data) {
|
2023-12-18 22:21:37 +11:00
|
|
|
|
tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite { error });
|
Use object crate for .rustc metadata generation
We already use the object crate for generating uncompressed .rmeta
metadata object files. This switches the generation of compressed
.rustc object files to use the object crate as well. These have
slightly different requirements in that .rmeta should be completely
excluded from any final compilation artifacts, while .rustc should
be part of shared objects, but not loaded into memory.
The primary motivation for this change is #90326: In LLVM 14, the
current way of setting section flags (and in particular, preventing
the setting of SHF_ALLOC) will no longer work. There are other ways
we could work around this, but switching to the object crate seems
like the most elegant, as we already use it for .rmeta, and as it
makes this independent of the codegen backend. In particular, we
don't need separate handling in codegen_llvm and codegen_gcc.
codegen_cranelift should be able to reuse the implementation as
well, though I have omitted that here, as it is not based on
codegen_ssa.
This change mostly extracts the existing code for .rmeta handling
to allow using it for .rustc as well, and adjust the codegen
infrastructure to handle the metadata object file separately: We
no longer create a backend-specific module for it, and directly
produce the compiled module instead.
This does not fix #90326 by itself yet, as .llvmbc will need to be
handled separately.
2021-12-02 12:24:25 +01:00
|
|
|
|
}
|
2023-02-15 11:43:41 +00:00
|
|
|
|
CompiledModule {
|
Use object crate for .rustc metadata generation
We already use the object crate for generating uncompressed .rmeta
metadata object files. This switches the generation of compressed
.rustc object files to use the object crate as well. These have
slightly different requirements in that .rmeta should be completely
excluded from any final compilation artifacts, while .rustc should
be part of shared objects, but not loaded into memory.
The primary motivation for this change is #90326: In LLVM 14, the
current way of setting section flags (and in particular, preventing
the setting of SHF_ALLOC) will no longer work. There are other ways
we could work around this, but switching to the object crate seems
like the most elegant, as we already use it for .rmeta, and as it
makes this independent of the codegen backend. In particular, we
don't need separate handling in codegen_llvm and codegen_gcc.
codegen_cranelift should be able to reuse the implementation as
well, though I have omitted that here, as it is not based on
codegen_ssa.
This change mostly extracts the existing code for .rmeta handling
to allow using it for .rustc as well, and adjust the codegen
infrastructure to handle the metadata object file separately: We
no longer create a backend-specific module for it, and directly
produce the compiled module instead.
This does not fix #90326 by itself yet, as .llvmbc will need to be
handled separately.
2021-12-02 12:24:25 +01:00
|
|
|
|
name: metadata_cgu_name,
|
|
|
|
|
kind: ModuleKind::Metadata,
|
|
|
|
|
object: Some(file_name),
|
|
|
|
|
dwarf_object: None,
|
|
|
|
|
bytecode: None,
|
2024-04-06 09:07:54 -04:00
|
|
|
|
assembly: None,
|
|
|
|
|
llvm_ir: None,
|
2023-02-15 11:43:41 +00:00
|
|
|
|
}
|
Use object crate for .rustc metadata generation
We already use the object crate for generating uncompressed .rmeta
metadata object files. This switches the generation of compressed
.rustc object files to use the object crate as well. These have
slightly different requirements in that .rmeta should be completely
excluded from any final compilation artifacts, while .rustc should
be part of shared objects, but not loaded into memory.
The primary motivation for this change is #90326: In LLVM 14, the
current way of setting section flags (and in particular, preventing
the setting of SHF_ALLOC) will no longer work. There are other ways
we could work around this, but switching to the object crate seems
like the most elegant, as we already use it for .rmeta, and as it
makes this independent of the codegen backend. In particular, we
don't need separate handling in codegen_llvm and codegen_gcc.
codegen_cranelift should be able to reuse the implementation as
well, though I have omitted that here, as it is not based on
codegen_ssa.
This change mostly extracts the existing code for .rmeta handling
to allow using it for .rustc as well, and adjust the codegen
infrastructure to handle the metadata object file separately: We
no longer create a backend-specific module for it, and directly
produce the compiled module instead.
This does not fix #90326 by itself yet, as .llvmbc will need to be
handled separately.
2021-12-02 12:24:25 +01:00
|
|
|
|
})
|
2023-02-15 11:43:41 +00:00
|
|
|
|
});
|
Use object crate for .rustc metadata generation
We already use the object crate for generating uncompressed .rmeta
metadata object files. This switches the generation of compressed
.rustc object files to use the object crate as well. These have
slightly different requirements in that .rmeta should be completely
excluded from any final compilation artifacts, while .rustc should
be part of shared objects, but not loaded into memory.
The primary motivation for this change is #90326: In LLVM 14, the
current way of setting section flags (and in particular, preventing
the setting of SHF_ALLOC) will no longer work. There are other ways
we could work around this, but switching to the object crate seems
like the most elegant, as we already use it for .rmeta, and as it
makes this independent of the codegen backend. In particular, we
don't need separate handling in codegen_llvm and codegen_gcc.
codegen_cranelift should be able to reuse the implementation as
well, though I have omitted that here, as it is not based on
codegen_ssa.
This change mostly extracts the existing code for .rmeta handling
to allow using it for .rustc as well, and adjust the codegen
infrastructure to handle the metadata object file separately: We
no longer create a backend-specific module for it, and directly
produce the compiled module instead.
This does not fix #90326 by itself yet, as .llvmbc will need to be
handled separately.
2021-12-02 12:24:25 +01:00
|
|
|
|
|
2023-06-20 15:08:49 +10:00
|
|
|
|
let ongoing_codegen =
|
|
|
|
|
start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
// Codegen an allocator shim, if necessary.
|
2023-02-13 18:48:06 -05:00
|
|
|
|
if let Some(kind) = allocator_kind_for_codegen(tcx) {
|
2019-12-24 17:38:22 -05:00
|
|
|
|
let llmod_id =
|
|
|
|
|
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
|
2022-04-30 21:20:08 +02:00
|
|
|
|
let module_llvm = tcx.sess.time("write_allocator_module", || {
|
2022-10-14 02:24:58 +01:00
|
|
|
|
backend.codegen_allocator(
|
|
|
|
|
tcx,
|
|
|
|
|
&llmod_id,
|
|
|
|
|
kind,
|
|
|
|
|
// If allocator_kind is Some then alloc_error_handler_kind must
|
|
|
|
|
// also be Some.
|
|
|
|
|
tcx.alloc_error_handler_kind(()).unwrap(),
|
|
|
|
|
)
|
2020-09-07 10:45:20 +02:00
|
|
|
|
});
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2023-07-20 09:09:09 +10:00
|
|
|
|
ongoing_codegen.wait_for_signal_to_codegen_item();
|
|
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
|
|
|
|
|
|
|
|
|
// These modules are generally cheap and won't throw off scheduling.
|
|
|
|
|
let cost = 0;
|
|
|
|
|
submit_codegened_module_to_llvm(
|
|
|
|
|
&backend,
|
|
|
|
|
&ongoing_codegen.coordinator.sender,
|
2023-02-13 18:48:06 -05:00
|
|
|
|
ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator },
|
2023-07-20 09:09:09 +10:00
|
|
|
|
cost,
|
2023-02-13 18:48:06 -05:00
|
|
|
|
);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-03 18:41:30 -08:00
|
|
|
|
// For better throughput during parallel processing by LLVM, we used to sort
|
|
|
|
|
// CGUs largest to smallest. This would lead to better thread utilization
|
|
|
|
|
// by, for example, preventing a large CGU from being processed last and
|
|
|
|
|
// having only one LLVM thread working while the rest remained idle.
|
|
|
|
|
//
|
|
|
|
|
// However, this strategy would lead to high memory usage, as it meant the
|
|
|
|
|
// LLVM-IR for all of the largest CGUs would be resident in memory at once.
|
|
|
|
|
//
|
|
|
|
|
// Instead, we can compromise by ordering CGUs such that the largest and
|
|
|
|
|
// smallest are first, second largest and smallest are next, etc. If there
|
|
|
|
|
// are large size variations, this can reduce memory usage significantly.
|
|
|
|
|
let codegen_units: Vec<_> = {
|
|
|
|
|
let mut sorted_cgus = codegen_units.iter().collect::<Vec<_>>();
|
2023-07-20 09:52:26 +10:00
|
|
|
|
sorted_cgus.sort_by_key(|cgu| cmp::Reverse(cgu.size_estimate()));
|
2021-02-03 18:41:30 -08:00
|
|
|
|
|
|
|
|
|
let (first_half, second_half) = sorted_cgus.split_at(sorted_cgus.len() / 2);
|
2023-07-20 09:52:26 +10:00
|
|
|
|
first_half.iter().interleave(second_half.iter().rev()).copied().collect()
|
2018-10-03 13:49:57 +02:00
|
|
|
|
};
|
|
|
|
|
|
2022-05-13 13:04:48 +00:00
|
|
|
|
// Calculate the CGU reuse
|
|
|
|
|
let cgu_reuse = tcx.sess.time("find_cgu_reuse", || {
|
2023-11-21 20:07:32 +01:00
|
|
|
|
codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, cgu)).collect::<Vec<_>>()
|
2022-05-13 13:04:48 +00:00
|
|
|
|
});
|
|
|
|
|
|
2023-09-19 11:23:35 +00:00
|
|
|
|
crate::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| {
|
|
|
|
|
for (i, cgu) in codegen_units.iter().enumerate() {
|
|
|
|
|
let cgu_reuse = cgu_reuse[i];
|
|
|
|
|
cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2022-05-13 13:17:07 +00:00
|
|
|
|
let mut total_codegen_time = Duration::new(0, 0);
|
2022-12-20 15:02:15 +01:00
|
|
|
|
let start_rss = tcx.sess.opts.unstable_opts.time_passes.then(|| get_resident_set_size());
|
2022-05-13 13:17:07 +00:00
|
|
|
|
|
2020-01-08 06:05:26 +01:00
|
|
|
|
// The non-parallel compiler can only translate codegen units to LLVM IR
|
|
|
|
|
// on a single thread, leading to a staircase effect where the N LLVM
|
|
|
|
|
// threads have to wait on the single codegen threads to generate work
|
|
|
|
|
// for them. The parallel compiler does not have this restriction, so
|
|
|
|
|
// we can pre-load the LLVM queue in parallel before handing off
|
|
|
|
|
// coordination to the OnGoingCodegen scheduler.
|
|
|
|
|
//
|
|
|
|
|
// This likely is a temporary measure. Once we don't have to support the
|
|
|
|
|
// non-parallel compiler anymore, we can compile CGUs end-to-end in
|
|
|
|
|
// parallel and get rid of the complicated scheduling logic.
|
2023-03-03 10:14:57 +08:00
|
|
|
|
let mut pre_compiled_cgus = if tcx.sess.threads() > 1 {
|
2022-02-08 22:21:16 +03:00
|
|
|
|
tcx.sess.time("compile_first_CGU_batch", || {
|
|
|
|
|
// Try to find one CGU to compile per thread.
|
|
|
|
|
let cgus: Vec<_> = cgu_reuse
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.filter(|&(_, reuse)| reuse == &CguReuse::No)
|
|
|
|
|
.take(tcx.sess.threads())
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
// Compile the found CGUs in parallel.
|
|
|
|
|
let start_time = Instant::now();
|
|
|
|
|
|
2023-03-03 10:14:57 +08:00
|
|
|
|
let pre_compiled_cgus = par_map(cgus, |(i, _)| {
|
|
|
|
|
let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
|
|
|
|
|
(i, module)
|
|
|
|
|
});
|
2022-02-08 22:21:16 +03:00
|
|
|
|
|
2022-05-13 13:17:07 +00:00
|
|
|
|
total_codegen_time += start_time.elapsed();
|
|
|
|
|
|
|
|
|
|
pre_compiled_cgus
|
2022-02-08 22:21:16 +03:00
|
|
|
|
})
|
2022-05-13 13:17:07 +00:00
|
|
|
|
} else {
|
|
|
|
|
FxHashMap::default()
|
2020-01-05 02:10:23 +01:00
|
|
|
|
};
|
|
|
|
|
|
2020-01-08 06:05:26 +01:00
|
|
|
|
for (i, cgu) in codegen_units.iter().enumerate() {
|
2018-10-23 17:01:35 +02:00
|
|
|
|
ongoing_codegen.wait_for_signal_to_codegen_item();
|
|
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2020-01-05 02:10:23 +01:00
|
|
|
|
let cgu_reuse = cgu_reuse[i];
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
match cgu_reuse {
|
|
|
|
|
CguReuse::No => {
|
2022-05-13 13:17:07 +00:00
|
|
|
|
let (module, cost) = if let Some(cgu) = pre_compiled_cgus.remove(&i) {
|
|
|
|
|
cgu
|
|
|
|
|
} else {
|
|
|
|
|
let start_time = Instant::now();
|
|
|
|
|
let module = backend.compile_codegen_unit(tcx, cgu.name());
|
|
|
|
|
total_codegen_time += start_time.elapsed();
|
|
|
|
|
module
|
|
|
|
|
};
|
2021-01-24 12:12:08 +01:00
|
|
|
|
// This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
|
|
|
|
|
// guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
|
|
|
|
|
// compilation hang on post-monomorphization errors.
|
2023-12-21 16:26:09 +11:00
|
|
|
|
tcx.dcx().abort_if_errors();
|
2021-01-24 12:12:08 +01:00
|
|
|
|
|
2020-01-05 02:10:23 +01:00
|
|
|
|
submit_codegened_module_to_llvm(
|
|
|
|
|
&backend,
|
2022-07-25 14:04:26 +02:00
|
|
|
|
&ongoing_codegen.coordinator.sender,
|
2020-01-05 02:10:23 +01:00
|
|
|
|
module,
|
|
|
|
|
cost,
|
|
|
|
|
);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
CguReuse::PreLto => {
|
2019-12-24 17:38:22 -05:00
|
|
|
|
submit_pre_lto_module_to_llvm(
|
|
|
|
|
&backend,
|
|
|
|
|
tcx,
|
2022-07-25 14:04:26 +02:00
|
|
|
|
&ongoing_codegen.coordinator.sender,
|
2019-12-24 17:38:22 -05:00
|
|
|
|
CachedModuleCodegen {
|
|
|
|
|
name: cgu.name().to_string(),
|
2022-05-13 10:32:03 +00:00
|
|
|
|
source: cgu.previous_work_product(tcx),
|
2019-12-24 17:38:22 -05:00
|
|
|
|
},
|
|
|
|
|
);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
CguReuse::PostLto => {
|
2019-12-24 17:38:22 -05:00
|
|
|
|
submit_post_lto_module_to_llvm(
|
|
|
|
|
&backend,
|
2022-07-25 14:04:26 +02:00
|
|
|
|
&ongoing_codegen.coordinator.sender,
|
2019-12-24 17:38:22 -05:00
|
|
|
|
CachedModuleCodegen {
|
|
|
|
|
name: cgu.name().to_string(),
|
2022-05-13 10:32:03 +00:00
|
|
|
|
source: cgu.previous_work_product(tcx),
|
2019-12-24 17:38:22 -05:00
|
|
|
|
},
|
|
|
|
|
);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
2023-07-31 16:34:13 +10:00
|
|
|
|
}
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-23 17:01:35 +02:00
|
|
|
|
ongoing_codegen.codegen_finished(tcx);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
|
|
|
|
// Since the main thread is sometimes blocked during codegen, we keep track
|
|
|
|
|
// -Ztime-passes output manually.
|
2022-12-20 15:02:15 +01:00
|
|
|
|
if tcx.sess.opts.unstable_opts.time_passes {
|
2021-01-25 12:56:21 -08:00
|
|
|
|
let end_rss = get_resident_set_size();
|
|
|
|
|
|
|
|
|
|
print_time_passes_entry(
|
|
|
|
|
"codegen_to_LLVM_IR",
|
|
|
|
|
total_codegen_time,
|
|
|
|
|
start_rss.unwrap(),
|
|
|
|
|
end_rss,
|
2023-02-06 06:32:34 +01:00
|
|
|
|
tcx.sess.opts.unstable_opts.time_passes_format,
|
2021-01-25 12:56:21 -08:00
|
|
|
|
);
|
|
|
|
|
}
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2018-10-23 17:01:35 +02:00
|
|
|
|
ongoing_codegen.check_for_errors(tcx.sess);
|
2022-07-25 14:04:26 +02:00
|
|
|
|
ongoing_codegen
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-15 23:43:52 +00:00
|
|
|
|
/// Returns whether a call from the current crate to the [`Instance`] would produce a call
|
|
|
|
|
/// from `compiler_builtins` to a symbol the linker must resolve.
|
|
|
|
|
///
|
|
|
|
|
/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some
|
|
|
|
|
/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is
|
|
|
|
|
/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any
|
|
|
|
|
/// unlinkable calls.
|
|
|
|
|
///
|
|
|
|
|
/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker.
|
|
|
|
|
pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>(
|
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
|
instance: Instance<'tcx>,
|
|
|
|
|
) -> bool {
|
|
|
|
|
fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
|
|
|
|
|
if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name {
|
|
|
|
|
name.as_str().starts_with("llvm.")
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let def_id = instance.def_id();
|
|
|
|
|
!def_id.is_local()
|
|
|
|
|
&& tcx.is_compiler_builtins(LOCAL_CRATE)
|
|
|
|
|
&& !is_llvm_intrinsic(tcx, def_id)
|
|
|
|
|
&& !tcx.should_codegen_locally(instance)
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-03 13:49:57 +02:00
|
|
|
|
impl CrateInfo {
|
2021-07-06 15:31:38 +02:00
|
|
|
|
pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
|
2023-08-08 18:28:20 +08:00
|
|
|
|
let crate_types = tcx.crate_types().to_vec();
|
|
|
|
|
let exported_symbols = crate_types
|
2021-07-06 18:28:07 +02:00
|
|
|
|
.iter()
|
|
|
|
|
.map(|&c| (c, crate::back::linker::exported_symbols(tcx, c)))
|
|
|
|
|
.collect();
|
2023-08-08 18:28:20 +08:00
|
|
|
|
let linked_symbols =
|
|
|
|
|
crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect();
|
2021-05-29 17:37:38 +02:00
|
|
|
|
let local_crate_name = tcx.crate_name(LOCAL_CRATE);
|
2021-05-29 17:08:46 +02:00
|
|
|
|
let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
|
2024-12-07 15:27:17 +01:00
|
|
|
|
let subsystem =
|
|
|
|
|
ast::attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
|
2021-05-29 17:08:46 +02:00
|
|
|
|
let windows_subsystem = subsystem.map(|subsystem| {
|
|
|
|
|
if subsystem != sym::windows && subsystem != sym::console {
|
2023-12-18 22:21:37 +11:00
|
|
|
|
tcx.dcx().emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
|
2021-05-29 17:08:46 +02:00
|
|
|
|
}
|
|
|
|
|
subsystem.to_string()
|
|
|
|
|
});
|
|
|
|
|
|
2021-06-07 15:23:44 +02:00
|
|
|
|
// This list is used when generating the command line to pass through to
|
|
|
|
|
// system linker. The linker expects undefined symbols on the left of the
|
|
|
|
|
// command line to be defined in libraries on the right, not the other way
|
|
|
|
|
// around. For more info, see some comments in the add_used_library function
|
|
|
|
|
// below.
|
|
|
|
|
//
|
|
|
|
|
// In order to get this left-to-right dependency ordering, we use the reverse
|
2024-10-23 02:45:24 -07:00
|
|
|
|
// postorder of all crates putting the leaves at the rightmost positions.
|
2022-10-20 18:57:47 +04:00
|
|
|
|
let mut compiler_builtins = None;
|
|
|
|
|
let mut used_crates: Vec<_> = tcx
|
2021-06-07 15:23:44 +02:00
|
|
|
|
.postorder_cnums(())
|
|
|
|
|
.iter()
|
|
|
|
|
.rev()
|
|
|
|
|
.copied()
|
2022-10-20 18:57:47 +04:00
|
|
|
|
.filter(|&cnum| {
|
|
|
|
|
let link = !tcx.dep_kind(cnum).macros_only();
|
|
|
|
|
if link && tcx.is_compiler_builtins(cnum) {
|
|
|
|
|
compiler_builtins = Some(cnum);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
link
|
|
|
|
|
})
|
2021-06-07 15:23:44 +02:00
|
|
|
|
.collect();
|
2022-10-20 18:57:47 +04:00
|
|
|
|
// `compiler_builtins` are always placed last to ensure that they're linked correctly.
|
|
|
|
|
used_crates.extend(compiler_builtins);
|
2021-06-07 15:23:44 +02:00
|
|
|
|
|
2024-06-06 09:45:50 +00:00
|
|
|
|
let crates = tcx.crates(());
|
2024-02-11 19:50:50 +08:00
|
|
|
|
let n_crates = crates.len();
|
2018-10-03 13:49:57 +02:00
|
|
|
|
let mut info = CrateInfo {
|
2021-07-06 18:28:07 +02:00
|
|
|
|
target_cpu,
|
2023-08-08 18:28:20 +08:00
|
|
|
|
crate_types,
|
2021-07-06 18:28:07 +02:00
|
|
|
|
exported_symbols,
|
2022-04-02 22:54:51 +01:00
|
|
|
|
linked_symbols,
|
2021-05-29 17:37:38 +02:00
|
|
|
|
local_crate_name,
|
2022-10-20 18:57:47 +04:00
|
|
|
|
compiler_builtins,
|
2018-10-03 13:49:57 +02:00
|
|
|
|
profiler_runtime: None,
|
2024-01-12 18:23:04 +08:00
|
|
|
|
is_no_builtins: Default::default(),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
native_libraries: Default::default(),
|
2020-12-19 22:36:35 +11:00
|
|
|
|
used_libraries: tcx.native_libraries(LOCAL_CRATE).iter().map(Into::into).collect(),
|
2024-02-11 19:50:50 +08:00
|
|
|
|
crate_name: UnordMap::with_capacity(n_crates),
|
2021-06-07 15:23:44 +02:00
|
|
|
|
used_crates,
|
2024-02-11 19:50:50 +08:00
|
|
|
|
used_crate_source: UnordMap::with_capacity(n_crates),
|
2024-10-07 22:22:51 +03:00
|
|
|
|
dependency_formats: Lrc::clone(tcx.dependency_formats(())),
|
2021-05-29 17:08:46 +02:00
|
|
|
|
windows_subsystem,
|
2022-05-24 11:14:48 -07:00
|
|
|
|
natvis_debugger_visualizers: Default::default(),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
info.native_libraries.reserve(n_crates);
|
|
|
|
|
|
|
|
|
|
for &cnum in crates.iter() {
|
2020-12-19 22:36:35 +11:00
|
|
|
|
info.native_libraries
|
|
|
|
|
.insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
|
2022-04-05 15:52:53 +03:00
|
|
|
|
info.crate_name.insert(cnum, tcx.crate_name(cnum));
|
2022-04-25 18:02:43 -07:00
|
|
|
|
|
|
|
|
|
let used_crate_source = tcx.used_crate_source(cnum);
|
2024-10-07 22:22:51 +03:00
|
|
|
|
info.used_crate_source.insert(cnum, Lrc::clone(used_crate_source));
|
2018-10-03 13:49:57 +02:00
|
|
|
|
if tcx.is_profiler_runtime(cnum) {
|
|
|
|
|
info.profiler_runtime = Some(cnum);
|
|
|
|
|
}
|
2024-01-12 18:23:04 +08:00
|
|
|
|
if tcx.is_no_builtins(cnum) {
|
|
|
|
|
info.is_no_builtins.insert(cnum);
|
|
|
|
|
}
|
2022-05-24 11:14:48 -07:00
|
|
|
|
}
|
2022-04-25 18:02:43 -07:00
|
|
|
|
|
2022-08-15 13:15:01 +03:00
|
|
|
|
// Handle circular dependencies in the standard library.
|
|
|
|
|
// See comment before `add_linked_symbol_object` function for the details.
|
2022-10-15 22:01:28 +04:00
|
|
|
|
// If global LTO is enabled then almost everything (*) is glued into a single object file,
|
|
|
|
|
// so this logic is not necessary and can cause issues on some targets (due to weak lang
|
|
|
|
|
// item symbols being "privatized" to that object file), so we disable it.
|
2024-01-12 18:23:04 +08:00
|
|
|
|
// (*) Native libs, and `#[compiler_builtins]` and `#[no_builtins]` crates are not glued,
|
|
|
|
|
// and we assume that they cannot define weak lang items. This is not currently enforced
|
|
|
|
|
// by the compiler, but that's ok because all this stuff is unstable anyway.
|
2022-09-02 14:31:08 +03:00
|
|
|
|
let target = &tcx.sess.target;
|
2022-10-15 22:01:28 +04:00
|
|
|
|
if !are_upstream_rust_objects_already_included(tcx.sess) {
|
2024-02-11 19:50:50 +08:00
|
|
|
|
let missing_weak_lang_items: FxIndexSet<Symbol> = info
|
2022-09-02 14:31:08 +03:00
|
|
|
|
.used_crates
|
|
|
|
|
.iter()
|
2022-10-26 16:18:59 -05:00
|
|
|
|
.flat_map(|&cnum| tcx.missing_lang_items(cnum))
|
|
|
|
|
.filter(|l| l.is_weak())
|
|
|
|
|
.filter_map(|&l| {
|
|
|
|
|
let name = l.link_name()?;
|
|
|
|
|
lang_items::required(tcx, l).then_some(name)
|
2022-09-02 14:31:08 +03:00
|
|
|
|
})
|
|
|
|
|
.collect();
|
Add arm64ec-pc-windows-msvc target
Introduces the `arm64ec-pc-windows-msvc` target for building Arm64EC ("Emulation Compatible") binaries for Windows.
For more information about Arm64EC see <https://learn.microsoft.com/en-us/windows/arm/arm64ec>.
Tier 3 policy:
> A tier 3 target must have a designated developer or developers (the "target maintainers") on record to be CCed when issues arise regarding the target. (The mechanism to track and CC such developers may evolve over time.)
I will be the maintainer for this target.
> Targets must use naming consistent with any existing targets; for instance, a target for the same CPU or OS as an existing Rust target should use the same name for that CPU or OS. Targets should normally use the same names and naming conventions as used elsewhere in the broader ecosystem beyond Rust (such as in other toolchains), unless they have a very good reason to diverge. Changing the name of a target can be highly disruptive, especially once the target reaches a higher tier, so getting the name right is important even for a tier 3 target.
Target uses the `arm64ec` architecture to match LLVM and MSVC, and the `-pc-windows-msvc` suffix to indicate that it targets Windows via the MSVC environment.
> Target names should not introduce undue confusion or ambiguity unless absolutely necessary to maintain ecosystem compatibility. For example, if the name of the target makes people extremely likely to form incorrect beliefs about what it targets, the name should be changed or augmented to disambiguate it.
Target name exactly specifies the type of code that will be produced.
> If possible, use only letters, numbers, dashes and underscores for the name. Periods (.) are known to cause issues in Cargo.
Done.
> Tier 3 targets may have unusual requirements to build or use, but must not create legal issues or impose onerous legal terms for the Rust project or for Rust developers or users.
> The target must not introduce license incompatibilities.
Uses the same dependencies, requirements and licensing as the other `*-pc-windows-msvc` targets.
> Anything added to the Rust repository must be under the standard Rust license (MIT OR Apache-2.0).
Understood.
> The target must not cause the Rust tools or libraries built for any other host (even when supporting cross-compilation to the target) to depend on any new dependency less permissive than the Rust licensing policy. This applies whether the dependency is a Rust crate that would require adding new license exceptions (as specified by the tidy tool in the rust-lang/rust repository), or whether the dependency is a native library or binary. In other words, the introduction of the target must not cause a user installing or running a version of Rust or the Rust tools to be subject to any new license requirements.
> Compiling, linking, and emitting functional binaries, libraries, or other code for the target (whether hosted on the target itself or cross-compiling from another target) must not depend on proprietary (non-FOSS) libraries. Host tools built for the target itself may depend on the ordinary runtime libraries supplied by the platform and commonly used by other applications built for the target, but those libraries must not be required for code generation for the target; cross-compilation to the target must not require such libraries at all. For instance, rustc built for the target may depend on a common proprietary C runtime library or console output library, but must not depend on a proprietary code generation library or code optimization library. Rust's license permits such combinations, but the Rust project has no interest in maintaining such combinations within the scope of Rust itself, even at tier 3.
> "onerous" here is an intentionally subjective term. At a minimum, "onerous" legal/licensing terms include but are not limited to: non-disclosure requirements, non-compete requirements, contributor license agreements (CLAs) or equivalent, "non-commercial"/"research-only"/etc terms, requirements conditional on the employer or employment of any particular Rust developers, revocable terms, any requirements that create liability for the Rust project or its developers or users, or any requirements that adversely affect the livelihood or prospects of the Rust project or its developers or users.
Uses the same dependencies, requirements and licensing as the other `*-pc-windows-msvc` targets.
> Neither this policy nor any decisions made regarding targets shall create any binding agreement or estoppel by any party. If any member of an approving Rust team serves as one of the maintainers of a target, or has any legal or employment requirement (explicit or implicit) that might affect their decisions regarding a target, they must recuse themselves from any approval decisions regarding the target's tier status, though they may otherwise participate in discussions.
> This requirement does not prevent part or all of this policy from being cited in an explicit contract or work agreement (e.g. to implement or maintain support for a target). This requirement exists to ensure that a developer or team responsible for reviewing and approving a target does not face any legal threats or obligations that would prevent them from freely exercising their judgment in such approval, even if such judgment involves subjective matters or goes beyond the letter of these requirements.
Understood, I am not a member of the Rust team.
> Tier 3 targets should attempt to implement as much of the standard libraries as possible and appropriate (core for most targets, alloc for targets that can support dynamic memory allocation, std for targets with an operating system or equivalent layer of system-provided functionality), but may leave some code unimplemented (either unavailable or stubbed out as appropriate), whether because the target makes it impossible to implement or challenging to implement. The authors of pull requests are not obligated to avoid calling any portions of the standard library on the basis of a tier 3 target not implementing those portions.
Both `core` and `alloc` are supported.
Support for `std` dependends on making changes to the standard library, `stdarch` and `backtrace` which cannot be done yet as the bootstrapping compiler raises a warning ("unexpected `cfg` condition value") for `target_arch = "arm64ec"`.
> The target must provide documentation for the Rust community explaining how to build for the target, using cross-compilation if possible. If the target supports running binaries, or running tests (even if they do not pass), the documentation must explain how to run such binaries or tests for the target, using emulation if possible or dedicated hardware if necessary.
Documentation is provided in src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md
> Tier 3 targets must not impose burden on the authors of pull requests, or other developers in the community, to maintain the target. In particular, do not post comments (automated or manual) on a PR that derail or suggest a block on the PR based on a tier 3 target. Do not send automated messages or notifications (via any medium, including via @) to a PR author or others involved with a PR regarding a tier 3 target, unless they have opted into such messages.
> Backlinks such as those generated by the issue/PR tracker when linking to an issue or PR are not considered a violation of this policy, within reason. However, such messages (even on a separate repository) must not generate notifications to anyone involved with a PR who has not requested such notifications.
> Patches adding or updating tier 3 targets must not break any existing tier 2 or tier 1 target, and must not knowingly break another tier 3 target without approval of either the compiler team or the maintainers of the other tier 3 target.
> In particular, this may come up when working on closely related targets, such as variations of the same architecture with different features. Avoid introducing unconditional uses of features that another variation of the target may not have; use conditional compilation or runtime detection, as appropriate, to let each target run code supported by that target.
Understood.
2023-12-15 16:46:34 -08:00
|
|
|
|
let prefix = match (target.is_like_windows, target.arch.as_ref()) {
|
|
|
|
|
(true, "x86") => "_",
|
|
|
|
|
(true, "arm64ec") => "#",
|
|
|
|
|
_ => "",
|
|
|
|
|
};
|
2023-12-29 13:41:35 +01:00
|
|
|
|
|
|
|
|
|
// This loop only adds new items to values of the hash map, so the order in which we
|
|
|
|
|
// iterate over the values is not important.
|
|
|
|
|
#[allow(rustc::potential_query_instability)]
|
2022-09-02 14:31:08 +03:00
|
|
|
|
info.linked_symbols
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.filter(|(crate_type, _)| {
|
|
|
|
|
!matches!(crate_type, CrateType::Rlib | CrateType::Staticlib)
|
|
|
|
|
})
|
|
|
|
|
.for_each(|(_, linked_symbols)| {
|
2023-12-29 13:41:35 +01:00
|
|
|
|
let mut symbols = missing_weak_lang_items
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
symbols.sort_unstable_by(|a, b| a.0.cmp(&b.0));
|
|
|
|
|
linked_symbols.extend(symbols);
|
2023-06-19 13:39:17 +00:00
|
|
|
|
if tcx.allocator_kind(()).is_some() {
|
|
|
|
|
// At least one crate needs a global allocator. This crate may be placed
|
|
|
|
|
// after the crate that defines it in the linker order, in which case some
|
|
|
|
|
// linkers return an error. By adding the global allocator shim methods to
|
|
|
|
|
// the linked_symbols list, linking the generated symbols.o will ensure that
|
|
|
|
|
// circular dependencies involving the global allocator don't lead to linker
|
|
|
|
|
// errors.
|
|
|
|
|
linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
|
|
|
|
|
(
|
|
|
|
|
format!("{prefix}{}", global_fn_name(method.name).as_str()),
|
|
|
|
|
SymbolExportKind::Text,
|
|
|
|
|
)
|
|
|
|
|
}));
|
|
|
|
|
}
|
2022-09-02 14:31:08 +03:00
|
|
|
|
});
|
|
|
|
|
}
|
2022-08-15 13:15:01 +03:00
|
|
|
|
|
2023-08-08 18:28:20 +08:00
|
|
|
|
let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
|
2022-05-24 11:14:48 -07:00
|
|
|
|
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
|
|
|
|
|
// These are crate types for which we invoke the linker and can embed
|
|
|
|
|
// NatVis visualizers.
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
CrateType::ProcMacro => {
|
|
|
|
|
// We could embed NatVis for proc macro crates too (to improve the debugging
|
|
|
|
|
// experience for them) but it does not seem like a good default, since
|
|
|
|
|
// this is a rare use case and we don't want to slow down the common case.
|
|
|
|
|
false
|
2022-04-25 18:02:43 -07:00
|
|
|
|
}
|
2022-05-24 11:14:48 -07:00
|
|
|
|
CrateType::Staticlib | CrateType::Rlib => {
|
2024-09-11 09:59:50 +10:00
|
|
|
|
// We don't invoke the linker for these, so we don't need to collect the NatVis for
|
|
|
|
|
// them.
|
2022-05-24 11:14:48 -07:00
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2022-09-02 14:31:08 +03:00
|
|
|
|
if target.is_like_msvc && embed_visualizers {
|
2022-05-24 11:14:48 -07:00
|
|
|
|
info.natvis_debugger_visualizers =
|
|
|
|
|
collect_debugger_visualizers_transitive(tcx, DebuggerVisualizerType::Natvis);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-20 15:03:11 +01:00
|
|
|
|
info
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-05 15:16:55 +10:00
|
|
|
|
pub(crate) fn provide(providers: &mut Providers) {
|
2018-10-27 15:29:06 +03:00
|
|
|
|
providers.backend_optimization_level = |tcx, cratenum| {
|
|
|
|
|
let for_speed = match tcx.sess.opts.optimize {
|
|
|
|
|
// If globally no optimisation is done, #[optimize] has no effect.
|
|
|
|
|
//
|
|
|
|
|
// This is done because if we ended up "upgrading" to `-O2` here, we’d populate the
|
|
|
|
|
// pass manager and it is likely that some module-wide passes (such as inliner or
|
|
|
|
|
// cross-function constant propagation) would ignore the `optnone` annotation we put
|
|
|
|
|
// on the functions, thus necessarily involving these functions into optimisations.
|
|
|
|
|
config::OptLevel::No => return config::OptLevel::No,
|
|
|
|
|
// If globally optimise-speed is already specified, just use that level.
|
|
|
|
|
config::OptLevel::Less => return config::OptLevel::Less,
|
|
|
|
|
config::OptLevel::Default => return config::OptLevel::Default,
|
|
|
|
|
config::OptLevel::Aggressive => return config::OptLevel::Aggressive,
|
|
|
|
|
// If globally optimize-for-size has been requested, use -O2 instead (if optimize(size)
|
|
|
|
|
// are present).
|
|
|
|
|
config::OptLevel::Size => config::OptLevel::Default,
|
|
|
|
|
config::OptLevel::SizeMin => config::OptLevel::Default,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let (defids, _) = tcx.collect_and_partition_mono_items(cratenum);
|
2022-12-02 16:27:25 +01:00
|
|
|
|
|
|
|
|
|
let any_for_speed = defids.items().any(|id| {
|
2019-12-24 05:30:02 +01:00
|
|
|
|
let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
|
2018-10-27 15:29:06 +03:00
|
|
|
|
match optimize {
|
2022-12-02 16:27:25 +01:00
|
|
|
|
attr::OptimizeAttr::None | attr::OptimizeAttr::Size => false,
|
|
|
|
|
attr::OptimizeAttr::Speed => true,
|
2018-10-27 15:29:06 +03:00
|
|
|
|
}
|
2022-12-02 16:27:25 +01:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if any_for_speed {
|
|
|
|
|
return for_speed;
|
2018-10-27 15:29:06 +03:00
|
|
|
|
}
|
2022-12-02 16:27:25 +01:00
|
|
|
|
|
2020-03-20 15:03:11 +01:00
|
|
|
|
tcx.sess.opts.optimize
|
2018-10-27 15:29:06 +03:00
|
|
|
|
};
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-09-16 14:36:23 +00:00
|
|
|
|
pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse {
|
2018-10-03 13:49:57 +02:00
|
|
|
|
if !tcx.dep_graph.is_fully_enabled() {
|
2019-12-24 17:38:22 -05:00
|
|
|
|
return CguReuse::No;
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let work_product_id = &cgu.work_product_id();
|
|
|
|
|
if tcx.dep_graph.previous_work_product(work_product_id).is_none() {
|
|
|
|
|
// We don't have anything cached for this CGU. This can happen
|
|
|
|
|
// if the CGU did not exist in the previous session.
|
2019-12-24 17:38:22 -05:00
|
|
|
|
return CguReuse::No;
|
2018-10-03 13:49:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to mark the CGU as green. If it we can do so, it means that nothing
|
|
|
|
|
// affecting the LLVM module has changed and we can re-use a cached version.
|
|
|
|
|
// If we compile with any kind of LTO, this means we can re-use the bitcode
|
|
|
|
|
// of the Pre-LTO stage (possibly also the Post-LTO version but we'll only
|
|
|
|
|
// know that later). If we are not doing LTO, there is only one optimized
|
|
|
|
|
// version of each module, so we re-use that.
|
|
|
|
|
let dep_node = cgu.codegen_dep_node(tcx);
|
2019-12-24 17:38:22 -05:00
|
|
|
|
assert!(
|
|
|
|
|
!tcx.dep_graph.dep_node_exists(&dep_node),
|
2018-10-03 13:49:57 +02:00
|
|
|
|
"CompileCodegenUnit dep-node for CGU `{}` already exists before marking.",
|
2019-12-24 17:38:22 -05:00
|
|
|
|
cgu.name()
|
|
|
|
|
);
|
2018-10-03 13:49:57 +02:00
|
|
|
|
|
2021-01-18 23:53:42 +01:00
|
|
|
|
if tcx.try_mark_green(&dep_node) {
|
2020-05-08 09:27:59 -07:00
|
|
|
|
// We can re-use either the pre- or the post-thinlto state. If no LTO is
|
|
|
|
|
// being performed then we can use post-LTO artifacts, otherwise we must
|
|
|
|
|
// reuse pre-LTO artifacts
|
|
|
|
|
match compute_per_cgu_lto_type(
|
|
|
|
|
&tcx.sess.lto(),
|
|
|
|
|
&tcx.sess.opts,
|
2023-08-08 18:28:20 +08:00
|
|
|
|
tcx.crate_types(),
|
2020-05-08 09:27:59 -07:00
|
|
|
|
ModuleKind::Regular,
|
|
|
|
|
) {
|
|
|
|
|
ComputedLtoType::No => CguReuse::PostLto,
|
|
|
|
|
_ => CguReuse::PreLto,
|
|
|
|
|
}
|
2018-10-03 13:49:57 +02:00
|
|
|
|
} else {
|
|
|
|
|
CguReuse::No
|
|
|
|
|
}
|
|
|
|
|
}
|