Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add instance evaluation and methods to read an allocation in StableMIR #118694

Merged
merged 4 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4492,6 4492,7 @@ dependencies = [
name = "rustc_smir"
version = "0.0.0"
dependencies = [
"rustc_abi",
"rustc_data_structures",
"rustc_hir",
"rustc_middle",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_smir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 5,7 @@ edition = "2021"

[dependencies]
# tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" }
rustc_middle = { path = "../rustc_middle" }
Expand Down
37 changes: 26 additions & 11 deletions compiler/rustc_smir/src/rustc_smir/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 2,7 @@ use rustc_middle::mir::{
interpret::{alloc_range, AllocRange, Pointer},
ConstValue,
};
use stable_mir::Error;

use crate::rustc_smir::{Stable, Tables};
use stable_mir::mir::Mutability;
Expand All @@ -26,23 27,35 @@ pub fn new_allocation<'tcx>(
const_value: ConstValue<'tcx>,
tables: &mut Tables<'tcx>,
) -> Allocation {
match const_value {
try_new_allocation(ty, const_value, tables).unwrap()
}

#[allow(rustc::usage_of_qualified_ty)]
pub fn try_new_allocation<'tcx>(
ty: rustc_middle::ty::Ty<'tcx>,
const_value: ConstValue<'tcx>,
tables: &mut Tables<'tcx>,
) -> Result<Allocation, Error> {
Ok(match const_value {
ConstValue::Scalar(scalar) => {
let size = scalar.size();
let align = tables
.tcx
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
.unwrap()
.map_err(|e| e.stable(tables))?
.align;
let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
allocation
.write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar)
.unwrap();
.map_err(|e| e.stable(tables))?;
allocation.stable(tables)
}
ConstValue::ZeroSized => {
let align =
tables.tcx.layout_of(rustc_middle::ty::ParamEnv::empty().and(ty)).unwrap().align;
let align = tables
.tcx
.layout_of(rustc_middle::ty::ParamEnv::empty().and(ty))
.map_err(|e| e.stable(tables))?
.align;
new_empty_allocation(align.abi)
}
ConstValue::Slice { data, meta } => {
Expand All @@ -51,8 64,10 @@ pub fn new_allocation<'tcx>(
let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
let scalar_meta =
rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
let layout =
tables.tcx.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty)).unwrap();
let layout = tables
.tcx
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
.map_err(|e| e.stable(tables))?;
let mut allocation =
rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
allocation
Expand All @@ -61,26 76,26 @@ pub fn new_allocation<'tcx>(
alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size),
scalar_ptr,
)
.unwrap();
.map_err(|e| e.stable(tables))?;
allocation
.write_scalar(
&tables.tcx,
alloc_range(tables.tcx.data_layout.pointer_size, scalar_meta.size()),
scalar_meta,
)
.unwrap();
.map_err(|e| e.stable(tables))?;
allocation.stable(tables)
}
ConstValue::Indirect { alloc_id, offset } => {
let alloc = tables.tcx.global_alloc(alloc_id).unwrap_memory();
let ty_size = tables
.tcx
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
.unwrap()
.map_err(|e| e.stable(tables))?
.size;
allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables)
}
}
})
}

/// Creates an `Allocation` only from information within the `AllocRange`.
Expand Down
30 changes: 28 additions & 2 deletions compiler/rustc_smir/src/rustc_smir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 11,29 @@ use stable_mir::compiler_interface::Context;
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::{InstanceDef, StaticDef};
use stable_mir::mir::Body;
use stable_mir::target::{MachineInfo, MachineSize};
use stable_mir::ty::{
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
LineInfo, PolyFnSig, RigidTy, Span, TyKind, VariantDef,
LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
};
use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
use std::cell::RefCell;

use crate::rustc_internal::{internal, RustcInternal};
use crate::rustc_smir::builder::BodyBuilder;
use crate::rustc_smir::{new_item_kind, smir_crate, Stable, Tables};
use crate::rustc_smir::{alloc, new_item_kind, smir_crate, Stable, Tables};

impl<'tcx> Context for TablesWrapper<'tcx> {
fn target_info(&self) -> MachineInfo {
let mut tables = self.0.borrow_mut();
MachineInfo {
endian: tables.tcx.data_layout.endian.stable(&mut *tables),
pointer_width: MachineSize::from_bits(
tables.tcx.data_layout.pointer_size.bits().try_into().unwrap(),
),
}
}

fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
Expand Down Expand Up @@ -382,6 393,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
}

fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
let mut tables = self.0.borrow_mut();
let instance = tables.instances[def];
let result = tables.tcx.const_eval_instance(
ParamEnv::reveal_all(),
instance,
Some(tables.tcx.def_span(instance.def_id())),
);
result
.map(|const_val| {
alloc::try_new_allocation(const_ty.internal(&mut *tables), const_val, &mut *tables)
})
.map_err(|e| e.stable(&mut *tables))?
}

fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
let mut tables = self.0.borrow_mut();
let def_id = def.0.internal(&mut *tables);
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_smir/src/rustc_smir/convert/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 1,22 @@
//! Handle the conversion of different internal errors into a stable version.
//!
//! Currently we encode everything as [stable_mir::Error], which is represented as a string.
use crate::rustc_smir::{Stable, Tables};
use rustc_middle::mir::interpret::AllocError;
use rustc_middle::ty::layout::LayoutError;

impl<'tcx> Stable<'tcx> for LayoutError<'tcx> {
type T = stable_mir::Error;

fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
stable_mir::Error::new(format!("{self:?}"))
}
}

