Skip to content

Commit ad2de8b

Browse files
committed
miri/CTFE refactor
* Value gets renamed to Operand, so that now interpret::{Place, Operand} are the "dynamic" versions of mir::{Place, Operand}. * Operand and Place share the data for their "stuff is in memory"-base in a new type, MemPlace. This also makes it possible to give some more precise types in other areas. Both Operand and MemPlace have methods available to project into fields (and other kinds of projections) without causing further allocations. * The type for "a Scalar or a ScalarPair" is called Value, and again used to give some more precise types. * All of these have versions with an attached layout, so that we can more often drag the layout along instead of recomputing it. This lets us get rid of `PlaceExtra::Downcast`. MPlaceTy and PlaceTy can only be constructed in place.rs, making sure the layout is handled properly. (The same should eventually be done for ValTy and OpTy.) * All the high-level functions to write typed memory take a Place, and live in place.rs. All the high-level typed functions to read typed memory take an Operand, and live in operands.rs.
1 parent 7d4f5f7 commit ad2de8b

File tree

31 files changed

+1997
-1935
lines changed

31 files changed

+1997
-1935
lines changed

src/librustc/dep_graph/dep_node.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ define_dep_nodes!( <'tcx>
632632
// queries). Making them anonymous avoids hashing the result, which
633633
// may save a bit of time.
634634
[anon] EraseRegionsTy { ty: Ty<'tcx> },
635-
[anon] ConstValueToAllocation { val: &'tcx ty::Const<'tcx> },
635+
[anon] ConstToAllocation { val: &'tcx ty::Const<'tcx> },
636636

637637
[input] Freevars(DefId),
638638
[input] MaybeUnusedTraitImport(DefId),

src/librustc/ich/impls_ty.rs

-6
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,6 @@ impl_stable_hash_for!(enum mir::interpret::ScalarMaybeUndef {
397397
Undef
398398
});
399399

400-
impl_stable_hash_for!(enum mir::interpret::Value {
401-
Scalar(v),
402-
ScalarPair(a, b),
403-
ByRef(ptr, align)
404-
});
405-
406400
impl_stable_hash_for!(struct mir::interpret::Pointer {
407401
alloc_id,
408402
offset

src/librustc/mir/interpret/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub use self::error::{
1313
FrameInfo, ConstEvalResult,
1414
};
1515

16-
pub use self::value::{Scalar, Value, ConstValue, ScalarMaybeUndef};
16+
pub use self::value::{Scalar, ConstValue, ScalarMaybeUndef};
1717

1818
use std::fmt;
1919
use mir;
@@ -135,7 +135,7 @@ impl<'tcx> Pointer {
135135
Pointer { alloc_id, offset }
136136
}
137137

138-
pub(crate) fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
138+
pub fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
139139
Pointer::new(
140140
self.alloc_id,
141141
Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
@@ -147,7 +147,7 @@ impl<'tcx> Pointer {
147147
(Pointer::new(self.alloc_id, Size::from_bytes(res)), over)
148148
}
149149

150-
pub(crate) fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
150+
pub fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
151151
Ok(Pointer::new(
152152
self.alloc_id,
153153
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),

src/librustc/mir/interpret/value.rs

+77-123
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
#![allow(unknown_lints)]
22

3-
use ty::layout::{Align, HasDataLayout, Size};
4-
use ty;
3+
use ty::layout::{HasDataLayout, Size};
54
use ty::subst::Substs;
65
use hir::def_id::DefId;
76

87
use super::{EvalResult, Pointer, PointerArithmetic, Allocation};
98

109
/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
11-
/// matches Value's optimizations for easy conversions between these two types
10+
/// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
1211
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
1312
pub enum ConstValue<'tcx> {
1413
/// Never returned from the `const_eval` query, but the HIR contains these frequently in order
1514
/// to allow HIR creation to happen for everything before needing to be able to run constant
1615
/// evaluation
1716
Unevaluated(DefId, &'tcx Substs<'tcx>),
1817
/// Used only for types with layout::abi::Scalar ABI and ZSTs
18+
///
19+
/// Not using the enum `Value` to encode that this must not be `Undef`
1920
Scalar(Scalar),
2021
/// Used only for types with layout::abi::ScalarPair
2122
///
@@ -26,25 +27,6 @@ pub enum ConstValue<'tcx> {
2627
}
2728

2829
impl<'tcx> ConstValue<'tcx> {
29-
#[inline]
30-
pub fn from_byval_value(val: Value) -> EvalResult<'static, Self> {
31-
Ok(match val {
32-
Value::ByRef(..) => bug!(),
33-
Value::ScalarPair(a, b) => ConstValue::ScalarPair(a.unwrap_or_err()?, b),
34-
Value::Scalar(val) => ConstValue::Scalar(val.unwrap_or_err()?),
35-
})
36-
}
37-
38-
#[inline]
39-
pub fn to_byval_value(&self) -> Option<Value> {
40-
match *self {
41-
ConstValue::Unevaluated(..) |
42-
ConstValue::ByRef(..) => None,
43-
ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a.into(), b)),
44-
ConstValue::Scalar(val) => Some(Value::Scalar(val.into())),
45-
}
46-
}
47-
4830
#[inline]
4931
pub fn try_to_scalar(&self) -> Option<Scalar> {
5032
match *self {
@@ -56,58 +38,44 @@ impl<'tcx> ConstValue<'tcx> {
5638
}
5739

5840
#[inline]
59-
pub fn to_bits(&self, size: Size) -> Option<u128> {
41+
pub fn try_to_bits(&self, size: Size) -> Option<u128> {
6042
self.try_to_scalar()?.to_bits(size).ok()
6143
}
6244

6345
#[inline]
64-
pub fn to_ptr(&self) -> Option<Pointer> {
46+
pub fn try_to_ptr(&self) -> Option<Pointer> {
6547
self.try_to_scalar()?.to_ptr().ok()
6648
}
67-
}
68-
69-
/// A `Value` represents a single self-contained Rust value.
70-
///
71-
/// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitive
72-
/// value held directly, outside of any allocation (`Scalar`). For `ByRef`-values, we remember
73-
/// whether the pointer is supposed to be aligned or not (also see Place).
74-
///
75-
/// For optimization of a few very common cases, there is also a representation for a pair of
76-
/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary
77-
/// operations and fat pointers. This idea was taken from rustc's codegen.
78-
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
79-
pub enum Value {
80-
ByRef(Scalar, Align),
81-
Scalar(ScalarMaybeUndef),
82-
ScalarPair(ScalarMaybeUndef, ScalarMaybeUndef),
83-
}
8449

85-
impl<'tcx> ty::TypeFoldable<'tcx> for Value {
86-
fn super_fold_with<'gcx: 'tcx, F: ty::fold::TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> Self {
87-
*self
50+
pub fn new_slice(
51+
val: Scalar,
52+
len: u64,
53+
cx: impl HasDataLayout
54+
) -> Self {
55+
ConstValue::ScalarPair(val, Scalar::Bits {
56+
bits: len as u128,
57+
size: cx.data_layout().pointer_size.bytes() as u8,
58+
}.into())
8859
}
89-
fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
90-
false
60+
61+
pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
62+
ConstValue::ScalarPair(val, Scalar::Ptr(vtable).into())
9163
}
9264
}
9365

9466
impl<'tcx> Scalar {
95-
pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
67+
pub fn ptr_null(cx: impl HasDataLayout) -> Self {
9668
Scalar::Bits {
9769
bits: 0,
9870
size: cx.data_layout().pointer_size.bytes() as u8,
9971
}
10072
}
10173

102-
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
103-
ScalarMaybeUndef::Scalar(self).to_value_with_len(len, cx)
104-
}
105-
106-
pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
107-
ScalarMaybeUndef::Scalar(self).to_value_with_vtable(vtable)
74+
pub fn zst() -> Self {
75+
Scalar::Bits { bits: 0, size: 0 }
10876
}
10977

110-
pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
78+
pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
11179
let layout = cx.data_layout();
11280
match self {
11381
Scalar::Bits { bits, size } => {
@@ -121,7 +89,7 @@ impl<'tcx> Scalar {
12189
}
12290
}
12391

124-
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
92+
pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
12593
let layout = cx.data_layout();
12694
match self {
12795
Scalar::Bits { bits, size } => {
@@ -135,7 +103,7 @@ impl<'tcx> Scalar {
135103
}
136104
}
137105

138-
pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
106+
pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
139107
let layout = cx.data_layout();
140108
match self {
141109
Scalar::Bits { bits, size } => {
@@ -149,7 +117,7 @@ impl<'tcx> Scalar {
149117
}
150118
}
151119

152-
pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> bool {
120+
pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
153121
match self {
154122
Scalar::Bits { bits, size } => {
155123
assert_eq!(size as u64, cx.data_layout().pointer_size.bytes());
@@ -159,8 +127,52 @@ impl<'tcx> Scalar {
159127
}
160128
}
161129

162-
pub fn to_value(self) -> Value {
163-
Value::Scalar(ScalarMaybeUndef::Scalar(self))
130+
pub fn from_bool(b: bool) -> Self {
131+
Scalar::Bits { bits: b as u128, size: 1 }
132+
}
133+
134+
pub fn from_char(c: char) -> Self {
135+
Scalar::Bits { bits: c as u128, size: 4 }
136+
}
137+
138+
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
139+
match self {
140+
Scalar::Bits { bits, size } => {
141+
assert_eq!(target_size.bytes(), size as u64);
142+
assert_ne!(size, 0, "to_bits cannot be used with zsts");
143+
Ok(bits)
144+
}
145+
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
146+
}
147+
}
148+
149+
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
150+
match self {
151+
Scalar::Bits {..} => err!(ReadBytesAsPointer),
152+
Scalar::Ptr(p) => Ok(p),
153+
}
154+
}
155+
156+
pub fn is_bits(self) -> bool {
157+
match self {
158+
Scalar::Bits { .. } => true,
159+
_ => false,
160+
}
161+
}
162+
163+
pub fn is_ptr(self) -> bool {
164+
match self {
165+
Scalar::Ptr(_) => true,
166+
_ => false,
167+
}
168+
}
169+
170+
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
171+
match self {
172+
Scalar::Bits { bits: 0, size: 1 } => Ok(false),
173+
Scalar::Bits { bits: 1, size: 1 } => Ok(true),
174+
_ => err!(InvalidBool),
175+
}
164176
}
165177
}
166178

@@ -202,81 +214,23 @@ impl From<Scalar> for ScalarMaybeUndef {
202214
}
203215
}
204216

