Remove PrimValKind field from PrimVal.
This commit is contained in:
parent
16f3b590e4
commit
49f784a3e4
@ -11,17 +11,24 @@ use rustc::ty::Ty;
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, '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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, '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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, '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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
} 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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
) -> 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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
"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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
"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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
"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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
"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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
"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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
// .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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
"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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
|
||||
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 @@ macro_rules! integer_intrinsic {
|
||||
_ => 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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
|
||||
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 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
}
|
||||
};
|
||||
|
||||
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 rustc::ty::layout::{self, TargetDataLayout};
|
||||
use syntax::abi::Abi;
|
||||
|
||||
use error::{EvalError, EvalResult};
|
||||
use primval::PrimVal;
|
||||
use primval::{PrimVal, PrimValKind};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Allocations and pointers
|
||||
@ -559,13 +559,18 @@ impl<'a, 'tcx> Memory<'a, '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),
|
||||
|
154
src/primval.rs
154
src/primval.rs
@ -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 @@ impl PrimValKind {
|
||||
}
|
||||
|
||||
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 @@ impl PrimVal {
|
||||
}
|
||||
|
||||
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 @@ impl PrimVal {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ impl PrimVal {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 @@ macro_rules! int_arithmetic {
|
||||
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 @@ macro_rules! int_shift {
|
||||
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 @@ macro_rules! f64_arithmetic {
|
||||
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))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user