[llvm] [InstCombine] Support well-defined recurrences in isGuaranteedNotToBeUndefOrPoison (PR #150420)

Cullen Rhodes via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 25 05:45:33 PDT 2025


================
@@ -7569,6 +7569,66 @@ bool llvm::impliesPoison(const Value *ValAssumedPoison, const Value *V) {
 
 static bool programUndefinedIfUndefOrPoison(const Value *V, bool PoisonOnly);
 
+Use *llvm::canFoldFreezeIntoRecurrence(
+    PHINode *PN, DominatorTree *DT, bool &StartNeedsFreeze,
+    SmallVectorImpl<Instruction *> *DropFlags) {
+  // Detect whether this is a recurrence with a start value and some number of
+  // backedge values. We'll check whether we can push the freeze through the
+  // backedge values (possibly dropping poison flags along the way) until we
+  // reach the phi again. In that case, we can move the freeze to the start
+  // value.
+  Use *StartU = nullptr;
+  SmallVector<Value *> Worklist;
+  for (Use &U : PN->incoming_values()) {
+    if (DT && DT->dominates(PN->getParent(), PN->getIncomingBlock(U))) {
+      // Add backedge value to worklist.
+      Worklist.push_back(U.get());
+      continue;
+    }
+
+    // Don't bother handling multiple start values.
+    if (StartU)
+      return nullptr;
+    StartU = &U;
+  }
+
+  if (!StartU || Worklist.empty())
+    return nullptr; // Not a recurrence.
+
+  Value *StartV = StartU->get();
+  BasicBlock *StartBB = PN->getIncomingBlock(*StartU);
+  StartNeedsFreeze = !isGuaranteedNotToBeUndefOrPoison(StartV);
+  // We can't insert freeze if the start value is the result of the
+  // terminator (e.g. an invoke).
+  if (StartNeedsFreeze && StartBB->getTerminator() == StartV)
+    return nullptr;
+
+  SmallPtrSet<Value *, 32> Visited;
+  while (!Worklist.empty()) {
+    Value *V = Worklist.pop_back_val();
+    if (!Visited.insert(V).second)
+      continue;
+
+    if (Visited.size() > 32)
+      return nullptr; // Limit the total number of values we inspect.
+
+    // Assume that PN is non-poison, because it will be after the transform.
+    if (V == PN || isGuaranteedNotToBeUndefOrPoison(V))
----------------
c-rhodes wrote:

Looking at `isGuaranteedNotToBeUndefOrPoison` it's only used as long as the `AssumptionCache` and `CtxI` are passed. I've tried your suggestion (see patch below), but it makes no testable difference so I'm not sure it's worth it, unless you're aware of some case that's missing?

```
diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index a9dcc65d02a0..a4f8c22226e0 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -780,9 +780,11 @@ LLVM_ABI bool impliesPoison(const Value *ValAssumedPoison, const Value *V);
 /// values. We'll check whether we can push the freeze through the backedge
 /// values (possibly dropping poison flags along the way) until we reach the
 /// phi again. In that case, we can move the freeze to the start value.
-LLVM_ABI Use *canFoldFreezeIntoRecurrence(
-    PHINode *PN, DominatorTree *DT, bool &StartNeedsFreeze,
-    SmallVectorImpl<Instruction *> *DropFlags = nullptr, unsigned Depth = 0);
+LLVM_ABI Use *
+canFoldFreezeIntoRecurrence(PHINode *PN, AssumptionCache *AC, Instruction *CtxI,
+                            DominatorTree *DT, bool &StartNeedsFreeze,
+                            SmallVectorImpl<Instruction *> *DropFlags = nullptr,
+                            unsigned Depth = 0);

 /// Return true if this function can prove that V does not have undef bits
 /// and is never poison. If V is an aggregate value or vector, check whether
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 948562c90709..fdb0725e361d 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -7570,8 +7570,9 @@ bool llvm::impliesPoison(const Value *ValAssumedPoison, const Value *V) {
 static bool programUndefinedIfUndefOrPoison(const Value *V, bool PoisonOnly);

 Use *llvm::canFoldFreezeIntoRecurrence(
-    PHINode *PN, DominatorTree *DT, bool &StartNeedsFreeze,
-    SmallVectorImpl<Instruction *> *DropFlags, unsigned Depth) {
+    PHINode *PN, AssumptionCache *AC, Instruction *CtxI, DominatorTree *DT,
+    bool &StartNeedsFreeze, SmallVectorImpl<Instruction *> *DropFlags,
+    unsigned Depth) {
   // Detect whether this is a recurrence with a start value and some number of
   // backedge values. We'll check whether we can push the freeze through the
   // backedge values (possibly dropping poison flags along the way) until we
@@ -7723,8 +7724,9 @@ static bool isGuaranteedNotToBeUndefOrPoison(

       bool StartNeedsFreeze;
       if (canFoldFreezeIntoRecurrence(
-              const_cast<PHINode *>(PN), const_cast<DominatorTree *>(DT),
-              StartNeedsFreeze, /*DropFlags=*/nullptr, Depth) &&
+              const_cast<PHINode *>(PN), AC, const_cast<Instruction *>(CtxI),
+              const_cast<DominatorTree *>(DT), StartNeedsFreeze,
+              /*DropFlags=*/nullptr, Depth) &&
           !StartNeedsFreeze)
         return true;
     } else if (!::canCreateUndefOrPoison(Opr, Kind,
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index e28f2abdede7..b32c39faafc8 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -4962,8 +4962,8 @@ Instruction *InstCombinerImpl::foldFreezeIntoRecurrence(FreezeInst &FI,
                                                         PHINode *PN) {
   bool StartNeedsFreeze;
   SmallVector<Instruction *> DropFlags;
-  Use *StartU =
-      canFoldFreezeIntoRecurrence(PN, &DT, StartNeedsFreeze, &DropFlags);
+  Use *StartU = canFoldFreezeIntoRecurrence(PN, &AC, PN, &DT, StartNeedsFreeze,
+                                            &DropFlags);
   if (!StartU)
     return nullptr;
```

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


More information about the llvm-commits mailing list