Skip to content

Commit 1889e5a

Browse files
authoredDec 8, 2023
Rollup merge of #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``````
2 parents 9041d1c + 9e15c49 commit 1889e5a

File tree

15 files changed

+458
-29
lines changed

15 files changed

+458
-29
lines changed
 

‎Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -4494,6 +4494,7 @@ dependencies = [
44944494
name = "rustc_smir"
44954495
version = "0.0.0"
44964496
dependencies = [
4497+
"rustc_abi",
44974498
"rustc_data_structures",
44984499
"rustc_hir",
44994500
"rustc_middle",

‎compiler/rustc_smir/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
# tidy-alphabetical-start
8+
rustc_abi = { path = "../rustc_abi" }
89
rustc_data_structures = { path = "../rustc_data_structures" }
910
rustc_hir = { path = "../rustc_hir" }
1011
rustc_middle = { path = "../rustc_middle" }

‎compiler/rustc_smir/src/rustc_smir/alloc.rs

+26-11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc_middle::mir::{
22
interpret::{alloc_range, AllocRange, Pointer},
33
ConstValue,
44
};
5+
use stable_mir::Error;
56

67
use crate::rustc_smir::{Stable, Tables};
78
use stable_mir::mir::Mutability;
@@ -26,23 +27,35 @@ pub fn new_allocation<'tcx>(
2627
const_value: ConstValue<'tcx>,
2728
tables: &mut Tables<'tcx>,
2829
) -> Allocation {
29-
match const_value {
30+
try_new_allocation(ty, const_value, tables).unwrap()
31+
}
32+
33+
#[allow(rustc::usage_of_qualified_ty)]
34+
pub fn try_new_allocation<'tcx>(
35+
ty: rustc_middle::ty::Ty<'tcx>,
36+
const_value: ConstValue<'tcx>,
37+
tables: &mut Tables<'tcx>,
38+
) -> Result<Allocation, Error> {
39+
Ok(match const_value {
3040
ConstValue::Scalar(scalar) => {
3141
let size = scalar.size();
3242
let align = tables
3343
.tcx
3444
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
35-
.unwrap()
45+
.map_err(|e| e.stable(tables))?
3646
.align;
3747
let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
3848
allocation
3949
.write_scalar(&tables.tcx, alloc_range(rustc_target::abi::Size::ZERO, size), scalar)
40-
.unwrap();
50+
.map_err(|e| e.stable(tables))?;
4151
allocation.stable(tables)
4252
}
4353
ConstValue::ZeroSized => {
44-
let align =
45-
tables.tcx.layout_of(rustc_middle::ty::ParamEnv::empty().and(ty)).unwrap().align;
54+
let align = tables
55+
.tcx
56+
.layout_of(rustc_middle::ty::ParamEnv::empty().and(ty))
57+
.map_err(|e| e.stable(tables))?
58+
.align;
4659
new_empty_allocation(align.abi)
4760
}
4861
ConstValue::Slice { data, meta } => {
@@ -51,8 +64,10 @@ pub fn new_allocation<'tcx>(
5164
let scalar_ptr = rustc_middle::mir::interpret::Scalar::from_pointer(ptr, &tables.tcx);
5265
let scalar_meta =
5366
rustc_middle::mir::interpret::Scalar::from_target_usize(meta, &tables.tcx);
54-
let layout =
55-
tables.tcx.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty)).unwrap();
67+
let layout = tables
68+
.tcx
69+
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
70+
.map_err(|e| e.stable(tables))?;
5671
let mut allocation =
5772
rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
5873
allocation
@@ -61,26 +76,26 @@ pub fn new_allocation<'tcx>(
6176
alloc_range(rustc_target::abi::Size::ZERO, tables.tcx.data_layout.pointer_size),
6277
scalar_ptr,
6378
)
64-
.unwrap();
79+
.map_err(|e| e.stable(tables))?;
6580
allocation
6681
.write_scalar(
6782
&tables.tcx,
6883
alloc_range(tables.tcx.data_layout.pointer_size, scalar_meta.size()),
6984
scalar_meta,
7085
)
71-
.unwrap();
86+
.map_err(|e| e.stable(tables))?;
7287
allocation.stable(tables)
7388
}
7489
ConstValue::Indirect { alloc_id, offset } => {
7590
let alloc = tables.tcx.global_alloc(alloc_id).unwrap_memory();
7691
let ty_size = tables
7792
.tcx
7893
.layout_of(rustc_middle::ty::ParamEnv::reveal_all().and(ty))
79-
.unwrap()
94+
.map_err(|e| e.stable(tables))?
8095
.size;
8196
allocation_filter(&alloc.0, alloc_range(offset, ty_size), tables)
8297
}
83-
}
98+
})
8499
}
85100

86101
/// Creates an `Allocation` only from information within the `AllocRange`.

