Rollup merge of #125336 - momvart:smir-77-intrinsic, r=celinval
Add dedicated definition for intrinsics Closes rust-lang/project-stable-mir#77
This commit is contained in:
commit
c70059062a
@ -23,8 +23,8 @@
|
|||||||
use stable_mir::target::{MachineInfo, MachineSize};
|
use stable_mir::target::{MachineInfo, MachineSize};
|
||||||
use stable_mir::ty::{
|
use stable_mir::ty::{
|
||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||||
ForeignItemKind, GenericArgs, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, UintTy,
|
ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind,
|
||||||
VariantDef,
|
UintTy, VariantDef,
|
||||||
};
|
};
|
||||||
use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
|
use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@ -312,6 +312,28 @@ fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
|
|||||||
sig.stable(&mut *tables)
|
sig.stable(&mut *tables)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn intrinsic(&self, def: DefId) -> Option<IntrinsicDef> {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let tcx = tables.tcx;
|
||||||
|
let def_id = def.internal(&mut *tables, tcx);
|
||||||
|
let intrinsic = tcx.intrinsic_raw(def_id);
|
||||||
|
intrinsic.map(|_| IntrinsicDef(def))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol {
|
||||||
|
let mut tables = self.0.borrow_mut();
|
||||||
|
let tcx = tables.tcx;
|
||||||
|
let def_id = def.0.internal(&mut *tables, tcx);
|
||||||
|
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 {
|
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
let tcx = tables.tcx;
|
let tcx = tables.tcx;
|
||||||
@ -650,16 +672,6 @@ fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the plain intrinsic name of an instance.
|
|
||||||
///
|
|
||||||
/// This assumes that the instance is an intrinsic.
|
|
||||||
fn intrinsic_name(&self, def: InstanceDef) -> Symbol {
|
|
||||||
let tables = self.0.borrow_mut();
|
|
||||||
let instance = tables.instances[def];
|
|
||||||
let intrinsic = tables.tcx.intrinsic(instance.def_id()).unwrap();
|
|
||||||
intrinsic.name.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
|
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
|
||||||
let mut tables = self.0.borrow_mut();
|
let mut tables = self.0.borrow_mut();
|
||||||
let tcx = tables.tcx;
|
let tcx = tables.tcx;
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef,
|
||||||
ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics,
|
ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics,
|
||||||
ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty, TyKind,
|
ImplDef, ImplTrait, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty,
|
||||||
UintTy, VariantDef,
|
TyKind, UintTy, VariantDef,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
|
mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
|
||||||
@ -88,6 +88,16 @@ pub trait Context {
|
|||||||
/// Retrieve the function signature for the given generic arguments.
|
/// Retrieve the function signature for the given generic arguments.
|
||||||
fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig;
|
fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig;
|
||||||
|
|
||||||
|
/// Retrieve the intrinsic definition if the item corresponds one.
|
||||||
|
fn intrinsic(&self, item: DefId) -> Option<IntrinsicDef>;
|
||||||
|
|
||||||
|
/// 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.
|
/// Retrieve the closure signature for the given generic arguments.
|
||||||
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
|
fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig;
|
||||||
|
|
||||||
@ -198,7 +208,6 @@ fn resolve_closure(
|
|||||||
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
|
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
|
||||||
fn krate(&self, def_id: DefId) -> Crate;
|
fn krate(&self, def_id: DefId) -> Crate;
|
||||||
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
|
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
|
||||||
fn intrinsic_name(&self, def: InstanceDef) -> Symbol;
|
|
||||||
|
|
||||||
/// Return information about the target machine.
|
/// Return information about the target machine.
|
||||||
fn target_info(&self) -> MachineInfo;
|
fn target_info(&self) -> MachineInfo;
|
||||||
|
@ -106,7 +106,9 @@ pub fn trimmed_name(&self) -> Symbol {
|
|||||||
/// which is more convenient to match with intrinsic symbols.
|
/// which is more convenient to match with intrinsic symbols.
|
||||||
pub fn intrinsic_name(&self) -> Option<Symbol> {
|
pub fn intrinsic_name(&self) -> Option<Symbol> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
InstanceKind::Intrinsic => Some(with(|context| context.intrinsic_name(self.def))),
|
InstanceKind::Intrinsic => {
|
||||||
|
Some(with(|context| context.intrinsic(self.def.def_id()).unwrap().fn_name()))
|
||||||
|
}
|
||||||
InstanceKind::Item | InstanceKind::Virtual { .. } | InstanceKind::Shim => None,
|
InstanceKind::Item | InstanceKind::Virtual { .. } | InstanceKind::Shim => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -621,6 +621,41 @@ impl FnDef {
|
|||||||
pub fn body(&self) -> Option<Body> {
|
pub fn body(&self) -> Option<Body> {
|
||||||
with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
|
with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_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()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if the function is an intrinsic.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_intrinsic(&self) -> bool {
|
||||||
|
self.as_intrinsic().is_some()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
crate_def! {
|
||||||
|
pub IntrinsicDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntrinsicDef {
|
||||||
|
/// Returns the plain name of the intrinsic.
|
||||||
|
/// e.g., `transmute` for `core::intrinsics::transmute`.
|
||||||
|
pub fn fn_name(&self) -> Symbol {
|
||||||
|
with(|cx| cx.intrinsic_name(*self))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IntrinsicDef> for FnDef {
|
||||||
|
fn from(def: IntrinsicDef) -> Self {
|
||||||
|
FnDef(def.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
crate_def! {
|
crate_def! {
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
|
//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
|
||||||
|
|
||||||
#![feature(rustc_private)]
|
#![feature(rustc_private)]
|
||||||
|
#![feature(assert_matches)]
|
||||||
|
|
||||||
extern crate rustc_hir;
|
extern crate rustc_hir;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -23,8 +24,8 @@
|
|||||||
use stable_mir::mir::mono::{Instance, InstanceKind};
|
use stable_mir::mir::mono::{Instance, InstanceKind};
|
||||||
use stable_mir::mir::visit::{Location, MirVisitor};
|
use stable_mir::mir::visit::{Location, MirVisitor};
|
||||||
use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind};
|
use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind};
|
||||||
use stable_mir::ty::{RigidTy, TyKind};
|
use stable_mir::ty::{FnDef, GenericArgs, RigidTy, TyKind};
|
||||||
use std::collections::HashSet;
|
use std::assert_matches::assert_matches;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
@ -39,9 +40,10 @@ fn test_intrinsics() -> ControlFlow<()> {
|
|||||||
visitor.visit_body(&main_body);
|
visitor.visit_body(&main_body);
|
||||||
|
|
||||||
let calls = visitor.calls;
|
let calls = visitor.calls;
|
||||||
assert_eq!(calls.len(), 2, "Expected 2 calls, but found: {calls:?}");
|
assert_eq!(calls.len(), 3, "Expected 3 calls, but found: {calls:?}");
|
||||||
for intrinsic in &calls {
|
for (fn_def, args) in calls.into_iter() {
|
||||||
check_intrinsic(intrinsic)
|
check_instance(&Instance::resolve(fn_def, &args).unwrap());
|
||||||
|
check_def(fn_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
ControlFlow::Continue(())
|
ControlFlow::Continue(())
|
||||||
@ -53,22 +55,39 @@ fn test_intrinsics() -> ControlFlow<()> {
|
|||||||
///
|
///
|
||||||
/// If by any chance this test breaks because you changed how an intrinsic is implemented, please
|
/// If by any chance this test breaks because you changed how an intrinsic is implemented, please
|
||||||
/// update the test to invoke a different intrinsic.
|
/// update the test to invoke a different intrinsic.
|
||||||
fn check_intrinsic(intrinsic: &Instance) {
|
fn check_instance(instance: &Instance) {
|
||||||
assert_eq!(intrinsic.kind, InstanceKind::Intrinsic);
|
assert_eq!(instance.kind, InstanceKind::Intrinsic);
|
||||||
let name = intrinsic.intrinsic_name().unwrap();
|
let name = instance.intrinsic_name().unwrap();
|
||||||
if intrinsic.has_body() {
|
if instance.has_body() {
|
||||||
let Some(body) = intrinsic.body() else { unreachable!("Expected a body") };
|
let Some(body) = instance.body() else { unreachable!("Expected a body") };
|
||||||
assert!(!body.blocks.is_empty());
|
assert!(!body.blocks.is_empty());
|
||||||
assert_eq!(&name, "likely");
|
assert_matches!(name.as_str(), "likely" | "vtable_size");
|
||||||
} else {
|
} else {
|
||||||
assert!(intrinsic.body().is_none());
|
assert!(instance.body().is_none());
|
||||||
assert_eq!(&name, "size_of_val");
|
assert_eq!(&name, "size_of_val");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_def(fn_def: FnDef) {
|
||||||
|
assert!(fn_def.is_intrinsic());
|
||||||
|
let intrinsic = fn_def.as_intrinsic().unwrap();
|
||||||
|
assert_eq!(fn_def, intrinsic.into());
|
||||||
|
|
||||||
|
let name = intrinsic.fn_name();
|
||||||
|
match name.as_str() {
|
||||||
|
"likely" | "size_of_val" => {
|
||||||
|
assert!(!intrinsic.must_be_overridden());
|
||||||
|
}
|
||||||
|
"vtable_size" => {
|
||||||
|
assert!(intrinsic.must_be_overridden());
|
||||||
|
}
|
||||||
|
_ => unreachable!("Unexpected intrinsic: {}", name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct CallsVisitor<'a> {
|
struct CallsVisitor<'a> {
|
||||||
locals: &'a [LocalDecl],
|
locals: &'a [LocalDecl],
|
||||||
calls: HashSet<Instance>,
|
calls: Vec<(FnDef, GenericArgs)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MirVisitor for CallsVisitor<'a> {
|
impl<'a> MirVisitor for CallsVisitor<'a> {
|
||||||
@ -77,10 +96,10 @@ fn visit_terminator(&mut self, term: &Terminator, _loc: Location) {
|
|||||||
TerminatorKind::Call { func, .. } => {
|
TerminatorKind::Call { func, .. } => {
|
||||||
let TyKind::RigidTy(RigidTy::FnDef(def, args)) =
|
let TyKind::RigidTy(RigidTy::FnDef(def, args)) =
|
||||||
func.ty(self.locals).unwrap().kind()
|
func.ty(self.locals).unwrap().kind()
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
self.calls.insert(Instance::resolve(def, &args).unwrap());
|
self.calls.push((def, args.clone()));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@ -106,6 +125,7 @@ fn generate_input(path: &str) -> std::io::Result<()> {
|
|||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
use std::intrinsics::*;
|
use std::intrinsics::*;
|
||||||
pub fn use_intrinsics(init: bool) -> bool {{
|
pub fn use_intrinsics(init: bool) -> bool {{
|
||||||
|
let vtable_sz = unsafe {{ vtable_size(0 as *const ()) }};
|
||||||
let sz = unsafe {{ size_of_val("hi") }};
|
let sz = unsafe {{ size_of_val("hi") }};
|
||||||
likely(init && sz == 2)
|
likely(init && sz == 2)
|
||||||
}}
|
}}
|
||||||
|
Loading…
Reference in New Issue
Block a user