Use packed struct instead of manually packing into an array

This commit is contained in:
oli 2020-10-29 10:15:54 +00:00
parent ed7a4adeb3
commit 02131f4dcd
3 changed files with 41 additions and 38 deletions

View File

@ -2,7 +2,6 @@ use crate::mir::interpret::{sign_extend, truncate, InterpErrorInfo, InterpResult
use crate::throw_ub;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_macros::HashStable;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_target::abi::{Size, TargetDataLayout};
use std::convert::{TryFrom, TryInto};
@ -29,7 +28,7 @@ impl std::fmt::Debug for ConstInt {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { int, signed, is_ptr_sized_integral } = *self;
let size = int.size().bytes();
let raw = int.data();
let raw = int.data;
if signed {
let bit_size = size * 8;
let min = 1u128 << (bit_size - 1);
@ -116,41 +115,46 @@ impl std::fmt::Debug for ConstInt {
// FIXME: reuse in `super::int::ConstInt` and `Scalar::Bits`
/// The raw bytes of a simple value.
///
/// This is a packed struct in order to allow this type to be optimally embedded in enums
/// (like Scalar).
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[derive(HashStable)]
#[repr(packed)]
pub struct ScalarInt {
/// The first `size` bytes of `data` are the value.
/// Do not try to read less or more bytes than that. The remaining bytes must be 0.
///
/// This is an array in order to allow this type to be optimally embedded in enums
/// (like Scalar).
bytes: [u8; 16],
data: u128,
size: u8,
}
// Cannot derive these, as the derives take references to the fields, and we
// can't take references to fields of packed structs.
impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut crate::ty::StableHasher) {
{ self.data }.hash_stable(hcx, hasher);
self.size.hash_stable(hcx, hasher);
}
}
impl<S: Encoder> Encodable<S> for ScalarInt {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_u128(self.data())?;
s.emit_u128(self.data)?;
s.emit_u8(self.size)
}
}
impl<D: Decoder> Decodable<D> for ScalarInt {
fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
Ok(ScalarInt { bytes: d.read_u128()?.to_ne_bytes(), size: d.read_u8()? })
Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? })
}
}
impl ScalarInt {
pub const TRUE: ScalarInt = ScalarInt { bytes: 1_u128.to_ne_bytes(), size: 1 };
pub const TRUE: ScalarInt = ScalarInt { data: 1_u128, size: 1 };
pub const FALSE: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 1 };
pub const FALSE: ScalarInt = ScalarInt { data: 0_u128, size: 1 };
pub const ZST: ScalarInt = ScalarInt { bytes: 0_u128.to_ne_bytes(), size: 0 };
fn data(self) -> u128 {
u128::from_ne_bytes(self.bytes)
}
pub const ZST: ScalarInt = ScalarInt { data: 0_u128, size: 0 };
#[inline]
pub fn size(self) -> Size {
@ -164,10 +168,10 @@ impl ScalarInt {
#[inline(always)]
fn check_data(self) {
debug_assert_eq!(
truncate(self.data(), self.size()),
self.data(),
truncate(self.data, self.size()),
{ self.data },
"Scalar value {:#x} exceeds size of {} bytes",
self.data(),
{ self.data },
self.size
);
}
@ -179,7 +183,7 @@ impl ScalarInt {
#[inline]
pub fn null(size: Size) -> Self {
Self { bytes: [0; 16], size: size.bytes() as u8 }
Self { data: 0, size: size.bytes() as u8 }
}
pub(crate) fn ptr_sized_op<'tcx>(
@ -188,17 +192,14 @@ impl ScalarInt {
f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
) -> InterpResult<'tcx, Self> {
assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
Ok(Self {
bytes: u128::from(f_int(u64::try_from(self.data()).unwrap())?).to_ne_bytes(),
size: self.size,
})
Ok(Self { data: u128::from(f_int(u64::try_from(self.data).unwrap())?), size: self.size })
}
#[inline]
pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
let data = i.into();
if truncate(data, size) == data {
Some(Self { bytes: data.to_ne_bytes(), size: size.bytes() as u8 })
Some(Self { data, size: size.bytes() as u8 })
} else {
None
}
@ -210,7 +211,7 @@ impl ScalarInt {
// `into` performed sign extension, we have to truncate
let truncated = truncate(i as u128, size);
if sign_extend(truncated, size) as i128 == i {
Some(Self { bytes: truncated.to_ne_bytes(), size: size.bytes() as u8 })
Some(Self { data: truncated, size: size.bytes() as u8 })
} else {
None
}
@ -221,7 +222,7 @@ impl ScalarInt {
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
assert_eq!(target_size.bytes(), u64::from(self.size));
self.check_data();
self.data()
self.data
}
#[inline]
@ -234,7 +235,7 @@ impl ScalarInt {
});
}
self.check_data();
Ok(self.data())
Ok(self.data)
}
}
@ -245,7 +246,7 @@ macro_rules! from {
#[inline]
fn from(u: $ty) -> Self {
Self {
bytes: u128::from(u).to_ne_bytes(),
data: u128::from(u),
size: std::mem::size_of::<$ty>() as u8,
}
}
@ -274,7 +275,7 @@ try_from!(u8, u16, u32, u64, u128);
impl From<char> for ScalarInt {
#[inline]
fn from(c: char) -> Self {
Self { bytes: (c as u128).to_ne_bytes(), size: std::mem::size_of::<char>() as u8 }
Self { data: c as u128, size: std::mem::size_of::<char>() as u8 }
}
}
@ -291,7 +292,7 @@ impl From<Single> for ScalarInt {
#[inline]
fn from(f: Single) -> Self {
// We trust apfloat to give us properly truncated data.
Self { bytes: f.to_bits().to_ne_bytes(), size: 4 }
Self { data: f.to_bits(), size: 4 }
}
}
@ -307,7 +308,7 @@ impl From<Double> for ScalarInt {
#[inline]
fn from(f: Double) -> Self {
// We trust apfloat to give us properly truncated data.
Self { bytes: f.to_bits().to_ne_bytes(), size: 8 }
Self { data: f.to_bits(), size: 8 }
}
}
@ -335,6 +336,6 @@ impl fmt::LowerHex for ScalarInt {
self.check_data();
// Format as hex number wide enough to fit any value of the given `size`.
// So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014".
write!(f, "{:01$x}", self.data(), self.size as usize * 2)
write!(f, "{:01$x}", { self.data }, self.size as usize * 2)
}
}

