[llvm] [ValueTracking] Add `matchSimpleBinaryIntrinsicRecurrence` helper (PR #145964)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 27 08:40:10 PDT 2025


https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/145964

>From be2ef9afc6d02776a755d6d3205e1a25a4885dfb Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Thu, 26 Jun 2025 21:55:17 +0200
Subject: [PATCH 1/8] [ValueTracking] Add
 `matchSimpleBinaryIntrinsicRecurrence` helper

Similarly to what it is being done to match simple recurrence cycle
relations, attempt to match value-accumulating recurrences of kind:
```
  %umax.acc = phi i8 [ %umax, %backedge ], [ %a, %entry ]
  %umax = call i8 @llvm.umax.i8(i8 %umax.acc, i8 %b)
```
Preliminary work to let InstCombine avoid folding such recurrences,
so that simple loop-invariant computation may get hoisted. Minor
opportunity to refactor out code as well.
---
 llvm/include/llvm/Analysis/ValueTracking.h | 16 +++++
 llvm/lib/Analysis/ValueTracking.cpp        | 79 ++++++++++++++--------
 2 files changed, 65 insertions(+), 30 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index c804f551f5a75..384e9915a3bca 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -21,6 +21,7 @@
 #include "llvm/IR/FMF.h"
 #include "llvm/IR/InstrTypes.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/Support/Compiler.h"
 #include <cassert>
@@ -965,6 +966,21 @@ LLVM_ABI bool matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO,
 LLVM_ABI bool matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
                                     Value *&Start, Value *&Step);
 
+/// Attempt to match a simple value-accumulating recurrence of the form:
+///   %llvm.intrinsic.acc = phi Ty [%Init, %Entry], [%llvm.intrinsic, %backedge]
+///   %llvm.intrinsic = call Ty @llvm.intrinsic(%Invariant, %llvm.intrinsic.acc)
+/// OR
+///   %llvm.intrinsic.acc = phi Ty [%Init, %Entry], [%llvm.intrinsic, %backedge]
+///   %llvm.intrinsic = call Ty @llvm.intrinsic(%llvm.intrinsic.acc, %Invariant)
+///
+/// The recurrence relation is of kind:
+///   X_0 = %a (initial value),
+///   X_i = call @llvm.binary.intrinsic(X_i-1, %b)
+/// Where both %a and %b may be loop-invariant.
+LLVM_ABI bool matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
+                                                   PHINode *&P, Value *&Init,
+                                                   Value *&Invariant);
+
 /// Return true if RHS is known to be implied true by LHS.  Return false if
 /// RHS is known to be implied false by LHS.  Otherwise, return std::nullopt if
 /// no implication can be made. A & B must be i1 (boolean) values or a vector of
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 93c22212a27ce..fe831236aef54 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9070,46 +9070,48 @@ llvm::canConvertToMinOrMaxIntrinsic(ArrayRef<Value *> VL) {
   return {Intrinsic::not_intrinsic, false};
 }
 
