[llvm] [IVDescriptors] Implement MonotonicDescriptor (PR #214490)

Andrei Elovikov via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 20 11:24:16 PDT 2026


================
@@ -1696,3 +1696,164 @@ bool InductionDescriptor::isInductionPHI(
                           /*InductionBinOp=*/nullptr, /*Casts=*/nullptr, Preds);
   return true;
 }
+
+// Recognize monotonic phi variable by matching the following pattern:
+// loop_header:
+//   %monotonic_phi = phi [ %start, %preheader ], [ %chain_phi0, %latch ]
+//   br i1 %do_step, label %step_bb, label %latch
+//
+// step_bb:
+//   %step = add/gep %monotonic_phi, %step_val
+//   br label %latch
+//
+// latch:
+//   %chain_phi0 = phi [ %monotonic_phi, %loop_header ], [ %step, %step_bb ]
+//   br label %loop_header
+//
+// For this pattern, monotonic phi is described by {%start, +, %step}
+// recurrence and predicate is CFG edge %step_bb -> %latch.
+std::optional<MonotonicDescriptor::MonotonicPHI>
+MonotonicDescriptor::matchMonotonicPHI(PHINode *PN, const Loop *L,
+                                       ScalarEvolution &SE) {
+  if (!PN->getType()->isIntOrPtrTy() || PN->getParent() != L->getHeader())
+    return std::nullopt;
+  auto *BackedgeInst =
+      dyn_cast<PHINode>(PN->getIncomingValueForBlock(L->getLoopLatch()));
+  if (!BackedgeInst)
+    return std::nullopt;
+
+  // Ensure the only user of the backedge are out of the loop or the PN.
+  for (User *U : BackedgeInst->users()) {
+    auto *UI = dyn_cast<Instruction>(U);
+    if (UI == PN || (UI && !L->contains(UI)))
+      continue;
+    return std::nullopt;
+  }
+
+  // Find the StepOp (that increments PN). TODO: Support chains of phis.
+  Value *StepOp = nullptr;
+  for (auto [Block, Incoming] :
+       zip_equal(BackedgeInst->blocks(), BackedgeInst->incoming_values())) {
+    if (Incoming == PN)
+      continue;
+    if (!Incoming->hasOneUse())
+      return {};
+    StepOp = Incoming;
+  }
+
+  auto *StepInst = dyn_cast_if_present<Instruction>(StepOp);
+  if (!StepInst)
+    return std::nullopt;
+
+  Value *Start = PN->getIncomingValueForBlock(L->getLoopPreheader());
+
+  Value *Step = nullptr;
+  bool StepMatch =
+      PN->getType()->isPointerTy()
+          ? match(StepInst, m_PtrAdd(m_Specific(PN), m_Value(Step)))
+          : match(StepInst, m_Add(m_Specific(PN), m_Value(Step)));
----------------
eas wrote:

```suggestion
          : match(StepInst, m_c_Add(m_Specific(PN), m_Value(Step)));
```
?

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


More information about the llvm-commits mailing list