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

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

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