‎compiler/rustc_smir/src/rustc_smir/context.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,29 @@ use stable_mir::compiler_interface::Context;
1111
use stable_mir::mir::alloc::GlobalAlloc;
1212
use stable_mir::mir::mono::{InstanceDef, StaticDef};
1313
use stable_mir::mir::Body;
14+
use stable_mir::target::{MachineInfo, MachineSize};
1415
use stable_mir::ty::{
1516
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
16-
LineInfo, PolyFnSig, RigidTy, Span, TyKind, VariantDef,
17+
LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
1718
};
1819
use stable_mir::{self, Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
1920
use std::cell::RefCell;
2021

2122
use crate::rustc_internal::{internal, RustcInternal};
2223
use crate::rustc_smir::builder::BodyBuilder;
23-
use crate::rustc_smir::{new_item_kind, smir_crate, Stable, Tables};
24+
use crate::rustc_smir::{alloc, new_item_kind, smir_crate, Stable, Tables};
2425

2526
impl<'tcx> Context for TablesWrapper<'tcx> {
27+
fn target_info(&self) -> MachineInfo {
28+
let mut tables = self.0.borrow_mut();
29+
MachineInfo {
30+
endian: tables.tcx.data_layout.endian.stable(&mut *tables),
31+
pointer_width: MachineSize::from_bits(
32+
tables.tcx.data_layout.pointer_size.bits().try_into().unwrap(),
33+
),
34+
}
35+
}
36+
2637
fn entry_fn(&self) -> Option<stable_mir::CrateItem> {
2738
let mut tables = self.0.borrow_mut();
2839
let tcx = tables.tcx;
@@ -382,6 +393,21 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
382393
Instance::resolve_closure(tables.tcx, def_id, args_ref, closure_kind).stable(&mut *tables)
383394
}
384395

396+
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error> {
397+
let mut tables = self.0.borrow_mut();
398+
let instance = tables.instances[def];
399+
let result = tables.tcx.const_eval_instance(
400+
ParamEnv::reveal_all(),
401+
instance,
402+
Some(tables.tcx.def_span(instance.def_id())),
403+
);
404+
result
405+
.map(|const_val| {
406+
alloc::try_new_allocation(const_ty.internal(&mut *tables), const_val, &mut *tables)
407+
})
408+
.map_err(|e| e.stable(&mut *tables))?
409+
}
410+
385411
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error> {
386412
let mut tables = self.0.borrow_mut();
387413
let def_id = def.0.internal(&mut *tables);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//! Handle the conversion of different internal errors into a stable version.
2+
//!
3+
//! Currently we encode everything as [stable_mir::Error], which is represented as a string.
4+
use crate::rustc_smir::{Stable, Tables};
5+
use rustc_middle::mir::interpret::AllocError;
6+
use rustc_middle::ty::layout::LayoutError;
7+
8+
impl<'tcx> Stable<'tcx> for LayoutError<'tcx> {
9+
type T = stable_mir::Error;
10+
11+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
12+
stable_mir::Error::new(format!("{self:?}"))
13+
}
14+
}
15+
16+
impl<'tcx> Stable<'tcx> for AllocError {
17+
type T = stable_mir::Error;
18+
19+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
20+
stable_mir::Error::new(format!("{self:?}"))
21+
}
22+
}

‎compiler/rustc_smir/src/rustc_smir/convert/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use stable_mir::ty::{IndexedVal, VariantIdx};
55

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

8+
mod error;
89
mod mir;
910
mod ty;
1011

@@ -76,3 +77,14 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
7677
tables.create_span(*self)
7778
}
7879
}
80+
81+
impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
82+
type T = stable_mir::target::Endian;
83+
84+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
85+
match self {
86+
rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
87+
rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
88+
}
89+
}
90+
}

‎compiler/stable_mir/src/compiler_interface.rs

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::cell::Cell;
88
use crate::mir::alloc::{AllocId, GlobalAlloc};
99
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
1010
use crate::mir::Body;
11+
use crate::target::MachineInfo;
1112
use crate::ty::{
1213
AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
1314
GenericPredicates, Generics, ImplDef, ImplTrait, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl,
@@ -150,13 +151,19 @@ pub trait Context {
150151
/// Evaluate a static's initializer.
151152
fn eval_static_initializer(&self, def: StaticDef) -> Result<Allocation, Error>;
152153

154+
/// Try to evaluate an instance into a constant.
155+
fn eval_instance(&self, def: InstanceDef, const_ty: Ty) -> Result<Allocation, Error>;
156+
153157
/// Retrieve global allocation for the given allocation ID.
154158
fn global_alloc(&self, id: AllocId) -> GlobalAlloc;
155159

156160
/// Retrieve the id for the virtual table.
157161
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
158162
fn krate(&self, def_id: DefId) -> Crate;
159163
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
164+
165+
/// Return information about the target machine.
166+
fn target_info(&self) -> MachineInfo;
160167
}
161168

162169
// A thread local variable that stores a pointer to the tables mapping between TyCtxt

‎compiler/stable_mir/src/error.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
77
use std::convert::From;
88
use std::fmt::{Debug, Display, Formatter};
9-
use std::{error, fmt};
9+
use std::{error, fmt, io};
1010

1111
macro_rules! error {
1212
($fmt: literal $(,)?) => { Error(format!($fmt)) };
13-
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg:tt)*)) };
13+
($fmt: literal, $($arg:tt)*) => { Error(format!($fmt, $($arg)*)) };
1414
}
1515

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

