summaryrefslogtreecommitdiffstats
path: root/compiler/stable_mir/src/mir/mono.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/stable_mir/src/mir/mono.rs')
-rw-r--r--compiler/stable_mir/src/mir/mono.rs206
1 files changed, 188 insertions, 18 deletions
diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs
index 8f5333498..6c791ae85 100644
--- a/compiler/stable_mir/src/mir/mono.rs
+++ b/compiler/stable_mir/src/mir/mono.rs
@@ -1,16 +1,18 @@
+use crate::abi::FnAbi;
+use crate::crate_def::CrateDef;
use crate::mir::Body;
-use crate::ty::{FnDef, GenericArgs, IndexedVal, Ty};
-use crate::{with, CrateItem, DefId, Error, Opaque};
-use std::fmt::Debug;
+use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
+use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
+use std::fmt::{Debug, Formatter};
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum MonoItem {
Fn(Instance),
Static(StaticDef),
GlobalAsm(Opaque),
}
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct Instance {
/// The type of instance.
pub kind: InstanceKind,
@@ -19,33 +21,75 @@ pub struct Instance {
pub def: InstanceDef,
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum InstanceKind {
/// A user defined item.
Item,
/// A compiler intrinsic function.
Intrinsic,
/// A virtual function definition stored in a VTable.
- Virtual,
+ /// The `idx` field indicates the position in the VTable for this instance.
+ Virtual { idx: usize },
/// A compiler generated shim.
Shim,
}
impl Instance {
+ /// Get the arguments this instance was instantiated with.
+ pub fn args(&self) -> GenericArgs {
+ with(|cx| cx.instance_args(self.def))
+ }
+
/// Get the body of an Instance. The body will be eagerly monomorphized.
- pub fn body(&self) -> Body {
+ pub fn body(&self) -> Option<Body> {
with(|context| context.instance_body(self.def))
}
+ /// Check whether this instance has a body available.
+ ///
+ /// This call is much cheaper than `instance.body().is_some()`, since it doesn't try to build
+ /// the StableMIR body.
+ pub fn has_body(&self) -> bool {
+ with(|cx| cx.has_body(self.def.def_id()))
+ }
+
+ pub fn is_foreign_item(&self) -> bool {
+ with(|cx| cx.is_foreign_item(self.def.def_id()))
+ }
+
/// Get the instance type with generic substitutions applied and lifetimes erased.
pub fn ty(&self) -> Ty {
with(|context| context.instance_ty(self.def))
}
- pub fn mangled_name(&self) -> String {
+ /// Retrieve information about this instance binary interface.
+ pub fn fn_abi(&self) -> Result<FnAbi, Error> {
+ with(|cx| cx.instance_abi(self.def))
+ }
+
+ /// Retrieve the instance's mangled name used for calling the given instance.
+ ///
+ /// This will also look up the correct name of instances from upstream crates.
+ pub fn mangled_name(&self) -> Symbol {
with(|context| context.instance_mangled_name(self.def))
}
+ /// Retrieve the instance name for diagnostic messages.
+ ///
+ /// This will return the specialized name, e.g., `std::vec::Vec<u8>::new`.
+ pub fn name(&self) -> Symbol {
+ with(|context| context.instance_name(self.def, false))
+ }
+
+ /// Return a trimmed name of the given instance including its args.
+ ///
+ /// If a symbol name can only be imported from one place for a type, and as
+ /// long as it was not glob-imported anywhere in the current crate, we trim its
+ /// path and print only the name.
+ pub fn trimmed_name(&self) -> Symbol {
+ with(|context| context.instance_name(self.def, true))
+ }
+
/// Resolve an instance starting from a function definition and generic arguments.
pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
with(|context| {
@@ -54,6 +98,64 @@ impl Instance {
})
})
}
+
+ /// Resolve the drop in place for a given type.
+ pub fn resolve_drop_in_place(ty: Ty) -> Instance {
+ with(|cx| cx.resolve_drop_in_place(ty))
+ }
+
+ /// Resolve an instance for a given function pointer.
+ pub fn resolve_for_fn_ptr(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
+ with(|context| {
+ context.resolve_for_fn_ptr(def, args).ok_or_else(|| {
+ crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
+ })
+ })
+ }
+
+ /// Resolve a closure with the expected kind.
+ pub fn resolve_closure(
+ def: ClosureDef,
+ args: &GenericArgs,
+ kind: ClosureKind,
+ ) -> Result<Instance, crate::Error> {
+ with(|context| {
+ context.resolve_closure(def, args, kind).ok_or_else(|| {
+ crate::Error::new(format!("Failed to resolve `{def:?}` with `{args:?}`"))
+ })
+ })
+ }
+
+ /// Check whether this instance is an empty shim.
+ ///
+ /// Allow users to check if this shim can be ignored when called directly.
+ ///
+ /// We have decided not to export different types of Shims to StableMIR users, however, this
+ /// is a query that can be very helpful for users when processing DropGlue.
+ ///
+ /// When generating code for a Drop terminator, users can ignore an empty drop glue.
+ /// These shims are only needed to generate a valid Drop call done via VTable.
+ pub fn is_empty_shim(&self) -> bool {
+ self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def))
+ }
+
+ /// Try to constant evaluate the instance into a constant with the given type.
+ ///
+ /// This can be used to retrieve a constant that represents an intrinsic return such as
+ /// `type_id`.
+ pub fn try_const_eval(&self, const_ty: Ty) -> Result<Allocation, Error> {
+ with(|cx| cx.eval_instance(self.def, const_ty))
+ }
+}
+
+impl Debug for Instance {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("Instance")
+ .field("kind", &self.kind)
+ .field("def", &self.mangled_name())
+ .field("args", &self.args())
+ .finish()
+ }
}
/// Try to convert a crate item into an instance.
@@ -63,8 +165,9 @@ impl TryFrom<CrateItem> for Instance {
fn try_from(item: CrateItem) -> Result<Self, Self::Error> {
with(|context| {
- if !context.requires_monomorphization(item.0) {
- Ok(context.mono_instance(item))
+ let def_id = item.def_id();
+ if !context.requires_monomorphization(def_id) {
+ Ok(context.mono_instance(def_id))
} else {
Err(Error::new("Item requires monomorphization".to_string()))
}
@@ -78,19 +181,86 @@ impl TryFrom<Instance> for CrateItem {
type Error = crate::Error;
fn try_from(value: Instance) -> Result<Self, Self::Error> {
- if value.kind == InstanceKind::Item {
- Ok(CrateItem(with(|context| context.instance_def_id(value.def))))
+ with(|context| {
+ if value.kind == InstanceKind::Item && context.has_body(value.def.def_id()) {
+ Ok(CrateItem(context.instance_def_id(value.def)))
+ } else {
+ Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind)))
+ }
+ })
+ }
+}
+
+impl From<Instance> for MonoItem {
+ fn from(value: Instance) -> Self {
+ MonoItem::Fn(value)
+ }
+}
+
+impl From<StaticDef> for MonoItem {
+ fn from(value: StaticDef) -> Self {
+ MonoItem::Static(value)
+ }
+}
+
+impl From<StaticDef> for CrateItem {
+ fn from(value: StaticDef) -> Self {
+ CrateItem(value.0)
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct InstanceDef(usize);
+
+impl CrateDef for InstanceDef {
+ fn def_id(&self) -> DefId {
+ with(|context| context.instance_def_id(*self))
+ }
+}
+
+crate_def! {
+ /// Holds information about a static variable definition.
+ pub StaticDef;
+}
+
+impl TryFrom<CrateItem> for StaticDef {
+ type Error = crate::Error;
+
+ fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
+ if matches!(value.kind(), ItemKind::Static) {
+ Ok(StaticDef(value.0))
} else {
- Err(Error::new(format!("Item kind `{:?}` cannot be converted", value.kind)))
+ Err(Error::new(format!("Expected a static item, but found: {value:?}")))
}
}
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub struct InstanceDef(usize);
+impl TryFrom<Instance> for StaticDef {
+ type Error = crate::Error;
+
+ fn try_from(value: Instance) -> Result<Self, Self::Error> {
+ StaticDef::try_from(CrateItem::try_from(value)?)
+ }
+}
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
-pub struct StaticDef(pub DefId);
+impl From<StaticDef> for Instance {
+ fn from(value: StaticDef) -> Self {
+ // A static definition should always be convertible to an instance.
+ with(|cx| cx.mono_instance(value.def_id()))
+ }
+}
+
+impl StaticDef {
+ /// Return the type of this static definition.
+ pub fn ty(&self) -> Ty {
+ with(|cx| cx.def_ty(self.0))
+ }
+
+ /// Evaluate a static's initializer, returning the allocation of the initializer's memory.
+ pub fn eval_initializer(&self) -> Result<Allocation, Error> {
+ with(|cx| cx.eval_static_initializer(*self))
+ }
+}
impl IndexedVal for InstanceDef {
fn to_val(index: usize) -> Self {