change Value::Bytes
to Value::Bits
This commit is contained in:
parent
3bbf2fd715
commit
64a75ecc80
24 changed files with 436 additions and 281 deletions
|
@ -473,11 +473,24 @@ impl_stable_hash_for!(enum ::syntax::ast::Mutability {
|
|||
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 @@ impl<'tcx> ConstValue<'tcx> {
|
|||
}
|
||||
|
||||
#[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 @@ impl<'tcx> ty::TypeFoldable<'tcx> for Value {
|
|||
}
|
||||
|
||||
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 @@ impl From<Pointer> for Scalar {
|
|||
/// 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 @@ impl<'tcx> Scalar {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ impl<'tcx> TerminatorKind<'tcx> {
|
|||
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 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||
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 middle::region;
|
|||
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 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
|||
_ => 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 @@ impl<'tcx> Const<'tcx> {
|
|||
#[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 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
#[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 @@ impl<'tcx> Const<'tcx> {
|
|||
}
|
||||
|
||||
#[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 @@ impl<'tcx> Const<'tcx> {
|
|||
|
||||
#[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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
|
||||
// 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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
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 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, '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::def_id::{DefId, LOCAL_CRATE};
|
|||
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 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, '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 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
|
||||
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 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
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 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
|
|||
};
|
||||
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 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
|||
};
|
||||
// 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 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
|||
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 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
|
|||
};
|
||||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
|
|||
"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 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
::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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
|
||||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
// 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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
dataful_variant as u128
|
||||
}
|
||||
},
|
||||
Scalar::Undef => return err!(ReadUndefBytes),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -990,7 +1014,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
|
||||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
) -> 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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
|
|||
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 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
// 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
} 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
|
|||
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 @@ pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
|||
|
||||
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 @@ pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
// 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
};
|
||||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
}
|
||||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
};
|
||||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
(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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
) -> 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 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||
) -> 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 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
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 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
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 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
|
|||
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 @@ impl MirPass for SimplifyBranches {
|
|||
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()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue