提交 49f784a3 编写于 作者: S Scott Olson

Remove PrimValKind field from PrimVal.

上级 16f3b590
......@@ -11,17 +11,24 @@
use syntax::ast::{FloatTy, IntTy, UintTy};
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub(super) fn cast_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
pub(super) fn cast_primval(
&self,
val: PrimVal,
src_ty: Ty<'tcx>,
dest_ty: Ty<'tcx>
) -> EvalResult<'tcx, PrimVal> {
let kind = self.ty_to_primval_kind(src_ty)?;
use primval::PrimValKind::*;
match val.kind {
F32 => self.cast_float(val.to_f32() as f64, ty),
F64 => self.cast_float(val.to_f64(), ty),
match kind {
F32 => self.cast_float(val.to_f32() as f64, dest_ty),
F64 => self.cast_float(val.to_f64(), dest_ty),
I8 | I16 | I32 | I64 => self.cast_signed_int(val.bits as i64, ty),
I8 | I16 | I32 | I64 => self.cast_signed_int(val.bits as i64, dest_ty),
Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, ty, false),
Bool | Char | U8 | U16 | U32 | U64 => self.cast_int(val.bits, dest_ty, false),
FnPtr | Ptr => self.cast_ptr(val.to_ptr(), ty),
FnPtr | Ptr => self.cast_ptr(val.to_ptr(), dest_ty),
}
}
......@@ -30,22 +37,21 @@ fn cast_signed_int(&self, val: i64, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVa
}
fn cast_int(&self, v: u64, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx, PrimVal> {
use primval::PrimValKind::*;
use rustc::ty::TypeVariants::*;
match ty.sty {
TyBool if v == 0 => Ok(PrimVal::from_bool(false)),
TyBool if v == 1 => Ok(PrimVal::from_bool(true)),
TyBool => Err(EvalError::InvalidBool),
TyInt(IntTy::I8) => Ok(PrimVal::new(v as i64 as i8 as u64, I8)),
TyInt(IntTy::I16) => Ok(PrimVal::new(v as i64 as i16 as u64, I16)),
TyInt(IntTy::I32) => Ok(PrimVal::new(v as i64 as i32 as u64, I32)),
TyInt(IntTy::I64) => Ok(PrimVal::new(v as i64 as i64 as u64, I64)),
TyInt(IntTy::I8) => Ok(PrimVal::new(v as i64 as i8 as u64)),
TyInt(IntTy::I16) => Ok(PrimVal::new(v as i64 as i16 as u64)),
TyInt(IntTy::I32) => Ok(PrimVal::new(v as i64 as i32 as u64)),
TyInt(IntTy::I64) => Ok(PrimVal::new(v as i64 as i64 as u64)),
TyUint(UintTy::U8) => Ok(PrimVal::new(v as u8 as u64, U8)),
TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64, U16)),
TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64, U32)),
TyUint(UintTy::U64) => Ok(PrimVal::new(v, U64)),
TyUint(UintTy::U8) => Ok(PrimVal::new(v as u8 as u64)),
TyUint(UintTy::U16) => Ok(PrimVal::new(v as u16 as u64)),
TyUint(UintTy::U32) => Ok(PrimVal::new(v as u32 as u64)),
TyUint(UintTy::U64) => Ok(PrimVal::new(v)),
TyInt(IntTy::Is) => {
let int_ty = self.tcx.sess.target.int_type;
......@@ -64,7 +70,7 @@ fn cast_int(&self, v: u64, ty: ty::Ty<'tcx>, negative: bool) -> EvalResult<'tcx,
TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i64 as f32)),
TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)),
TyChar if v as u8 as u64 == v => Ok(PrimVal::new(v, Char)),
TyChar if v as u8 as u64 == v => Ok(PrimVal::new(v)),
TyChar => Err(EvalError::InvalidChar(v)),
TyRawPtr(_) => Ok(PrimVal::from_ptr(Pointer::from_int(v))),
......@@ -91,8 +97,7 @@ fn cast_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
fn cast_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
use rustc::ty::TypeVariants::*;
match ty.sty {
TyRef(..) | TyRawPtr(_) => Ok(PrimVal::from_ptr(ptr)),
TyFnPtr(_) => Ok(PrimVal::from_fn_ptr(ptr)),
TyRef(..) | TyRawPtr(_) | TyFnPtr(_) => Ok(PrimVal::from_ptr(ptr)),
TyInt(_) | TyUint(_) => self.transmute_primval(PrimVal::from_ptr(ptr), ty),
_ => Err(EvalError::Unimplemented(format!("ptr to {:?} cast", ty))),
}
......
......@@ -222,16 +222,12 @@ pub fn stack(&self) -> &[Frame<'tcx>] {
&self.stack
}
fn usize_primval(&self, n: u64) -> PrimVal {
PrimVal::from_uint_with_size(n, self.memory.pointer_size())
}
fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
// FIXME: cache these allocs
let ptr = self.memory.allocate(s.len() as u64, 1)?;
self.memory.write_bytes(ptr, s.as_bytes())?;
self.memory.freeze(ptr.alloc_id)?;
Ok(Value::ByValPair(PrimVal::from_ptr(ptr), self.usize_primval(s.len() as u64)))
Ok(Value::ByValPair(PrimVal::from_ptr(ptr), PrimVal::from_uint(s.len() as u64)))
}
fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> {
......@@ -239,27 +235,7 @@ fn const_to_value(&mut self, const_val: &ConstVal) -> EvalResult<'tcx, Value> {
use rustc_const_math::ConstFloat;
let primval = match *const_val {
Integral(const_int) => {
use rustc_const_math::ConstInt::*;
use rustc_const_math::ConstIsize::*;
use rustc_const_math::ConstUsize::*;
let kind = match const_int {
I8(_) => PrimValKind::I8,
I16(_) | Isize(Is16(_)) => PrimValKind::I16,
I32(_) | Isize(Is32(_)) => PrimValKind::I32,
I64(_) | Isize(Is64(_)) => PrimValKind::I64,
U8(_) => PrimValKind::U8,
U16(_) | Usize(Us16(_)) => PrimValKind::U16,
U32(_) | Usize(Us32(_)) => PrimValKind::U32,
U64(_) | Usize(Us64(_)) => PrimValKind::U64,
Infer(_) | InferSigned(_) =>
bug!("uninferred constants only exist before typeck"),
};
PrimVal::new(const_int.to_u64_unchecked(), kind)
}
Integral(const_int) => PrimVal::new(const_int.to_u64_unchecked()),
Float(ConstFloat::F32(f)) => PrimVal::from_f32(f),
Float(ConstFloat::F64(f)) => PrimVal::from_f64(f),
......@@ -306,7 +282,8 @@ pub fn load_mir(&self, def_id: DefId) -> EvalResult<'tcx, MirRef<'tcx>> {
pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
let substituted = ty.subst(self.tcx, substs);
self.tcx.normalize_associated_type(&substituted)
let new = self.tcx.normalize_associated_type(&substituted);
new
}
fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<u64>> {
......@@ -432,9 +409,13 @@ fn binop_with_overflow(
left: &mir::Operand<'tcx>,
right: &mir::Operand<'tcx>,
) -> EvalResult<'tcx, (PrimVal, bool)> {
let left_primval = self.eval_operand_to_primval(left)?;
let right_primval = self.eval_operand_to_primval(right)?;
primval::binary_op(op, left_primval, right_primval)
let left_ty = self.operand_ty(left);
let right_ty = self.operand_ty(right);
let left_kind = self.ty_to_primval_kind(left_ty)?;
let right_kind = self.ty_to_primval_kind(right_ty)?;
let left_val = self.eval_operand_to_primval(left)?;
let right_val = self.eval_operand_to_primval(right)?;
primval::binary_op(op, left_val, left_kind, right_val, right_kind)
}
/// Applies the binary operation `op` to the two operands and writes a tuple of the result
......@@ -460,9 +441,10 @@ fn intrinsic_overflowing(
left: &mir::Operand<'tcx>,
right: &mir::Operand<'tcx>,
dest: Lvalue<'tcx>,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, bool> {
let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
self.write_primval(dest, val)?;
self.write_primval(dest, val, dest_ty)?;
Ok(overflowed)
}
......@@ -506,7 +488,7 @@ fn eval_rvalue_into_lvalue(
BinaryOp(bin_op, ref left, ref right) => {
// ignore overflow bit, rustc inserts check branches for us
self.intrinsic_overflowing(bin_op, left, right, dest)?;
self.intrinsic_overflowing(bin_op, left, right, dest, dest_ty)?;
}
CheckedBinaryOp(bin_op, ref left, ref right) => {
......@@ -515,7 +497,8 @@ fn eval_rvalue_into_lvalue(
UnaryOp(un_op, ref operand) => {
let val = self.eval_operand_to_primval(operand)?;
self.write_primval(dest, primval::unary_op(un_op, val)?)?;
let kind = self.ty_to_primval_kind(dest_ty)?;
self.write_primval(dest, primval::unary_op(un_op, val, kind)?, dest_ty)?;
}
Aggregate(ref kind, ref operands) => {
......@@ -571,9 +554,7 @@ fn eval_rvalue_into_lvalue(
let operand_ty = self.operand_ty(operand);
assert_eq!(self.type_size(operand_ty)?, Some(0));
}
let value_size = self.type_size(dest_ty)?.expect("pointer types are sized");
let zero = PrimVal::from_int_with_size(0, value_size);
self.write_primval(dest, zero)?;
self.write_primval(dest, PrimVal::from_int(0), dest_ty)?;
}
} else {
bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
......@@ -604,19 +585,11 @@ fn eval_rvalue_into_lvalue(
}
}
CEnum { discr, signed, .. } => {
CEnum { .. } => {
assert_eq!(operands.len(), 0);
if let mir::AggregateKind::Adt(adt_def, variant, _, _) = *kind {
let n = adt_def.variants[variant].disr_val.to_u64_unchecked();
let size = discr.size().bytes();
let val = if signed {
PrimVal::from_int_with_size(n as i64, size)
} else {
PrimVal::from_uint_with_size(n, size)
};
self.write_primval(dest, val)?;
self.write_primval(dest, PrimVal::new(n), dest_ty)?;
} else {
bug!("tried to assign {:?} to Layout::CEnum", kind);
}
......@@ -655,8 +628,7 @@ fn eval_rvalue_into_lvalue(
let src = self.eval_lvalue(lvalue)?;
let ty = self.lvalue_ty(lvalue);
let (_, len) = src.elem_ty_and_len(ty);
let len_val = self.usize_primval(len);
self.write_primval(dest, len_val)?;
self.write_primval(dest, PrimVal::from_uint(len), dest_ty)?;
}
Ref(_, _, ref lvalue) => {
......@@ -666,7 +638,7 @@ fn eval_rvalue_into_lvalue(
let val = match extra {
LvalueExtra::None => Value::ByVal(ptr),
LvalueExtra::Length(len) => Value::ByValPair(ptr, self.usize_primval(len)),
LvalueExtra::Length(len) => Value::ByValPair(ptr, PrimVal::from_uint(len)),
LvalueExtra::Vtable(vtable) => Value::ByValPair(ptr, PrimVal::from_ptr(vtable)),
LvalueExtra::DowncastVariant(..) =>
bug!("attempted to take a reference to an enum downcast lvalue"),
......@@ -677,7 +649,7 @@ fn eval_rvalue_into_lvalue(
Box(ty) => {
let ptr = self.alloc_ptr(ty)?;
self.write_primval(dest, PrimVal::from_ptr(ptr))?;
self.write_primval(dest, PrimVal::from_ptr(ptr), dest_ty)?;
}
Cast(kind, ref operand, cast_ty) => {
......@@ -707,7 +679,7 @@ fn eval_rvalue_into_lvalue(
}
} else {
let src_val = self.value_to_primval(src, src_ty)?;
let dest_val = self.cast_primval(src_val, dest_ty)?;
let dest_val = self.cast_primval(src_val, src_ty, dest_ty)?;
self.write_value(Value::ByVal(dest_val), dest, dest_ty)?;
}
}
......@@ -716,7 +688,7 @@ fn eval_rvalue_into_lvalue(
ty::TyFnDef(def_id, substs, fn_ty) => {
let fn_ty = self.tcx.erase_regions(&fn_ty);
let fn_ptr = self.memory.create_fn_ptr(self.tcx,def_id, substs, fn_ty);
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
self.write_value(Value::ByVal(PrimVal::from_ptr(fn_ptr)), dest, dest_ty)?;
},
ref other => bug!("reify fn pointer on {:?}", other),
},
......@@ -728,7 +700,7 @@ fn eval_rvalue_into_lvalue(
let (def_id, substs, _, _) = self.memory.get_fn(ptr.alloc_id)?;
let unsafe_fn_ty = self.tcx.erase_regions(&unsafe_fn_ty);
let fn_ptr = self.memory.create_fn_ptr(self.tcx, def_id, substs, unsafe_fn_ty);
self.write_value(Value::ByVal(PrimVal::from_fn_ptr(fn_ptr)), dest, dest_ty)?;
self.write_value(Value::ByVal(PrimVal::from_ptr(fn_ptr)), dest, dest_ty)?;
},
ref other => bug!("fn to unsafe fn cast on {:?}", other),
},
......@@ -1059,8 +1031,7 @@ fn eval_lvalue_projection(
let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
let n_ptr = self.eval_operand(operand)?;
let usize = self.tcx.types.usize;
let n = self.value_to_primval(n_ptr, usize)?
.expect_uint("Projection::Index expected usize");
let n = self.value_to_primval(n_ptr, usize)?.to_u64();
assert!(n < len);
let ptr = base_ptr.offset(n * elem_size);
(ptr, LvalueExtra::None)
......@@ -1124,6 +1095,7 @@ fn force_allocation(&mut self, lvalue: Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue<
Some(Value::ByRef(ptr)) => Lvalue::from_ptr(ptr),
opt_val => {
let ty = self.stack[frame].mir.local_decls[local].ty;
let ty = self.monomorphize(ty, self.stack[frame].substs);
let substs = self.stack[frame].substs;
let ptr = self.alloc_ptr_with_substs(ty, substs)?;
self.stack[frame].set_local(local, Value::ByRef(ptr));
......@@ -1168,7 +1140,8 @@ fn value_to_ptr_dont_use(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'t
Value::ByVal(primval) => {
let ptr = self.alloc_ptr(ty)?;
self.memory.write_primval(ptr, primval)?;
let kind = self.ty_to_primval_kind(ty)?;
self.memory.write_primval(ptr, primval, kind)?;
Ok(ptr)
}
......@@ -1202,19 +1175,22 @@ fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, P
}
}
fn transmute_primval(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
Ok(PrimVal { kind: self.ty_to_primval_kind(ty)?, ..val })
// FIXME(solson): Delete this.
fn transmute_primval(&self, val: PrimVal, _ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
Ok(val)
}
fn write_primval(
&mut self,
dest: Lvalue<'tcx>,
val: PrimVal,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, ()> {
match dest {
Lvalue::Ptr { ptr, extra } => {
assert_eq!(extra, LvalueExtra::None);
self.memory.write_primval(ptr, val)
let kind = self.ty_to_primval_kind(dest_ty)?;
self.memory.write_primval(ptr, val, kind)
}
Lvalue::Local { frame, local } => {
self.stack[frame].set_local(local, Value::ByVal(val));
......@@ -1319,7 +1295,10 @@ fn write_value_to_ptr(
) -> EvalResult<'tcx, ()> {
match value {
Value::ByRef(ptr) => self.copy(ptr, dest, dest_ty),
Value::ByVal(primval) => self.memory.write_primval(dest, primval),
Value::ByVal(primval) => {
let kind = self.ty_to_primval_kind(dest_ty)?;
self.memory.write_primval(dest, primval, kind)
}
Value::ByValPair(a, b) => self.write_pair_to_ptr(a, b, dest, dest_ty),
}
}
......@@ -1334,8 +1313,12 @@ fn write_pair_to_ptr(
assert_eq!(self.get_field_count(ty)?, 2);
let field_0 = self.get_field_offset(ty, 0)?.bytes();
let field_1 = self.get_field_offset(ty, 1)?.bytes();
self.memory.write_primval(ptr.offset(field_0), a)?;
self.memory.write_primval(ptr.offset(field_1), b)?;
let field_0_ty = self.get_field_ty(ty, 0)?;
let field_1_ty = self.get_field_ty(ty, 1)?;
let field_0_kind = self.ty_to_primval_kind(field_0_ty)?;
let field_1_kind = self.ty_to_primval_kind(field_1_ty)?;
self.memory.write_primval(ptr.offset(field_0), a, field_0_kind)?;
self.memory.write_primval(ptr.offset(field_1), b, field_1_kind)?;
Ok(())
}
......@@ -1432,8 +1415,7 @@ fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value>
I64 => 8,
Is => self.memory.pointer_size(),
};
let n = self.memory.read_int(ptr, size)?;
PrimVal::from_int_with_size(n, size)
PrimVal::from_int(self.memory.read_int(ptr, size)?)
}
ty::TyUint(uint_ty) => {
......@@ -1445,17 +1427,18 @@ fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value>
U64 => 8,
Us => self.memory.pointer_size(),
};
let n = self.memory.read_uint(ptr, size)?;
PrimVal::from_uint_with_size(n, size)
PrimVal::from_uint(self.memory.read_uint(ptr, size)?)
}
ty::TyFloat(FloatTy::F32) => PrimVal::from_f32(self.memory.read_f32(ptr)?),
ty::TyFloat(FloatTy::F64) => PrimVal::from_f64(self.memory.read_f64(ptr)?),
// TODO(solson): Should this even be here? Fn items aren't primvals, are they?
ty::TyFnDef(def_id, substs, fn_ty) => {
PrimVal::from_fn_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty))
PrimVal::from_ptr(self.memory.create_fn_ptr(self.tcx, def_id, substs, fn_ty))
},
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_fn_ptr)?,
ty::TyFnPtr(_) => self.memory.read_ptr(ptr).map(PrimVal::from_ptr)?,
ty::TyBox(ty) |
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
......@@ -1468,7 +1451,7 @@ fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value>
let extra = match self.tcx.struct_tail(ty).sty {
ty::TyTrait(..) => PrimVal::from_ptr(self.memory.read_ptr(extra)?),
ty::TySlice(..) |
ty::TyStr => self.usize_primval(self.memory.read_usize(extra)?),
ty::TyStr => PrimVal::from_uint(self.memory.read_usize(extra)?),
_ => bug!("unsized primval ptr read from {:?}", ty),
};
return Ok(Value::ByValPair(PrimVal::from_ptr(p), extra));
......@@ -1480,11 +1463,9 @@ fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value>
if let CEnum { discr, signed, .. } = *self.type_layout(ty)? {
let size = discr.size().bytes();
if signed {
let n = self.memory.read_int(ptr, size)?;
PrimVal::from_int_with_size(n, size)
PrimVal::from_int(self.memory.read_int(ptr, size)?)
} else {
let n = self.memory.read_uint(ptr, size)?;
PrimVal::from_uint_with_size(n, size)
PrimVal::from_uint(self.memory.read_uint(ptr, size)?)
}
} else {
bug!("primitive read of non-clike enum: {:?}", ty);
......@@ -1531,7 +1512,7 @@ fn unsize_into(
match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
(&ty::TyArray(_, length), &ty::TySlice(_)) => {
let ptr = src.read_ptr(&self.memory)?;
let len = self.usize_primval(length as u64);
let len = PrimVal::from_uint(length as u64);
let ptr = PrimVal::from_ptr(ptr);
self.write_value(Value::ByValPair(ptr, len), dest, dest_ty)?;
}
......
......@@ -44,10 +44,9 @@ pub(super) fn call_intrinsic(
"arith_offset" => {
let ptr = arg_vals[0].read_ptr(&self.memory)?;
let offset = self.value_to_primval(arg_vals[1], isize)?
.expect_int("arith_offset second arg not isize");
let offset = self.value_to_primval(arg_vals[1], isize)?.to_i64();
let new_ptr = ptr.signed_offset(offset);
self.write_primval(dest, PrimVal::from_ptr(new_ptr))?;
self.write_primval(dest, PrimVal::from_ptr(new_ptr), dest_ty)?;
}
"assume" => {
......@@ -85,8 +84,8 @@ pub(super) fn call_intrinsic(
Value::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"),
};
self.write_primval(dest, old)?;
self.write_primval(Lvalue::from_ptr(ptr), change)?;
self.write_primval(dest, old, ty)?;
self.write_primval(Lvalue::from_ptr(ptr), change, ty)?;
}
"atomic_cxchg" => {
......@@ -100,10 +99,11 @@ pub(super) fn call_intrinsic(
Value::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
};
let (val, _) = primval::binary_op(mir::BinOp::Eq, old, expect_old)?;
let kind = self.ty_to_primval_kind(ty)?;
let (val, _) = primval::binary_op(mir::BinOp::Eq, old, kind, expect_old, kind)?;
let dest = self.force_allocation(dest)?.to_ptr();
self.write_pair_to_ptr(old, val, dest, dest_ty)?;
self.write_primval(Lvalue::from_ptr(ptr), change)?;
self.write_primval(Lvalue::from_ptr(ptr), change, ty)?;
}
"atomic_xadd_relaxed" => {
......@@ -116,10 +116,11 @@ pub(super) fn call_intrinsic(
Value::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_xadd_relaxed doesn't work with nonprimitives"),
};
self.write_primval(dest, old)?;
self.write_primval(dest, old, ty)?;
let kind = self.ty_to_primval_kind(ty)?;
// FIXME: what do atomics do on overflow?
let (val, _) = primval::binary_op(mir::BinOp::Add, old, change)?;
self.write_primval(Lvalue::from_ptr(ptr), val)?;
let (val, _) = primval::binary_op(mir::BinOp::Add, old, kind, change, kind)?;
self.write_primval(Lvalue::from_ptr(ptr), val, ty)?;
},
"atomic_xsub_rel" => {
......@@ -132,10 +133,11 @@ pub(super) fn call_intrinsic(
Value::ByRef(_) => bug!("just read the value, can't be byref"),
Value::ByValPair(..) => bug!("atomic_xsub_rel doesn't work with nonprimitives"),
};
self.write_primval(dest, old)?;
self.write_primval(dest, old, ty)?;
let kind = self.ty_to_primval_kind(ty)?;
// FIXME: what do atomics do on overflow?
let (val, _) = primval::binary_op(mir::BinOp::Sub, old, change)?;
self.write_primval(Lvalue::from_ptr(ptr), val)?;
let (val, _) = primval::binary_op(mir::BinOp::Sub, old, kind, change, kind)?;
self.write_primval(Lvalue::from_ptr(ptr), val, ty)?;
}
"breakpoint" => unimplemented!(), // halt miri
......@@ -148,8 +150,7 @@ pub(super) fn call_intrinsic(
let elem_align = self.type_align(elem_ty)?;
let src = arg_vals[0].read_ptr(&self.memory)?;
let dest = arg_vals[1].read_ptr(&self.memory)?;
let count = self.value_to_primval(arg_vals[2], usize)?
.expect_uint("arith_offset second arg not isize");
let count = self.value_to_primval(arg_vals[2], usize)?.to_u64();
self.memory.copy(src, dest, count * elem_size, elem_align)?;
}
......@@ -157,17 +158,18 @@ pub(super) fn call_intrinsic(
"cttz" |
"ctlz" |
"bswap" => {
let elem_ty = substs.type_at(0);
let num = self.value_to_primval(arg_vals[0], elem_ty)?;
let num = numeric_intrinsic(intrinsic_name, num);
self.write_primval(dest, num)?;
let ty = substs.type_at(0);
let num = self.value_to_primval(arg_vals[0], ty)?;
let kind = self.ty_to_primval_kind(ty)?;
let num = numeric_intrinsic(intrinsic_name, num, kind);
self.write_primval(dest, num, ty)?;
}
"discriminant_value" => {
let ty = substs.type_at(0);
let adt_ptr = arg_vals[0].read_ptr(&self.memory)?;
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
self.write_primval(dest, PrimVal::new(discr_val, PrimValKind::U64))?;
self.write_primval(dest, PrimVal::new(discr_val), dest_ty)?;
}
"drop_in_place" => {
......@@ -196,23 +198,22 @@ pub(super) fn call_intrinsic(
}
"fabsf32" => {
let f = self.value_to_primval(arg_vals[2], f32)?
.expect_f32("fabsf32 read non f32");
self.write_primval(dest, PrimVal::from_f32(f.abs()))?;
let f = self.value_to_primval(arg_vals[2], f32)?.to_f32();
self.write_primval(dest, PrimVal::from_f32(f.abs()), dest_ty)?;
}
"fabsf64" => {
let f = self.value_to_primval(arg_vals[2], f64)?
.expect_f64("fabsf64 read non f64");
self.write_primval(dest, PrimVal::from_f64(f.abs()))?;
let f = self.value_to_primval(arg_vals[2], f64)?.to_f64();
self.write_primval(dest, PrimVal::from_f64(f.abs()), dest_ty)?;
}
"fadd_fast" => {
let ty = substs.type_at(0);
let kind = self.ty_to_primval_kind(ty)?;
let a = self.value_to_primval(arg_vals[0], ty)?;
let b = self.value_to_primval(arg_vals[0], ty)?;
let result = primval::binary_op(mir::BinOp::Add, a, b)?;
self.write_primval(dest, result.0)?;
let result = primval::binary_op(mir::BinOp::Add, a, kind, b, kind)?;
self.write_primval(dest, result.0, dest_ty)?;
}
"likely" |
......@@ -220,27 +221,26 @@ pub(super) fn call_intrinsic(
"forget" => {}
"init" => {
let size = dest_layout.size(&self.tcx.data_layout).bytes();
let size = self.type_size(dest_ty)?.expect("cannot init unsized value");;
let init = |this: &mut Self, val: Option<Value>| {
match val {
let zero_val = match val {
Some(Value::ByRef(ptr)) => {
this.memory.write_repeat(ptr, 0, size)?;
Ok(Some(Value::ByRef(ptr)))
Value::ByRef(ptr)
},
None => match this.ty_to_primval_kind(dest_ty) {
Ok(kind) => Ok(Some(Value::ByVal(PrimVal::new(0, kind)))),
Ok(_) => Value::ByVal(PrimVal::new(0)),
Err(_) => {
let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?;
this.memory.write_repeat(ptr, 0, size)?;
Ok(Some(Value::ByRef(ptr)))
Value::ByRef(ptr)
}
},
Some(Value::ByVal(value)) => Ok(Some(Value::ByVal(PrimVal::new(0, value.kind)))),
Some(Value::ByValPair(a, b)) => Ok(Some(Value::ByValPair(
PrimVal::new(0, a.kind),
PrimVal::new(0, b.kind),
))),
}
Some(Value::ByVal(_)) => Value::ByVal(PrimVal::new(0)),
Some(Value::ByValPair(..)) =>
Value::ByValPair(PrimVal::new(0), PrimVal::new(0)),
};
Ok(Some(zero_val))
};
match dest {
Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?,
......@@ -253,16 +253,16 @@ pub(super) fn call_intrinsic(
"min_align_of" => {
let elem_ty = substs.type_at(0);
let elem_align = self.type_align(elem_ty)?;
let align_val = self.usize_primval(elem_align as u64);
self.write_primval(dest, align_val)?;
let align_val = PrimVal::from_uint(elem_align as u64);
self.write_primval(dest, align_val, dest_ty)?;
}
"pref_align_of" => {
let ty = substs.type_at(0);
let layout = self.type_layout(ty)?;
let align = layout.align(&self.tcx.data_layout).pref();
let align_val = self.usize_primval(align);
self.write_primval(dest, align_val)?;
let align_val = PrimVal::from_uint(align);
self.write_primval(dest, align_val, dest_ty)?;
}
"move_val_init" => {
......@@ -275,59 +275,52 @@ pub(super) fn call_intrinsic(
let ty = substs.type_at(0);
let env = self.tcx.empty_parameter_environment();
let needs_drop = self.tcx.type_needs_drop_given_env(ty, &env);
self.write_primval(dest, PrimVal::from_bool(needs_drop))?;
self.write_primval(dest, PrimVal::from_bool(needs_drop), dest_ty)?;
}
"offset" => {
let pointee_ty = substs.type_at(0);
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.type_size(pointee_ty)?.expect("cannot offset a pointer to an unsized type") as i64;
let offset = self.value_to_primval(arg_vals[1], isize)?
.expect_int("offset second arg not isize");
let offset = self.value_to_primval(arg_vals[1], isize)?.to_i64();
let ptr = arg_vals[0].read_ptr(&self.memory)?;
let result_ptr = ptr.signed_offset(offset * pointee_size);
self.write_primval(dest, PrimVal::from_ptr(result_ptr))?;
self.write_primval(dest, PrimVal::from_ptr(result_ptr), dest_ty)?;
}
"overflowing_sub" => {
self.intrinsic_overflowing(mir::BinOp::Sub, &args[0], &args[1], dest)?;
self.intrinsic_overflowing(mir::BinOp::Sub, &args[0], &args[1], dest, dest_ty)?;
}
"overflowing_mul" => {
self.intrinsic_overflowing(mir::BinOp::Mul, &args[0], &args[1], dest)?;
self.intrinsic_overflowing(mir::BinOp::Mul, &args[0], &args[1], dest, dest_ty)?;
}
"overflowing_add" => {
self.intrinsic_overflowing(mir::BinOp::Add, &args[0], &args[1], dest)?;
self.intrinsic_overflowing(mir::BinOp::Add, &args[0], &args[1], dest, dest_ty)?;
}
"powif32" => {
let f = self.value_to_primval(arg_vals[0], f32)?
.expect_f32("powif32 first arg not f32");
let i = self.value_to_primval(arg_vals[1], i32)?
.expect_int("powif32 second arg not i32");
self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)))?;
let f = self.value_to_primval(arg_vals[0], f32)?.to_f32();
let i = self.value_to_primval(arg_vals[1], i32)?.to_i64();
self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)), dest_ty)?;
}
"powif64" => {
let f = self.value_to_primval(arg_vals[0], f64)?
.expect_f64("powif64 first arg not f64");
let i = self.value_to_primval(arg_vals[1], i32)?
.expect_int("powif64 second arg not i32");
self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)))?;
let f = self.value_to_primval(arg_vals[0], f64)?.to_f64();
let i = self.value_to_primval(arg_vals[1], i32)?.to_i64();
self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)), dest_ty)?;
}
"sqrtf32" => {
let f = self.value_to_primval(arg_vals[0], f32)?
.expect_f32("sqrtf32 first arg not f32");
self.write_primval(dest, PrimVal::from_f32(f.sqrt()))?;
let f = self.value_to_primval(arg_vals[0], f32)?.to_f32();
self.write_primval(dest, PrimVal::from_f32(f.sqrt()), dest_ty)?;
}
"sqrtf64" => {
let f = self.value_to_primval(arg_vals[0], f64)?
.expect_f64("sqrtf64 first arg not f64");
self.write_primval(dest, PrimVal::from_f64(f.sqrt()))?;
let f = self.value_to_primval(arg_vals[0], f64)?.to_f64();
self.write_primval(dest, PrimVal::from_f64(f.sqrt()), dest_ty)?;
}
"size_of" => {
......@@ -337,23 +330,20 @@ pub(super) fn call_intrinsic(
// .expect("size_of intrinsic called on unsized value")
// see https://github.com/rust-lang/rust/pull/37708
let size = self.type_size(ty)?.unwrap_or(!0) as u64;
let size_val = self.usize_primval(size);
self.write_primval(dest, size_val)?;
self.write_primval(dest, PrimVal::from_uint(size), dest_ty)?;
}
"size_of_val" => {
let ty = substs.type_at(0);
let (size, _) = self.size_and_align_of_dst(ty, arg_vals[0])?;
let size_val = self.usize_primval(size);
self.write_primval(dest, size_val)?;
self.write_primval(dest, PrimVal::from_uint(size), dest_ty)?;
}
"min_align_of_val" |
"align_of_val" => {
let ty = substs.type_at(0);
let (_, align) = self.size_and_align_of_dst(ty, arg_vals[0])?;
let align_val = self.usize_primval(align);
self.write_primval(dest, align_val)?;
self.write_primval(dest, PrimVal::from_uint(align), dest_ty)?;
}
"type_name" => {
......@@ -365,17 +355,12 @@ pub(super) fn call_intrinsic(
"type_id" => {
let ty = substs.type_at(0);
let n = self.tcx.type_id_hash(ty);
self.write_primval(dest, PrimVal::new(n, PrimValKind::U64))?;
self.write_primval(dest, PrimVal::new(n), dest_ty)?;
}
"transmute" => {
let dest_ty = substs.type_at(1);
let val = match arg_vals[0] {
Value::ByVal(primval) =>
Value::ByVal(self.transmute_primval(primval, dest_ty)?),
v => v,
};
self.write_value(val, dest, dest_ty)?;
self.write_value(arg_vals[0], dest, dest_ty)?;
}
"uninit" => {
......@@ -511,11 +496,11 @@ fn field_ty(
}
macro_rules! integer_intrinsic {
($name:expr, $val:expr, $method:ident) => ({
($name:expr, $val:expr, $kind:expr, $method:ident) => ({
let val = $val;
use primval::PrimValKind::*;
let bits = match val.kind {
let bits = match $kind {
I8 => (val.bits as i8).$method() as u64,
U8 => (val.bits as u8).$method() as u64,
I16 => (val.bits as i16).$method() as u64,
......@@ -527,16 +512,16 @@ fn field_ty(
_ => bug!("invalid `{}` argument: {:?}", $name, val),
};
PrimVal::new(bits, val.kind)
PrimVal::new(bits)
});
}
fn numeric_intrinsic(name: &str, val: PrimVal) -> PrimVal {
fn numeric_intrinsic(name: &str, val: PrimVal, kind: PrimValKind) -> PrimVal {
match name {
"bswap" => integer_intrinsic!("bswap", val, swap_bytes),
"ctlz" => integer_intrinsic!("ctlz", val, leading_zeros),
"ctpop" => integer_intrinsic!("ctpop", val, count_ones),
"cttz" => integer_intrinsic!("cttz", val, trailing_zeros),
"bswap" => integer_intrinsic!("bswap", val, kind, swap_bytes),
"ctlz" => integer_intrinsic!("ctlz", val, kind, leading_zeros),
"ctpop" => integer_intrinsic!("ctpop", val, kind, count_ones),
"cttz" => integer_intrinsic!("cttz", val, kind, trailing_zeros),
_ => bug!("not a numeric intrinsic: {}", name),
}
}
......@@ -100,7 +100,10 @@ pub(super) fn eval_terminator(
terminator.source_info.span)?
}
_ => return Err(EvalError::Unimplemented(format!("can't handle callee of type {:?}", func_ty))),
_ => {
let msg = format!("can't handle callee of type {:?}", func_ty);
return Err(EvalError::Unimplemented(msg));
}
}
}
......@@ -126,11 +129,12 @@ pub(super) fn eval_terminator(
return match *msg {
mir::AssertMessage::BoundsCheck { ref len, ref index } => {
let span = terminator.source_info.span;
let len = self.eval_operand_to_primval(len).expect("can't eval len")
.expect_uint("BoundsCheck len wasn't a uint");
let len = self.eval_operand_to_primval(len)
.expect("can't eval len")
.to_u64();
let index = self.eval_operand_to_primval(index)
.expect("can't eval index")
.expect_uint("BoundsCheck index wasn't a uint");
.to_u64();
Err(EvalError::ArrayIndexOutOfBounds(span, len, index))
},
mir::AssertMessage::Math(ref err) =>
......@@ -194,9 +198,8 @@ fn eval_fn_call(
Abi::C => {
let ty = fn_ty.sig.0.output;
let size = self.type_size(ty)?.expect("function return type cannot be unsized");
let (ret, target) = destination.unwrap();
self.call_c_abi(def_id, arg_operands, ret, size)?;
self.call_c_abi(def_id, arg_operands, ret, ty)?;
self.goto_block(target);
Ok(())
}
......@@ -303,7 +306,7 @@ fn call_c_abi(
def_id: DefId,
args: &[mir::Operand<'tcx>],
dest: Lvalue<'tcx>,
dest_size: u64,
dest_ty: Ty<'tcx>,
) -> EvalResult<'tcx, ()> {
let name = self.tcx.item_name(def_id);
let attrs = self.tcx.get_attrs(def_id);
......@@ -325,36 +328,32 @@ fn call_c_abi(
match &link_name[..] {
"__rust_allocate" => {
let size = self.value_to_primval(args[0], usize)?
.expect_uint("__rust_allocate first arg not usize");
let align = self.value_to_primval(args[1], usize)?
.expect_uint("__rust_allocate second arg not usize");
let size = self.value_to_primval(args[0], usize)?.to_u64();
let align = self.value_to_primval(args[1], usize)?.to_u64();
let ptr = self.memory.allocate(size, align)?;
self.write_primval(dest, PrimVal::from_ptr(ptr))?;
self.write_primval(dest, PrimVal::from_ptr(ptr), dest_ty)?;
}
"__rust_deallocate" => {
let ptr = args[0].read_ptr(&self.memory)?;
// FIXME: insert sanity check for size and align?
let _old_size = self.value_to_primval(args[1], usize)?
.expect_uint("__rust_deallocate second arg not usize");
let _align = self.value_to_primval(args[2], usize)?
.expect_uint("__rust_deallocate third arg not usize");
let _old_size = self.value_to_primval(args[1], usize)?.to_u64();
let _align = self.value_to_primval(args[2], usize)?.to_u64();
self.memory.deallocate(ptr)?;
},
"__rust_reallocate" => {
let ptr = args[0].read_ptr(&self.memory)?;
let size = self.value_to_primval(args[2], usize)?.expect_uint("__rust_reallocate third arg not usize");
let align = self.value_to_primval(args[3], usize)?.expect_uint("__rust_reallocate fourth arg not usize");
let size = self.value_to_primval(args[2], usize)?.to_u64();
let align = self.value_to_primval(args[3], usize)?.to_u64();
let new_ptr = self.memory.reallocate(ptr, size, align)?;
self.write_primval(dest, PrimVal::from_ptr(new_ptr))?;
self.write_primval(dest, PrimVal::from_ptr(new_ptr), dest_ty)?;
}
"memcmp" => {
let left = args[0].read_ptr(&self.memory)?;
let right = args[1].read_ptr(&self.memory)?;
let n = self.value_to_primval(args[2], usize)?.expect_uint("__rust_reallocate first arg not usize");
let n = self.value_to_primval(args[2], usize)?.to_u64();
let result = {
let left_bytes = self.memory.read_bytes(left, n)?;
......@@ -368,7 +367,7 @@ fn call_c_abi(
}
};
self.write_primval(dest, PrimVal::from_int_with_size(result, dest_size))?;
self.write_primval(dest, PrimVal::new(result as u64), dest_ty)?;
}
_ => {
......
......@@ -11,7 +11,7 @@
use syntax::abi::Abi;
use error::{EvalError, EvalResult};
use primval::PrimVal;
use primval::{PrimVal, PrimValKind};
////////////////////////////////////////////////////////////////////////////////
// Allocations and pointers
......@@ -559,13 +559,18 @@ pub fn write_ptr(&mut self, dest: Pointer, ptr: Pointer) -> EvalResult<'tcx, ()>
Ok(())
}
pub fn write_primval(&mut self, dest: Pointer, val: PrimVal) -> EvalResult<'tcx, ()> {
pub fn write_primval(
&mut self,
dest: Pointer,
val: PrimVal,
kind: PrimValKind,
) -> EvalResult<'tcx, ()> {
if let Some(alloc_id) = val.relocation {
return self.write_ptr(dest, Pointer::new(alloc_id, val.bits));
}
use primval::PrimValKind::*;
let (size, bits) = match val.kind {
let (size, bits) = match kind {
I8 | U8 | Bool => (1, val.bits as u8 as u64),
I16 | U16 => (2, val.bits as u16 as u64),
I32 | U32 | F32 | Char => (4, val.bits as u32 as u64),
......
......@@ -38,11 +38,6 @@ pub struct PrimVal {
/// `Allocation` in the `memory` module has a list of relocations, but a `PrimVal` is only
/// large enough to contain one, hence the `Option`.
pub relocation: Option<AllocId>,
// FIXME(solson): I think we can make this field unnecessary, or at least move it outside of
// this struct. We can either match over `Ty`s or generate simple `PrimVal`s from `Ty`s and
// match over those to decide which operations to perform on `PrimVal`s.
pub kind: PrimValKind,
}
#[derive(Clone, Copy, Debug, PartialEq)]
......@@ -87,44 +82,40 @@ pub fn from_int_size(size: u64) -> Self {
}
impl PrimVal {
pub fn new(bits: u64, kind: PrimValKind) -> Self {
PrimVal { bits: bits, relocation: None, kind: kind }
pub fn new(bits: u64) -> Self {
PrimVal { bits: bits, relocation: None }
}
pub fn new_with_relocation(bits: u64, kind: PrimValKind, alloc_id: AllocId) -> Self {
PrimVal { bits: bits, relocation: Some(alloc_id), kind: kind }
pub fn new_with_relocation(bits: u64, alloc_id: AllocId) -> Self {
PrimVal { bits: bits, relocation: Some(alloc_id) }
}
pub fn from_ptr(ptr: Pointer) -> Self {
PrimVal::new_with_relocation(ptr.offset as u64, PrimValKind::Ptr, ptr.alloc_id)
}
pub fn from_fn_ptr(ptr: Pointer) -> Self {
PrimVal::new_with_relocation(ptr.offset as u64, PrimValKind::FnPtr, ptr.alloc_id)
PrimVal::new_with_relocation(ptr.offset as u64, ptr.alloc_id)
}
pub fn from_bool(b: bool) -> Self {
PrimVal::new(b as u64, PrimValKind::Bool)
PrimVal::new(b as u64)
}
pub fn from_char(c: char) -> Self {
PrimVal::new(c as u64, PrimValKind::Char)
PrimVal::new(c as u64)
}
pub fn from_f32(f: f32) -> Self {
PrimVal::new(f32_to_bits(f), PrimValKind::F32)
PrimVal::new(f32_to_bits(f))
}
pub fn from_f64(f: f64) -> Self {
PrimVal::new(f64_to_bits(f), PrimValKind::F64)
PrimVal::new(f64_to_bits(f))
}
pub fn from_uint_with_size(n: u64, size: u64) -> Self {
PrimVal::new(n, PrimValKind::from_uint_size(size))
pub fn from_uint(n: u64) -> Self {
PrimVal::new(n)
}
pub fn from_int_with_size(n: i64, size: u64) -> Self {
PrimVal::new(n as u64, PrimValKind::from_int_size(size))
pub fn from_int(n: i64) -> Self {
PrimVal::new(n as u64)
}
pub fn to_f32(self) -> f32 {
......@@ -144,31 +135,27 @@ pub fn to_ptr(self) -> Pointer {
}
pub fn try_as_uint<'tcx>(self) -> EvalResult<'tcx, u64> {
self.to_ptr().to_int().map(|val| val as u64)
self.to_ptr().to_int().map(|val| val)
}
pub fn expect_uint(self, error_msg: &str) -> u64 {
if let Ok(int) = self.try_as_uint() {
return int;
}
use self::PrimValKind::*;
match self.kind {
U8 | U16 | U32 | U64 => self.bits,
_ => bug!("{}", error_msg),
pub fn to_u64(self) -> u64 {
if let Some(ptr) = self.try_as_ptr() {
return ptr.to_int().expect("non abstract ptr") as u64;
}
self.bits
}
pub fn expect_int(self, error_msg: &str) -> i64 {
if let Ok(int) = self.try_as_uint() {
return int as i64;
pub fn to_i64(self) -> i64 {
if let Some(ptr) = self.try_as_ptr() {
return ptr.to_int().expect("non abstract ptr") as i64;
}
self.bits as i64
}
use self::PrimValKind::*;
match self.kind {
I8 | I16 | I32 | I64 => self.bits as i64,
_ => bug!("{}", error_msg),
}
pub fn try_as_ptr(self) -> Option<Pointer> {
self.relocation.map(|alloc_id| {
Pointer::new(alloc_id, self.bits)
})
}
pub fn try_as_bool<'tcx>(self) -> EvalResult<'tcx, bool> {
......@@ -179,19 +166,6 @@ pub fn try_as_bool<'tcx>(self) -> EvalResult<'tcx, bool> {
}
}
pub fn expect_f32(self, error_msg: &str) -> f32 {
match self.kind {
PrimValKind::F32 => bits_to_f32(self.bits),
_ => bug!("{}", error_msg),
}
}
pub fn expect_f64(self, error_msg: &str) -> f64 {
match self.kind {
PrimValKind::F32 => bits_to_f64(self.bits),
_ => bug!("{}", error_msg),
}
}
}
////////////////////////////////////////////////////////////////////////////////
......@@ -199,9 +173,9 @@ pub fn expect_f64(self, error_msg: &str) -> f64 {
////////////////////////////////////////////////////////////////////////////////
macro_rules! overflow {
($kind:expr, $op:ident, $l:expr, $r:expr) => ({
($op:ident, $l:expr, $r:expr) => ({
let (val, overflowed) = $l.$op($r);
let primval = PrimVal::new(val as u64, $kind);
let primval = PrimVal::new(val as u64);
Ok((primval, overflowed))
})
}
......@@ -211,14 +185,14 @@ pub fn expect_f64(self, error_msg: &str) -> f64 {
let l = $l;
let r = $r;
match $kind {
I8 => overflow!(I8, $int_op, l as i8, r as i8),
I16 => overflow!(I16, $int_op, l as i16, r as i16),
I32 => overflow!(I32, $int_op, l as i32, r as i32),
I64 => overflow!(I64, $int_op, l as i64, r as i64),
U8 => overflow!(U8, $int_op, l as u8, r as u8),
U16 => overflow!(U16, $int_op, l as u16, r as u16),
U32 => overflow!(U32, $int_op, l as u32, r as u32),
U64 => overflow!(U64, $int_op, l as u64, r as u64),
I8 => overflow!($int_op, l as i8, r as i8),
I16 => overflow!($int_op, l as i16, r as i16),
I32 => overflow!($int_op, l as i32, r as i32),
I64 => overflow!($int_op, l as i64, r as i64),
U8 => overflow!($int_op, l as u8, r as u8),
U16 => overflow!($int_op, l as u16, r as u16),
U32 => overflow!($int_op, l as u32, r as u32),
U64 => overflow!($int_op, l as u64, r as u64),
_ => bug!("int_arithmetic should only be called on int primvals"),
}
})
......@@ -229,37 +203,37 @@ pub fn expect_f64(self, error_msg: &str) -> f64 {
let l = $l;
let r = $r;
match $kind {
I8 => overflow!(I8, $int_op, l as i8, r),
I16 => overflow!(I16, $int_op, l as i16, r),
I32 => overflow!(I32, $int_op, l as i32, r),
I64 => overflow!(I64, $int_op, l as i64, r),
U8 => overflow!(U8, $int_op, l as u8, r),
U16 => overflow!(U16, $int_op, l as u16, r),
U32 => overflow!(U32, $int_op, l as u32, r),
U64 => overflow!(U64, $int_op, l as u64, r),
I8 => overflow!($int_op, l as i8, r),
I16 => overflow!($int_op, l as i16, r),
I32 => overflow!($int_op, l as i32, r),
I64 => overflow!($int_op, l as i64, r),
U8 => overflow!($int_op, l as u8, r),
U16 => overflow!($int_op, l as u16, r),
U32 => overflow!($int_op, l as u32, r),
U64 => overflow!($int_op, l as u64, r),
_ => bug!("int_shift should only be called on int primvals"),
}
})
}
macro_rules! float_arithmetic {
($kind:expr, $from_bits:ident, $to_bits:ident, $float_op:tt, $l:expr, $r:expr) => ({
($from_bits:ident, $to_bits:ident, $float_op:tt, $l:expr, $r:expr) => ({
let l = $from_bits($l);
let r = $from_bits($r);
let bits = $to_bits(l $float_op r);
PrimVal::new(bits, $kind)
PrimVal::new(bits)
})
}
macro_rules! f32_arithmetic {
($float_op:tt, $l:expr, $r:expr) => (
float_arithmetic!(F32, bits_to_f32, f32_to_bits, $float_op, $l, $r)
float_arithmetic!(bits_to_f32, f32_to_bits, $float_op, $l, $r)
)
}
macro_rules! f64_arithmetic {
($float_op:tt, $l:expr, $r:expr) => (
float_arithmetic!(F64, bits_to_f64, f64_to_bits, $float_op, $l, $r)
float_arithmetic!(bits_to_f64, f64_to_bits, $float_op, $l, $r)
)
}
......@@ -267,7 +241,9 @@ pub fn expect_f64(self, error_msg: &str) -> f64 {
pub fn binary_op<'tcx>(
bin_op: mir::BinOp,
left: PrimVal,
right: PrimVal
left_kind: PrimValKind,
right: PrimVal,
right_kind: PrimValKind,
) -> EvalResult<'tcx, (PrimVal, bool)> {
use rustc::mir::BinOp::*;
use self::PrimValKind::*;
......@@ -288,7 +264,7 @@ pub fn binary_op<'tcx>(
// These are the maximum values a bitshift RHS could possibly have. For example, u16
// can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in
// that range.
let type_bits: u32 = match left.kind {
let type_bits: u32 = match left_kind {
I8 | U8 => 8,
I16 | U16 => 16,
I32 | U32 => 32,
......@@ -301,18 +277,18 @@ pub fn binary_op<'tcx>(
let r = (right.bits as u32) & (type_bits - 1);
return match bin_op {
Shl => int_shift!(left.kind, overflowing_shl, l, r),
Shr => int_shift!(left.kind, overflowing_shr, l, r),
Shl => int_shift!(left_kind, overflowing_shl, l, r),
Shr => int_shift!(left_kind, overflowing_shr, l, r),
_ => bug!("it has already been checked that this is a shift op"),
};
}
if left.kind != right.kind {
if left_kind != right_kind {
let msg = format!("unimplemented binary op: {:?}, {:?}, {:?}", left, right, bin_op);
return Err(EvalError::Unimplemented(msg));
}
let val = match (bin_op, left.kind) {
let val = match (bin_op, left_kind) {
(Eq, F32) => PrimVal::from_bool(bits_to_f32(l) == bits_to_f32(r)),
(Ne, F32) => PrimVal::from_bool(bits_to_f32(l) != bits_to_f32(r)),
(Lt, F32) => PrimVal::from_bool(bits_to_f32(l) < bits_to_f32(r)),
......@@ -346,9 +322,9 @@ pub fn binary_op<'tcx>(
(Gt, _) => PrimVal::from_bool(l > r),
(Ge, _) => PrimVal::from_bool(l >= r),
(BitOr, k) => PrimVal::new(l | r, k),
(BitAnd, k) => PrimVal::new(l & r, k),
(BitXor, k) => PrimVal::new(l ^ r, k),
(BitOr, _) => PrimVal::new(l | r),
(BitAnd, _) => PrimVal::new(l & r),
(BitXor, _) => PrimVal::new(l ^ r),
(Add, k) if k.is_int() => return int_arithmetic!(k, overflowing_add, l, r),
(Sub, k) if k.is_int() => return int_arithmetic!(k, overflowing_sub, l, r),
......@@ -378,11 +354,15 @@ fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp, left: Pointer, right: Pointer) ->
}
}
pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
pub fn unary_op<'tcx>(
un_op: mir::UnOp,
val: PrimVal,
val_kind: PrimValKind,
) -> EvalResult<'tcx, PrimVal> {
use rustc::mir::UnOp::*;
use self::PrimValKind::*;
let bits = match (un_op, val.kind) {
let bits = match (un_op, val_kind) {
(Not, Bool) => !bits_to_bool(val.bits) as u64,
(Not, U8) => !(val.bits as u8) as u64,
......@@ -409,5 +389,5 @@ pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVa
}
};
Ok(PrimVal::new(bits, val.kind))
Ok(PrimVal::new(bits))
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册