Skip to content

Commit

Permalink
miri: use separate Pointer and Align instead of PtrAndAlign.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Dec 17, 2017
1 parent ff080d3 commit 08646c6
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 177 deletions.
2 changes: 1 addition & 1 deletion src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod value;

pub use self::error::{EvalError, EvalResult, EvalErrorKind};

pub use self::value::{PrimVal, PrimValKind, Value, Pointer, PtrAndAlign, bytes_to_f32, bytes_to_f64};
pub use self::value::{PrimVal, PrimValKind, Value, Pointer, bytes_to_f32, bytes_to_f64};

use std::collections::BTreeMap;
use ty::layout::HasDataLayout;
Expand Down
20 changes: 1 addition & 19 deletions src/librustc/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,6 @@ use super::{EvalResult, MemoryPointer, PointerArithmetic};
use syntax::ast::FloatTy;
use rustc_const_math::ConstFloat;

#[derive(Copy, Clone, Debug)]
pub struct PtrAndAlign {
pub ptr: Pointer,
pub align: Align,
}

impl PtrAndAlign {
pub fn to_ptr<'tcx>(self) -> EvalResult<'tcx, MemoryPointer> {
self.ptr.to_ptr()
}
pub fn offset<'tcx, C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> {
Ok(PtrAndAlign {
ptr: self.ptr.offset(i, cx)?,
align: self.align,
})
}
}

pub fn bytes_to_f32(bits: u128) -> ConstFloat {
ConstFloat {
bits,
Expand All @@ -49,7 +31,7 @@ pub fn bytes_to_f64(bits: u128) -> ConstFloat {
/// operations and fat pointers. This idea was taken from rustc's trans.
#[derive(Clone, Copy, Debug)]
pub enum Value {
ByRef(PtrAndAlign),
ByRef(Pointer, Align),
ByVal(PrimVal),
ByValPair(PrimVal, PrimVal),
}
Expand Down
98 changes: 38 additions & 60 deletions src/librustc_mir/interpret/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use rustc_data_structures::indexed_vec::Idx;
use syntax::ast::Mutability;
use syntax::codemap::Span;

use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal, PtrAndAlign};
use super::{Place, PlaceExtra, EvalContext, StackPopCleanup, ValTy, HasMemory};
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal};
use super::{Place, EvalContext, StackPopCleanup, ValTy};

use rustc_const_math::ConstInt;

Expand Down Expand Up @@ -357,11 +357,9 @@ pub fn const_eval_provider<'a, 'tcx>(
(_, Err(err)) => Err(err),
(Ok((miri_val, miri_ty)), Ok(ctfe)) => {
let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap();
let miri_ptr = PtrAndAlign {
ptr: miri_val,
align: ecx.layout_of(miri_ty).unwrap().align
};
check_ctfe_against_miri(&mut ecx, miri_ptr, miri_ty, ctfe.val);
let layout = ecx.layout_of(miri_ty).unwrap();
let miri_place = Place::from_primval_ptr(miri_val, layout.align);
check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val);
Ok(ctfe)
}
}
Expand All @@ -372,60 +370,49 @@ pub fn const_eval_provider<'a, 'tcx>(

fn check_ctfe_against_miri<'a, 'tcx>(
ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>,
miri_val: PtrAndAlign,
miri_place: Place,
miri_ty: Ty<'tcx>,
ctfe: ConstVal<'tcx>,
) {
use rustc::middle::const_val::ConstAggregate::*;
use rustc_const_math::ConstFloat;
use rustc::ty::TypeVariants::*;
let miri_val = ValTy {
value: ecx.read_place(miri_place).unwrap(),
ty: miri_ty
};
match miri_ty.sty {
TyInt(int_ty) => {
let value = ecx.read_with_align(miri_val.align, |ectx| {
ectx.try_read_value(miri_val.ptr, miri_ty)
});
let prim = get_prim(ecx, value);
let prim = get_prim(ecx, miri_val);
let c = ConstInt::new_signed_truncating(prim as i128,
int_ty,
ecx.tcx.sess.target.isize_ty);
let c = ConstVal::Integral(c);
assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe);
},
TyUint(uint_ty) => {
let value = ecx.read_with_align(miri_val.align, |ectx| {
ectx.try_read_value(miri_val.ptr, miri_ty)
});
let prim = get_prim(ecx, value);
let prim = get_prim(ecx, miri_val);
let c = ConstInt::new_unsigned_truncating(prim,
uint_ty,
ecx.tcx.sess.target.usize_ty);
let c = ConstVal::Integral(c);
assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe);
},
TyFloat(ty) => {
let value = ecx.read_with_align(miri_val.align, |ectx| {
ectx.try_read_value(miri_val.ptr, miri_ty)
});
let prim = get_prim(ecx, value);
let prim = get_prim(ecx, miri_val);
let f = ConstVal::Float(ConstFloat { bits: prim, ty });
assert_eq!(f, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", f, ctfe);
},
TyBool => {
let value = ecx.read_with_align(miri_val.align, |ectx| {
ectx.try_read_value(miri_val.ptr, miri_ty)
});
let bits = get_prim(ecx, value);
let bits = get_prim(ecx, miri_val);
if bits > 1 {
bug!("miri evaluated to {}, but expected a bool {:?}", bits, ctfe);
}
let b = ConstVal::Bool(bits == 1);
assert_eq!(b, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", b, ctfe);
},
TyChar => {
let value = ecx.read_with_align(miri_val.align, |ectx| {
ectx.try_read_value(miri_val.ptr, miri_ty)
});
let bits = get_prim(ecx, value);
let bits = get_prim(ecx, miri_val);
if let Some(cm) = ::std::char::from_u32(bits as u32) {
assert_eq!(
ConstVal::Char(cm), ctfe,
Expand All @@ -436,10 +423,8 @@ fn check_ctfe_against_miri<'a, 'tcx>(
}
},
TyStr => {
let value = ecx.read_with_align(miri_val.align, |ectx| {
ectx.try_read_value(miri_val.ptr, miri_ty)
});
if let Ok(Some(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)))) = value {
let value = ecx.follow_by_ref_value(miri_val.value, miri_val.ty);
if let Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) = value {
let bytes = ecx
.memory
.read_bytes(ptr.into(), len as u64)
Expand All @@ -463,7 +448,6 @@ fn check_ctfe_against_miri<'a, 'tcx>(
},
TyArray(elem_ty, n) => {
let n = n.val.to_const_int().unwrap().to_u64().unwrap();
let size = ecx.layout_of(elem_ty).unwrap().size.bytes();
let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe {
ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| {
(ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8)
Expand All @@ -476,10 +460,12 @@ fn check_ctfe_against_miri<'a, 'tcx>(
},
_ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe),
};
let layout = ecx.layout_of(miri_ty).unwrap();
for (i, elem) in vec.into_iter().enumerate() {
assert!((i as u64) < n);
let ptr = miri_val.offset(size * i as u64, &ecx).unwrap();
check_ctfe_against_miri(ecx, ptr, elem_ty, elem.0);
let (field_place, _) =
ecx.place_field(miri_place, Field::new(i), layout).unwrap();
check_ctfe_against_miri(ecx, field_place, elem_ty, elem.0);
}
},
TyTuple(..) => {
Expand All @@ -489,22 +475,22 @@ fn check_ctfe_against_miri<'a, 'tcx>(
};
let layout = ecx.layout_of(miri_ty).unwrap();
for (i, elem) in vec.into_iter().enumerate() {
let offset = layout.fields.offset(i);
let ptr = miri_val.offset(offset.bytes(), &ecx).unwrap();
check_ctfe_against_miri(ecx, ptr, elem.ty, elem.val);
let (field_place, _) =
ecx.place_field(miri_place, Field::new(i), layout).unwrap();
check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val);
}
},
TyAdt(def, _) => {
let (struct_variant, extra) = if def.is_enum() {
let discr = ecx.read_discriminant_value(
Place::Ptr { ptr: miri_val, extra: PlaceExtra::None },
miri_ty).unwrap();
let mut miri_place = miri_place;
let struct_variant = if def.is_enum() {
let discr = ecx.read_discriminant_value(miri_place, miri_ty).unwrap();
let variant = def.discriminants(ecx.tcx).position(|variant_discr| {
variant_discr.to_u128_unchecked() == discr
}).expect("miri produced invalid enum discriminant");
(&def.variants[variant], PlaceExtra::DowncastVariant(variant))
miri_place = ecx.place_downcast(miri_place, variant).unwrap();
&def.variants[variant]
} else {
(def.struct_variant(), PlaceExtra::None)
def.struct_variant()
};
let vec = match ctfe {
ConstVal::Aggregate(Struct(v)) => v,
Expand All @@ -518,12 +504,9 @@ fn check_ctfe_against_miri<'a, 'tcx>(
let layout = ecx.layout_of(miri_ty).unwrap();
for &(name, elem) in vec.into_iter() {
let field = struct_variant.fields.iter().position(|f| f.name == name).unwrap();
let (place, _) = ecx.place_field(
Place::Ptr { ptr: miri_val, extra },
Field::new(field),
layout,
).unwrap();
check_ctfe_against_miri(ecx, place.to_ptr_align(), elem.ty, elem.val);
let (field_place, _) =
ecx.place_field(miri_place, Field::new(field), layout).unwrap();
check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val);
}
},
TySlice(_) => bug!("miri produced a slice?"),
Expand All @@ -543,11 +526,9 @@ fn check_ctfe_against_miri<'a, 'tcx>(
// should be fine
TyFnDef(..) => {}
TyFnPtr(_) => {
let value = ecx.read_with_align(miri_val.align, |ectx| {
ectx.try_read_value(miri_val.ptr, miri_ty)
});
let value = ecx.value_to_primval(miri_val);
let ptr = match value {
Ok(Some(Value::ByVal(PrimVal::Ptr(ptr)))) => ptr,
Ok(PrimVal::Ptr(ptr)) => ptr,
value => bug!("expected fn ptr, got {:?}", value),
};
let inst = ecx.memory.get_fn(ptr).unwrap();
Expand All @@ -569,13 +550,10 @@ fn check_ctfe_against_miri<'a, 'tcx>(

fn get_prim<'a, 'tcx>(
ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>,
res: Result<Option<Value>, EvalError<'tcx>>,
val: ValTy<'tcx>,
) -> u128 {
match res {
Ok(Some(Value::ByVal(prim))) => unwrap_miri(ecx, prim.to_bytes()),
Err(err) => unwrap_miri(ecx, Err(err)),
val => bug!("got {:?}", val),
}
let res = ecx.value_to_primval(val).and_then(|prim| prim.to_bytes());
unwrap_miri(ecx, res)
}

fn unwrap_miri<'a, 'tcx, T>(
Expand Down
Loading

0 comments on commit 08646c6

Please sign in to comment.