8080
impl error::Error for Error {}
8181
impl<T> error::Error for CompilerError<T> where T: Display + Debug {}
82+
83+
impl From<io::Error> for Error {
84+
fn from(value: io::Error) -> Self {
85+
Error(value.to_string())
86+
}
87+
}

‎compiler/stable_mir/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub mod compiler_interface;
3939
#[macro_use]
4040
pub mod error;
4141
pub mod mir;
42+
pub mod target;
4243
pub mod ty;
4344
pub mod visitor;
4445

‎compiler/stable_mir/src/mir/alloc.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
//! This module provides methods to retrieve allocation information, such as static variables.
22
use crate::mir::mono::{Instance, StaticDef};
3+
use crate::target::{Endian, MachineInfo};
34
use crate::ty::{Allocation, Binder, ExistentialTraitRef, IndexedVal, Ty};
4-
use crate::with;
5+
use crate::{with, Error};
6+
use std::io::Read;
57

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

4042
/// A unique identification number for each provenance
41-
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
43+
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
4244
pub struct AllocId(usize);
4345

4446
impl IndexedVal for AllocId {
@@ -49,3 +51,33 @@ impl IndexedVal for AllocId {
4951
self.0
5052
}
5153
}
54+
55+
/// Utility function used to read an allocation data into a unassigned integer.
56+
pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result<u128, Error> {
57+
let mut buf = [0u8; std::mem::size_of::<u128>()];
58+
match MachineInfo::target_endianess() {
59+
Endian::Little => {
60+
bytes.read(&mut buf)?;
61+
Ok(u128::from_le_bytes(buf))
62+
}
63+
Endian::Big => {
64+
bytes.read(&mut buf[16 - bytes.len()..])?;
65+
Ok(u128::from_be_bytes(buf))
66+
}
67+
}
68+
}
69+
70+
/// Utility function used to read an allocation data into an assigned integer.
71+
pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result<i128, Error> {
72+
let mut buf = [0u8; std::mem::size_of::<i128>()];
73+
match MachineInfo::target_endianess() {
74+
Endian::Little => {
75+
bytes.read(&mut buf)?;
76+
Ok(i128::from_le_bytes(buf))
77+
}
78+
Endian::Big => {
79+
bytes.read(&mut buf[16 - bytes.len()..])?;
80+
Ok(i128::from_be_bytes(buf))
81+
}
82+
}
83+
}

‎compiler/stable_mir/src/mir/body.rs

+20-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub struct Body {
2121
pub(super) arg_count: usize,
2222

2323
/// Debug information pertaining to user variables, including captures.
24-
pub(super) var_debug_info: Vec<VarDebugInfo>,
24+
pub var_debug_info: Vec<VarDebugInfo>,
2525
}
2626

2727
pub type BasicBlockIdx = usize;
@@ -616,6 +616,24 @@ pub struct VarDebugInfo {
616616
pub argument_index: Option<u16>,
617617
}
618618

619+
impl VarDebugInfo {
620+
/// Return a local variable if this info is related to one.
621+
pub fn local(&self) -> Option<Local> {
622+
match &self.value {
623+
VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
624+
VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
625+
}
626+
}
627+
628+
/// Return a constant if this info is related to one.
629+
pub fn constant(&self) -> Option<&ConstOperand> {
630+
match &self.value {
631+
VarDebugInfoContents::Place(_) => None,
632+
VarDebugInfoContents::Const(const_op) => Some(const_op),
633+
}
634+
}
635+
}
636+
619637
pub type SourceScope = u32;
620638

621639
#[derive(Clone, Debug, Eq, PartialEq)]
@@ -832,7 +850,7 @@ pub enum MutBorrowKind {
832850
ClosureCapture,
833851
}
834852

835-
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
853+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
836854
pub enum Mutability {
837855
Not,
838856
Mut,

‎compiler/stable_mir/src/mir/mono.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,14 @@ impl Instance {
132132
pub fn is_empty_shim(&self) -> bool {
133133
self.kind == InstanceKind::Shim && with(|cx| cx.is_empty_drop_shim(self.def))
134134
}
135+
136+
/// Try to constant evaluate the instance into a constant with the given type.
137+
///
138+
/// This can be used to retrieve a constant that represents an intrinsic return such as
139+
/// `type_id`.
140+
pub fn try_const_eval(&self, const_ty: Ty) -> Result<Allocation, Error> {
141+
with(|cx| cx.eval_instance(self.def, const_ty))
142+
}
135143
}
136144

137145
impl Debug for Instance {
@@ -212,7 +220,7 @@ impl TryFrom<CrateItem> for StaticDef {
212220
type Error = crate::Error;
213221

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

0 commit comments

Comments
 (0)
Please sign in to comment.