Skip to content

Commit c8c6598

Browse files
committed
Unify intrinsics body handling in StableMIR
rust-lang#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.
1 parent 0285dab commit c8c6598

File tree

5 files changed

+42
-25
lines changed

5 files changed

+42
-25
lines changed

compiler/rustc_smir/src/rustc_smir/context.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
6363
}
6464

6565
fn has_body(&self, def: DefId) -> bool {
66-
let tables = self.0.borrow();
67-
let def_id = tables[def];
68-
tables.tcx.is_mir_available(def_id)
66+
let mut tables = self.0.borrow_mut();
67+
let tcx = tables.tcx;
68+
let def_id = def.internal(&mut *tables, tcx);
69+
tables.item_has_body(def_id)
6970
}
7071

7172
fn foreign_modules(&self, crate_num: CrateNum) -> Vec<stable_mir::ty::ForeignModuleDef> {
@@ -322,13 +323,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
322323
tcx.intrinsic(def_id).unwrap().name.to_string()
323324
}
324325

325-
fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool {
326-
let mut tables = self.0.borrow_mut();
327-
let tcx = tables.tcx;
328-
let def_id = def.0.internal(&mut *tables, tcx);
329-
tcx.intrinsic_raw(def_id).unwrap().must_be_overridden
330-
}
331-
332326
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
333327
let mut tables = self.0.borrow_mut();
334328
let tcx = tables.tcx;
@@ -515,7 +509,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
515509
let mut tables = self.0.borrow_mut();
516510
let instance = tables.instances[def];
517511
tables
518-
.has_body(instance)
512+
.instance_has_body(instance)
519513
.then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables))
520514
}
521515

compiler/rustc_smir/src/rustc_smir/mod.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,33 @@ impl<'tcx> Tables<'tcx> {
5151
self.mir_consts.create_or_fetch(constant)
5252
}
5353

54-
pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool {
54+
/// Return whether the instance as a body available.
55+
///
56+
/// Items and intrinsics may have a body available from its definition.
57+
/// Shims body may be generated depending on their type.
58+
pub(crate) fn instance_has_body(&self, instance: Instance<'tcx>) -> bool {
5559
let def_id = instance.def_id();
56-
self.tcx.is_mir_available(def_id)
60+
self.item_has_body(def_id)
5761
|| !matches!(
5862
instance.def,
5963
ty::InstanceDef::Virtual(..)
6064
| ty::InstanceDef::Intrinsic(..)
6165
| ty::InstanceDef::Item(..)
6266
)
6367
}
68+
69+
/// Return whether the item has a body defined by the user.
70+
///
71+
/// Note that intrinsics may have a placeholder body that shouldn't be used in practice.
72+
/// In StableMIR, we handle this case as if the body is not available.
73+
pub(crate) fn item_has_body(&self, def_id: DefId) -> bool {
74+
let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) {
75+
intrinsic.must_be_overridden
76+
} else {
77+
false
78+
};
79+
!must_override && self.tcx.is_mir_available(def_id)
80+
}
6481
}
6582

6683
/// Build a stable mir crate from a given crate number.

compiler/stable_mir/src/compiler_interface.rs

-4
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,6 @@ pub trait Context {
9494
/// Retrieve the plain function name of an intrinsic.
9595
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol;
9696

97-
/// Returns whether the intrinsic has no meaningful body and all backends
98-
/// need to shim all calls to it.
99-
fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool;
100-
10197
/// Retrieve the closure signature for the given generic arguments.
10298
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
10399

compiler/stable_mir/src/ty.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,11 @@ impl FnDef {
658658
with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
659659
}
660660

661+
// Check if the function body is available.
662+
pub fn has_body(&self) -> bool {
663+
with(|ctx| ctx.has_body(self.0))
664+
}
665+
661666
/// Get the information of the intrinsic if this function is a definition of one.
662667
pub fn as_intrinsic(&self) -> Option<IntrinsicDef> {
663668
with(|cx| cx.intrinsic(self.def_id()))
@@ -684,7 +689,7 @@ impl IntrinsicDef {
684689
/// Returns whether the intrinsic has no meaningful body and all backends
685690
/// need to shim all calls to it.
686691
pub fn must_be_overridden(&self) -> bool {
687-
with(|cx| cx.intrinsic_must_be_overridden(*self))
692+
with(|cx| !cx.has_body(self.0))
688693
}
689694
}
690695

tests/ui-fulldeps/stable-mir/check_intrinsics.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -55,16 +55,19 @@ fn test_intrinsics() -> ControlFlow<()> {
5555
///
5656
/// If by any chance this test breaks because you changed how an intrinsic is implemented, please
5757
/// update the test to invoke a different intrinsic.
58+
///
59+
/// In StableMIR, we only expose intrinsic body if they are not marked with
60+
/// `rustc_intrinsic_must_be_overridden`.
5861
fn check_instance(instance: &Instance) {
5962
assert_eq!(instance.kind, InstanceKind::Intrinsic);
6063
let name = instance.intrinsic_name().unwrap();
6164
if instance.has_body() {
6265
let Some(body) = instance.body() else { unreachable!("Expected a body") };
6366
assert!(!body.blocks.is_empty());
64-
assert_matches!(name.as_str(), "likely" | "vtable_size");
67+
assert_eq!(&name, "likely");
6568
} else {
6669
assert!(instance.body().is_none());
67-
assert_eq!(&name, "size_of_val");
70+
assert_matches!(name.as_str(), "size_of_val" | "vtable_size");
6871
}
6972
}
7073

@@ -75,11 +78,13 @@ fn check_def(fn_def: FnDef) {
7578

7679
let name = intrinsic.fn_name();
7780
match name.as_str() {
78-
"likely" | "size_of_val" => {
81+
"likely" => {
7982
assert!(!intrinsic.must_be_overridden());
83+
assert!(fn_def.has_body());
8084
}
81-
"vtable_size" => {
85+
"vtable_size" | "size_of_val" => {
8286
assert!(intrinsic.must_be_overridden());
87+
assert!(!fn_def.has_body());
8388
}
8489
_ => unreachable!("Unexpected intrinsic: {}", name),
8590
}
@@ -96,9 +101,9 @@ impl<'a> MirVisitor for CallsVisitor<'a> {
96101
TerminatorKind::Call { func, .. } => {
97102
let TyKind::RigidTy(RigidTy::FnDef(def, args)) =
98103
func.ty(self.locals).unwrap().kind()
99-
else {
100-
return;
101-
};
104+
else {
105+
return;
106+
};
102107
self.calls.push((def, args.clone()));
103108
}
104109
_ => {}

0 commit comments

Comments
 (0)