View File

@ -982,8 +982,8 @@ pub trait PrettyPrinter<'tcx>:
None => p!("<dangling pointer>"),
},
// Bool
(Scalar::Raw(ScalarInt::FALSE), ty::Bool) => p!("false"),
(Scalar::Raw(ScalarInt::TRUE), ty::Bool) => p!("true"),
(Scalar::Raw(int), ty::Bool) if int == ScalarInt::FALSE => p!("false"),
(Scalar::Raw(int), ty::Bool) if int == ScalarInt::TRUE => p!("true"),
// Float
(Scalar::Raw(int), ty::Float(ast::FloatTy::F32)) => {
p!(write("{}f32", Single::try_from(int).unwrap()))
@ -1025,7 +1025,9 @@ pub trait PrettyPrinter<'tcx>:
)?;
}
// For function type zsts just printing the path is enough
(Scalar::Raw(ScalarInt::ZST), ty::FnDef(d, s)) => p!(print_value_path(*d, s)),
(Scalar::Raw(int), ty::FnDef(d, s)) if int == ScalarInt::ZST => {
p!(print_value_path(*d, s))
}
// Nontrivial types with scalar bit representation
(Scalar::Raw(int), _) => {
let print = |mut this: Self| {

View File

@ -3,8 +3,8 @@
// revisions: legacy v0
//[legacy]compile-flags: -Z symbol-mangling-version=legacy
//[v0]compile-flags: -Z symbol-mangling-version=v0
//[legacy]normalize-stderr-32bit: "h30edc7aa010c48ae" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-64bit: "h56362331c4f93d19" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-32bit: "hee444285569b39c2" -> "SYMBOL_HASH"
//[legacy]normalize-stderr-64bit: "h310ea0259fc3d32d" -> "SYMBOL_HASH"
#![feature(optin_builtin_traits, rustc_attrs)]
#![allow(dead_code)]