-bool llvm::matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO,
-                                 Value *&Start, Value *&Step) {
+template <typename InstTy>
+static bool
+matchTwoInputRecurrence(const PHINode *PN, InstTy *&Inst, Value *&Init,
+                        Value *&OtherOp,
+                        std::function<bool(const InstTy *)> Pred = nullptr) {
   // Handle the case of a simple two-predecessor recurrence PHI.
   // There's a lot more that could theoretically be done here, but
   // this is sufficient to catch some interesting cases.
   // TODO: Expand list -- gep, uadd.sat etc.
-  if (P->getNumIncomingValues() != 2)
+  if (PN->getNumIncomingValues() != 2)
     return false;
 
-  for (unsigned i = 0; i != 2; ++i) {
-    Value *L = P->getIncomingValue(i);
-    Value *R = P->getIncomingValue(!i);
-    auto *LU = dyn_cast<BinaryOperator>(L);
-    if (!LU)
-      continue;
-    Value *LL = LU->getOperand(0);
-    Value *LR = LU->getOperand(1);
-
-    // Find a recurrence.
-    if (LL == P)
-      L = LR;
-    else if (LR == P)
-      L = LL;
-    else
-      continue; // Check for recurrence with L and R flipped.
-
-    // We have matched a recurrence of the form:
-    //   %iv = [R, %entry], [%iv.next, %backedge]
-    //   %iv.next = binop %iv, L
-    // OR
-    //   %iv = [R, %entry], [%iv.next, %backedge]
-    //   %iv.next = binop L, %iv
-    BO = LU;
-    Start = R;
-    Step = L;
-    return true;
+  for (unsigned I = 0; I != 2; ++I) {
+    if (auto *Operation = dyn_cast<InstTy>(PN->getIncomingValue(I))) {
+      if (Pred && !(Pred)(Operation))
+        continue;
+
+      Value *LHS = Operation->getOperand(0);
+      Value *RHS = Operation->getOperand(1);
+      if (LHS != PN && RHS != PN)
+        continue;
+
+      Inst = Operation;
+      Init = PN->getIncomingValue(!I);
+      OtherOp = (LHS == PN) ? RHS : LHS;
+      return true;
+    }
   }
   return false;
 }
 
+bool llvm::matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO,
+                                 Value *&Start, Value *&Step) {
+  // We have matched a recurrence of the form:
+  //   %iv = [Start, %entry], [%iv.next, %backedge]
+  //   %iv.next = binop %iv, Step
+  // Or:
+  //   %iv = [Start, %entry], [%iv.next, %backedge]
+  //   %iv.next = binop Step, %iv
+  return matchTwoInputRecurrence(P, BO, Start, Step);
+}
+
 bool llvm::matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
                                  Value *&Start, Value *&Step) {
   BinaryOperator *BO = nullptr;
@@ -9119,6 +9121,23 @@ bool llvm::matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
   return P && matchSimpleRecurrence(P, BO, Start, Step) && BO == I;
 }
 
