}
}
-pub fn write_target_int(
- endianness: layout::Endian,
- mut target: &mut [u8],
- data: i128,
-) -> Result<(), io::Error> {
- let len = target.len();
- match endianness {
- layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
- layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
- }
-}
-
pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
match endianness {
layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
}
}
+////////////////////////////////////////////////////////////////////////////////
+// Methods to faciliate working with signed integers stored in a u128
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn sign_extend(value: u128, size: Size) -> u128 {
+ let size = size.bits();
+ // sign extend
+ let shift = 128 - size;
+ // shift the unsigned value to the left
+ // and back to the right as signed (essentially fills with FF on the left)
+ (((value << shift) as i128) >> shift) as u128
+}
+
+pub fn truncate(value: u128, size: Size) -> u128 {
+ let size = size.bits();
+ let shift = 128 - size;
+ // truncate (shift left to drop out leftover values, shift right to fill with zeroes)
+ (value << shift) >> shift
+}
+
////////////////////////////////////////////////////////////////////////////////
// Undefined byte tracking
////////////////////////////////////////////////////////////////////////////////
/// The raw bytes of a simple value.
Bits {
/// The first `size` bytes are the value.
- /// Do not try to read less or more bytes that that
+ /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
size: u8,
bits: u128,
},
pub use self::check_match::check_crate;
pub(crate) use self::check_match::check_match;
-use interpret::{const_field, const_variant_index, self};
+use interpret::{const_field, const_variant_index};
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
-use rustc::mir::interpret::{Scalar, GlobalId, ConstValue};
+use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
ty::TyInt(_) => {
let layout = tcx.layout_of(ty).ok()?;
assert!(layout.abi.is_signed());
- let a = interpret::sign_extend(a, layout.size);
- let b = interpret::sign_extend(b, layout.size);
+ let a = sign_extend(a, layout.size);
+ let b = sign_extend(b, layout.size);
Some((a as i128).cmp(&(b as i128)))
},
_ => Some(a.cmp(&b)),
use rustc::ty::{self, Ty, TypeAndMut};
-use rustc::ty::layout::{self, TyLayout};
+use rustc::ty::layout::{self, TyLayout, Size};
use syntax::ast::{FloatTy, IntTy, UintTy};
use rustc_apfloat::ieee::{Single, Double};
-use rustc::mir::interpret::{Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind};
+use rustc::mir::interpret::{
+ Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind,
+ truncate, sign_extend
+};
use rustc::mir::CastKind;
use rustc_apfloat::Float;
match val {
Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_layout.ty),
Scalar::Bits { bits, size } => {
- assert_eq!(size as u64, src_layout.size.bytes());
- match src_layout.ty.sty {
- TyFloat(fty) => self.cast_from_float(bits, fty, dest_layout.ty),
- _ => self.cast_from_int(bits, src_layout, dest_layout),
+ debug_assert_eq!(size as u64, src_layout.size.bytes());
+ debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
+ "Unexpected value of size {} before casting", size);
+
+ let res = match src_layout.ty.sty {
+ TyFloat(fty) => self.cast_from_float(bits, fty, dest_layout.ty)?,
+ _ => self.cast_from_int(bits, src_layout, dest_layout)?,
+ };
+
+ // Sanity check
+ match res {
+ Scalar::Ptr(_) => bug!("Fabricated a ptr value from an int...?"),
+ Scalar::Bits { bits, size } => {
+ debug_assert_eq!(size as u64, dest_layout.size.bytes());
+ debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
+ "Unexpected value of size {} after casting", size);
+ }
}
+ // Done
+ Ok(res)
}
}
}
// float -> uint
TyUint(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
- match fty {
- FloatTy::F32 => Ok(Scalar::Bits {
- bits: Single::from_bits(bits).to_u128(width).value,
- size: (width / 8) as u8,
- }),
- FloatTy::F64 => Ok(Scalar::Bits {
- bits: Double::from_bits(bits).to_u128(width).value,
- size: (width / 8) as u8,
- }),
- }
+ let v = match fty {
+ FloatTy::F32 => Single::from_bits(bits).to_u128(width).value,
+ FloatTy::F64 => Double::from_bits(bits).to_u128(width).value,
+ };
+ // This should already fit the bit width
+ Ok(Scalar::Bits {
+ bits: v,
+ size: (width / 8) as u8,
+ })
},
// float -> int
TyInt(t) => {
let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
- match fty {
- FloatTy::F32 => Ok(Scalar::Bits {
- bits: Single::from_bits(bits).to_i128(width).value as u128,
- size: (width / 8) as u8,
- }),
- FloatTy::F64 => Ok(Scalar::Bits {
- bits: Double::from_bits(bits).to_i128(width).value as u128,
- size: (width / 8) as u8,
- }),
- }
+ let v = match fty {
+ FloatTy::F32 => Single::from_bits(bits).to_i128(width).value,
+ FloatTy::F64 => Double::from_bits(bits).to_i128(width).value,
+ };
+ // We got an i128, but we may need something smaller. We have to truncate ourselves.
+ let truncated = truncate(v as u128, Size::from_bits(width as u64));
+ assert_eq!(sign_extend(truncated, Size::from_bits(width as u64)) as i128, v,
+ "truncating and extending changed the value?!?");
+ Ok(Scalar::Bits {
+ bits: truncated,
+ size: (width / 8) as u8,
+ })
},
// f64 -> f32
TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
GlobalId, Scalar, FrameInfo, AllocType,
EvalResult, EvalErrorKind,
ScalarMaybeUndef,
+ truncate, sign_extend,
};
use syntax::source_map::{self, Span};
}
}
+ #[inline(always)]
pub fn frame(&self) -> &Frame<'mir, 'tcx> {
self.stack.last().expect("no call frames exist")
}
+ #[inline(always)]
pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
self.stack.last_mut().expect("no call frames exist")
}
(frames, self.tcx.span)
}
+ #[inline(always)]
pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
assert!(ty.abi.is_signed());
- super::sign_extend(value, ty.size)
+ sign_extend(value, ty.size)
}
+ #[inline(always)]
pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
- super::truncate(value, ty.size)
+ truncate(value, ty.size)
}
fn dump_field_name(&self, s: &mut String, ty: Ty<'tcx>, i: usize, variant: usize) -> ::std::fmt::Result {
}
}
-pub fn sign_extend(value: u128, size: Size) -> u128 {
- let size = size.bits();
- // sign extend
- let shift = 128 - size;
- // shift the unsigned value to the left
- // and back to the right as signed (essentially fills with FF on the left)
- (((value << shift) as i128) >> shift) as u128
-}
-
-pub fn truncate(value: u128, size: Size) -> u128 {
- let size = size.bits();
- let shift = 128 - size;
- // truncate (shift left to drop out leftover values, shift right to fill with zeroes)
- (value << shift) >> shift
-}
use rustc::ty::query::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout, Size};
use rustc::mir::interpret::{Pointer, AllocId, Allocation, AccessKind, ScalarMaybeUndef,
- EvalResult, Scalar, EvalErrorKind, GlobalId, AllocType};
-pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
+ EvalResult, Scalar, EvalErrorKind, GlobalId, AllocType, truncate};
+pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
use syntax::ast::Mutability;
val: ScalarMaybeUndef,
type_size: Size,
type_align: Align,
- signed: bool,
) -> EvalResult<'tcx> {
let endianness = self.endianness();
self.check_align(ptr, ptr_align)?;
Scalar::Bits { bits, size } => {
assert_eq!(size as u64, type_size.bytes());
+ assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
+ "Unexpected value of size {} when writing to memory", size);
bits
},
};
{
let dst = self.get_bytes_mut(ptr, type_size, ptr_align.min(type_align))?;
- // TODO: Why do we still need `signed` here? We do NOT have it for loading!
- if signed {
- write_target_int(endianness, dst, bytes as i128).unwrap();
- } else {
- write_target_uint(endianness, dst, bytes).unwrap();
- }
+ write_target_uint(endianness, dst, bytes).unwrap();
}
// See if we have to also write a relocation
Ok(())
}
- pub fn write_ptr_sized_unsigned(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef) -> EvalResult<'tcx> {
+ pub fn write_ptr_sized(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef) -> EvalResult<'tcx> {
let ptr_size = self.pointer_size();
- self.write_scalar(ptr.into(), ptr_align, val, ptr_size, ptr_align, false)
+ self.write_scalar(ptr.into(), ptr_align, val, ptr_size, ptr_align)
}
fn int_align(&self, size: Size) -> Align {
mod const_eval;
pub use self::eval_context::{
- EvalContext, Frame, StackPopCleanup,
- sign_extend, truncate, LocalValue,
+ EvalContext, Frame, StackPopCleanup, LocalValue,
};
pub use self::place::{Place, PlaceExtra, PlaceTy, MemPlace, MPlaceTy};
// correct if we never look at this data with the wrong type.
match value {
Value::Scalar(scalar) => {
- let signed = match dest.layout.abi {
- layout::Abi::Scalar(ref scal) => match scal.value {
- layout::Primitive::Int(_, signed) => signed,
- _ => false,
- },
- _ => false,
- };
self.memory.write_scalar(
- dest.ptr, dest.align, scalar, dest.layout.size, dest.layout.align, signed
+ dest.ptr, dest.align, scalar, dest.layout.size, dest.layout.align
)
}
Value::ScalarPair(a_val, b_val) => {
let a_ptr = dest.ptr;
let b_offset = a_size.abi_align(b_align);
let b_ptr = a_ptr.ptr_offset(b_offset, &self)?.into();
- // TODO: What about signedess?
- self.memory.write_scalar(a_ptr, dest.align, a_val, a_size, a_align, false)?;
- self.memory.write_scalar(b_ptr, dest.align, b_val, b_size, b_align, false)
+
+ self.memory.write_scalar(a_ptr, dest.align, a_val, a_size, a_align)?;
+ self.memory.write_scalar(b_ptr, dest.align, b_val, b_size, b_align)
}
}
}
let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
let drop = self.memory.create_fn_alloc(drop);
- self.memory.write_ptr_sized_unsigned(vtable, ptr_align, Scalar::Ptr(drop).into())?;
+ self.memory.write_ptr_sized(vtable, ptr_align, Scalar::Ptr(drop).into())?;
let size_ptr = vtable.offset(ptr_size, &self)?;
- self.memory.write_ptr_sized_unsigned(size_ptr, ptr_align, Scalar::Bits {
+ self.memory.write_ptr_sized(size_ptr, ptr_align, Scalar::Bits {
bits: size as u128,
size: ptr_size.bytes() as u8,
}.into())?;
let align_ptr = vtable.offset(ptr_size * 2, &self)?;
- self.memory.write_ptr_sized_unsigned(align_ptr, ptr_align, Scalar::Bits {
+ self.memory.write_ptr_sized(align_ptr, ptr_align, Scalar::Bits {
bits: align as u128,
size: ptr_size.bytes() as u8,
}.into())?;
let instance = self.resolve(def_id, substs)?;
let fn_ptr = self.memory.create_fn_alloc(instance);
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &self)?;
- self.memory.write_ptr_sized_unsigned(method_ptr, ptr_align, Scalar::Ptr(fn_ptr).into())?;
+ self.memory.write_ptr_sized(method_ptr, ptr_align, Scalar::Ptr(fn_ptr).into())?;
}
}