u128
truncation and sign extension are not just interpreter related
This commit is contained in:
parent
e67c768110
commit
abacaf2aef
18 changed files with 73 additions and 89 deletions
|
@ -110,7 +110,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_macros::HashStable;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_target::abi::{Endian, Size};
|
||||
use rustc_target::abi::Endian;
|
||||
|
||||
use crate::mir;
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
|
@ -590,39 +590,6 @@ pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result<u128, i
|
|||
uint
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Methods to facilitate working with signed integers stored in a u128
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Truncates `value` to `size` bits and then sign-extend it to 128 bits
|
||||
/// (i.e., if it is negative, fill with 1's on the left).
|
||||
#[inline]
|
||||
pub fn sign_extend(value: u128, size: Size) -> u128 {
|
||||
let size = size.bits();
|
||||
if size == 0 {
|
||||
// Truncated until nothing is left.
|
||||
return 0;
|
||||
}
|
||||
// Sign-extend it.
|
||||
let shift = 128 - size;
|
||||
// Shift the unsigned value to the left, then shift back to the right as signed
|
||||
// (essentially fills with FF on the left).
|
||||
(((value << shift) as i128) >> shift) as u128
|
||||
}
|
||||
|
||||
/// Truncates `value` to `size` bits.
|
||||
#[inline]
|
||||
pub fn truncate(value: u128, size: Size) -> u128 {
|
||||
let size = size.bits();
|
||||
if size == 0 {
|
||||
// Truncated until nothing is left.
|
||||
return 0;
|
||||
}
|
||||
let shift = 128 - size;
|
||||
// Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
|
||||
(value << shift) >> shift
|
||||
}
|
||||
|
||||
/// Computes the unsigned absolute value without wrapping or panicking.
|
||||
#[inline]
|
||||
pub fn uabs(value: i64) -> u64 {
|
||||
|
|
|
@ -10,7 +10,7 @@ use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
|
|||
|
||||
use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
|
||||
|
||||
use super::{sign_extend, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
|
||||
use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic};
|
||||
|
||||
/// Represents the result of const evaluation via the `eval_to_allocation` query.
|
||||
#[derive(Clone, HashStable, TyEncodable, TyDecodable)]
|
||||
|
@ -448,7 +448,7 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
fn to_signed_with_bit_width(self, bits: u64) -> InterpResult<'static, i128> {
|
||||
let sz = Size::from_bits(bits);
|
||||
let b = self.to_bits(sz)?;
|
||||
Ok(sign_extend(b, sz) as i128)
|
||||
Ok(sz.sign_extend(b) as i128)
|
||||
}
|
||||
|
||||
/// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer.
|
||||
|
@ -479,7 +479,7 @@ impl<'tcx, Tag> Scalar<Tag> {
|
|||
pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> {
|
||||
let sz = cx.data_layout().pointer_size;
|
||||
let b = self.to_bits(sz)?;
|
||||
let b = sign_extend(b, sz) as i128;
|
||||
let b = sz.sign_extend(b) as i128;
|
||||
Ok(i64::try_from(b).unwrap())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::mir::interpret::{sign_extend, truncate, InterpResult};
|
||||
use crate::mir::interpret::InterpResult;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
use rustc_apfloat::Float;
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
|
@ -75,7 +75,7 @@ impl std::fmt::Debug for ConstInt {
|
|||
Ok(())
|
||||
}
|
||||
} else {
|
||||
let max = truncate(u128::MAX, Size::from_bytes(size));
|
||||
let max = Size::from_bytes(size).truncate(u128::MAX);
|
||||
if raw == max {
|
||||
match (size, is_ptr_sized_integral) {
|
||||
(_, true) => write!(fmt, "usize::MAX"),
|
||||
|
@ -174,7 +174,7 @@ impl ScalarInt {
|
|||
// is a packed struct, that would create a possibly unaligned reference, which
|
||||
// is UB.
|
||||
debug_assert_eq!(
|
||||
truncate(self.data, self.size()),
|
||||
self.size().truncate(self.data),
|
||||
{ self.data },
|
||||
"Scalar value {:#x} exceeds size of {} bytes",
|
||||
{ self.data },
|
||||
|
@ -204,7 +204,7 @@ impl ScalarInt {
|
|||
#[inline]
|
||||
pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
|
||||
let data = i.into();
|
||||
if truncate(data, size) == data {
|
||||
if size.truncate(data) == data {
|
||||
Some(Self { data, size: size.bytes() as u8 })
|
||||
} else {
|
||||
None
|
||||
|
@ -215,8 +215,8 @@ impl ScalarInt {
|
|||
pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> {
|
||||
let i = i.into();
|
||||
// `into` performed sign extension, we have to truncate
|
||||
let truncated = truncate(i as u128, size);
|
||||
if sign_extend(truncated, size) as i128 == i {
|
||||
let truncated = size.truncate(i as u128);
|
||||
if size.sign_extend(truncated) as i128 == i {
|
||||
Some(Self { data: truncated, size: size.bytes() as u8 })
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use crate::ich::NodeIdHashingMode;
|
||||
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use crate::mir::interpret::{sign_extend, truncate};
|
||||
use crate::ty::fold::TypeFolder;
|
||||
use crate::ty::layout::IntegerExt;
|
||||
use crate::ty::query::TyCtxtAt;
|
||||
|
@ -38,7 +37,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> {
|
|||
let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size());
|
||||
let x = self.val;
|
||||
// sign extend the raw representation to be an i128
|
||||
let x = sign_extend(x, size) as i128;
|
||||
let x = size.sign_extend(x) as i128;
|
||||
write!(fmt, "{}", x)
|
||||
}
|
||||
_ => write!(fmt, "{}", self.val),
|
||||
|
@ -47,7 +46,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> {
|
|||
}
|
||||
|
||||
fn signed_min(size: Size) -> i128 {
|
||||
sign_extend(1_u128 << (size.bits() - 1), size) as i128
|
||||
size.sign_extend(1_u128 << (size.bits() - 1)) as i128
|
||||
}
|
||||
|
||||
fn signed_max(size: Size) -> i128 {
|
||||
|
@ -77,14 +76,14 @@ impl<'tcx> Discr<'tcx> {
|
|||
let (val, oflo) = if signed {
|
||||
let min = signed_min(size);
|
||||
let max = signed_max(size);
|
||||
let val = sign_extend(self.val, size) as i128;
|
||||
let val = size.sign_extend(self.val) as i128;
|
||||
assert!(n < (i128::MAX as u128));
|
||||
let n = n as i128;
|
||||
let oflo = val > max - n;
|
||||
let val = if oflo { min + (n - (max - val) - 1) } else { val + n };
|
||||
// zero the upper bits
|
||||
let val = val as u128;
|
||||
let val = truncate(val, size);
|
||||
let val = size.truncate(val);
|
||||
(val, oflo)
|
||||
} else {
|
||||
let max = unsigned_max(size);
|
||||
|
@ -650,7 +649,7 @@ impl<'tcx> ty::TyS<'tcx> {
|
|||
let val = match self.kind() {
|
||||
ty::Int(_) | ty::Uint(_) => {
|
||||
let (size, signed) = int_size_and_signed(tcx, self);
|
||||
let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 };
|
||||
let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 };
|
||||
Some(val)
|
||||
}
|
||||
ty::Char => Some(0),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue