From 0529dc818f4f603c5419e25f44bd1a0b7526c6ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 12:45:21 +0100 Subject: [PATCH] proide ptr_wrapping_offset on Scalars --- src/librustc/mir/interpret/mod.rs | 99 +++++++++++++++-------------- src/librustc/mir/interpret/value.rs | 47 +++++++++----- 2 files changed, 84 insertions(+), 62 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index f8a5dbc6905..e2abf7970d6 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -91,12 +91,33 @@ fn pointer_size(&self) -> Size { } //// Trunace the given value to the pointer size; also return whether there was an overflow + #[inline] fn truncate_to_ptr(&self, val: u128) -> (u64, bool) { let max_ptr_plus_1 = 1u128 << self.pointer_size().bits(); ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1) } + #[inline] + fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> { + let (res, over) = self.overflowing_offset(val, i); + if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } + } + + #[inline] + fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) { + let (res, over1) = val.overflowing_add(i); + let (res, over2) = self.truncate_to_ptr(u128::from(res)); + (res, over1 || over2) + } + + #[inline] + fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> { + let (res, over) = self.overflowing_signed_offset(val, i128::from(i)); + if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(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? if i < 0 { @@ -108,26 +129,6 @@ fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) { self.overflowing_offset(val, i as u64) } } - - fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) { - let (res, over1) = val.overflowing_add(i); - let (res, over2) = self.truncate_to_ptr(res as u128); - (res, over1 || over2) - } - - fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_signed_offset(val, i as i128); - if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } - } - - fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_offset(val, i); - if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } - } - - fn wrapping_signed_offset(&self, val: u64, i: i64) -> u64 { - self.overflowing_signed_offset(val, i as i128).0 - } } impl PointerArithmetic for T {} @@ -176,32 +177,7 @@ pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self { Pointer { alloc_id, offset, tag } } - pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { - Pointer::new_with_tag( - self.alloc_id, - Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)), - self.tag, - ) - } - - pub fn overflowing_signed_offset(self, i: i128, 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) - } - - pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { - Ok(Pointer::new_with_tag( - self.alloc_id, - Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?), - self.tag, - )) - } - - pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes()); - (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over) - } - + #[inline] pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { Ok(Pointer::new_with_tag( self.alloc_id, @@ -211,6 +187,37 @@ pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> } #[inline] + pub fn overflowing_offset(self, i: Size, cx: &impl HasDataLayout) -> (Self, bool) { + let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes()); + (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over) + } + + #[inline(always)] + pub fn wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self { + self.overflowing_offset(i, cx).0 + } + + #[inline] + pub fn signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { + Ok(Pointer::new_with_tag( + self.alloc_id, + Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?), + self.tag, + )) + } + + #[inline] + pub fn overflowing_signed_offset(self, i: i128, 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 + } + + #[inline(always)] pub fn erase_tag(self) -> Pointer { Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () } } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 64723405b03..66faebb8c03 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -142,21 +142,6 @@ pub fn zst() -> Self { Scalar::Bits { bits: 0, size: 0 } } - #[inline] - pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { - let dl = cx.data_layout(); - match self { - Scalar::Bits { bits, size } => { - assert_eq!(size as u64, dl.pointer_size.bytes()); - Ok(Scalar::Bits { - bits: dl.signed_offset(bits as u64, i)? as u128, - size, - }) - } - Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr), - } - } - #[inline] pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { let dl = cx.data_layout(); @@ -172,6 +157,36 @@ pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Se } } + #[inline] + pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self { + let dl = cx.data_layout(); + match self { + Scalar::Bits { bits, size } => { + assert_eq!(size as u64, dl.pointer_size.bytes()); + Scalar::Bits { + bits: dl.overflowing_offset(bits as u64, i.bytes()).0 as u128, + size, + } + } + Scalar::Ptr(ptr) => Scalar::Ptr(ptr.wrapping_offset(i, dl)), + } + } + + #[inline] + pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { + let dl = cx.data_layout(); + match self { + Scalar::Bits { bits, size } => { + assert_eq!(size as u64, dl.pointer_size().bytes()); + Ok(Scalar::Bits { + bits: dl.signed_offset(bits as u64, i)? as u128, + size, + }) + } + Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr), + } + } + #[inline] pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { let dl = cx.data_layout(); @@ -179,7 +194,7 @@ pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self Scalar::Bits { bits, size } => { assert_eq!(size as u64, dl.pointer_size.bytes()); Scalar::Bits { - bits: dl.wrapping_signed_offset(bits as u64, i) as u128, + bits: dl.overflowing_signed_offset(bits as u64, i128::from(i)).0 as u128, size, } }