+bool llvm::matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
+                                                PHINode *&P, Value *&Init,
+                                                Value *&Invariant) {
+  IntrinsicInst *II = nullptr;
+  P = dyn_cast<PHINode>(I->getArgOperand(0));
+  if (!P)
+    P = dyn_cast<PHINode>(I->getArgOperand(1));
+
+  std::function<bool(const IntrinsicInst *)> IsBinaryOrMinMaxFn =
+      [](const IntrinsicInst *I) {
+        return isa<BinaryOpIntrinsic, MinMaxIntrinsic>(I);
+      };
+  return P &&
+         matchTwoInputRecurrence(P, II, Init, Invariant, IsBinaryOrMinMaxFn) &&
+         II == I;
+}
+
 /// Return true if "icmp Pred LHS RHS" is always true.
 static bool isTruePredicate(CmpInst::Predicate Pred, const Value *LHS,
                             const Value *RHS) {

>From 8a5c734e599c6ad7c71d5202dd6ba600a1a6c218 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 27 Jun 2025 12:29:04 +0200
Subject: [PATCH 2/8] !fixup unittests, use llvm::function_ref

---
 llvm/lib/Analysis/ValueTracking.cpp           | 22 ++++----
 llvm/unittests/Analysis/ValueTrackingTest.cpp | 52 +++++++++++++++++++
 2 files changed, 65 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index fe831236aef54..78f68ee45f3f9 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9071,10 +9071,9 @@ llvm::canConvertToMinOrMaxIntrinsic(ArrayRef<Value *> VL) {
 }
 
 template <typename InstTy>
-static bool
-matchTwoInputRecurrence(const PHINode *PN, InstTy *&Inst, Value *&Init,
-                        Value *&OtherOp,
-                        std::function<bool(const InstTy *)> Pred = nullptr) {
+static bool matchTwoInputRecurrence(
+    const PHINode *PN, InstTy *&Inst, Value *&Init, Value *&OtherOp,
+    llvm::function_ref<bool(const InstTy *)> Pred = nullptr) {
   // Handle the case of a simple two-predecessor recurrence PHI.
   // There's a lot more that could theoretically be done here, but
   // this is sufficient to catch some interesting cases.
@@ -9129,12 +9128,17 @@ bool llvm::matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
   if (!P)
     P = dyn_cast<PHINode>(I->getArgOperand(1));
 
-  std::function<bool(const IntrinsicInst *)> IsBinaryOrMinMaxFn =
-      [](const IntrinsicInst *I) {
-        return isa<BinaryOpIntrinsic, MinMaxIntrinsic>(I);
-      };
   return P &&
-         matchTwoInputRecurrence(P, II, Init, Invariant, IsBinaryOrMinMaxFn) &&
+         matchTwoInputRecurrence<IntrinsicInst>(
+             P, II, Init, Invariant,
+             [](const IntrinsicInst *I) {
+               Intrinsic::ID IID = I->getIntrinsicID();
+               return isa<SaturatingInst, MinMaxIntrinsic>(I) ||
+                      IID == Intrinsic::minnum || IID == Intrinsic::maxnum ||
+                      IID == Intrinsic::minimum || IID == Intrinsic::maximum ||
+                      IID == Intrinsic::minimumnum ||
+                      IID == Intrinsic::maximumnum;
+             }) &&
          II == I;
 }
 
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 6031898f7f679..e7c0512f14cbe 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1257,6 +1257,58 @@ TEST_F(ValueTrackingTest, computePtrAlignment) {
   EXPECT_EQ(getKnownAlignment(A, DL, CxtI3, &AC, &DT), Align(16));
 }
 
+TEST_F(ValueTrackingTest, MatchBinaryIntrinsicRecurrenceUMax) {
+  auto M = parseModule(R"(
+    define i8 @test(i8 %a, i8 %b) {
+    entry:
+      br label %loop
+    loop:
+      %iv = phi i8 [ %iv.next, %loop ], [ 0, %entry ]
+      %umax.acc = phi i8 [ %umax, %loop ], [ %a, %entry ]
+      %umax = call i8 @llvm.umax.i8(i8 %umax.acc, i8 %b)
+      %iv.next = add nuw i8 %iv, 1
+      %cmp = icmp ult i8 %iv.next, 10
+      br i1 %cmp, label %loop, label %exit
+    exit:
+      ret i8 %umax
+    }
+  )");
+
+  auto *F = M->getFunction("test");
+  auto *II = &cast<IntrinsicInst>(findInstructionByName(F, "umax"));
+  auto *UMaxAcc = &cast<PHINode>(findInstructionByName(F, "umax.acc"));
+  PHINode *PN;
+  Value *Init, *Invariant;
+  EXPECT_TRUE(matchSimpleBinaryIntrinsicRecurrence(II, PN, Init, Invariant));
+  EXPECT_EQ(UMaxAcc, PN);
+  EXPECT_EQ(F->getArg(0), Init);
+  EXPECT_EQ(F->getArg(1), Invariant);
+}
+
+TEST_F(ValueTrackingTest, MatchBinaryIntrinsicRecurrenceNegativeFSHR) {
+  auto M = parseModule(R"(
+    define i8 @test(i8 %a, i8 %b, i8 %c) {
+    entry:
+      br label %loop
+    loop:
+      %iv = phi i8 [ %iv.next, %loop ], [ 0, %entry ]
+      %fshr.acc = phi i8 [ %fshr, %loop ], [ %a, %entry ]
+      %fshr = call i8 @llvm.fshr.i8(i8 %fshr.acc, i8 %b, i8 %c)
+      %iv.next = add nuw i8 %iv, 1
+      %cmp = icmp ult i8 %iv.next, 10
+      br i1 %cmp, label %loop, label %exit
+    exit:
+      ret i8 %fshr
+    }
+  )");
+
+  auto *F = M->getFunction("test");
+  auto *II = &cast<IntrinsicInst>(findInstructionByName(F, "fshr"));
+  PHINode *PN;
+  Value *Init, *Invariant;
+  EXPECT_FALSE(matchSimpleBinaryIntrinsicRecurrence(II, PN, Init, Invariant));
+}
+
 TEST_F(ComputeKnownBitsTest, ComputeKnownBits) {
   parseAssembly(
       "define i32 @test(i32 %a, i32 %b) {\n"

>From 18eb7bfdaa29c53aef1e441aacae8a35b0c98d95 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 27 Jun 2025 14:16:58 +0200
Subject: [PATCH 3/8] !fixup simplify match recurrence

---
 llvm/lib/Analysis/ValueTracking.cpp | 26 ++++++++------------------
 1 file changed, 8 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 78f68ee45f3f9..77f1477a82ea6 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9071,9 +9071,8 @@ llvm::canConvertToMinOrMaxIntrinsic(ArrayRef<Value *> VL) {
 }
 
 template <typename InstTy>
-static bool matchTwoInputRecurrence(
-    const PHINode *PN, InstTy *&Inst, Value *&Init, Value *&OtherOp,
-    llvm::function_ref<bool(const InstTy *)> Pred = nullptr) {
+static bool matchTwoInputRecurrence(const PHINode *PN, InstTy *&Inst,
+                                    Value *&Init, Value *&OtherOp) {
   // Handle the case of a simple two-predecessor recurrence PHI.
   // There's a lot more that could theoretically be done here, but
   // this is sufficient to catch some interesting cases.
@@ -9083,9 +9082,6 @@ static bool matchTwoInputRecurrence(
 
   for (unsigned I = 0; I != 2; ++I) {
     if (auto *Operation = dyn_cast<InstTy>(PN->getIncomingValue(I))) {
-      if (Pred && !(Pred)(Operation))
-        continue;
-
       Value *LHS = Operation->getOperand(0);
       Value *RHS = Operation->getOperand(1);
       if (LHS != PN && RHS != PN)
@@ -9123,23 +9119,17 @@ bool llvm::matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
 bool llvm::matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
                                                 PHINode *&P, Value *&Init,
                                                 Value *&Invariant) {
+  // Binary intrinsics only supported for now.
+  if (I->arg_size() != 2 || I->getType() != I->getOperand(0)->getType() ||
+      I->getType() != I->getOperand(1)->getType())
+    return false;
+
   IntrinsicInst *II = nullptr;
   P = dyn_cast<PHINode>(I->getArgOperand(0));
   if (!P)
     P = dyn_cast<PHINode>(I->getArgOperand(1));
 
-  return P &&
-         matchTwoInputRecurrence<IntrinsicInst>(
-             P, II, Init, Invariant,
-             [](const IntrinsicInst *I) {
-               Intrinsic::ID IID = I->getIntrinsicID();
-               return isa<SaturatingInst, MinMaxIntrinsic>(I) ||
-                      IID == Intrinsic::minnum || IID == Intrinsic::maxnum ||
-                      IID == Intrinsic::minimum || IID == Intrinsic::maximum ||
-                      IID == Intrinsic::minimumnum ||
-                      IID == Intrinsic::maximumnum;
-             }) &&
-         II == I;
+  return P && matchTwoInputRecurrence(P, II, Init, Invariant) && II == I;
 }
 
 /// Return true if "icmp Pred LHS RHS" is always true.

>From 3c5d070fb0b1a94f2c6460c4ac5fa34d216fdc5f Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 27 Jun 2025 14:19:09 +0200
Subject: [PATCH 4/8] !fixup prefer getArgOperand

---
 llvm/lib/Analysis/ValueTracking.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 77f1477a82ea6..6fca2b6b5e590 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9120,8 +9120,8 @@ bool llvm::matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
                                                 PHINode *&P, Value *&Init,
                                                 Value *&Invariant) {
   // Binary intrinsics only supported for now.
-  if (I->arg_size() != 2 || I->getType() != I->getOperand(0)->getType() ||
-      I->getType() != I->getOperand(1)->getType())
+  if (I->arg_size() != 2 || I->getType() != I->getArgOperand(0)->getType() ||
+      I->getType() != I->getArgOperand(1)->getType())
     return false;
 
   IntrinsicInst *II = nullptr;

>From 8ffcb4c7486464300f0038608cc2688a10dff5da Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 27 Jun 2025 15:24:04 +0200
Subject: [PATCH 5/8] !fixup refine comment

---
 llvm/lib/Analysis/ValueTracking.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 6fca2b6b5e590..99e830a957e4f 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9098,7 +9098,7 @@ static bool matchTwoInputRecurrence(const PHINode *PN, InstTy *&Inst,
 
 bool llvm::matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO,
                                  Value *&Start, Value *&Step) {
-  // We have matched a recurrence of the form:
+  // We try to match a recurrence of the form:
   //   %iv = [Start, %entry], [%iv.next, %backedge]
   //   %iv.next = binop %iv, Step
   // Or:

>From b1eaf2c0d6cad999435754c119212d459f375ff6 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 27 Jun 2025 17:23:18 +0200
Subject: [PATCH 6/8] !fixup refine var name

---
 llvm/include/llvm/Analysis/ValueTracking.h    |  6 +++---
 llvm/lib/Analysis/ValueTracking.cpp           |  4 ++--
 llvm/unittests/Analysis/ValueTrackingTest.cpp | 10 +++++-----
 3 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 384e9915a3bca..f8c0fb2261615 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -968,10 +968,10 @@ LLVM_ABI bool matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
 
 /// Attempt to match a simple value-accumulating recurrence of the form:
 ///   %llvm.intrinsic.acc = phi Ty [%Init, %Entry], [%llvm.intrinsic, %backedge]
-///   %llvm.intrinsic = call Ty @llvm.intrinsic(%Invariant, %llvm.intrinsic.acc)
+///   %llvm.intrinsic = call Ty @llvm.intrinsic(%OtherOp, %llvm.intrinsic.acc)
 /// OR
 ///   %llvm.intrinsic.acc = phi Ty [%Init, %Entry], [%llvm.intrinsic, %backedge]
-///   %llvm.intrinsic = call Ty @llvm.intrinsic(%llvm.intrinsic.acc, %Invariant)
+///   %llvm.intrinsic = call Ty @llvm.intrinsic(%llvm.intrinsic.acc, %OtherOp)
 ///
 /// The recurrence relation is of kind:
 ///   X_0 = %a (initial value),
@@ -979,7 +979,7 @@ LLVM_ABI bool matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
 /// Where both %a and %b may be loop-invariant.
 LLVM_ABI bool matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
                                                    PHINode *&P, Value *&Init,
-                                                   Value *&Invariant);
+                                                   Value *&OtherOp);
 
 /// Return true if RHS is known to be implied true by LHS.  Return false if
 /// RHS is known to be implied false by LHS.  Otherwise, return std::nullopt if
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 99e830a957e4f..e576f4899810a 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9118,7 +9118,7 @@ bool llvm::matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
 
 bool llvm::matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
                                                 PHINode *&P, Value *&Init,
-                                                Value *&Invariant) {
+                                                Value *&OtherOp) {
   // Binary intrinsics only supported for now.
   if (I->arg_size() != 2 || I->getType() != I->getArgOperand(0)->getType() ||
       I->getType() != I->getArgOperand(1)->getType())
@@ -9129,7 +9129,7 @@ bool llvm::matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
   if (!P)
     P = dyn_cast<PHINode>(I->getArgOperand(1));
 
-  return P && matchTwoInputRecurrence(P, II, Init, Invariant) && II == I;
+  return P && matchTwoInputRecurrence(P, II, Init, OtherOp) && II == I;
 }
 
 /// Return true if "icmp Pred LHS RHS" is always true.
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index e7c0512f14cbe..dbe72286c3a0b 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1278,11 +1278,11 @@ TEST_F(ValueTrackingTest, MatchBinaryIntrinsicRecurrenceUMax) {
   auto *II = &cast<IntrinsicInst>(findInstructionByName(F, "umax"));
   auto *UMaxAcc = &cast<PHINode>(findInstructionByName(F, "umax.acc"));
   PHINode *PN;
-  Value *Init, *Invariant;
-  EXPECT_TRUE(matchSimpleBinaryIntrinsicRecurrence(II, PN, Init, Invariant));
+  Value *Init, *OtherOp;
+  EXPECT_TRUE(matchSimpleBinaryIntrinsicRecurrence(II, PN, Init, OtherOp));
   EXPECT_EQ(UMaxAcc, PN);
   EXPECT_EQ(F->getArg(0), Init);
-  EXPECT_EQ(F->getArg(1), Invariant);
+  EXPECT_EQ(F->getArg(1), OtherOp);
 }
 
 TEST_F(ValueTrackingTest, MatchBinaryIntrinsicRecurrenceNegativeFSHR) {
@@ -1305,8 +1305,8 @@ TEST_F(ValueTrackingTest, MatchBinaryIntrinsicRecurrenceNegativeFSHR) {
   auto *F = M->getFunction("test");
   auto *II = &cast<IntrinsicInst>(findInstructionByName(F, "fshr"));
   PHINode *PN;
-  Value *Init, *Invariant;
-  EXPECT_FALSE(matchSimpleBinaryIntrinsicRecurrence(II, PN, Init, Invariant));
+  Value *Init, *OtherOp;
+  EXPECT_FALSE(matchSimpleBinaryIntrinsicRecurrence(II, PN, Init, OtherOp));
 }
 
 TEST_F(ComputeKnownBitsTest, ComputeKnownBits) {

>From f67aab55be75bdf33e968ac7cf5c98aa86b07bcb Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 27 Jun 2025 17:32:38 +0200
Subject: [PATCH 7/8] !fixup fix wrong comment

---
 llvm/include/llvm/Analysis/ValueTracking.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index f8c0fb2261615..7855c97d5fc4a 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -976,7 +976,7 @@ LLVM_ABI bool matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
 /// The recurrence relation is of kind:
 ///   X_0 = %a (initial value),
 ///   X_i = call @llvm.binary.intrinsic(X_i-1, %b)
-/// Where both %a and %b may be loop-invariant.
+/// Where %b may be a loop-invariant value.
 LLVM_ABI bool matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
                                                    PHINode *&P, Value *&Init,
                                                    Value *&OtherOp);

>From 413db689ee19ff40a9ce945732e5709386de2e82 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 27 Jun 2025 17:39:35 +0200
Subject: [PATCH 8/8] !fixup improve comment

---
 llvm/include/llvm/Analysis/ValueTracking.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index 7855c97d5fc4a..15e23de3878dc 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -976,7 +976,7 @@ LLVM_ABI bool matchSimpleRecurrence(const BinaryOperator *I, PHINode *&P,
 /// The recurrence relation is of kind:
 ///   X_0 = %a (initial value),
 ///   X_i = call @llvm.binary.intrinsic(X_i-1, %b)
-/// Where %b may be a loop-invariant value.
+/// Where %b is not required to be loop-invariant.
 LLVM_ABI bool matchSimpleBinaryIntrinsicRecurrence(const IntrinsicInst *I,
                                                    PHINode *&P, Value *&Init,
                                                    Value *&OtherOp);



More information about the llvm-commits mailing list