about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2018-11-04 12:45:21 +0100
committerRalf Jung <post@ralfj.de>2018-11-05 10:30:56 +0100
commit0529dc818f4f603c5419e25f44bd1a0b7526c6ff (patch)
treeb8617319b5c86c0f227ea618e0ec6349e0067144
parent873041009d1c2f5e2034b021133d2f93e901e745 (diff)
downloadrust-0529dc818f4f603c5419e25f44bd1a0b7526c6ff.tar.gz
rust-0529dc818f4f603c5419e25f44bd1a0b7526c6ff.zip
proide ptr_wrapping_offset on Scalars
-rw-r--r--src/librustc/mir/interpret/mod.rs79
-rw-r--r--src/librustc/mir/interpret/value.rs29
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,
                 }
             }