impl<'tcx> Stable<'tcx> for AllocError {
type T = stable_mir::Error;

fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
stable_mir::Error::new(format!("{self:?}"))
}
}
12 changes: 12 additions & 0 deletions compiler/rustc_smir/src/rustc_smir/convert/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 5,7 @@ use stable_mir::ty::{IndexedVal, VariantIdx};

use crate::rustc_smir::{Stable, Tables};

mod error;
mod mir;
mod ty;

Expand Down Expand Up @@ -75,3 76,14 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
tables.create_span(*self)
}
}

impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
type T = stable_mir::target::Endian;

fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
match self {
rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
}
}
}
7 changes: 7 additions & 0 deletions compiler/stable_mir/src/compiler_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 8,7 @@ use std::cell::Cell;
use crate::mir::alloc::{AllocId, GlobalAlloc};
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
use crate::mir::Body;
use crate::target::MachineInfo;
use crate::ty::{
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl,
Expand Down Expand Up @@ -150,13 151,19 @@ pub trait Context {
/// Evaluate a static's initializer.
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;

/// Try to evaluate an instance into a constant.
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error>;

/// Retrieve global allocation for the given allocation ID.
fn global_alloc(&self, id: AllocId) -> GlobalAlloc;

/// Retrieve the id for the virtual table.
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
fn krate(&self, def_id: DefId) -> Crate;
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;

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

// A thread local variable that stores a pointer to the tables mapping between TyCtxt
Expand Down
10 changes: 8 additions & 2 deletions compiler/stable_mir/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 6,11 @@

use std::convert::From;
use std::fmt::{Debug, Display, Formatter};
use std::{error, fmt};
use std::{error, fmt, io};

macro_rules! error {
($fmt: literal $(,)?) => { Error(format!($fmt)) };
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg:tt)*)) };
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
}

/// An error type used to represent an error that has already been reported by the compiler.
Expand Down Expand Up @@ -79,3 79,9 @@ where

impl error::Error for Error {}
impl<T> error::Error for CompilerError<T> where T: Display Debug {}

impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Error(value.to_string())
}
}
1 change: 1 addition & 0 deletions compiler/stable_mir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 39,7 @@ pub mod compiler_interface;
#[macro_use]
pub mod error;
pub mod mir;
pub mod target;
pub mod ty;
pub mod visitor;

Expand Down
36 changes: 34 additions & 2 deletions compiler/stable_mir/src/mir/alloc.rs
Original file line number Diff line number Diff line change
@@ -1,7 1,9 @@
//! This module provides methods to retrieve allocation information, such as static variables.
use crate::mir::mono::{Instance, StaticDef};
use crate::target::{Endian, MachineInfo};
use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
use crate::with;
use crate::{with, Error};
use std::io::Read;

/// An allocation in the SMIR global memory can be either a function pointer,
/// a static, or a "real" allocation with some data in it.
Expand Down Expand Up @@ -38,7 40,7 @@ impl GlobalAlloc {
}

/// A unique identification number for each provenance
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct AllocId(usize);

impl IndexedVal for AllocId {
Expand All @@ -49,3 51,33 @@ impl IndexedVal for AllocId {
self.0
}
}

/// Utility function used to read an allocation data into a unassigned integer.
pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> {
let mut buf = [0u8; std::mem::size_of::<u128>()];
match MachineInfo::target_endianess() {
Endian::Little => {
bytes.read(&mut buf)?;
Ok(u128::from_le_bytes(buf))
}
Endian::Big => {
bytes.read(&mut buf[16 - bytes.len()..])?;
Ok(u128::from_be_bytes(buf))
}
}
}

/// Utility function used to read an allocation data into an assigned integer.
pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result<i128, Error> {
let mut buf = [0u8; std::mem::size_of::<i128>()];
match MachineInfo::target_endianess() {
Endian::Little => {
bytes.read(&mut buf)?;
Ok(i128::from_le_bytes(buf))
}
Endian::Big => {
bytes.read(&mut buf[16 - bytes.len()..])?;
Ok(i128::from_be_bytes(buf))
}
}
}
22 changes: 20 additions & 2 deletions compiler/stable_mir/src/mir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 21,7 @@ pub struct Body {
pub(super) arg_count: usize,

/// Debug information pertaining to user variables, including captures.
pub(super) var_debug_info: Vec<VarDebugInfo>,
pub var_debug_info: Vec<VarDebugInfo>,
}

pub type BasicBlockIdx = usize;
Expand Down Expand Up @@ -616,6 616,24 @@ pub struct VarDebugInfo {
pub argument_index: Option<u16>,
}

impl VarDebugInfo {
/// Return a local variable if this info is related to one.
pub fn local(&self) -> Option<Local> {
match &self.value {
VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
}
}

/// Return a constant if this info is related to one.
pub fn constant(&self) -> Option<&ConstOperand> {
match &self.value {
VarDebugInfoContents::Place(_) => None,
VarDebugInfoContents::Const(const_op) => Some(const_op),
}
}
}

pub type SourceScope = u32;

#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -832,7 850,7 @@ pub enum MutBorrowKind {
ClosureCapture,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Mutability {
Not,
Mut,
Expand Down
10 changes: 9 additions & 1 deletion compiler/stable_mir/src/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 132,14 @@ impl Instance {
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 {
Expand Down Expand Up @@ -212,7 220,7 @@ impl TryFrom<CrateItem> for StaticDef {
type Error = crate::Error;

fn try_from(value: CrateItem) -> Result<Self, Self::Error> {
if matches!(value.kind(), ItemKind::Static | ItemKind::Const) {
if matches!(value.kind(), ItemKind::Static) {
Ok(StaticDef(value.0))
} else {
Err(Error::new(format!("Expected a static item, but found: {value:?}")))
Expand Down
Loading
Loading