ConstValue, Pointer, Scalar,
EvalResult, EvalErrorKind,
};
-use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
+use super::{
+ EvalContext, Machine,
+ MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind,
+};
pub use rustc::mir::interpret::ScalarMaybeUndef;
/// A `Value` represents a single immediate self-contained Rust value.
}
impl<'tcx, Tag> Immediate<Tag> {
+ #[inline]
+ pub fn from_scalar(val: Scalar<Tag>) -> Self {
+ Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
+ }
+
#[inline]
pub fn erase_tag(self) -> Immediate
{
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
pub struct ImmTy<'tcx, Tag=()> {
- immediate: Immediate<Tag>,
+ pub imm: Immediate<Tag>,
pub layout: TyLayout<'tcx>,
}
type Target = Immediate<Tag>;
#[inline(always)]
fn deref(&self) -> &Immediate<Tag> {
- &self.immediate
+ &self.imm
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
pub struct OpTy<'tcx, Tag=()> {
- crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
+ op: Operand<Tag>,
pub layout: TyLayout<'tcx>,
}
#[inline(always)]
fn from(val: ImmTy<'tcx, Tag>) -> Self {
OpTy {
- op: Operand::Immediate(val.immediate),
+ op: Operand::Immediate(val.imm),
layout: val.layout
}
}
}
+impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
+{
+ #[inline]
+ pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
+ ImmTy { imm: Immediate::from_scalar(val), layout }
+ }
+
+ #[inline]
+ pub fn to_bits(self) -> EvalResult<'tcx, u128> {
+ self.to_scalar()?.to_bits(self.layout.size)
+ }
+}
+
impl<'tcx, Tag> OpTy<'tcx, Tag>
{
#[inline]
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
/// Try reading an immediate in memory; this is interesting particularly for ScalarPair.
/// Returns `None` if the layout does not permit loading this as a value.
- pub(super) fn try_read_immediate_from_mplace(
+ fn try_read_immediate_from_mplace(
&self,
mplace: MPlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, Option<Immediate<M::PointerTag>>> {
/// Note that for a given layout, this operation will either always fail or always
/// succeed! Whether it succeeds depends on whether the layout can be represented
/// in a `Immediate`, not on which data is stored there currently.
- pub(crate) fn try_read_immediate(
+ pub(super) fn try_read_immediate(
&self,
src: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, Result<Immediate<M::PointerTag>, MemPlace<M::PointerTag>>> {
&self,
op: OpTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
- if let Ok(immediate) = self.try_read_immediate(op)? {
- Ok(ImmTy { immediate, layout: op.layout })
+ if let Ok(imm) = self.try_read_immediate(op)? {
+ Ok(ImmTy { imm, layout: op.layout })
} else {
bug!("primitive read failed for type: {:?}", op.layout.ty);
}
Ok(OpTy { op, layout })
}
+ /// Every place can be read from, so we can turm them into an operand
+ #[inline(always)]
+ pub fn place_to_op(
+ &self,
+ place: PlaceTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+ let op = match *place {
+ Place::Ptr(mplace) => {
+ Operand::Indirect(mplace)
+ }
+ Place::Local { frame, local } =>
+ *self.stack[frame].locals[local].access()?
+ };
+ Ok(OpTy { op, layout: place.layout })
+ }
+
// Evaluate a place with the goal of reading from it. This lets us sometimes
// avoid allocations.
- fn eval_place_to_op(
+ pub(super) fn eval_place_to_op(
&self,
mir_place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
Move(ref place) =>
self.eval_place_to_op(place, layout)?,
- Constant(ref constant) => {
- let layout = from_known_layout(layout, || {
- let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx))?;
- self.layout_of(ty)
- })?;
- let op = self.const_value_to_op(*constant.literal)?;
- OpTy { op, layout }
- }
+ Constant(ref constant) => self.eval_lazy_const_to_op(*constant.literal, layout)?,
};
trace!("{:?}: {:?}", mir_op, *op);
Ok(op)
.collect()
}
- // Used when miri runs into a constant, and by CTFE.
- // FIXME: CTFE should use allocations, then we can make this private (embed it into
- // `eval_operand`, ideally).
- pub(crate) fn const_value_to_op(
+ // Used when Miri runs into a constant, and by const propagation.
+ crate fn eval_lazy_const_to_op(
&self,
val: ty::LazyConst<'tcx>,
- ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
- trace!("const_value_to_op: {:?}", val);
- let val = match val {
+ layout: Option<TyLayout<'tcx>>,
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+ trace!("const_to_op: {:?}", val);
+ match val {
ty::LazyConst::Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?;
- return Ok(*OpTy::from(self.const_eval_raw(GlobalId {
+ return Ok(OpTy::from(self.const_eval_raw(GlobalId {
instance,
promoted: None,
})?));
},
- ty::LazyConst::Evaluated(c) => c,
- };
- match val.val {
- ConstValue::ByRef(id, alloc, offset) => {
+ ty::LazyConst::Evaluated(c) => self.const_to_op(c, layout),
+ }
+ }
+
+ // Used when the miri-engine runs into a constant and for extracting information from constants
+ // in patterns via the `const_eval` module
+ crate fn const_to_op(
+ &self,
+ val: ty::Const<'tcx>,
+ layout: Option<TyLayout<'tcx>>,
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+ let layout = from_known_layout(layout, || {
+ let ty = self.monomorphize(val.ty)?;
+ self.layout_of(ty)
+ })?;
+ let op = match val.val {
+ ConstValue::ByRef(ptr, alloc) => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen -- and for `static mut`, we copy on demand anyway.
- Ok(Operand::Indirect(
- MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)
- ).with_default_tag())
+ Operand::Indirect(
+ MemPlace::from_ptr(ptr, alloc.align)
+ ).with_default_tag()
},
ConstValue::Slice(a, b) =>
- Ok(Operand::Immediate(Immediate::ScalarPair(
+ Operand::Immediate(Immediate::ScalarPair(
a.into(),
Scalar::from_uint(b, self.tcx.data_layout.pointer_size).into(),
- )).with_default_tag()),
+ )).with_default_tag(),
ConstValue::Scalar(x) =>
- Ok(Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag()),
- }
+ Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag(),
+ };
+ Ok(OpTy {
+ op,
+ layout,
+ })
}
/// Read discriminant, return the runtime value as well as the variant index.
}
})
}
-
}