Unify intrinsics body handling in StableMIR
rust-lang/rust#120675 introduced a new mechanism to declare intrinsics which will potentially replace the rust-intrinsic ABI. The new mechanism introduces a placeholder body and mark the intrinsic with #[rustc_intrinsic_must_be_overridden]. In practice, this means that backends should not generate code for the placeholder, and shim the intrinsic. The new annotation is an internal compiler implementation, and it doesn't need to be exposed to StableMIR users. In this PR, intrinsics marked with `rustc_intrinsic_must_be_overridden` are handled the same way as intrinsics that do not have a body.
This commit is contained in:
parent
0285dab54f
commit
c8c6598f17
@ -63,9 +63,10 @@ fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body {
|
||||
}
|
||||
|
||||
fn has_body(&self, def: DefId) -> bool {
|
||||
let tables = self.0.borrow();
|
||||
let def_id = tables[def];
|
||||
tables.tcx.is_mir_available(def_id)
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.internal(&mut *tables, tcx);
|
||||
tables.item_has_body(def_id)
|
||||
}
|
||||
|
||||
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
|
||||
@ -322,13 +323,6 @@ fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
|
||||
tcx.intrinsic(def_id).unwrap().name.to_string()
|
||||
}
|
||||
|
||||
fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
let def_id = def.0.internal(&mut *tables, tcx);
|
||||
tcx.intrinsic_raw(def_id).unwrap().must_be_overridden
|
||||
}
|
||||
|
||||
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let tcx = tables.tcx;
|
||||
@ -515,7 +509,7 @@ fn instance_body(&self, def: InstanceDef) -> Option<Body> {
|
||||
let mut tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
tables
|
||||
.has_body(instance)
|
||||
.instance_has_body(instance)
|
||||
.then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
|
||||
}
|
||||
|
||||
|
@ -51,9 +51,13 @@ pub(crate) fn intern_mir_const(&mut self, constant: mir::Const<'tcx>) -> MirCons
|
||||
self.mir_consts.create_or_fetch(constant)
|
||||
}
|
||||
|
||||
pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool {
|
||||
/// Return whether the instance as a body available.
|
||||
///
|
||||
/// Items and intrinsics may have a body available from its definition.
|
||||
/// Shims body may be generated depending on their type.
|
||||
pub(crate) fn instance_has_body(&self, instance: Instance<'tcx>) -> bool {
|
||||
let def_id = instance.def_id();
|
||||
self.tcx.is_mir_available(def_id)
|
||||
self.item_has_body(def_id)
|
||||
|| !matches!(
|
||||
instance.def,
|
||||
ty::InstanceDef::Virtual(..)
|
||||
@ -61,6 +65,19 @@ pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool {
|
||||
| ty::InstanceDef::Item(..)
|
||||
)
|
||||
}
|
||||
|
||||
/// Return whether the item has a body defined by the user.
|
||||
///
|
||||
/// Note that intrinsics may have a placeholder body that shouldn't be used in practice.
|
||||
/// In StableMIR, we handle this case as if the body is not available.
|
||||
pub(crate) fn item_has_body(&self, def_id: DefId) -> bool {
|
||||
let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) {
|
||||
intrinsic.must_be_overridden
|
||||
} else {
|
||||
false
|
||||
};
|
||||
!must_override && self.tcx.is_mir_available(def_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a stable mir crate from a given crate number.
|
||||
|
@ -94,10 +94,6 @@ pub trait Context {
|
||||
/// Retrieve the plain function name of an intrinsic.
|
||||
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol;
|
||||
|
||||
/// Returns whether the intrinsic has no meaningful body and all backends
|
||||
/// need to shim all calls to it.
|
||||
fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool;
|
||||
|
||||
/// Retrieve the closure signature for the given generic arguments.
|
||||
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
|
||||
|
||||
|
@ -658,6 +658,11 @@ pub fn body(&self) -> Option<Body> {
|
||||
with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
|
||||
}
|
||||
|
||||
// Check if the function body is available.
|
||||
pub fn has_body(&self) -> bool {
|
||||
with(|ctx| ctx.has_body(self.0))
|
||||
}
|
||||
|
||||
/// Get the information of the intrinsic if this function is a definition of one.
|
||||
pub fn as_intrinsic(&self) -> Option<IntrinsicDef> {
|
||||
with(|cx| cx.intrinsic(self.def_id()))
|
||||
@ -684,7 +689,7 @@ pub fn fn_name(&self) -> Symbol {
|
||||
/// Returns whether the intrinsic has no meaningful body and all backends
|
||||
/// need to shim all calls to it.
|
||||
pub fn must_be_overridden(&self) -> bool {
|
||||
with(|cx| cx.intrinsic_must_be_overridden(*self))
|
||||
with(|cx| !cx.has_body(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,16 +55,19 @@ fn test_intrinsics() -> ControlFlow<()> {
|
||||
///
|
||||
/// If by any chance this test breaks because you changed how an intrinsic is implemented, please
|
||||
/// update the test to invoke a different intrinsic.
|
||||
///
|
||||
/// In StableMIR, we only expose intrinsic body if they are not marked with
|
||||
/// `rustc_intrinsic_must_be_overridden`.
|
||||
fn check_instance(instance: &Instance) {
|
||||
assert_eq!(instance.kind, InstanceKind::Intrinsic);
|
||||
let name = instance.intrinsic_name().unwrap();
|
||||
if instance.has_body() {
|
||||
let Some(body) = instance.body() else { unreachable!("Expected a body") };
|
||||
assert!(!body.blocks.is_empty());
|
||||
assert_matches!(name.as_str(), "likely" | "vtable_size");
|
||||
assert_eq!(&name, "likely");
|
||||
} else {
|
||||
assert!(instance.body().is_none());
|
||||
assert_eq!(&name, "size_of_val");
|
||||
assert_matches!(name.as_str(), "size_of_val" | "vtable_size");
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,11 +78,13 @@ fn check_def(fn_def: FnDef) {
|
||||
|
||||
let name = intrinsic.fn_name();
|
||||
match name.as_str() {
|
||||
"likely" | "size_of_val" => {
|
||||
"likely" => {
|
||||
assert!(!intrinsic.must_be_overridden());
|
||||
assert!(fn_def.has_body());
|
||||
}
|
||||
"vtable_size" => {
|
||||
"vtable_size" | "size_of_val" => {
|
||||
assert!(intrinsic.must_be_overridden());
|
||||
assert!(!fn_def.has_body());
|
||||
}
|
||||
_ => unreachable!("Unexpected intrinsic: {}", name),
|
||||
}
|
||||
@ -96,9 +101,9 @@ fn visit_terminator(&mut self, term: &Terminator, _loc: Location) {
|
||||
TerminatorKind::Call { func, .. } => {
|
||||
let TyKind::RigidTy(RigidTy::FnDef(def, args)) =
|
||||
func.ty(self.locals).unwrap().kind()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
else {
|
||||
return;
|
||||
};
|
||||
self.calls.push((def, args.clone()));
|
||||
}
|
||||
_ => {}
|
||||
|
Loading…
Reference in New Issue
Block a user