205-
impl ScalarMaybeUndef {
206-
pub fn unwrap_or_err(self) -> EvalResult<'static, Scalar> {
217+
impl<'tcx> ScalarMaybeUndef {
218+
pub fn not_undef(self) -> EvalResult<'static, Scalar> {
207219
match self {
208220
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
209221
ScalarMaybeUndef::Undef => err!(ReadUndefBytes),
210222
}
211223
}
212224

213-
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
214-
Value::ScalarPair(self, Scalar::Bits {
215-
bits: len as u128,
216-
size: cx.data_layout().pointer_size.bytes() as u8,
217-
}.into())
218-
}
219-
220-
pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
221-
Value::ScalarPair(self, Scalar::Ptr(vtable).into())
222-
}
223-
224-
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
225-
match self {
226-
ScalarMaybeUndef::Scalar(scalar) => {
227-
scalar.ptr_offset(i, cx).map(ScalarMaybeUndef::Scalar)
228-
},
229-
ScalarMaybeUndef::Undef => Ok(ScalarMaybeUndef::Undef)
230-
}
231-
}
232-
}
233-
234-
impl<'tcx> Scalar {
235-
pub fn from_bool(b: bool) -> Self {
236-
Scalar::Bits { bits: b as u128, size: 1 }
237-
}
238-
239-
pub fn from_char(c: char) -> Self {
240-
Scalar::Bits { bits: c as u128, size: 4 }
241-
}
242-
243-
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
244-
match self {
245-
Scalar::Bits { bits, size } => {
246-
assert_eq!(target_size.bytes(), size as u64);
247-
assert_ne!(size, 0, "to_bits cannot be used with zsts");
248-
Ok(bits)
249-
}
250-
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
251-
}
252-
}
253-
254225
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
255-
match self {
256-
Scalar::Bits {..} => err!(ReadBytesAsPointer),
257-
Scalar::Ptr(p) => Ok(p),
258-
}
259-
}
260-
261-
pub fn is_bits(self) -> bool {
262-
match self {
263-
Scalar::Bits { .. } => true,
264-
_ => false,
265-
}
226+
self.not_undef()?.to_ptr()
266227
}
267228

268-
pub fn is_ptr(self) -> bool {
269-
match self {
270-
Scalar::Ptr(_) => true,
271-
_ => false,
272-
}
229+
pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
230+
self.not_undef()?.to_bits(target_size)
273231
}
274232

275233
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
276-
match self {
277-
Scalar::Bits { bits: 0, size: 1 } => Ok(false),
278-
Scalar::Bits { bits: 1, size: 1 } => Ok(true),
279-
_ => err!(InvalidBool),
280-
}
234+
self.not_undef()?.to_bool()
281235
}
282236
}

0 commit comments

Comments
 (0)