From fa5ff859e610b46b924ac17df63de69c734759f8 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Tue, 7 Nov 2023 14:12:58 -0800 Subject: [PATCH] Add support to global allocation to stable-mir --- .../rustc_smir/src/rustc_internal/internal.rs | 3 +- compiler/rustc_smir/src/rustc_internal/mod.rs | 2 +- compiler/rustc_smir/src/rustc_smir/mod.rs | 73 +++++++++++++++++-- compiler/stable_mir/src/lib.rs | 30 ++++---- compiler/stable_mir/src/mir.rs | 1 + compiler/stable_mir/src/mir/alloc.rs | 37 ++++++++++ compiler/stable_mir/src/mir/mono.rs | 25 ++++++- compiler/stable_mir/src/ty.rs | 3 +- 8 files changed, 150 insertions(+), 24 deletions(-) create mode 100644 compiler/stable_mir/src/mir/alloc.rs diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 24b1a3c63be..988d1d7226a 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -7,12 +7,13 @@ use crate::rustc_smir::Tables; use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy}; use rustc_span::Symbol; +use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; use stable_mir::ty::{ AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef, Ty, UintTy, }; -use stable_mir::{AllocId, CrateItem, DefId}; +use stable_mir::{CrateItem, DefId}; use super::RustcInternal; diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index fa75fd3076c..b37c9a1f632 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -118,7 +118,7 @@ impl<'tcx> Tables<'tcx> { self.def_ids.create_or_fetch(did) } - fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::AllocId { + fn create_alloc_id(&mut self, aid: AllocId) -> stable_mir::mir::alloc::AllocId { self.alloc_ids.create_or_fetch(aid) } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 2a9f0b42678..509706387db 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -17,15 +17,16 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_target::abi::FieldIdx; -use stable_mir::mir::mono::InstanceDef; +use stable_mir::mir::alloc::GlobalAlloc; +use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::{ Body, ConstOperand, CopyNonOverlapping, Statement, UserTypeProjection, VarDebugInfoFragment, VariantIdx, }; use stable_mir::ty::{ - AdtDef, AdtKind, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, EarlyParamRegion, - FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, RigidTy, Span, - TyKind, UintTy, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, ConstId, ConstantKind, + EarlyParamRegion, FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability, + RigidTy, Span, TyKind, UintTy, }; use stable_mir::{self, opaque, Context, CrateItem, Error, Filename, ItemKind}; use std::cell::RefCell; @@ -318,6 +319,18 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } + fn eval_static_initializer(&self, def: StaticDef) -> Result { + let mut tables = self.0.borrow_mut(); + let def_id = def.0.internal(&mut *tables); + tables.tcx.eval_static_initializer(def_id).stable(&mut *tables) + } + + fn global_alloc(&self, alloc: stable_mir::mir::alloc::AllocId) -> GlobalAlloc { + let mut tables = self.0.borrow_mut(); + let alloc_id = alloc.internal(&mut *tables); + tables.tcx.global_alloc(alloc_id).stable(&mut *tables) + } + fn usize_to_const(&self, val: u64) -> Result { let mut tables = self.0.borrow_mut(); let ty = tables.tcx.types.usize; @@ -342,7 +355,7 @@ pub(crate) struct TablesWrapper<'tcx>(pub(crate) RefCell>); pub struct Tables<'tcx> { pub(crate) tcx: TyCtxt<'tcx>, pub(crate) def_ids: IndexMap, - pub(crate) alloc_ids: IndexMap, + pub(crate) alloc_ids: IndexMap, pub(crate) spans: IndexMap, pub(crate) types: IndexMap, stable_mir::ty::Ty>, pub(crate) instances: IndexMap, InstanceDef>, @@ -1590,6 +1603,14 @@ impl<'tcx> Stable<'tcx> for ty::BoundTy { } } +impl<'tcx> Stable<'tcx> for mir::interpret::ConstAllocation<'tcx> { + type T = Allocation; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + self.inner().stable(tables) + } +} + impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { type T = stable_mir::ty::Allocation; @@ -1602,6 +1623,25 @@ impl<'tcx> Stable<'tcx> for mir::interpret::Allocation { } } +impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { + type T = GlobalAlloc; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + mir::interpret::GlobalAlloc::Function(instance) => { + GlobalAlloc::Function(instance.stable(tables)) + } + mir::interpret::GlobalAlloc::VTable(ty, trait_ref) => { + GlobalAlloc::VTable(ty.stable(tables), trait_ref.stable(tables)) + } + mir::interpret::GlobalAlloc::Static(def) => { + GlobalAlloc::Static(tables.static_def(*def)) + } + mir::interpret::GlobalAlloc::Memory(alloc) => GlobalAlloc::Memory(alloc.stable(tables)), + } + } +} + impl<'tcx> Stable<'tcx> for ty::trait_def::TraitSpecializationKind { type T = stable_mir::ty::TraitSpecializationKind; fn stable(&self, _: &mut Tables<'tcx>) -> Self::T { @@ -1989,6 +2029,14 @@ impl<'tcx> Stable<'tcx> for MonoItem<'tcx> { } } +impl<'tcx> Stable<'tcx> for mir::interpret::ErrorHandled { + type T = Error; + + fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { + Error::new(format!("{self:?}")) + } +} + impl<'tcx, T> Stable<'tcx> for &T where T: Stable<'tcx>, @@ -2010,3 +2058,18 @@ where self.as_ref().map(|value| value.stable(tables)) } } + +impl<'tcx, T, E> Stable<'tcx> for Result +where + T: Stable<'tcx>, + E: Stable<'tcx>, +{ + type T = Result; + + fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { + match self { + Ok(val) => Ok(val.stable(tables)), + Err(error) => Err(error.stable(tables)), + } + } +} diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 5eb6a8a5e54..d5c4881c89d 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -17,7 +17,7 @@ //! The goal is to eventually be published on //! [crates.io](https://crates.io). -use crate::mir::mono::InstanceDef; +use crate::mir::mono::{InstanceDef, StaticDef}; use crate::mir::Body; use std::fmt; use std::fmt::Debug; @@ -37,9 +37,10 @@ pub mod mir; pub mod ty; pub mod visitor; +use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::pretty::function_name; use crate::mir::Mutability; -use crate::ty::{AdtDef, AdtKind, ClosureDef, ClosureKind, Const, RigidTy}; +use crate::ty::{AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, RigidTy}; pub use error::*; use mir::mono::Instance; use ty::{FnDef, GenericArgs}; @@ -73,19 +74,6 @@ impl IndexedVal for DefId { } } -/// A unique identification number for each provenance -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct AllocId(usize); - -impl IndexedVal for AllocId { - fn to_val(index: usize) -> Self { - AllocId(index) - } - fn to_index(&self) -> usize { - self.0 - } -} - /// A list of crate items. pub type CrateItems = Vec; @@ -141,6 +129,10 @@ impl CrateItem { with(|cx| cx.def_ty(self.0)) } + pub fn is_foreign_item(&self) -> bool { + with(|cx| cx.is_foreign_item(*self)) + } + pub fn dump(&self, w: &mut W) -> io::Result<()> { writeln!(w, "{}", function_name(*self))?; self.body().dump(w) @@ -190,6 +182,8 @@ pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait { with(|cx| cx.trait_impl(trait_impl)) } +/// This trait defines the interface between stable_mir and the Rust compiler. +/// Do not use this directly. pub trait Context { fn entry_fn(&self) -> Option; /// Retrieve all items of the local crate that have a MIR associated with them. @@ -291,6 +285,12 @@ pub trait Context { args: &GenericArgs, kind: ClosureKind, ) -> Option; + + /// Evaluate a static's initializer. + fn eval_static_initializer(&self, def: StaticDef) -> Result; + + /// Retrieve global allocation for the given allocation ID. + fn global_alloc(&self, id: AllocId) -> GlobalAlloc; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir.rs b/compiler/stable_mir/src/mir.rs index 2cbe6eb4ad1..82555461d64 100644 --- a/compiler/stable_mir/src/mir.rs +++ b/compiler/stable_mir/src/mir.rs @@ -1,3 +1,4 @@ +pub mod alloc; mod body; pub mod mono; pub mod pretty; diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs new file mode 100644 index 00000000000..ca24653585c --- /dev/null +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -0,0 +1,37 @@ +use crate::mir::mono::{Instance, StaticDef}; +use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty}; +use crate::with; + +/// An allocation in the SMIR global memory can be either a function pointer, +/// a static, or a "real" allocation with some data in it. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum GlobalAlloc { + /// The alloc ID is used as a function pointer. + Function(Instance), + /// This alloc ID points to a symbolic (not-reified) vtable. + VTable(Ty, Option>), + /// The alloc ID points to a "lazy" static variable that did not get computed (yet). + /// This is also used to break the cycle in recursive statics. + Static(StaticDef), + /// The alloc ID points to memory. + Memory(Allocation), +} + +impl From for GlobalAlloc { + fn from(value: AllocId) -> Self { + with(|cx| cx.global_alloc(value)) + } +} + +/// A unique identification number for each provenance +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct AllocId(usize); + +impl IndexedVal for AllocId { + fn to_val(index: usize) -> Self { + AllocId(index) + } + fn to_index(&self) -> usize { + self.0 + } +} diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 8c43f2c4b8f..9cec963cf84 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -1,5 +1,5 @@ use crate::mir::Body; -use crate::ty::{ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; +use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty}; use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque}; use std::fmt::{Debug, Formatter}; @@ -37,6 +37,11 @@ impl Instance { with(|context| context.instance_body(self.def)) } + pub fn is_foreign_item(&self) -> bool { + let item = CrateItem::try_from(*self); + item.as_ref().map_or(false, CrateItem::is_foreign_item) + } + /// Get the instance type with generic substitutions applied and lifetimes erased. pub fn ty(&self) -> Ty { with(|context| context.instance_ty(self.def)) @@ -128,6 +133,18 @@ impl From for MonoItem { } } +impl From for MonoItem { + fn from(value: StaticDef) -> Self { + MonoItem::Static(value) + } +} + +impl From for CrateItem { + fn from(value: StaticDef) -> Self { + CrateItem(value.0) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct InstanceDef(usize); @@ -147,9 +164,15 @@ impl TryFrom for StaticDef { } 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 { + with(|cx| cx.eval_static_initializer(*self)) + } } impl IndexedVal for InstanceDef { diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index abe6f8ec12f..010e2e7e4a6 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1,8 +1,9 @@ use super::{ mir::Safety, mir::{Body, Mutability}, - with, AllocId, DefId, Error, Symbol, + with, DefId, Error, Symbol, }; +use crate::mir::alloc::AllocId; use crate::{Filename, Opaque}; use std::fmt::{self, Debug, Display, Formatter};