Skip to content

Commit c700590

Browse files
authored
Rollup merge of #125336 - momvart:smir-77-intrinsic, r=celinval
Add dedicated definition for intrinsics Closes rust-lang/project-stable-mir#77
2 parents d392d68 + 6743fc7 commit c700590

File tree

5 files changed

+111
-33
lines changed

5 files changed

+111
-33
lines changed

compiler/rustc_smir/src/rustc_smir/context.rs

+24-12
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use stable_mir::mir::{BinOp, Body, Place};
2323
use stable_mir::target::{MachineInfo, MachineSize};
2424
use stable_mir::ty::{
2525
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
26-
ForeignItemKind, GenericArgs, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, UintTy,
27-
VariantDef,
26+
ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind,
27+
UintTy, VariantDef,
2828
};
2929
use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
3030
use std::cell::RefCell;
@@ -312,6 +312,28 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
312312
sig.stable(&mut *tables)
313313
}
314314

315+
fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
316+
let mut tables = self.0.borrow_mut();
317+
let tcx = tables.tcx;
318+
let def_id = def.internal(&mut *tables, tcx);
319+
let intrinsic = tcx.intrinsic_raw(def_id);
320+
intrinsic.map(|_| IntrinsicDef(def))
321+
}
322+
323+
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
324+
let mut tables = self.0.borrow_mut();
325+
let tcx = tables.tcx;
326+
let def_id = def.0.internal(&mut *tables, tcx);
327+
tcx.intrinsic(def_id).unwrap().name.to_string()
328+
}
329+
330+
fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool {
331+
let mut tables = self.0.borrow_mut();
332+
let tcx = tables.tcx;
333+
let def_id = def.0.internal(&mut *tables, tcx);
334+
tcx.intrinsic_raw(def_id).unwrap().must_be_overridden
335+
}
336+
315337
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
316338
let mut tables = self.0.borrow_mut();
317339
let tcx = tables.tcx;
@@ -650,16 +672,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
650672
}
651673
}
652674

653-
/// Retrieve the plain intrinsic name of an instance.
654-
///
655-
/// This assumes that the instance is an intrinsic.
656-
fn intrinsic_name(&self, def: InstanceDef) -> Symbol {
657-
let tables = self.0.borrow_mut();
658-
let instance = tables.instances[def];
659-
let intrinsic = tables.tcx.intrinsic(instance.def_id()).unwrap();
660-
intrinsic.name.to_string()
661-
}
662-
663675
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
664676
let mut tables = self.0.borrow_mut();
665677
let tcx = tables.tcx;

compiler/stable_mir/src/compiler_interface.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use crate::target::MachineInfo;
1313
use crate::ty::{
1414
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
1515
ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics,
16-
ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty, TyKind,
17-
UintTy, VariantDef,
16+
ImplDef, ImplTrait, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty,
17+
TyKind, UintTy, VariantDef,
1818
};
1919
use crate::{
2020
mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
@@ -88,6 +88,16 @@ pub trait Context {
8888
/// Retrieve the function signature for the given generic arguments.
8989
fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig;
9090

91+
/// Retrieve the intrinsic definition if the item corresponds one.
92+
fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef>;
93+
94+
/// Retrieve the plain function name of an intrinsic.
95+
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol;
96+
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+
91101
/// Retrieve the closure signature for the given generic arguments.
92102
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
93103

@@ -198,7 +208,6 @@ pub trait Context {
198208
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
199209
fn krate(&self, def_id: DefId) -> Crate;
200210
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
201-
fn intrinsic_name(&self, def: InstanceDef) -> Symbol;
202211

203212
/// Return information about the target machine.
204213
fn target_info(&self) -> MachineInfo;

compiler/stable_mir/src/mir/mono.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ impl Instance {
106106
/// which is more convenient to match with intrinsic symbols.
107107
pub fn intrinsic_name(&self) -> Option<Symbol> {
108108
match self.kind {
109-
InstanceKind::Intrinsic => Some(with(|context| context.intrinsic_name(self.def))),
109+
InstanceKind::Intrinsic => {
110+
Some(with(|context| context.intrinsic(self.def.def_id()).unwrap().fn_name()))
111+
}
110112
InstanceKind::Item | InstanceKind::Virtual { .. } | InstanceKind::Shim => None,
111113
}
112114
}

compiler/stable_mir/src/ty.rs

+35
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,41 @@ impl FnDef {
621621
pub fn body(&self) -> Option<Body> {
622622
with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
623623
}
624+
625+
/// Get the information of the intrinsic if this function is a definition of one.
626+
pub fn as_intrinsic(&self) -> Option<IntrinsicDef> {
627+
with(|cx| cx.intrinsic(self.def_id()))
628+
}
629+
630+
/// Check if the function is an intrinsic.
631+
#[inline]
632+
pub fn is_intrinsic(&self) -> bool {
633+
self.as_intrinsic().is_some()
634+
}
635+
}
636+
637+
crate_def! {
638+
pub IntrinsicDef;
639+
}
640+
641+
impl IntrinsicDef {
642+
/// Returns the plain name of the intrinsic.
643+
/// e.g., `transmute` for `core::intrinsics::transmute`.
644+
pub fn fn_name(&self) -> Symbol {
645+
with(|cx| cx.intrinsic_name(*self))
646+
}
647+
648+
/// Returns whether the intrinsic has no meaningful body and all backends
649+
/// need to shim all calls to it.
650+
pub fn must_be_overridden(&self) -> bool {
651+
with(|cx| cx.intrinsic_must_be_overridden(*self))
652+
}
653+
}
654+
655+
impl From<IntrinsicDef> for FnDef {
656+
fn from(def: IntrinsicDef) -> Self {
657+
FnDef(def.0)
658+
}
624659
}
625660

626661
crate_def! {

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

+37-17
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
1212

1313
#![feature(rustc_private)]
14+
#![feature(assert_matches)]
1415

1516
extern crate rustc_hir;
1617
#[macro_use]
@@ -23,8 +24,8 @@ use rustc_smir::rustc_internal;
2324
use stable_mir::mir::mono::{Instance, InstanceKind};
2425
use stable_mir::mir::visit::{Location, MirVisitor};
2526
use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind};
26-
use stable_mir::ty::{RigidTy, TyKind};
27-
use std::collections::HashSet;
27+
use stable_mir::ty::{FnDef, GenericArgs, RigidTy, TyKind};
28+
use std::assert_matches::assert_matches;
2829
use std::convert::TryFrom;
2930
use std::io::Write;
3031
use std::ops::ControlFlow;
@@ -39,9 +40,10 @@ fn test_intrinsics() -> ControlFlow<()> {
3940
visitor.visit_body(&main_body);
4041

4142
let calls = visitor.calls;
42-
assert_eq!(calls.len(), 2, "Expected 2 calls, but found: {calls:?}");
43-
for intrinsic in &calls {
44-
check_intrinsic(intrinsic)
43+
assert_eq!(calls.len(), 3, "Expected 3 calls, but found: {calls:?}");
44+
for (fn_def, args) in calls.into_iter() {
45+
check_instance(&Instance::resolve(fn_def, &args).unwrap());
46+
check_def(fn_def);
4547
}
4648

4749
ControlFlow::Continue(())
@@ -53,22 +55,39 @@ fn test_intrinsics() -> ControlFlow<()> {
5355
///
5456
/// If by any chance this test breaks because you changed how an intrinsic is implemented, please
5557
/// update the test to invoke a different intrinsic.
56-
fn check_intrinsic(intrinsic: &Instance) {
57-
assert_eq!(intrinsic.kind, InstanceKind::Intrinsic);
58-
let name = intrinsic.intrinsic_name().unwrap();
59-
if intrinsic.has_body() {
60-
let Some(body) = intrinsic.body() else { unreachable!("Expected a body") };
58+
fn check_instance(instance: &Instance) {
59+
assert_eq!(instance.kind, InstanceKind::Intrinsic);
60+
let name = instance.intrinsic_name().unwrap();
61+
if instance.has_body() {
62+
let Some(body) = instance.body() else { unreachable!("Expected a body") };
6163
assert!(!body.blocks.is_empty());
62-
assert_eq!(&name, "likely");
64+
assert_matches!(name.as_str(), "likely" | "vtable_size");
6365
} else {
64-
assert!(intrinsic.body().is_none());
66+
assert!(instance.body().is_none());
6567
assert_eq!(&name, "size_of_val");
6668
}
6769
}
6870

71+
fn check_def(fn_def: FnDef) {
72+
assert!(fn_def.is_intrinsic());
73+
let intrinsic = fn_def.as_intrinsic().unwrap();
74+
assert_eq!(fn_def, intrinsic.into());
75+
76+
let name = intrinsic.fn_name();
77+
match name.as_str() {
78+
"likely" | "size_of_val" => {
79+
assert!(!intrinsic.must_be_overridden());
80+
}
81+
"vtable_size" => {
82+
assert!(intrinsic.must_be_overridden());
83+
}
84+
_ => unreachable!("Unexpected intrinsic: {}", name),
85+
}
86+
}
87+
6988
struct CallsVisitor<'a> {
7089
locals: &'a [LocalDecl],
71-
calls: HashSet<Instance>,
90+
calls: Vec<(FnDef, GenericArgs)>,
7291
}
7392

7493
impl<'a> MirVisitor for CallsVisitor<'a> {
@@ -77,10 +96,10 @@ impl<'a> MirVisitor for CallsVisitor<'a> {
7796
TerminatorKind::Call { func, .. } => {
7897
let TyKind::RigidTy(RigidTy::FnDef(def, args)) =
7998
func.ty(self.locals).unwrap().kind()
80-
else {
81-
return;
82-
};
83-
self.calls.insert(Instance::resolve(def, &args).unwrap());
99+
else {
100+
return;
101+
};
102+
self.calls.push((def, args.clone()));
84103
}
85104
_ => {}
86105
}
@@ -106,6 +125,7 @@ fn generate_input(path: &str) -> std::io::Result<()> {
106125
#![feature(core_intrinsics)]
107126
use std::intrinsics::*;
108127
pub fn use_intrinsics(init: bool) -> bool {{
128+
let vtable_sz = unsafe {{ vtable_size(0 as *const ()) }};
109129
let sz = unsafe {{ size_of_val("hi") }};
110130
likely(init && sz == 2)
111131
}}

0 commit comments

Comments
 (0)