about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs66
-rw-r--r--tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff37
-rw-r--r--tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff37
3 files changed, 104 insertions, 36 deletions
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 6a37047a693..547375d47db 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -2,7 +2,9 @@
 //!
 //! Currently, this pass only propagates scalar values.
 
-use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
+use rustc_const_eval::interpret::{
+    ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Pointer, PointerArithmetic, Projectable,
+};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult, Scalar};
@@ -936,12 +938,64 @@ impl<'mir, 'tcx: 'mir> rustc_const_eval::interpret::Machine<'mir, 'tcx> for Dumm
     }
 
     fn binary_ptr_op(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        _bin_op: BinOp,
-        _left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
-        _right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
+        ecx: &InterpCx<'mir, 'tcx, Self>,
+        bin_op: BinOp,
+        left: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
+        right: &rustc_const_eval::interpret::ImmTy<'tcx, Self::Provenance>,
     ) -> interpret::InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)> {
-        throw_machine_stop_str!("can't do pointer arithmetic");
+        use rustc_middle::mir::BinOp::*;
+        Ok(match bin_op {
+            Eq | Ne | Lt | Le | Gt | Ge => {
+                assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for`
+                let size = ecx.pointer_size();
+                // Just compare the bits. ScalarPairs are compared lexicographically.
+                // We thus always compare pairs and simply fill scalars up with 0.
+                let left = match **left {
+                    Immediate::Scalar(l) => (l.to_bits(size)?, 0),
+                    Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?),
+                    Immediate::Uninit => panic!("we should never see uninit data here"),
+                };
+                let right = match **right {
+                    Immediate::Scalar(r) => (r.to_bits(size)?, 0),
+                    Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?),
+                    Immediate::Uninit => panic!("we should never see uninit data here"),
+                };
+                let res = match bin_op {
+                    Eq => left == right,
+                    Ne => left != right,
+                    Lt => left < right,
+                    Le => left <= right,
+                    Gt => left > right,
+                    Ge => left >= right,
+                    _ => bug!(),
+                };
+                (ImmTy::from_bool(res, *ecx.tcx), false)
+            }
+
+            // Some more operations are possible with atomics.
+            // The return value always has the provenance of the *left* operand.
+            Add | Sub | BitOr | BitAnd | BitXor => {
+                assert!(left.layout.ty.is_unsafe_ptr());
+                assert!(right.layout.ty.is_unsafe_ptr());
+                let ptr = left.to_scalar().to_pointer(ecx)?;
+                // We do the actual operation with usize-typed scalars.
+                let usize_layout = ecx.layout_of(ecx.tcx.types.usize).unwrap();
+                let left = ImmTy::from_uint(ptr.addr().bytes(), usize_layout);
+                let right = ImmTy::from_uint(right.to_scalar().to_target_usize(ecx)?, usize_layout);
+                let (result, overflowing) = ecx.overflowing_binary_op(bin_op, &left, &right)?;
+                // Construct a new pointer with the provenance of `ptr` (the LHS).
+                let result_ptr = Pointer::new(
+                    ptr.provenance,
+                    Size::from_bytes(result.to_scalar().to_target_usize(ecx)?),
+                );
+                (
+                    ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, ecx), left.layout),
+                    overflowing,
+                )
+            }
+
+            _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op),
+        })
     }
 
     fn expose_ptr(
diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
index e49d759b8fc..9ffac0f88de 100644
--- a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-abort.diff
@@ -247,13 +247,14 @@
 -         _45 = _39;
 -         _43 = Eq(move _44, move _45);
 +         _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _43 = const false;
           StorageDead(_45);
           StorageDead(_44);
-          _42 = Not(move _43);
+-         _42 = Not(move _43);
++         _42 = const true;
           StorageDead(_43);
 -         _41 = opaque::<bool>(move _42) -> [return: bb1, unwind unreachable];
-+         _41 = opaque::<bool>(_42) -> [return: bb1, unwind unreachable];
++         _41 = opaque::<bool>(const true) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
@@ -269,11 +270,11 @@
 -         _49 = _39;
 -         _47 = Ne(move _48, move _49);
 +         _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _47 = _42;
++         _47 = const true;
           StorageDead(_49);
           StorageDead(_48);
 -         _46 = opaque::<bool>(move _47) -> [return: bb2, unwind unreachable];
-+         _46 = opaque::<bool>(_42) -> [return: bb2, unwind unreachable];
++         _46 = opaque::<bool>(const true) -> [return: bb2, unwind unreachable];
       }
   
       bb2: {
@@ -288,10 +289,11 @@
 -         _53 = _39;
 -         _51 = Le(move _52, move _53);
 +         _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _51 = const true;
           StorageDead(_53);
           StorageDead(_52);
-          _50 = opaque::<bool>(move _51) -> [return: bb3, unwind unreachable];
+-         _50 = opaque::<bool>(move _51) -> [return: bb3, unwind unreachable];
++         _50 = opaque::<bool>(const true) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
@@ -306,10 +308,11 @@
 -         _57 = _39;
 -         _55 = Lt(move _56, move _57);
 +         _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _55 = const true;
           StorageDead(_57);
           StorageDead(_56);
-          _54 = opaque::<bool>(move _55) -> [return: bb4, unwind unreachable];
+-         _54 = opaque::<bool>(move _55) -> [return: bb4, unwind unreachable];
++         _54 = opaque::<bool>(const true) -> [return: bb4, unwind unreachable];
       }
   
       bb4: {
@@ -325,12 +328,14 @@
 -         _62 = _39;
 -         _60 = Ge(move _61, move _62);
 +         _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _60 = const false;
           StorageDead(_62);
           StorageDead(_61);
-          _59 = Not(move _60);
+-         _59 = Not(move _60);
++         _59 = const true;
           StorageDead(_60);
-          _58 = opaque::<bool>(move _59) -> [return: bb5, unwind unreachable];
+-         _58 = opaque::<bool>(move _59) -> [return: bb5, unwind unreachable];
++         _58 = opaque::<bool>(const true) -> [return: bb5, unwind unreachable];
       }
   
       bb5: {
@@ -346,12 +351,14 @@
 -         _67 = _39;
 -         _65 = Gt(move _66, move _67);
 +         _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _65 = const false;
           StorageDead(_67);
           StorageDead(_66);
-          _64 = Not(move _65);
+-         _64 = Not(move _65);
++         _64 = const true;
           StorageDead(_65);
-          _63 = opaque::<bool>(move _64) -> [return: bb6, unwind unreachable];
+-         _63 = opaque::<bool>(move _64) -> [return: bb6, unwind unreachable];
++         _63 = opaque::<bool>(const true) -> [return: bb6, unwind unreachable];
       }
   
       bb6: {
diff --git a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff
index 4e5608a4425..96234cb14ef 100644
--- a/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.wide_ptr_ops.GVN.panic-unwind.diff
@@ -247,13 +247,14 @@
 -         _45 = _39;
 -         _43 = Eq(move _44, move _45);
 +         _45 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _43 = Eq(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _43 = const false;
           StorageDead(_45);
           StorageDead(_44);
-          _42 = Not(move _43);
+-         _42 = Not(move _43);
++         _42 = const true;
           StorageDead(_43);
 -         _41 = opaque::<bool>(move _42) -> [return: bb1, unwind continue];
-+         _41 = opaque::<bool>(_42) -> [return: bb1, unwind continue];
++         _41 = opaque::<bool>(const true) -> [return: bb1, unwind continue];
       }
   
       bb1: {
@@ -269,11 +270,11 @@
 -         _49 = _39;
 -         _47 = Ne(move _48, move _49);
 +         _49 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _47 = _42;
++         _47 = const true;
           StorageDead(_49);
           StorageDead(_48);
 -         _46 = opaque::<bool>(move _47) -> [return: bb2, unwind continue];
-+         _46 = opaque::<bool>(_42) -> [return: bb2, unwind continue];
++         _46 = opaque::<bool>(const true) -> [return: bb2, unwind continue];
       }
   
       bb2: {
@@ -288,10 +289,11 @@
 -         _53 = _39;
 -         _51 = Le(move _52, move _53);
 +         _53 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _51 = Le(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _51 = const true;
           StorageDead(_53);
           StorageDead(_52);
-          _50 = opaque::<bool>(move _51) -> [return: bb3, unwind continue];
+-         _50 = opaque::<bool>(move _51) -> [return: bb3, unwind continue];
++         _50 = opaque::<bool>(const true) -> [return: bb3, unwind continue];
       }
   
       bb3: {
@@ -306,10 +308,11 @@
 -         _57 = _39;
 -         _55 = Lt(move _56, move _57);
 +         _57 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _55 = Lt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _55 = const true;
           StorageDead(_57);
           StorageDead(_56);
-          _54 = opaque::<bool>(move _55) -> [return: bb4, unwind continue];
+-         _54 = opaque::<bool>(move _55) -> [return: bb4, unwind continue];
++         _54 = opaque::<bool>(const true) -> [return: bb4, unwind continue];
       }
   
       bb4: {
@@ -325,12 +328,14 @@
 -         _62 = _39;
 -         _60 = Ge(move _61, move _62);
 +         _62 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _60 = Ge(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _60 = const false;
           StorageDead(_62);
           StorageDead(_61);
-          _59 = Not(move _60);
+-         _59 = Not(move _60);
++         _59 = const true;
           StorageDead(_60);
-          _58 = opaque::<bool>(move _59) -> [return: bb5, unwind continue];
+-         _58 = opaque::<bool>(move _59) -> [return: bb5, unwind continue];
++         _58 = opaque::<bool>(const true) -> [return: bb5, unwind continue];
       }
   
       bb5: {
@@ -346,12 +351,14 @@
 -         _67 = _39;
 -         _65 = Gt(move _66, move _67);
 +         _67 = const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8];
-+         _65 = Gt(const Indirect { alloc_id: ALLOC0, offset: Size(0 bytes) }: *const [u8], const Indirect { alloc_id: ALLOC1, offset: Size(0 bytes) }: *const [u8]);
++         _65 = const false;
           StorageDead(_67);
           StorageDead(_66);
-          _64 = Not(move _65);
+-         _64 = Not(move _65);
++         _64 = const true;
           StorageDead(_65);
-          _63 = opaque::<bool>(move _64) -> [return: bb6, unwind continue];
+-         _63 = opaque::<bool>(move _64) -> [return: bb6, unwind continue];
++         _63 = opaque::<bool>(const true) -> [return: bb6, unwind continue];
       }
   
       bb6: {