From 1d67ca00a1b2f667068e24d4f98676f3ec62de42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2020 10:16:39 +0100 Subject: [PATCH] add helper method for ptr ops on Scalar; reduce unnecessary large operand of overflowing_signed_offset --- src/librustc/mir/interpret/pointer.rs | 11 ++-- src/librustc/mir/interpret/value.rs | 73 +++++++++++---------------- 2 files changed, 35 insertions(+), 49 deletions(-) diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index ff479aee4e0a..3f841cfb3300 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -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 { } #[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)] diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index f00952e3725e..706cf1cd09a7 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -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 { 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) -> InterpResult<'tcx, Pointer>, + ) -> 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]