Skip to content

Commit 97e609c

Browse files
committed
Implement a few more rvalue translation to smir
- Introduce an Opaque type for adding information that is still internal to the compiler.
1 parent e4b4f05 commit 97e609c

File tree

4 files changed

+305
-9
lines changed

4 files changed

+305
-9
lines changed

compiler/rustc_smir/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![cfg_attr(not(feature = "default"), feature(rustc_private))]
1414
#![feature(local_key_cell_methods)]
1515
#![feature(ptr_metadata)]
16+
#![feature(type_alias_impl_trait)] // Used to define opaque types.
1617

1718
// Declare extern rustc_* crates to enable building this crate separately from the compiler.
1819
#[cfg(not(feature = "default"))]

compiler/rustc_smir/src/rustc_internal/mod.rs

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
44
//! until stable MIR is complete.
55
6+
use std::fmt::Debug;
7+
use std::string::ToString;
8+
69
use crate::{
710
rustc_smir::Tables,
811
stable_mir::{self, with},
@@ -49,3 +52,10 @@ pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
4952
pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
5053
crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f);
5154
}
55+
56+
/// A type that provides internal information but that can still be used for debug purpose.
57+
pub type Opaque = impl Debug + ToString + Clone;
58+
59+
pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque {
60+
format!("{value:?}")
61+
}

compiler/rustc_smir/src/rustc_smir/mod.rs

+116-7
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
//!
88
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
99
10+
use crate::rustc_internal::{self, opaque};
1011
use crate::stable_mir::{self, ty::TyKind, Context};
1112
use rustc_middle::mir;
1213
use rustc_middle::ty::{self, Ty, TyCtxt};
1314
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
15+
use rustc_target::abi::FieldIdx;
1416
use tracing::debug;
1517

1618
impl<'tcx> Context for Tables<'tcx> {
@@ -127,6 +129,13 @@ pub(crate) trait Stable {
127129
fn stable(&self) -> Self::T;
128130
}
129131

132+
impl Stable for DefId {
133+
type T = stable_mir::CrateItem;
134+
fn stable(&self) -> Self::T {
135+
rustc_internal::crate_item(*self)
136+
}
137+
}
138+
130139
impl<'tcx> Stable for mir::Statement<'tcx> {
131140
type T = stable_mir::mir::Statement;
132141
fn stable(&self) -> Self::T {
@@ -158,27 +167,127 @@ impl<'tcx> Stable for mir::Rvalue<'tcx> {
158167
match self {
159168
Use(op) => stable_mir::mir::Rvalue::Use(op.stable()),
160169
Repeat(_, _) => todo!(),
161-
Ref(_, _, _) => todo!(),
162-
ThreadLocalRef(_) => todo!(),
163-
AddressOf(_, _) => todo!(),
164-
Len(_) => todo!(),
170+
Ref(region, kind, place) => {
171+
stable_mir::mir::Rvalue::Ref(opaque(region), kind.stable(), place.stable())
172+
}
173+
ThreadLocalRef(def_id) => stable_mir::mir::Rvalue::ThreadLocalRef(def_id.stable()),
174+
AddressOf(mutability, place) => {
175+
stable_mir::mir::Rvalue::AddressOf(mutability.stable(), place.stable())
176+
}
177+
Len(place) => stable_mir::mir::Rvalue::Len(place.stable()),
165178
Cast(_, _, _) => todo!(),
166-
BinaryOp(_, _) => todo!(),
179+
BinaryOp(bin_op, ops) => {
180+
stable_mir::mir::Rvalue::BinaryOp(bin_op.stable(), ops.0.stable(), ops.1.stable())
181+
}
167182
CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
168183
bin_op.stable(),
169184
ops.0.stable(),
170185
ops.1.stable(),
171186
),
172187
NullaryOp(_, _) => todo!(),
173188
UnaryOp(un_op, op) => stable_mir::mir::Rvalue::UnaryOp(un_op.stable(), op.stable()),
174-
Discriminant(_) => todo!(),
189+
Discriminant(place) => stable_mir::mir::Rvalue::Discriminant(place.stable()),
175190
Aggregate(_, _) => todo!(),
176191
ShallowInitBox(_, _) => todo!(),
177-
CopyForDeref(_) => todo!(),
192+
CopyForDeref(place) => stable_mir::mir::Rvalue::CopyForDeref(place.stable()),
193+
}
194+
}
195+
}
196+
197+
impl Stable for mir::Mutability {
198+
type T = stable_mir::mir::Mutability;
199+
fn stable(&self) -> Self::T {
200+
use mir::Mutability::*;
201+
match *self {
202+
Not => stable_mir::mir::Mutability::Not,
203+
Mut => stable_mir::mir::Mutability::Mut,
204+
}
205+
}
206+
}
207+
208+
impl Stable for mir::BorrowKind {
209+
type T = stable_mir::mir::BorrowKind;
210+
fn stable(&self) -> Self::T {
211+
use mir::BorrowKind::*;
212+
match *self {
213+
Shared => stable_mir::mir::BorrowKind::Shared,
214+
Shallow => stable_mir::mir::BorrowKind::Shallow,
215+
Unique => stable_mir::mir::BorrowKind::Unique,
216+
Mut { allow_two_phase_borrow } => {
217+
stable_mir::mir::BorrowKind::Mut { allow_two_phase_borrow }
218+
}
219+
}
220+
}
221+
}
222+
223+
impl<'tcx> Stable for mir::NullOp<'tcx> {
224+
type T = stable_mir::mir::NullOp;
225+
fn stable(&self) -> Self::T {
226+
use mir::NullOp::*;
227+
match self {
228+
SizeOf => stable_mir::mir::NullOp::SizeOf,
229+
AlignOf => stable_mir::mir::NullOp::AlignOf,
230+
OffsetOf(indices) => {
231+
stable_mir::mir::NullOp::OffsetOf(indices.iter().map(|idx| idx.stable()).collect())
232+
}
233+
}
234+
}
235+
}
236+
237+
impl Stable for mir::CastKind {
238+
type T = stable_mir::mir::CastKind;
239+
fn stable(&self) -> Self::T {
240+
use mir::CastKind::*;
241+
match self {
242+
PointerExposeAddress => stable_mir::mir::CastKind::PointerExposeAddress,
243+
PointerFromExposedAddress => stable_mir::mir::CastKind::PointerFromExposedAddress,
244+
Pointer(cast) => stable_mir::mir::CastKind::Pointer(cast.stable()),
245+
DynStar => stable_mir::mir::CastKind::DynStar,
246+
IntToInt => stable_mir::mir::CastKind::IntToInt,
247+
FloatToInt => stable_mir::mir::CastKind::FloatToInt,
248+
FloatToFloat => stable_mir::mir::CastKind::FloatToFloat,
249+
IntToFloat => stable_mir::mir::CastKind::IntToFloat,
250+
PtrToPtr => stable_mir::mir::CastKind::PtrToPtr,
251+
FnPtrToPtr => stable_mir::mir::CastKind::FnPtrToPtr,
252+
Transmute => stable_mir::mir::CastKind::Transmute,
253+
}
254+
}
255+
}
256+
257+
impl Stable for ty::adjustment::PointerCast {
258+
type T = stable_mir::mir::PointerCast;
259+
fn stable(&self) -> Self::T {
260+
use ty::adjustment::PointerCast;
261+
match self {
262+
PointerCast::ReifyFnPointer => stable_mir::mir::PointerCast::ReifyFnPointer,
263+
PointerCast::UnsafeFnPointer => stable_mir::mir::PointerCast::UnsafeFnPointer,
264+
PointerCast::ClosureFnPointer(unsafety) => {
265+
stable_mir::mir::PointerCast::ClosureFnPointer(unsafety.stable())
266+
}
267+
PointerCast::MutToConstPointer => stable_mir::mir::PointerCast::MutToConstPointer,
268+
PointerCast::ArrayToPointer => stable_mir::mir::PointerCast::ArrayToPointer,
269+
PointerCast::Unsize => stable_mir::mir::PointerCast::Unsize,
270+
}
271+
}
272+
}
273+
274+
impl Stable for rustc_hir::Unsafety {
275+
type T = stable_mir::mir::Safety;
276+
fn stable(&self) -> Self::T {
277+
match self {
278+
rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe,
279+
rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal,
178280
}
179281
}
180282
}
181283

284+
impl Stable for FieldIdx {
285+
type T = usize;
286+
fn stable(&self) -> Self::T {
287+
self.as_usize()
288+
}
289+
}
290+
182291
impl<'tcx> Stable for mir::Operand<'tcx> {
183292
type T = stable_mir::mir::Operand;
184293
fn stable(&self) -> Self::T {

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

+178-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::stable_mir::ty::Ty;
1+
use crate::rustc_internal::Opaque;
2+
use crate::stable_mir::{self, ty::Ty};
23

34
#[derive(Clone, Debug)]
45
pub struct Body {
@@ -131,12 +132,98 @@ pub enum Statement {
131132
Nop,
132133
}
133134

135+
type Region = Opaque;
136+
134137
// FIXME this is incomplete
135138
#[derive(Clone, Debug)]
136139
pub enum Rvalue {
137-
Use(Operand),
140+
/// Creates a pointer with the indicated mutability to the place.
141+
///
142+
/// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
143+
/// `&raw v` or `addr_of!(v)`.
144+
AddressOf(Mutability, Place),
145+
146+
/// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second
147+
/// parameter may be a `usize` as well.
148+
/// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
149+
/// raw pointers, or function pointers and return a `bool`. The types of the operands must be
150+
/// matching, up to the usual caveat of the lifetimes in function pointers.
151+
/// * Left and right shift operations accept signed or unsigned integers not necessarily of the
152+
/// same type and return a value of the same type as their LHS. Like in Rust, the RHS is
153+
/// truncated as needed.
154+
/// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
155+
/// types and return a value of that type.
156+
/// * The remaining operations accept signed integers, unsigned integers, or floats with
157+
/// matching types and return a value of that type.
158+
BinaryOp(BinOp, Operand, Operand),
159+
160+
/// Performs essentially all of the casts that can be performed via `as`.
161+
///
162+
/// This allows for casts from/to a variety of types.
163+
Cast(CastKind, Operand, Ty),
164+
165+
/// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
166+
///
167+
/// For addition, subtraction, and multiplication on integers the error condition is set when
168+
/// the infinite precision result would not be equal to the actual result.
138169
CheckedBinaryOp(BinOp, Operand, Operand),
170+
171+
/// A CopyForDeref is equivalent to a read from a place.
172+
/// When such a read happens, it is guaranteed that the only use of the returned value is a
173+
/// deref operation, immediately followed by one or more projections.
174+
CopyForDeref(Place),
175+
176+
/// Computes the discriminant of the place, returning it as an integer of type
177+
/// [`discriminant_ty`]. Returns zero for types without discriminant.
178+
///
179+
/// The validity requirements for the underlying value are undecided for this rvalue, see
180+
/// [#91095]. Note too that the value of the discriminant is not the same thing as the
181+
/// variant index; use [`discriminant_for_variant`] to convert.
182+
///
183+
/// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
184+
/// [#91095]: https://github.com/rust-lang/rust/issues/91095
185+
/// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
186+
Discriminant(Place),
187+
188+
/// Yields the length of the place, as a `usize`.
189+
///
190+
/// If the type of the place is an array, this is the array length. For slices (`[T]`, not
191+
/// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
192+
/// ill-formed for places of other types.
193+
Len(Place),
194+
195+
/// Creates a reference to the place.
196+
Ref(Region, BorrowKind, Place),
197+
198+
/// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
199+
///
200+
/// This is different from a normal transmute because dataflow analysis will treat the box as
201+
/// initialized but its content as uninitialized. Like other pointer casts, this in general
202+
/// affects alias analysis.
203+
ShallowInitBox(Operand, Ty),
204+
205+
/// Creates a pointer/reference to the given thread local.
206+
///
207+
/// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
208+
/// `*const T`, and if neither of those apply a `&T`.
209+
///
210+
/// **Note:** This is a runtime operation that actually executes code and is in this sense more
211+
/// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
212+
/// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
213+
///
214+
/// **Needs clarification**: Are there weird additional semantics here related to the runtime
215+
/// nature of this operation?
216+
ThreadLocalRef(stable_mir::CrateItem),
217+
218+
/// Exactly like `BinaryOp`, but less operands.
219+
///
220+
/// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
221+
/// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
222+
/// return a value with the same type as their operand.
139223
UnaryOp(UnOp, Operand),
224+
225+
/// Yields the operand unchanged
226+
Use(Operand),
140227
}
141228

142229
#[derive(Clone, Debug)]
@@ -152,8 +239,97 @@ pub struct Place {
152239
pub projection: String,
153240
}
154241

242+
type FieldIdx = usize;
243+
155244
#[derive(Clone, Debug)]
156245
pub struct SwitchTarget {
157246
pub value: u128,
158247
pub target: usize,
159248
}
249+
250+
#[derive(Clone, Debug)]
251+
pub enum BorrowKind {
252+
/// Data must be immutable and is aliasable.
253+
Shared,
254+
255+
/// The immediately borrowed place must be immutable, but projections from
256+
/// it don't need to be. For example, a shallow borrow of `a.b` doesn't
257+
/// conflict with a mutable borrow of `a.b.c`.
258+
Shallow,
259+
260+
/// Data must be immutable but not aliasable. This kind of borrow
261+
/// cannot currently be expressed by the user and is used only in
262+
/// implicit closure bindings. It is needed when the closure is
263+
/// borrowing or mutating a mutable referent.
264+
Unique,
265+
266+
/// Data is mutable and not aliasable.
267+
Mut {
268+
/// `true` if this borrow arose from method-call auto-ref
269+
allow_two_phase_borrow: bool,
270+
},
271+
}
272+
273+
#[derive(Clone, Debug)]
274+
pub enum Mutability {
275+
Not,
276+
Mut,
277+
}
278+
279+
#[derive(Clone, Debug)]
280+
pub enum Safety {
281+
Unsafe,
282+
Normal,
283+
}
284+
285+
#[derive(Clone, Debug)]
286+
pub enum PointerCast {
287+
/// Go from a fn-item type to a fn-pointer type.
288+
ReifyFnPointer,
289+
290+
/// Go from a safe fn pointer to an unsafe fn pointer.
291+
UnsafeFnPointer,
292+
293+
/// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
294+
/// It cannot convert a closure that requires unsafe.
295+
ClosureFnPointer(Safety),
296+
297+
/// Go from a mut raw pointer to a const raw pointer.
298+
MutToConstPointer,
299+
300+
/// Go from `*const [T; N]` to `*const T`
301+
ArrayToPointer,
302+
303+
/// Unsize a pointer/reference value, e.g., `&[T; n]` to
304+
/// `&[T]`. Note that the source could be a thin or fat pointer.
305+
/// This will do things like convert thin pointers to fat
306+
/// pointers, or convert structs containing thin pointers to
307+
/// structs containing fat pointers, or convert between fat
308+
/// pointers.
309+
Unsize,
310+
}
311+
312+
#[derive(Clone, Debug)]
313+
pub enum CastKind {
314+
PointerExposeAddress,
315+
PointerFromExposedAddress,
316+
Pointer(PointerCast),
317+
DynStar,
318+
IntToInt,
319+
FloatToInt,
320+
FloatToFloat,
321+
IntToFloat,
322+
PtrToPtr,
323+
FnPtrToPtr,
324+
Transmute,
325+
}
326+
327+
#[derive(Clone, Debug)]
328+
pub enum NullOp {
329+
/// Returns the size of a value of that type.
330+
SizeOf,
331+
/// Returns the minimum alignment of a type.
332+
AlignOf,
333+
/// Returns the offset of a field.
334+
OffsetOf(Vec<FieldIdx>),
335+
}

0 commit comments

Comments
 (0)