add helper method for ptr ops on Scalar; reduce unnecessary large operand of overflowing_signed_offset

This commit is contained in:
Ralf Jung 2020-03-24 10:16:39 +01:00
parent afcb6342fa
commit 1d67ca00a1
2 changed files with 35 additions and 49 deletions

View file

@ -73,10 +73,8 @@ pub trait PointerArithmetic: layout::HasDataLayout {
self.truncate_to_ptr(res)
}
// Overflow checking only works properly on the range from -u64 to +u64.
#[inline]
fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) {
// FIXME: is it possible to over/underflow here?
fn overflowing_signed_offset(&self, val: u64, i: i64) -> (u64, bool) {
if i < 0 {
// Trickery to ensure that `i64::MIN` works fine: compute `n = -i`.
// This formula only works for true negative values; it overflows for zero!
@ -84,6 +82,7 @@ pub trait PointerArithmetic: layout::HasDataLayout {
let res = val.overflowing_sub(n);
self.truncate_to_ptr(res)
} else {
// `i >= 0`, so the cast is safe.
self.overflowing_offset(val, i as u64)
}
}
@ -96,7 +95,7 @@ pub trait PointerArithmetic: layout::HasDataLayout {
#[inline]
fn signed_offset<'tcx>(&self, val: u64, i: i64) -> InterpResult<'tcx, u64> {
let (res, over) = self.overflowing_signed_offset(val, i128::from(i));
let (res, over) = self.overflowing_signed_offset(val, i);
if over { throw_ub!(PointerArithOverflow) } else { Ok(res) }
}
}
@ -189,14 +188,14 @@ impl<'tcx, Tag> Pointer<Tag> {
}
#[inline]
pub fn overflowing_signed_offset(self, i: i128, cx: &impl HasDataLayout) -> (Self, bool) {
pub fn overflowing_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> (Self, bool) {
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
(Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
}
#[inline(always)]
pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
self.overflowing_signed_offset(i128::from(i), cx).0
self.overflowing_signed_offset(i, cx).0
}
#[inline(always)]

View file

@ -1,11 +1,12 @@
use std::convert::TryFrom;
use std::fmt;
use rustc_apfloat::{
ieee::{Double, Single},
Float,
};
use rustc_macros::HashStable;
use std::fmt;
use rustc_target::abi::TargetDataLayout;
use crate::ty::{
layout::{HasDataLayout, Size},
@ -200,68 +201,54 @@ impl<'tcx, Tag> Scalar<Tag> {
Scalar::Raw { data: 0, size: 0 }
}
#[inline]
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
let dl = cx.data_layout();
#[inline(always)]
fn ptr_op(
self,
dl: &TargetDataLayout,
f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
f_ptr: impl FnOnce(Pointer<Tag>) -> InterpResult<'tcx, Pointer<Tag>>,
) -> InterpResult<'tcx, Self> {
match self {
Scalar::Raw { data, size } => {
assert_eq!(u64::from(size), dl.pointer_size.bytes());
Ok(Scalar::Raw {
data: u128::from(dl.offset(u64::try_from(data).unwrap(), i.bytes())?),
size,
})
Ok(Scalar::Raw { data: u128::from(f_int(u64::try_from(data).unwrap())?), size })
}
Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr),
Scalar::Ptr(ptr) => Ok(Scalar::Ptr(f_ptr(ptr)?)),
}
}
#[inline]
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
let dl = cx.data_layout();
self.ptr_op(dl, |int| dl.offset(int, i.bytes()), |ptr| ptr.offset(i, dl))
}
#[inline]
pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
let dl = cx.data_layout();
match self {
Scalar::Raw { data, size } => {
assert_eq!(u64::from(size), dl.pointer_size.bytes());
Scalar::Raw {
data: u128::from(
dl.overflowing_offset(u64::try_from(data).unwrap(), i.bytes()).0,
),
size,
}
}
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_offset(i, dl)),
}
self.ptr_op(
dl,
|int| Ok(dl.overflowing_offset(int, i.bytes()).0),
|ptr| Ok(ptr.wrapping_offset(i, dl)),
)
.unwrap()
}
#[inline]
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
let dl = cx.data_layout();
match self {
Scalar::Raw { data, size } => {
assert_eq!(u64::from(size), dl.pointer_size.bytes());
Ok(Scalar::Raw {
data: u128::from(dl.signed_offset(u64::try_from(data).unwrap(), i)?),
size,
})
}
Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr),
}
self.ptr_op(dl, |int| dl.signed_offset(int, i), |ptr| ptr.signed_offset(i, dl))
}
#[inline]
pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
let dl = cx.data_layout();
match self {
Scalar::Raw { data, size } => {
assert_eq!(u64::from(size), dl.pointer_size.bytes());
Scalar::Raw {
data: u128::from(
dl.overflowing_signed_offset(u64::try_from(data).unwrap(), i128::from(i)).0,
),
size,
}
}
Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_signed_offset(i, dl)),
}
self.ptr_op(
dl,
|int| Ok(dl.overflowing_signed_offset(int, i).0),
|ptr| Ok(ptr.wrapping_signed_offset(i, dl)),
)
.unwrap()
}
#[inline]