提交 64a75ecc 编写于 作者: O Oliver Schneider

change `Value::Bytes` to `Value::Bits`

上级 3bbf2fd7
......@@ -473,11 +473,24 @@ fn hash_stable<W: StableHasherResult>(
Mutable
});
impl_stable_hash_for!(enum mir::interpret::Scalar {
Bytes(b),
Ptr(p),
Undef
});
impl<'a> HashStable<StableHashingContext<'a>>
for ::mir::interpret::Scalar {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use mir::interpret::Scalar::*;
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
Bits { bits, defined } => {
bits.hash_stable(hcx, hasher);
defined.hash_stable(hcx, hasher);
},
Ptr(ptr) => ptr.hash_stable(hcx, hasher),
}
}
}
impl_stable_hash_for!(struct ty::Const<'tcx> {
ty,
......
......@@ -51,19 +51,13 @@ pub fn to_primval(&self) -> Option<Scalar> {
}
#[inline]
pub fn to_bits(&self) -> Option<u128> {
match self.to_primval() {
Some(Scalar::Bytes(val)) => Some(val),
_ => None,
}
pub fn to_bits(&self, size: Size) -> Option<u128> {
self.to_primval()?.to_bits(size).ok()
}
#[inline]
pub fn to_ptr(&self) -> Option<Pointer> {
match self.to_primval() {
Some(Scalar::Ptr(ptr)) => Some(ptr),
_ => None,
}
self.to_primval()?.to_ptr().ok()
}
}
......@@ -93,56 +87,85 @@ fn super_visit_with<V: ty::fold::TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
}
impl<'tcx> Scalar {
pub fn ptr_null() -> Self {
Scalar::Bytes(0)
pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
Scalar::Bits {
bits: 0,
defined: cx.data_layout().pointer_size.bits() as u8,
}
}
pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
let layout = cx.data_layout();
match self {
Scalar::Bytes(b) => {
assert_eq!(b as u64 as u128, b);
Ok(Scalar::Bytes(layout.signed_offset(b as u64, i)? as u128))
Scalar::Bits { bits, defined } => {
let pointer_size = layout.pointer_size.bits() as u8;
if defined < pointer_size {
err!(ReadUndefBytes)
} else {
Ok(Scalar::Bits {
bits: layout.signed_offset(bits as u64, i)? as u128,
defined: pointer_size,
})
}
}
Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
Scalar::Undef => err!(ReadUndefBytes),
}
}
pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
let layout = cx.data_layout();
match self {
Scalar::Bytes(b) => {
assert_eq!(b as u64 as u128, b);
Ok(Scalar::Bytes(layout.offset(b as u64, i.bytes())? as u128))
Scalar::Bits { bits, defined } => {
let pointer_size = layout.pointer_size.bits() as u8;
if defined < pointer_size {
err!(ReadUndefBytes)
} else {
Ok(Scalar::Bits {
bits: layout.offset(bits as u64, i.bytes())? as u128,
defined: pointer_size,
})
}
}
Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
Scalar::Undef => err!(ReadUndefBytes),
}
}
pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
let layout = cx.data_layout();
match self {
Scalar::Bytes(b) => {
assert_eq!(b as u64 as u128, b);
Ok(Scalar::Bytes(layout.wrapping_signed_offset(b as u64, i) as u128))
Scalar::Bits { bits, defined } => {
let pointer_size = layout.pointer_size.bits() as u8;
if defined < pointer_size {
err!(ReadUndefBytes)
} else {
Ok(Scalar::Bits {
bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
defined: pointer_size,
})
}
}
Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))),
Scalar::Undef => err!(ReadUndefBytes),
}
}
pub fn is_null(self) -> EvalResult<'tcx, bool> {
pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> EvalResult<'tcx, bool> {
match self {
Scalar::Bytes(b) => Ok(b == 0),
Scalar::Bits {
bits, defined,
} => if defined < cx.data_layout().pointer_size.bits() as u8 {
err!(ReadUndefBytes)
} else {
Ok(bits == 0)
},
Scalar::Ptr(_) => Ok(false),
Scalar::Undef => err!(ReadUndefBytes),
}
}
pub fn to_value_with_len(self, len: u64) -> Value {
Value::ScalarPair(self, Scalar::from_u128(len as u128))
pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
Value::ScalarPair(self, Scalar::Bits {
bits: len as u128,
defined: cx.data_layout().pointer_size.bits() as u8,
})
}
pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
......@@ -163,20 +186,20 @@ fn from(ptr: Pointer) -> Self {
/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
/// of a simple value, a pointer into another `Allocation`, or be undefined.
/// of a simple value or a pointer into another `Allocation`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
pub enum Scalar {
/// The raw bytes of a simple value.
Bytes(u128),
Bits {
/// number of bits that are valid and may be read
defined: u8,
bits: u128,
},
/// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
/// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
/// relocation and its associated offset together as a `Pointer` here.
Ptr(Pointer),
/// An undefined `Scalar`, for representing values that aren't safe to examine, but are safe
/// to copy around, just like undefined bytes in an `Allocation`.
Undef,
}
#[derive(Clone, Copy, Debug, PartialEq)]
......@@ -190,41 +213,38 @@ pub enum ScalarKind {
}
impl<'tcx> Scalar {
pub fn from_u128(n: u128) -> Self {
Scalar::Bytes(n)
}
pub fn from_i128(n: i128) -> Self {
Scalar::Bytes(n as u128)
pub fn undef() -> Self {
Scalar::Bits { bits: 0, defined: 0 }
}
pub fn from_bool(b: bool) -> Self {
Scalar::Bytes(b as u128)
// FIXME: can we make defined `1`?
Scalar::Bits { bits: b as u128, defined: 8 }
}
pub fn from_char(c: char) -> Self {
Scalar::Bytes(c as u128)
Scalar::Bits { bits: c as u128, defined: 32 }
}
pub fn to_bytes(self) -> EvalResult<'tcx, u128> {
pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> {
match self {
Scalar::Bytes(b) => Ok(b),
Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes),
Scalar::Bits { bits, defined } if size.bits() <= defined as u64 => Ok(bits),
Scalar::Bits { .. } => err!(ReadUndefBytes),
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
Scalar::Undef => err!(ReadUndefBytes),
}
}
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
match self {
Scalar::Bytes(_) => err!(ReadBytesAsPointer),
Scalar::Bits {..} => err!(ReadBytesAsPointer),
Scalar::Ptr(p) => Ok(p),
Scalar::Undef => err!(ReadUndefBytes),
}
}
pub fn is_bytes(self) -> bool {
pub fn is_bits(self) -> bool {
match self {
Scalar::Bytes(_) => true,
Scalar::Bits { .. } => true,
_ => false,
}
}
......@@ -236,46 +256,10 @@ pub fn is_ptr(self) -> bool {
}
}
pub fn is_undef(self) -> bool {
match self {
Scalar::Undef => true,
_ => false,
}
}
pub fn to_u128(self) -> EvalResult<'tcx, u128> {
self.to_bytes()
}
pub fn to_u64(self) -> EvalResult<'tcx, u64> {
self.to_bytes().map(|b| {
assert_eq!(b as u64 as u128, b);
b as u64
})
}
pub fn to_i32(self) -> EvalResult<'tcx, i32> {
self.to_bytes().map(|b| {
assert_eq!(b as i32 as u128, b);
b as i32
})
}
pub fn to_i128(self) -> EvalResult<'tcx, i128> {
self.to_bytes().map(|b| b as i128)
}
pub fn to_i64(self) -> EvalResult<'tcx, i64> {
self.to_bytes().map(|b| {
assert_eq!(b as i64 as u128, b);
b as i64
})
}
pub fn to_bool(self) -> EvalResult<'tcx, bool> {
match self.to_bytes()? {
0 => Ok(false),
1 => Ok(true),
match self {
Scalar::Bits { bits: 0, defined: 8 } => Ok(false),
Scalar::Bits { bits: 1, defined: 8 } => Ok(true),
_ => err!(InvalidBool),
}
}
......
......@@ -1149,11 +1149,13 @@ pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
Goto { .. } => vec!["".into()],
SwitchInt { ref values, switch_ty, .. } => {
let size = ty::tls::with(|tcx| switch_ty.scalar_size(tcx));
let size = size.map_or(0, |size| size.bytes()) as u8;
values.iter()
.map(|&u| {
let mut s = String::new();
print_miri_value(
Value::Scalar(Scalar::Bytes(u)),
Value::Scalar(Scalar::Bits { bits: u, defined: size }),
switch_ty,
&mut s,
).unwrap();
......@@ -1893,19 +1895,22 @@ pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Resul
pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
use ty::TypeVariants::*;
match (value, &ty.sty) {
(Value::Scalar(Scalar::Bytes(0)), &TyBool) => write!(f, "false"),
(Value::Scalar(Scalar::Bytes(1)), &TyBool) => write!(f, "true"),
(Value::Scalar(Scalar::Bytes(bits)), &TyFloat(ast::FloatTy::F32)) =>
(Value::Scalar(Scalar::Bits { bits: 0, defined: 8 }), &TyBool) => write!(f, "false"),
(Value::Scalar(Scalar::Bits { bits: 1, defined: 8 }), &TyBool) => write!(f, "true"),
(Value::Scalar(Scalar::Bits { bits, defined: 32 }), &TyFloat(ast::FloatTy::F32)) =>
write!(f, "{}f32", Single::from_bits(bits)),
(Value::Scalar(Scalar::Bytes(bits)), &TyFloat(ast::FloatTy::F64)) =>
(Value::Scalar(Scalar::Bits { bits, defined: 64 }), &TyFloat(ast::FloatTy::F64)) =>
write!(f, "{}f64", Double::from_bits(bits)),
(Value::Scalar(Scalar::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
(Value::Scalar(Scalar::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
(Value::Scalar(Scalar::Bytes(n)), &TyChar) =>
write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
(Value::Scalar(Scalar::Undef), &TyFnDef(did, _)) =>
(Value::Scalar(Scalar::Bits { bits, .. }), &TyUint(ui)) => write!(f, "{:?}{}", bits, ui),
(Value::Scalar(Scalar::Bits { bits, defined }), &TyInt(i)) => {
let amt = 128 - defined;
write!(f, "{:?}{}", ((bits as i128) << amt) >> amt, i)
},
(Value::Scalar(Scalar::Bits { bits, defined: 32 }), &TyChar) =>
write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()),
(Value::Scalar(Scalar::Bits { defined: 0, .. }), &TyFnDef(did, _)) =>
write!(f, "{}", item_path_str(did)),
(Value::ScalarPair(Scalar::Ptr(ptr), Scalar::Bytes(len)),
(Value::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: len, .. }),
&TyRef(_, &ty::TyS { sty: TyStr, .. }, _)) => {
ty::tls::with(|tcx| {
match tcx.alloc_map.lock().get(ptr.alloc_id) {
......
......@@ -1982,7 +1982,7 @@ pub fn eval_explicit_discr(
match tcx.const_eval(param_env.and(cid)) {
Ok(val) => {
// FIXME: Find the right type and use it instead of `val.ty` here
if let Some(b) = val.assert_bits(val.ty) {
if let Some(b) = val.assert_bits(tcx, val.ty) {
trace!("discriminants: {} ({:?})", b, repr_type);
Some(Discr {
val: b,
......
......@@ -17,15 +17,17 @@
use rustc_data_structures::indexed_vec::Idx;
use ty::subst::{Substs, Subst, Kind, UnpackedKind};
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
use ty::{Slice, TyS, layout};
use util::captures::Captures;
use mir::interpret::{Scalar, Pointer, Value, ConstValue};
use rustc_target::abi::{Size, HasDataLayout};
use std::iter;
use std::cmp::Ordering;
use rustc_target::spec::abi;
use syntax::ast::{self, Name};
use syntax::symbol::{keywords, InternedString};
use syntax::attr;
use serialize;
......@@ -1755,6 +1757,23 @@ pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
_ => bug!("cannot convert type `{:?}` to a closure kind", self),
}
}
/// If this type is a scalar, compute its size without
/// going through `tcx.layout_of`
pub fn scalar_size<C: HasDataLayout>(
&self,
cx: C,
) -> Option<Size> {
let ty = match self.sty {
ty::TyBool => return Some(Size::from_bytes(1)),
ty::TyChar => return Some(Size::from_bytes(4)),
ty::TyInt(ity) => attr::IntType::SignedInt(ity),
ty::TyUint(uty) => attr::IntType::UnsignedInt(uty),
_ => return None,
};
use ty::layout::IntegerExt;
Some(layout::Integer::from_attr(cx, ty).size())
}
}
/// Typed constant value.
......@@ -1820,15 +1839,18 @@ pub fn from_primval(
#[inline]
pub fn from_bits(
tcx: TyCtxt<'_, '_, 'tcx>,
val: u128,
bits: u128,
ty: Ty<'tcx>,
) -> &'tcx Self {
Self::from_primval(tcx, Scalar::Bytes(val), ty)
let defined = ty.scalar_size(tcx).unwrap_or_else(|| {
panic!("non-scalar type in from_bits: {:?}", ty)
}).bits() as u8;
Self::from_primval(tcx, Scalar::Bits { bits, defined }, ty)
}
#[inline]
pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
Self::from_primval(tcx, Scalar::Undef, ty)
Self::from_primval(tcx, Scalar::undef(), ty)
}
#[inline]
......@@ -1842,12 +1864,13 @@ pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
}
#[inline]
pub fn to_bits(&self, ty: Ty<'_>) -> Option<u128> {
pub fn to_bits<C: HasDataLayout>(&self, cx: C, ty: Ty<'tcx>) -> Option<u128> {
if self.ty != ty {
return None;
}
let size = ty.scalar_size(cx)?;
match self.val {
ConstVal::Value(val) => val.to_bits(),
ConstVal::Value(val) => val.to_bits(size),
_ => None,
}
}
......@@ -1877,17 +1900,18 @@ pub fn to_primval(&self) -> Option<Scalar> {
}
#[inline]
pub fn assert_bits(&self, ty: Ty<'_>) -> Option<u128> {
pub fn assert_bits<C: HasDataLayout>(&self, cx: C, ty: Ty<'tcx>) -> Option<u128> {
assert_eq!(self.ty, ty);
let size = ty.scalar_size(cx)?;
match self.val {
ConstVal::Value(val) => val.to_bits(),
ConstVal::Value(val) => val.to_bits(size),
_ => None,
}
}
#[inline]
pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
self.assert_bits(tcx.types.bool).and_then(|v| match v {
self.assert_bits(tcx, tcx.types.bool).and_then(|v| match v {
0 => Some(false),
1 => Some(true),
_ => None,
......@@ -1896,12 +1920,12 @@ pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
#[inline]
pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
self.assert_bits(tcx.types.usize).map(|v| v as u64)
self.assert_bits(tcx, tcx.types.usize).map(|v| v as u64)
}
#[inline]
pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 {
match self.assert_bits(ty) {
pub fn unwrap_bits(&self, tcx: TyCtxt<'_, '_, '_>, ty: Ty<'tcx>) -> u128 {
match self.assert_bits(tcx, ty) {
Some(val) => val,
None => bug!("expected bits of {}, got {:#?}", ty, self),
}
......
......@@ -32,11 +32,13 @@ pub fn primval_to_llvm(cx: &CodegenCx,
cv: Scalar,
layout: &layout::Scalar,
llty: Type) -> ValueRef {
let bits = if layout.is_bool() { 1 } else { layout.value.size(cx).bits() };
let bitsize = if layout.is_bool() { 1 } else { layout.value.size(cx).bits() };
match cv {
Scalar::Undef => C_undef(Type::ix(cx, bits)),
Scalar::Bytes(b) => {
let llval = C_uint_big(Type::ix(cx, bits), b);
Scalar::Bits { defined, .. } if (defined as u64) < bitsize || defined == 0 => {
C_undef(Type::ix(cx, bitsize))
},
Scalar::Bits { bits, .. } => {
let llval = C_uint_big(Type::ix(cx, bitsize), bits);
if layout.value == layout::Pointer {
unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
} else {
......
......@@ -374,7 +374,7 @@ pub fn build_binary_op(&mut self, mut block: BasicBlock,
// Helper to get a `-1` value of the appropriate type
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let bits = self.hir.integer_bit_width(ty);
let bits = ty.scalar_size(self.hir.tcx()).expect("neg_1_literal expects integers").bits();
let n = (!0u128) >> (128 - bits);
let literal = Literal::Value {
value: ty::Const::from_bits(self.hir.tcx(), n, ty)
......@@ -386,7 +386,7 @@ fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
// Helper to get the minimum value of the appropriate type
fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
assert!(ty.is_signed());
let bits = self.hir.integer_bit_width(ty);
let bits = ty.scalar_size(self.hir.tcx()).expect("minval_literal expects integers").bits();
let n = 1 << (bits - 1);
let literal = Literal::Value {
value: ty::Const::from_bits(self.hir.tcx(), n, ty)
......
......@@ -124,7 +124,7 @@ pub fn add_cases_to_switch<'pat>(&mut self,
PatternKind::Constant { value } => {
indices.entry(value)
.or_insert_with(|| {
options.push(value.unwrap_bits(switch_ty));
options.push(value.unwrap_bits(self.hir.tcx(), switch_ty));
options.len() - 1
});
true
......
......@@ -52,15 +52,6 @@ pub fn unit_rvalue(&mut self) -> Rvalue<'tcx> {
// Returns a zero literal operand for the appropriate type, works for
// bool, char and integers.
pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
match ty.sty {
ty::TyBool |
ty::TyChar |
ty::TyUint(_) |
ty::TyInt(_) => {}
_ => {
span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
}
}
let literal = Literal::Value {
value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
};
......
......@@ -614,7 +614,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
let idx = adt_def.variant_index_with_id(variant_id);
let (d, o) = adt_def.discriminant_def_for_variant(idx);
use rustc::ty::util::IntTypeExt;
let ty = adt_def.repr.discr_type().to_ty(cx.tcx());
let ty = adt_def.repr.discr_type();
let ty = ty.to_ty(cx.tcx());
Some((d, o, ty))
}
_ => None,
......
......@@ -21,9 +21,8 @@
use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::region;
use rustc::infer::InferCtxt;
use rustc::ty::layout::IntegerExt;
use rustc::ty::subst::Subst;
use rustc::ty::{self, Ty, TyCtxt, layout};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Kind, Substs};
use syntax::ast::{self, LitKind};
use syntax::attr;
......@@ -139,18 +138,6 @@ pub fn false_literal(&mut self) -> Literal<'tcx> {
}
}
pub fn integer_bit_width(
&self,
ty: Ty,
) -> u64 {
let ty = match ty.sty {
ty::TyInt(ity) => attr::IntType::SignedInt(ity),
ty::TyUint(uty) => attr::IntType::UnsignedInt(uty),
_ => bug!("{} is not an integer", ty),
};
layout::Integer::from_attr(self.tcx, ty).size().bits()
}
// FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
pub fn const_eval_literal(
&mut self,
......@@ -169,12 +156,15 @@ pub fn const_eval_literal(
};
let clamp = |n| {
let size = self.integer_bit_width(ty);
let size = ty.scalar_size(self.tcx).expect("const_eval_lit::clamp expects ints").bits();
trace!("clamp {} with size {} and amt {}", n, size, 128 - size);
let amt = 128 - size;
let result = (n << amt) >> amt;
trace!("clamp result: {}", result);
result
ConstValue::Scalar(Scalar::Bits {
bits: result,
defined: size as u8,
})
};
use rustc::mir::interpret::*;
......@@ -184,21 +174,26 @@ pub fn const_eval_literal(
let id = self.tcx.allocate_bytes(s.as_bytes());
ConstValue::ScalarPair(
Scalar::Ptr(id.into()),
Scalar::from_u128(s.len() as u128),
Scalar::Bits {
bits: s.len() as u128,
defined: self.tcx.data_layout.pointer_size.bits() as u8,
}
)
},
LitKind::ByteStr(ref data) => {
let id = self.tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::Ptr(id.into()))
},
LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bytes(n as u128)),
LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
bits: n as u128,
defined: 8,
}),
LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
let n = clamp(n as u128);
ConstValue::Scalar(Scalar::Bytes(n))
clamp(n as u128)
},
LitKind::Int(n, _) => ConstValue::Scalar(Scalar::Bytes(clamp(n))),
LitKind::Int(n, _) => clamp(n),
LitKind::Float(n, fty) => {
parse_float(n, fty)
}
......@@ -209,8 +204,14 @@ pub fn const_eval_literal(
};
parse_float(n, fty)
}
LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bytes(b as u128)),
LitKind::Char(c) => ConstValue::Scalar(Scalar::Bytes(c as u128)),
LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
bits: b as u128,
defined: 8,
}),
LitKind::Char(c) => ConstValue::Scalar(Scalar::Bits {
bits: c as u128,
defined: 32,
}),
};
Literal::Value {
value: ty::Const::from_const_value(self.tcx, lit, ty)
......
......@@ -958,7 +958,7 @@ fn slice_pat_covered_by_constructor<'tcx>(
{
match pat.kind {
box PatternKind::Constant { value } => {
let b = value.unwrap_bits(pat.ty);
let b = value.unwrap_bits(tcx, pat.ty);
assert_eq!(b as u8 as u128, b);
if b as u8 != *ch {
return Ok(false);
......
......@@ -1057,7 +1057,7 @@ pub fn compare_const_vals<'a, 'tcx>(
// FIXME: This should use assert_bits(ty) instead of use_bits
// but triggers possibly bugs due to mismatching of arrays and slices
if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
if let (Some(a), Some(b)) = (a.to_bits(tcx, ty), b.to_bits(tcx, ty)) {
use ::rustc_apfloat::Float;
return match ty.sty {
ty::TyFloat(ast::FloatTy::F32) => {
......@@ -1130,20 +1130,26 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
let id = tcx.allocate_bytes(s.as_bytes());
ConstValue::ScalarPair(
Scalar::Ptr(id.into()),
Scalar::from_u128(s.len() as u128),
Scalar::Bits {
bits: s.len() as u128,
defined: tcx.data_layout.pointer_size.bits() as u8,
},
)
},
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::Ptr(id.into()))
},
LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bytes(n as u128)),
LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
bits: n as u128,
defined: 8,
}),
LitKind::Int(n, _) => {
enum Int {
Signed(IntTy),
Unsigned(UintTy),
}
let ty = match ty.sty {
let ity = match ty.sty {
ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
ty::TyInt(other) => Int::Signed(other),
ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
......@@ -1152,7 +1158,7 @@ enum Int {
};
// This converts from LitKind::Int (which is sign extended) to
// Scalar::Bytes (which is zero extended)
let n = match ty {
let n = match ity {
// FIXME(oli-obk): are these casts correct?
Int::Signed(IntTy::I8) if neg =>
(n as i8).overflowing_neg().0 as u8 as u128,
......@@ -1171,7 +1177,10 @@ enum Int {
Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
_ => bug!(),
};
ConstValue::Scalar(Scalar::Bytes(n))
ConstValue::Scalar(Scalar::Bits {
bits: n,
defined: ty.scalar_size(tcx).unwrap().bits() as u8,
})
},
LitKind::Float(n, fty) => {
parse_float(n, fty, neg)?
......@@ -1183,8 +1192,14 @@ enum Int {
};
parse_float(n, fty, neg)?
}
LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bytes(b as u128)),
LitKind::Char(c) => ConstValue::Scalar(Scalar::Bytes(c as u128)),
LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
bits: b as u128,
defined: 8,
}),
LitKind::Char(c) => ConstValue::Scalar(Scalar::Bits {
bits: c as u128,
defined: 32,
}),
};
Ok(ty::Const::from_const_value(tcx, lit, ty))
}
......@@ -1197,7 +1212,7 @@ pub fn parse_float<'tcx>(
let num = num.as_str();
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
let bits = match fty {
let (bits, defined) = match fty {
ast::FloatTy::F32 => {
num.parse::<f32>().map_err(|_| ())?;
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
......@@ -1206,7 +1221,7 @@ pub fn parse_float<'tcx>(
if neg {
f = -f;
}
f.to_bits()
(f.to_bits(), 32)
}
ast::FloatTy::F64 => {
num.parse::<f64>().map_err(|_| ())?;
......@@ -1216,9 +1231,9 @@ pub fn parse_float<'tcx>(
if neg {
f = -f;
}
f.to_bits()
(f.to_bits(), 64)
}
};
Ok(ConstValue::Scalar(Scalar::Bytes(bits)))
Ok(ConstValue::Scalar(Scalar::Bits { bits, defined }))
}
......@@ -18,12 +18,13 @@ pub(super) fn cast_primval(
trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
match val {
Scalar::Undef => Ok(Scalar::Undef),
Scalar::Bits { defined: 0, .. } => Ok(val),
Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
Scalar::Bytes(b) => {
Scalar::Bits { bits, .. } => {
// TODO(oli-obk): impl scalar_size for floats and check defined bits here
match src_ty.sty {
TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
_ => self.cast_from_int(b, src_ty, dest_ty),
TyFloat(fty) => self.cast_from_float(bits, fty, dest_ty),
_ => self.cast_from_int(bits, src_ty, dest_ty),
}
}
}
......@@ -46,20 +47,38 @@ fn cast_from_int(
match dest_ty.sty {
TyInt(_) | TyUint(_) => {
let v = self.truncate(v, dest_ty)?;
Ok(Scalar::Bytes(v))
Ok(Scalar::Bits {
bits: v,
defined: dest_ty.scalar_size(self.tcx.tcx).unwrap().bits() as u8,
})
}
TyFloat(FloatTy::F32) if signed => Ok(Scalar::Bytes(Single::from_i128(v as i128).value.to_bits())),
TyFloat(FloatTy::F64) if signed => Ok(Scalar::Bytes(Double::from_i128(v as i128).value.to_bits())),
TyFloat(FloatTy::F32) => Ok(Scalar::Bytes(Single::from_u128(v).value.to_bits())),
TyFloat(FloatTy::F64) => Ok(Scalar::Bytes(Double::from_u128(v).value.to_bits())),
TyFloat(FloatTy::F32) if signed => Ok(Scalar::Bits {
bits: Single::from_i128(v as i128).value.to_bits(),
defined: 32,
}),
TyFloat(FloatTy::F64) if signed => Ok(Scalar::Bits {
bits: Double::from_i128(v as i128).value.to_bits(),
defined: 64,
}),
TyFloat(FloatTy::F32) => Ok(Scalar::Bits {
bits: Single::from_u128(v).value.to_bits(),
defined: 32,
}),
TyFloat(FloatTy::F64) => Ok(Scalar::Bits {
bits: Double::from_u128(v).value.to_bits(),
defined: 64,
}),
TyChar if v as u8 as u128 == v => Ok(Scalar::Bytes(v)),
TyChar if v as u8 as u128 == v => Ok(Scalar::Bits { bits: v, defined: 32 }),
TyChar => err!(InvalidChar(v)),
// No alignment check needed for raw pointers. But we have to truncate to target ptr size.
TyRawPtr(_) => {
Ok(Scalar::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
Ok(Scalar::Bits {
bits: self.memory.truncate_to_ptr(v).0 as u128,
defined: self.memory.pointer_size().bits() as u8,
})
},
// Casts to bool are not permitted by rustc, no need to handle them here.
......@@ -75,28 +94,53 @@ fn cast_from_float(&self, bits: u128, fty: FloatTy, dest_ty: Ty<'tcx>) -> EvalRe
TyUint(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8);
match fty {
FloatTy::F32 => Ok(Scalar::Bytes(Single::from_bits(bits).to_u128(width).value)),
FloatTy::F64 => Ok(Scalar::Bytes(Double::from_bits(bits).to_u128(width).value)),
FloatTy::F32 => Ok(Scalar::Bits {
bits: Single::from_bits(bits).to_u128(width).value,
defined: 32,
}),
FloatTy::F64 => Ok(Scalar::Bits {
bits: Double::from_bits(bits).to_u128(width).value,
defined: 64,
}),
}
},
// float -> int
TyInt(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8);
match fty {
FloatTy::F32 => Ok(Scalar::from_i128(Single::from_bits(bits).to_i128(width).value)),
FloatTy::F64 => Ok(Scalar::from_i128(Double::from_bits(bits).to_i128(width).value)),
FloatTy::F32 => Ok(Scalar::Bits {
bits: Single::from_bits(bits).to_i128(width).value as u128,
defined: 32,
}),
FloatTy::F64 => Ok(Scalar::Bits {
bits: Double::from_bits(bits).to_i128(width).value as u128,
defined: 64,
}),
}
},
// f64 -> f32
TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
Ok(Scalar::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
Ok(Scalar::Bits {
bits: Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
defined: 32,
})
},
// f32 -> f64
TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
Ok(Scalar::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
Ok(Scalar::Bits {
bits: Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
defined: 64,
})
},
// identity cast
TyFloat(_) => Ok(Scalar::Bytes(bits)),
TyFloat(FloatTy:: F64) => Ok(Scalar::Bits {
bits,
defined: 64,
}),
TyFloat(FloatTy:: F32) => Ok(Scalar::Bits {
bits,
defined: 32,
}),
_ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
}
}
......
......@@ -100,7 +100,7 @@ pub fn value_to_const_value<'tcx>(
) -> &'tcx ty::Const<'tcx> {
let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
match (val, &layout.abi) {
(Value::Scalar(Scalar::Undef), _) if layout.is_zst() => {},
(Value::Scalar(Scalar::Bits { defined: 0, ..}), _) if layout.is_zst() => {},
(Value::ByRef(..), _) |
(Value::Scalar(_), &layout::Abi::Scalar(_)) |
(Value::ScalarPair(..), &layout::Abi::ScalarPair(..)) => {},
......@@ -319,20 +319,31 @@ fn call_intrinsic<'a>(
"min_align_of" => {
let elem_ty = substs.type_at(0);
let elem_align = ecx.layout_of(elem_ty)?.align.abi();
let align_val = Scalar::from_u128(elem_align as u128);
let align_val = Scalar::Bits {
bits: elem_align as u128,
defined: dest_layout.size.bits() as u8,
};
ecx.write_primval(dest, align_val, dest_layout.ty)?;
}
"size_of" => {
let ty = substs.type_at(0);
let size = ecx.layout_of(ty)?.size.bytes() as u128;
ecx.write_primval(dest, Scalar::from_u128(size), dest_layout.ty)?;
let size_val = Scalar::Bits {
bits: size,
defined: dest_layout.size.bits() as u8,
};
ecx.write_primval(dest, size_val, dest_layout.ty)?;
}
"type_id" => {
let ty = substs.type_at(0);
let type_id = ecx.tcx.type_id_hash(ty) as u128;
ecx.write_primval(dest, Scalar::from_u128(type_id), dest_layout.ty)?;
let id_val = Scalar::Bits {
bits: type_id,
defined: dest_layout.size.bits() as u8,
};
ecx.write_primval(dest, id_val, dest_layout.ty)?;
}
name => return Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()),
......@@ -354,7 +365,7 @@ fn try_ptr_op<'a>(
right: Scalar,
_right_ty: Ty<'tcx>,
) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
if left.is_bytes() && right.is_bytes() {
if left.is_bits() && right.is_bits() {
Ok(None)
} else {
Err(
......
......@@ -232,7 +232,10 @@ pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
let ptr = self.memory.allocate_bytes(s.as_bytes());
Ok(Value::ScalarPair(
Scalar::Ptr(ptr),
Scalar::from_u128(s.len() as u128),
Scalar::Bits {
bits: s.len() as u128,
defined: self.tcx.data_layout.pointer_size.bits() as u8,
},
))
}
......@@ -408,7 +411,7 @@ pub fn push_stack_frame(
::log_settings::settings().indentation += 1;
let locals = if mir.local_decls.len() > 1 {
let mut locals = IndexVec::from_elem(Some(Value::Scalar(Scalar::Undef)), &mir.local_decls);
let mut locals = IndexVec::from_elem(Some(Value::Scalar(Scalar::undef())), &mir.local_decls);
match self.tcx.describe_def(instance.def_id()) {
// statics and constants don't have `Storage*` statements, no need to look for them
Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {},
......@@ -606,9 +609,13 @@ pub(super) fn eval_rvalue_into_place(
let src = self.eval_place(place)?;
let ty = self.place_ty(place);
let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
let defined = self.memory.pointer_size().bits() as u8;
self.write_primval(
dest,
Scalar::from_u128(len as u128),
Scalar::Bits {
bits: len as u128,
defined,
},
dest_ty,
)?;
}
......@@ -621,7 +628,7 @@ pub(super) fn eval_rvalue_into_place(
let val = match extra {
PlaceExtra::None => ptr.to_value(),
PlaceExtra::Length(len) => ptr.to_value_with_len(len),
PlaceExtra::Length(len) => ptr.to_value_with_len(len, self.tcx.tcx),
PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
PlaceExtra::DowncastVariant(..) => {
bug!("attempted to take a reference to an enum downcast place")
......@@ -644,9 +651,13 @@ pub(super) fn eval_rvalue_into_place(
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(),
"SizeOf nullary MIR operator called for unsized type");
let defined = self.memory.pointer_size().bits() as u8;
self.write_primval(
dest,
Scalar::from_u128(layout.size.bytes() as u128),
Scalar::Bits {
bits: layout.size.bytes() as u128,
defined,
},
dest_ty,
)?;
}
......@@ -694,9 +705,16 @@ pub(super) fn eval_rvalue_into_place(
let discr_val = def
.discriminant_for_variant(*self.tcx, index)
.val;
let defined = dest_ty
.scalar_size(self.tcx.tcx)
.expect("can only cast variants to ints")
.bits() as u8;
return self.write_primval(
dest,
Scalar::Bytes(discr_val),
Scalar::Bits {
bits: discr_val,
defined,
},
dest_ty);
}
}
......@@ -780,7 +798,11 @@ pub(super) fn eval_rvalue_into_place(
let ty = self.place_ty(place);
let place = self.eval_place(place)?;
let discr_val = self.read_discriminant_value(place, ty)?;
self.write_primval(dest, Scalar::Bytes(discr_val), dest_ty)?;
let defined = ty.scalar_size(self.tcx.tcx).expect("discriminant must be scalar").bits() as u8;
self.write_primval(dest, Scalar::Bits {
bits: discr_val,
defined,
}, dest_ty)?;
}
}
......@@ -910,7 +932,7 @@ pub fn read_discriminant_value(
// FIXME: should we catch invalid discriminants here?
layout::Variants::Tagged { .. } => {
if discr.ty.is_signed() {
let i = raw_discr.to_bytes()? as i128;
let i = raw_discr.to_bits(discr.size)? as i128;
// going from layout tag type to typeck discriminant type
// requires first sign extending with the layout discriminant
let amt = 128 - discr.size.bits();
......@@ -925,7 +947,7 @@ pub fn read_discriminant_value(
let truncatee = sexted as u128;
(truncatee << amt) >> amt
} else {
raw_discr.to_bytes()?
raw_discr.to_bits(discr.size)?
}
},
layout::Variants::NicheFilling {
......@@ -942,7 +964,10 @@ pub fn read_discriminant_value(
assert!(variants_start == variants_end);
dataful_variant as u128
},
Scalar::Bytes(raw_discr) => {
Scalar::Bits { bits: raw_discr, defined } => {
if defined < discr.size.bits() as u8 {
return err!(ReadUndefBytes);
}
let discr = raw_discr.wrapping_sub(niche_start)
.wrapping_add(variants_start);
if variants_start <= discr && discr <= variants_end {
......@@ -951,7 +976,6 @@ pub fn read_discriminant_value(
dataful_variant as u128
}
},
Scalar::Undef => return err!(ReadUndefBytes),
}
}
};
......@@ -990,7 +1014,10 @@ pub fn write_discriminant_value(
let discr_val = (discr_val << amt) >> amt;
let (discr_dest, tag) = self.place_field(dest, mir::Field::new(0), layout)?;
self.write_primval(discr_dest, Scalar::Bytes(discr_val), tag.ty)?;
self.write_primval(discr_dest, Scalar::Bits {
bits: discr_val,
defined: size as u8,
}, tag.ty)?;
}
layout::Variants::NicheFilling {
dataful_variant,
......@@ -1003,7 +1030,10 @@ pub fn write_discriminant_value(
self.place_field(dest, mir::Field::new(0), layout)?;
let niche_value = ((variant_index - niche_variants.start()) as u128)
.wrapping_add(niche_start);
self.write_primval(niche_dest, Scalar::Bytes(niche_value), niche.ty)?;
self.write_primval(niche_dest, Scalar::Bits {
bits: niche_value,
defined: niche.size.bits() as u8,
}, niche.ty)?;
}
}
}
......@@ -1216,8 +1246,10 @@ pub fn write_value_to_ptr(
layout::Primitive::Int(_, signed) => signed,
_ => false,
},
_ if primval.is_undef() => false,
_ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
_ => match primval {
Scalar::Bits { defined: 0, .. } => false,
_ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout),
}
};
self.memory.write_primval(dest, dest_align, primval, layout.size, signed)
}
......@@ -1308,10 +1340,10 @@ pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, ScalarKind> {
fn ensure_valid_value(&self, val: Scalar, ty: Ty<'tcx>) -> EvalResult<'tcx> {
match ty.sty {
ty::TyBool if val.to_bytes()? > 1 => err!(InvalidBool),
ty::TyBool => val.to_bool().map(|_| ()),
ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() => {
err!(InvalidChar(val.to_bytes()? as u32 as u128))
ty::TyChar if ::std::char::from_u32(val.to_bits(Size::from_bytes(4))? as u32).is_none() => {
err!(InvalidChar(val.to_bits(Size::from_bytes(4))? as u32 as u128))
}
_ => Ok(()),
......@@ -1347,8 +1379,8 @@ pub(crate) fn read_ptr(
let len = self
.memory
.read_ptr_sized(extra, ptr_align)?
.to_bytes()?;
Ok(p.to_value_with_len(len as u64))
.to_bits(ptr_size)?;
Ok(p.to_value_with_len(len as u64, self.tcx.tcx))
},
_ => bug!("unsized primval ptr read from {:?}", pointee_ty),
}
......@@ -1363,15 +1395,10 @@ pub fn validate_ptr_target(
) -> EvalResult<'tcx> {
match ty.sty {
ty::TyBool => {
let val = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(1))?;
match val {
Scalar::Bytes(0) | Scalar::Bytes(1) => (),
// TODO: This seems a little overeager, should reading at bool type already be insta-UB?
_ => return err!(InvalidBool),
}
self.memory.read_primval(ptr, ptr_align, Size::from_bytes(1))?.to_bool()?;
}
ty::TyChar => {
let c = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(4))?.to_bytes()? as u32;
let c = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(4))?.to_bits(Size::from_bytes(4))? as u32;
match ::std::char::from_u32(c) {
Some(..) => (),
None => return err!(InvalidChar(c as u128)),
......@@ -1418,7 +1445,7 @@ pub fn try_read_value(&self, ptr: Scalar, ptr_align: Align, ty: Ty<'tcx>) -> Eva
self.memory.check_align(ptr, ptr_align)?;
if layout.size.bytes() == 0 {
return Ok(Some(Value::Scalar(Scalar::Undef)));
return Ok(Some(Value::Scalar(Scalar::undef())));
}
let ptr = ptr.to_ptr()?;
......@@ -1482,7 +1509,7 @@ fn unsize_into_ptr(
let ptr = self.into_ptr(src)?;
// u64 cast is from usize to u64, which is always good
let valty = ValTy {
value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)),
value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx), self.tcx.tcx),
ty: dest_ty,
};
self.write_value(valty, dest)
......@@ -1796,7 +1823,7 @@ pub fn storage_live(&mut self, local: mir::Local) -> Option<Value> {
trace!("{:?} is now live", local);
// StorageLive *always* kills the value that's currently stored
mem::replace(&mut self.locals[local], Some(Value::Scalar(Scalar::Undef)))
mem::replace(&mut self.locals[local], Some(Value::Scalar(Scalar::undef())))
}
/// Returns the old value of the local
......
......@@ -232,15 +232,18 @@ pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx
let alloc = self.get(ptr.alloc_id)?;
(ptr.offset.bytes(), alloc.align)
}
Scalar::Bytes(bytes) => {
let v = ((bytes as u128) % (1 << self.pointer_size().bytes())) as u64;
Scalar::Bits { bits, defined } => {
if defined <= self.pointer_size().bits() as u8 {
return err!(ReadUndefBytes);
}
// FIXME: what on earth does this line do? docs or fix needed!
let v = ((bits as u128) % (1 << self.pointer_size().bytes())) as u64;
if v == 0 {
return err!(InvalidNullPointerUsage);
}
// the base address if the "integer allocation" is 0 and hence always aligned
(v, required_align)
}
Scalar::Undef => return err!(ReadUndefBytes),
};
// Check alignment
if alloc_align.abi() < required_align.abi() {
......@@ -711,10 +714,10 @@ pub fn read_primval(&self, ptr: Pointer, ptr_align: Align, size: Size) -> EvalRe
// Undef check happens *after* we established that the alignment is correct.
// We must not return Ok() for unaligned pointers!
if self.check_defined(ptr, size).is_err() {
return Ok(Scalar::Undef.into());
return Ok(Scalar::undef().into());
}
// Now we do the actual reading
let bytes = read_target_uint(endianness, bytes).unwrap();
let bits = read_target_uint(endianness, bytes).unwrap();
// See if we got a pointer
if size != self.pointer_size() {
if self.relocations(ptr, size)?.len() != 0 {
......@@ -723,12 +726,15 @@ pub fn read_primval(&self, ptr: Pointer, ptr_align: Align, size: Size) -> EvalRe
} else {
let alloc = self.get(ptr.alloc_id)?;
match alloc.relocations.get(&ptr.offset) {
Some(&alloc_id) => return Ok(Pointer::new(alloc_id, Size::from_bytes(bytes as u64)).into()),
Some(&alloc_id) => return Ok(Pointer::new(alloc_id, Size::from_bytes(bits as u64)).into()),
None => {},
}
}
// We don't. Just return the bytes.
Ok(Scalar::Bytes(bytes))
// We don't. Just return the bits.
Ok(Scalar::Bits {
bits,
defined: size.bits() as u8,
})
}
pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align) -> EvalResult<'tcx, Scalar> {
......@@ -744,9 +750,9 @@ pub fn write_primval(&mut self, ptr: Scalar, ptr_align: Align, val: Scalar, size
val.offset.bytes() as u128
}
Scalar::Bytes(bytes) => bytes,
Scalar::Bits { bits, defined } if defined >= size.bits() as u8 && defined != 0 => bits,
Scalar::Undef => {
Scalar::Bits { .. } => {
self.check_align(ptr.into(), ptr_align)?;
self.mark_definedness(ptr, size, false)?;
return Ok(());
......@@ -951,7 +957,7 @@ fn into_ptr_vtable_pair(
Value::ScalarPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)),
Value::Scalar(Scalar::Undef) => err!(ReadUndefBytes),
Value::Scalar(Scalar::Bits { defined: 0, .. }) => err!(ReadUndefBytes),
_ => bug!("expected ptr and vtable, got {:?}", value),
}
}
......@@ -967,15 +973,14 @@ fn into_slice(
let len = mem.read_ptr_sized(
ref_ptr.ptr_offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
align
)?.to_bytes()? as u64;
)?.to_bits(mem.pointer_size())? as u64;
Ok((ptr, len))
}
Value::ScalarPair(ptr, val) => {
let len = val.to_u128()?;
assert_eq!(len as u64 as u128, len);
let len = val.to_bits(self.memory().pointer_size())?;
Ok((ptr.into(), len as u64))
}
Value::Scalar(Scalar::Undef) => err!(ReadUndefBytes),
Value::Scalar(Scalar::Bits { defined: 0, .. }) => err!(ReadUndefBytes),
Value::Scalar(_) => bug!("expected ptr and length, got {:?}", value),
}
}
......
......@@ -79,11 +79,12 @@ pub fn binary_op(
}
}
// II: From now on, everything must be bytes, no pointers
let l = left.to_bytes()?;
let r = right.to_bytes()?;
let left_layout = self.layout_of(left_ty)?;
let right_layout = self.layout_of(right_ty)?;
// II: From now on, everything must be bytes, no pointers
let l = left.to_bits(left_layout.size)?;
let r = right.to_bits(right_layout.size)?;
// These ops can have an RHS with a different numeric type.
if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
......@@ -110,7 +111,10 @@ pub fn binary_op(
}
};
let truncated = self.truncate(result, left_ty)?;
return Ok((Scalar::Bytes(truncated), oflo));
return Ok((Scalar::Bits {
bits: truncated,
defined: size as u8,
}, oflo));
}
if left_kind != right_kind {
......@@ -156,7 +160,7 @@ pub fn binary_op(
Rem | Div => {
// int_min / -1
if r == -1 && l == (1 << (size - 1)) {
return Ok((Scalar::Bytes(l), true));
return Ok((Scalar::Bits { bits: l, defined: size as u8 }, true));
}
},
_ => {},
......@@ -170,15 +174,22 @@ pub fn binary_op(
}
let result = result as u128;
let truncated = self.truncate(result, left_ty)?;
return Ok((Scalar::Bytes(truncated), oflo));
return Ok((Scalar::Bits {
bits: truncated,
defined: size as u8,
}, oflo));
}
}
if let ty::TyFloat(fty) = left_ty.sty {
macro_rules! float_math {
($ty:path) => {{
($ty:path, $bitsize:expr) => {{
let l = <$ty>::from_bits(l);
let r = <$ty>::from_bits(r);
let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
bits: res.value.to_bits(),
defined: $bitsize,
};
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
Ne => Scalar::from_bool(l != r),
......@@ -186,22 +197,24 @@ pub fn binary_op(
Le => Scalar::from_bool(l <= r),
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
Add => Scalar::Bytes((l + r).value.to_bits()),
Sub => Scalar::Bytes((l - r).value.to_bits()),
Mul => Scalar::Bytes((l * r).value.to_bits()),
Div => Scalar::Bytes((l / r).value.to_bits()),
Rem => Scalar::Bytes((l % r).value.to_bits()),
Add => bitify(l + r),
Sub => bitify(l - r),
Mul => bitify(l * r),
Div => bitify(l / r),
Rem => bitify(l % r),
_ => bug!("invalid float op: `{:?}`", bin_op),
};
return Ok((val, false));
}};
}
match fty {
FloatTy::F32 => float_math!(Single),
FloatTy::F64 => float_math!(Double),
FloatTy::F32 => float_math!(Single, 32),
FloatTy::F64 => float_math!(Double, 64),
}
}
let bitsize = left_ty.scalar_size(self).expect("operator type must be scalar").bits() as u8;
// only ints left
let val = match bin_op {
Eq => Scalar::from_bool(l == r),
......@@ -212,9 +225,9 @@ pub fn binary_op(
Gt => Scalar::from_bool(l > r),
Ge => Scalar::from_bool(l >= r),
BitOr => Scalar::Bytes(l | r),
BitAnd => Scalar::Bytes(l & r),
BitXor => Scalar::Bytes(l ^ r),
BitOr => Scalar::Bits { bits: l | r, defined: bitsize },
BitAnd => Scalar::Bits { bits: l & r, defined: bitsize },
BitXor => Scalar::Bits { bits: l ^ r, defined: bitsize },
Add | Sub | Mul | Rem | Div => {
let op: fn(u128, u128) -> (u128, bool) = match bin_op {
......@@ -229,7 +242,10 @@ pub fn binary_op(
};
let (result, oflo) = op(l, r);
let truncated = self.truncate(result, left_ty)?;
return Ok((Scalar::Bytes(truncated), oflo || truncated != result));
return Ok((Scalar::Bits {
bits: truncated,
defined: bitsize,
}, oflo || truncated != result));
}
_ => {
......@@ -258,8 +274,9 @@ pub fn unary_op(
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
let bytes = val.to_bytes()?;
let size = self.layout_of(ty)?.size.bits();
let size = self.layout_of(ty)?.size;
let bytes = val.to_bits(size)?;
let size = size.bits();
let result_bytes = match (un_op, &ty.sty) {
......@@ -274,6 +291,9 @@ pub fn unary_op(
(Neg, _) => (-(bytes as i128)) as u128,
};
Ok(Scalar::Bytes(self.truncate(result_bytes, ty)?))
Ok(Scalar::Bits {
bits: self.truncate(result_bytes, ty)?,
defined: size as u8,
})
}
}
......@@ -35,7 +35,7 @@ pub enum PlaceExtra {
impl<'tcx> Place {
/// Produces a Place that will error if attempted to be read from
pub fn undef() -> Self {
Self::from_primval_ptr(Scalar::Undef.into(), Align::from_bytes(1, 1).unwrap())
Self::from_primval_ptr(Scalar::undef().into(), Align::from_bytes(1, 1).unwrap())
}
pub fn from_primval_ptr(ptr: Scalar, align: Align) -> Self {
......@@ -128,7 +128,7 @@ pub fn read_field(
let field_index = field.index();
let field = base_layout.field(self, field_index)?;
if field.size.bytes() == 0 {
return Ok(Some((Value::Scalar(Scalar::Undef), field.ty)))
return Ok(Some((Value::Scalar(Scalar::undef()), field.ty)))
}
let offset = base_layout.fields.offset(field_index);
match base {
......@@ -387,8 +387,10 @@ pub fn eval_place_projection(
Index(local) => {
let value = self.frame().get_local(local)?;
let ty = self.tcx.types.usize;
let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?;
self.place_index(base, base_ty, n)
let n = self
.value_to_primval(ValTy { value, ty })?
.to_bits(self.tcx.data_layout.pointer_size)?;
self.place_index(base, base_ty, n as u64)
}
ConstantIndex {
......
......@@ -28,7 +28,7 @@ pub(crate) fn drop_place(
ptr,
align: _,
extra: PlaceExtra::Length(len),
} => ptr.to_value_with_len(len),
} => ptr.to_value_with_len(len, self.tcx.tcx),
Place::Ptr {
ptr,
align: _,
......
......@@ -44,7 +44,7 @@ pub(super) fn eval_terminator(
let mut target_block = targets[targets.len() - 1];
for (index, &const_int) in values.iter().enumerate() {
if discr_prim.to_bytes()? == const_int {
if discr_prim.to_bits(discr_val.ty.scalar_size(self.tcx.tcx).expect("discr must be scalar"))? == const_int {
target_block = targets[index];
break;
}
......@@ -153,10 +153,10 @@ pub(super) fn eval_terminator(
BoundsCheck { ref len, ref index } => {
let len = self.eval_operand_to_primval(len)
.expect("can't eval len")
.to_u64()?;
.to_bits(self.memory().pointer_size())? as u64;
let index = self.eval_operand_to_primval(index)
.expect("can't eval index")
.to_u64()?;
.to_bits(self.memory().pointer_size())? as u64;
err!(BoundsCheck { len, index })
}
Overflow(op) => Err(Overflow(op).into()),
......@@ -359,7 +359,7 @@ fn eval_fn_call(
self.write_value(valty, dest)?;
}
}
Value::Scalar(Scalar::Undef) => {}
Value::Scalar(Scalar::Bits { defined: 0, .. }) => {}
other => {
trace!("{:#?}, {:#?}", other, layout);
let mut layout = layout;
......
......@@ -38,9 +38,15 @@ pub fn get_vtable(
self.memory.write_ptr_sized_unsigned(vtable, ptr_align, drop.into())?;
let size_ptr = vtable.offset(ptr_size, &self)?;
self.memory.write_ptr_sized_unsigned(size_ptr, ptr_align, Scalar::Bytes(size as u128))?;
self.memory.write_ptr_sized_unsigned(size_ptr, ptr_align, Scalar::Bits {
bits: size as u128,
defined: ptr_size.bits() as u8,
})?;
let align_ptr = vtable.offset(ptr_size * 2, &self)?;
self.memory.write_ptr_sized_unsigned(align_ptr, ptr_align, Scalar::Bytes(align as u128))?;
self.memory.write_ptr_sized_unsigned(align_ptr, ptr_align, Scalar::Bits {
bits: align as u128,
defined: ptr_size.bits() as u8,
})?;
for (i, method) in methods.iter().enumerate() {
if let Some((def_id, substs)) = *method {
......@@ -65,9 +71,10 @@ pub fn read_drop_type_from_vtable(
) -> EvalResult<'tcx, Option<ty::Instance<'tcx>>> {
// we don't care about the pointee type, we just want a pointer
let pointer_align = self.tcx.data_layout.pointer_align;
let pointer_size = self.tcx.data_layout.pointer_size.bits() as u8;
match self.read_ptr(vtable, pointer_align, self.tcx.mk_nil_ptr())? {
// some values don't need to call a drop impl, so the value is null
Value::Scalar(Scalar::Bytes(0)) => Ok(None),
Value::Scalar(Scalar::Bits { bits: 0, defined} ) if defined == pointer_size => Ok(None),
Value::Scalar(Scalar::Ptr(drop_fn)) => self.memory.get_fn(drop_fn).map(Some),
_ => err!(ReadBytesAsPointer),
}
......@@ -79,11 +86,11 @@ pub fn read_size_and_align_from_vtable(
) -> EvalResult<'tcx, (Size, Align)> {
let pointer_size = self.memory.pointer_size();
let pointer_align = self.tcx.data_layout.pointer_align;
let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.to_bytes()? as u64;
let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.to_bits(pointer_size)? as u64;
let align = self.memory.read_ptr_sized(
vtable.offset(pointer_size * 2, self)?,
pointer_align
)?.to_bytes()? as u64;
)?.to_bits(pointer_size)? as u64;
Ok((Size::from_bytes(size), Align::from_bytes(align, align).unwrap()))
}
}
......@@ -283,7 +283,10 @@ fn const_prop(
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
let param_env = self.tcx.param_env(self.source.def_id);
type_size_of(self.tcx, param_env, ty).map(|n| (
Value::Scalar(Scalar::Bytes(n as u128)),
Value::Scalar(Scalar::Bits {
bits: n as u128,
defined: self.tcx.data_layout.pointer_size.bits() as u8,
}),
self.tcx.types.usize,
span,
))
......@@ -326,10 +329,10 @@ fn const_prop(
this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
})?;
if op == BinOp::Shr || op == BinOp::Shl {
let param_env = self.tcx.param_env(self.source.def_id);
let left_ty = left.ty(self.mir, self.tcx);
let bits = self.tcx.layout_of(param_env.and(left_ty)).unwrap().size.bits();
if r.to_bytes().ok().map_or(false, |b| b >= bits as u128) {
let left_bits = left_ty.scalar_size(self.tcx).unwrap().bits();
let right_size = right.1.scalar_size(self.tcx).unwrap();
if r.to_bits(right_size).ok().map_or(false, |b| b >= left_bits as u128) {
let scope_info = match self.mir.visibility_scope_info {
ClearCrossCrate::Set(ref data) => data,
ClearCrossCrate::Clear => return None,
......@@ -520,14 +523,14 @@ fn visit_terminator_kind(
BoundsCheck { ref len, ref index } => {
let len = self.eval_operand(len).expect("len must be const");
let len = match len.0 {
Value::Scalar(Scalar::Bytes(n)) => n,
Value::Scalar(Scalar::Bits { bits, ..}) => bits,
_ => bug!("const len not primitive: {:?}", len),
};
let index = self
.eval_operand(index)
.expect("index must be const");
let index = match index.0 {
Value::Scalar(Scalar::Bytes(n)) => n,
Value::Scalar(Scalar::Bits { bits, .. }) => bits,
_ => bug!("const index not primitive: {:?}", index),
};
format!(
......
......@@ -39,7 +39,7 @@ fn run_pass<'a, 'tcx>(&self,
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
literal: Literal::Value { ref value }, ..
}), switch_ty, ref values, ref targets, .. } => {
if let Some(constint) = value.assert_bits(switch_ty) {
if let Some(constint) = value.assert_bits(tcx, switch_ty) {
let (otherwise, targets) = targets.split_last().unwrap();
let mut ret = TerminatorKind::Goto { target: *otherwise };
for (&v, t) in values.iter().zip(targets.iter()) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册