diff options
| author | Ralf Jung <post@ralfj.de> | 2018-11-04 12:45:21 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2018-11-05 10:30:56 +0100 |
| commit | 0529dc818f4f603c5419e25f44bd1a0b7526c6ff (patch) | |
| tree | b8617319b5c86c0f227ea618e0ec6349e0067144 | |
| parent | 873041009d1c2f5e2034b021133d2f93e901e745 (diff) | |
| download | rust-0529dc818f4f603c5419e25f44bd1a0b7526c6ff.tar.gz rust-0529dc818f4f603c5419e25f44bd1a0b7526c6ff.zip | |
proide ptr_wrapping_offset on Scalars
| -rw-r--r-- | src/librustc/mir/interpret/mod.rs | 79 | ||||
| -rw-r--r-- | src/librustc/mir/interpret/value.rs | 29 |
2 files changed, 65 insertions, 43 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,42 +91,43 @@ pub trait PointerArithmetic: layout::HasDataLayout { } //// 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) } - // Overflow checking only works properly on the range from -u64 to +u64. - fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) { - // FIXME: is it possible to over/underflow here? - if i < 0 { - // trickery to ensure that i64::min_value() works fine - // this formula only works for true negative values, it panics for zero! - let n = u64::max_value() - (i as u64) + 1; - val.overflowing_sub(n) - } else { - self.overflowing_offset(val, i as u64) - } + #[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(res as u128); + 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, i as i128); + let (res, over) = self.overflowing_signed_offset(val, i128::from(i)); 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 + // 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 { + // trickery to ensure that i64::min_value() works fine + // this formula only works for true negative values, it panics for zero! + let n = u64::max_value() - (i as u64) + 1; + val.overflowing_sub(n) + } else { + self.overflowing_offset(val, i as u64) + } } } @@ -176,19 +177,27 @@ impl<'tcx, Tag> Pointer<Tag> { Pointer { alloc_id, offset, tag } } - pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { - Pointer::new_with_tag( + #[inline] + pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { + Ok(Pointer::new_with_tag( self.alloc_id, - Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)), - self.tag, - ) + Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?), + 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); + #[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, @@ -197,20 +206,18 @@ impl<'tcx, Tag> Pointer<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()); + #[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) } - pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { - Ok(Pointer::new_with_tag( - self.alloc_id, - Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?), - self.tag - )) + #[inline(always)] + pub fn wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { + self.overflowing_signed_offset(i128::from(i), cx).0 } - #[inline] + #[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 @@ -143,32 +143,47 @@ impl<'tcx, Tag> Scalar<Tag> { } #[inline] - pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { + pub fn ptr_offset(self, i: Size, 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, + bits: dl.offset(bits as u64, i.bytes())? as u128, size, }) } - Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr), + Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr), } } #[inline] - pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { + 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.offset(bits as u64, i.bytes())? as u128, + bits: dl.signed_offset(bits as u64, i)? as u128, size, }) } - Scalar::Ptr(ptr) => ptr.offset(i, dl).map(Scalar::Ptr), + Scalar::Ptr(ptr) => ptr.signed_offset(i, dl).map(Scalar::Ptr), } } @@ -179,7 +194,7 @@ impl<'tcx, Tag> Scalar<Tag> { 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, } } |
