1
Fork 0

Add a scheme for moving away from extern "rust-intrinsic" entirely

This commit is contained in:
Oli Scherer 2024-02-19 17:35:12 +00:00
parent f2612daf58
commit 1e57df1969
16 changed files with 131 additions and 8 deletions

View file

@ -1255,7 +1255,17 @@ fn codegen_regular_intrinsic_call<'tcx>(
// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
// by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`.
_ => return Err(Instance::new(instance.def_id(), instance.args)),
_ => {
let intrinsic = fx.tcx.intrinsic(instance.def_id()).unwrap();
if intrinsic.must_be_overridden {
span_bug!(
source_info.span,
"intrinsic {} must be overridden by codegen_cranelift, but isn't",
intrinsic.name,
);
}
return Err(Instance::new(instance.def_id(), instance.args));
}
}
let ret_block = fx.get_block(destination.unwrap());

View file

@ -16,6 +16,7 @@ use rustc_middle::ty::{self, SymbolName, TyCtxt};
use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
use rustc_middle::util::Providers;
use rustc_session::config::{CrateType, OomStrategy};
use rustc_span::sym;
use rustc_target::spec::{SanitizerSet, TlsModel};
pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
@ -81,6 +82,10 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<S
return library.kind.is_statically_included().then_some(def_id);
}
if tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) {
return None;
}
// Only consider nodes that actually have exported symbols.
match tcx.def_kind(def_id) {
DefKind::Fn | DefKind::Static(_) => {}

View file

@ -903,7 +903,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
MergingSucc::False
};
}
Err(instance) => Some(instance),
Err(instance) => {
if intrinsic.must_be_overridden {
span_bug!(
span,
"intrinsic {} must be overridden by codegen backend, but isn't",
intrinsic.name,
);
}
Some(instance)
}
}
}
};

View file

@ -867,6 +867,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing,
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
),
rustc_attr!(
rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing,
"the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
),
// ==========================================================================
// Internal attributes, Testing:

View file

@ -1051,13 +1051,18 @@ fn should_encode_mir(
// Coroutines require optimized MIR to compute layout.
DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => (false, true),
// Full-fledged functions + closures
DefKind::AssocFn | DefKind::Fn | DefKind::Closure => {
def_kind @ (DefKind::AssocFn | DefKind::Fn | DefKind::Closure) => {
let generics = tcx.generics_of(def_id);
let opt = tcx.sess.opts.unstable_opts.always_encode_mir
let mut opt = tcx.sess.opts.unstable_opts.always_encode_mir
|| (tcx.sess.opts.output_types.should_codegen()
&& reachable_set.contains(&def_id)
&& (generics.requires_monomorphization(tcx)
|| tcx.cross_crate_inlinable(def_id)));
if matches!(def_kind, DefKind::AssocFn | DefKind::Fn) {
if let Some(intrinsic) = tcx.intrinsic(def_id) {
opt &= !intrinsic.must_be_overridden;
}
}
// The function has a `const` modifier or is in a `#[const_trait]`.
let is_const_fn = tcx.is_const_fn_raw(def_id.to_def_id())
|| tcx.is_const_default_method(def_id.to_def_id());

View file

@ -5,6 +5,8 @@ use super::TyCtxt;
#[derive(Copy, Clone, Debug, Decodable, Encodable, HashStable)]
pub struct IntrinsicDef {
pub name: Symbol,
/// Whether the intrinsic has no meaningful body and all backends need to shim all calls to it.
pub must_be_overridden: bool,
}
impl TyCtxt<'_> {

View file

@ -1646,7 +1646,10 @@ pub fn intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::IntrinsicDef
if matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic)
|| tcx.has_attr(def_id, sym::rustc_intrinsic)
{
Some(ty::IntrinsicDef { name: tcx.item_name(def_id.into()) })
Some(ty::IntrinsicDef {
name: tcx.item_name(def_id.into()),
must_be_overridden: tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden),
})
} else {
None
}

View file

@ -23,6 +23,10 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
return false;
}
if tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) {
return false;
}
// This just reproduces the logic from Instance::requires_inline.
match tcx.def_kind(def_id) {
DefKind::Ctor(..) | DefKind::Closure => return true,

View file

@ -632,6 +632,12 @@ fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> {
}
fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
if let Some(attr) = tcx.get_attr(did, sym::rustc_intrinsic_must_be_overridden) {
span_bug!(
attr.span,
"this intrinsic must be overridden by the codegen backend, it has no meaningful body",
)
}
if tcx.is_constructor(did.to_def_id()) {
// There's no reason to run all of the MIR passes on constructors when
// we can just output the MIR we want directly. This also saves const

View file

@ -1019,6 +1019,11 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
return false;
}
if tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden) {
// These are implemented by backends directly and have no meaningful body.
return false;
}
if def_id.is_local() {
// Local items cannot be referred to locally without monomorphizing them locally.
return true;

View file

@ -1525,6 +1525,7 @@ symbols! {
rustc_inherit_overflow_checks,
rustc_insignificant_dtor,
rustc_intrinsic,
rustc_intrinsic_must_be_overridden,
rustc_layout,
rustc_layout_scalar_valid_range_end,
rustc_layout_scalar_valid_range_start,