[llvm] [ValueTracking] isNonZero sub of ptr2int's with recursive GEP (PR #68680)

via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 25 06:54:34 PDT 2023


================
@@ -2410,9 +2410,76 @@ static bool isNonZeroAdd(const APInt &DemandedElts, unsigned Depth,
       .isNonZero();
 }
 
+static bool isNonZeroSubWithRecursiveGEP(const SimplifyQuery &Q, Value *X,
+                                         Value *Y) {
+  // Handle sub(PtrtoInt(LHS), PtrtoInt(RHS))
+  // Where LHS is a recursive GEP for an incoming value of PHI indicating a
+  // loop. RHS can be a ptr/GEP.
+  // If the PHI has 2 incoming values, one of it being the recursive GEP
+  // and other a ptr at same base and at an same/higher offset than RHS we are
+  // only incrementing the pointer further in loop if offset of recursive GEP is
+  // greater than 0.
+  Value *LHS, *RHS;
+  // sub(PtrtoInt(LHS), PtrtoInt(RHS))
+  if (match(X, m_PtrToInt(m_Value(LHS))) &&
+      match(Y, m_PtrToInt(m_Value(RHS)))) {
+    GEPOperator *LHSGEP = dyn_cast<GEPOperator>(LHS);
+    // Make sure LHS GEP pointer operand is a PHI. If sub(A,B) is non zero, so
+    // is sub(B,A)
+    if (!LHSGEP || !isa<PHINode>(LHSGEP->getPointerOperand())) {
+      LHSGEP = dyn_cast<GEPOperator>(RHS);
+      std::swap(LHS, RHS);
+    }
+    if (LHSGEP && isa<PHINode>(LHSGEP->getPointerOperand())) {
+      // Handle 2 incoming values with one being a recursive GEP.
+      auto *PN = dyn_cast<PHINode>(LHSGEP->getPointerOperand());
+      if (PN->getNumIncomingValues() == 2) {
+        // Recursive GEP in second incoming value. Always keep Recursive GEP as
+        // FirstInst
+        Value *FirstInst = nullptr, *SecondInst = nullptr;
+        for (unsigned i = 0; i != 2; ++i) {
+          // Check if LHS is a Recursive GEP in one of the incoming values.
+          if (PN->getIncomingValue(i) == LHS && LHSGEP->getNumIndices() == 1 &&
+              isa<Constant>(LHSGEP->idx_begin())) {
+            FirstInst = PN->getIncomingValue(i);
+            SecondInst = PN->getIncomingValue(!i);
+            continue;
+          }
+        }
+
+        if (FirstInst && SecondInst) {
+          // Other incoming node base should match the RHS base.
+          // SecondInstOffset >= RHSOffset && FirstInstOffset > 0?
+          // SecondInstOffset <= RHSOffset && FirstInstOffset < 0?
+          // Is non-zero if above are true.
+          APInt FirstInstOffset(
+              Q.DL.getIndexTypeSizeInBits(FirstInst->getType()), 0);
+          FirstInst = FirstInst->stripAndAccumulateConstantOffsets(
+              Q.DL, FirstInstOffset, /* AllowNonInbounds */ true);
+          APInt SecondInstOffset(
+              Q.DL.getIndexTypeSizeInBits(SecondInst->getType()), 0);
+          SecondInst = SecondInst->stripAndAccumulateConstantOffsets(
+              Q.DL, SecondInstOffset, /* AllowNonInbounds */ true);
+          APInt RHSOffset(Q.DL.getIndexTypeSizeInBits(RHS->getType()), 0);
+          RHS = RHS->stripAndAccumulateConstantOffsets(
+              Q.DL, RHSOffset, /* AllowNonInbounds */ true);
+          if (SecondInst == RHS &&
----------------
bipmis wrote:

Thanks for the review.
It is handling a recursive GEP as an operand to the sub, so something like
(sub (ptrint (gep(phi X, Y))), (ptrint y))
We handle 2 incoming Values to PHI, in this case one being the recursive GEP itself. So in this case if we can identify that the second incoming ptr Y>y and GEP offset is positive, the sub is always greater than zero. Similarly if Y<y and GEP offset is negative, the sub is always less than zero. We can build the isKnownNonZero based on this.
The scenario provided by you should not apply in this case. I can add an example for the same.

https://github.com/llvm/llvm-project/pull/68680


More information about the llvm-commits mailing list