Skip to content

Commit

Permalink
Unrolled build for rust-lang#118694
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#118694 - celinval:smir-alloc-methods, r=ouz-a

Add instance evaluation and methods to read an allocation in StableMIR

The instance evaluation is needed to handle intrinsics such as `type_id` and `type_name`.

Since we now use Allocation to represent all evaluated constants, provide a few methods to help process the data inside an allocation.

I've also started to add a structured way to get information about the compilation target machine. For now, I've only added information needed to process an allocation.

r? ``````@ouz-a``````
  • Loading branch information
rust-timer authored Dec 9, 2023
2 parents 2d2f1b2 + 9e15c49 commit 7d2fe7b
Show file tree
Hide file tree
Showing 15 changed files with 458 additions and 29 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4487,6 +4487,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 @@ -76,3 +77,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

0 comments on commit 7d2fe7b

Please sign in to comment.