[llvm] [HashRecognize] Use loop latch to determine step/start for conditional recurrence (PR #211916)

Sean Clarke via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 27 07:16:31 PDT 2026


https://github.com/xarkenz updated https://github.com/llvm/llvm-project/pull/211916

>From 88ae6d344f3959e3a94820a139cabaeed94b194d Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Fri, 24 Jul 2026 13:26:37 -0500
Subject: [PATCH 1/4] Add baseline test

---
 .../HashRecognize/cyclic-redundancy-check.ll  | 27 +++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
index b7139a7367829..4c0e51b67dd59 100644
--- a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
+++ b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
@@ -335,6 +335,33 @@ exit:                                              ; preds = %loop
   ret i16 %crc.next
 }
 
+define i16 @crc16.be.tc8.crc.init.select(i16 %a, i16 %b) {
+; CHECK-LABEL: 'crc16.be.tc8.crc.init.select'
+; CHECK-NEXT:  Did not find a hash algorithm
+; CHECK-NEXT:  Reason: Unable to find conditional recurrence
+;
+entry:
+  %a.inc = add i16 %a, 1
+  %b.inc = add i16 %b, 2
+  %init.cond = icmp ult i16 %a, %b
+  %crc.init = select i1 %init.cond, i16 %a.inc, i16 %b.inc
+  br label %loop
+
+loop:                                              ; preds = %loop, %entry
+  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
+  %crc = phi i16 [ %crc.init, %entry ], [ %crc.next, %loop ]
+  %crc.shl = shl i16 %crc, 1
+  %crc.xor = xor i16 %crc.shl, 4129
+  %check.sb = icmp slt i16 %crc, 0
+  %crc.next = select i1 %check.sb, i16 %crc.xor, i16 %crc.shl
+  %iv.next = add nuw nsw i32 %iv, 1
+  %exit.cond = icmp samesign ult i32 %iv, 7
+  br i1 %exit.cond, label %loop, label %exit
+
+exit:                                              ; preds = %loop
+  ret i16 %crc.next
+}
+
 define i8 @crc8.be.tc8.ptr.nested.loop(ptr %msg, i32 %loop.limit) {
 ; CHECK-LABEL: 'crc8.be.tc8.ptr.nested.loop'
 ; CHECK-NEXT:  Found big-endian CRC-8 loop with trip count 8

>From 731245e267806c320413b323be741140439ff1ff Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Fri, 24 Jul 2026 19:51:57 -0500
Subject: [PATCH 2/4] Dedent loop for diff purposes

---
 llvm/lib/Analysis/HashRecognize.cpp | 44 ++++++++++++++---------------
 1 file changed, 22 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Analysis/HashRecognize.cpp b/llvm/lib/Analysis/HashRecognize.cpp
index 1b6a2acc1a584..560e5566f5c9d 100644
--- a/llvm/lib/Analysis/HashRecognize.cpp
+++ b/llvm/lib/Analysis/HashRecognize.cpp
@@ -291,31 +291,31 @@ bool RecurrenceInfo::matchConditionalRecurrence(
     return false;
 
   for (unsigned Idx = 0; Idx != 2; ++Idx) {
-    Value *FoundStep = Phi->getIncomingValue(Idx);
-    Value *FoundStart = Phi->getIncomingValue(!Idx);
+  Value *FoundStep = Phi->getIncomingValue(Idx);
+  Value *FoundStart = Phi->getIncomingValue(!Idx);
 
-    Instruction *TV, *FV;
-    if (!match(FoundStep,
-               m_Select(m_Cmp(), m_Instruction(TV), m_Instruction(FV))))
-      continue;
+  Instruction *TV, *FV;
+  if (!match(FoundStep,
+             m_Select(m_Cmp(), m_Instruction(TV), m_Instruction(FV))))
+    continue;
+
+  // For a conditional recurrence, both the true and false values of the
+  // select must ultimately end up in the same recurrent BinOp.
+  BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);
+  BinaryOperator *AltBO = digRecurrence(FV, BOWithConstOpToMatch);
+  if (!FoundBO || FoundBO != AltBO)
+    return false;
 
-    // For a conditional recurrence, both the true and false values of the
-    // select must ultimately end up in the same recurrent BinOp.
-    BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);
-    BinaryOperator *AltBO = digRecurrence(FV, BOWithConstOpToMatch);
-    if (!FoundBO || FoundBO != AltBO)
-      return false;
-
-    if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && !ExtraConst) {
-      LLVM_DEBUG(dbgs() << "HashRecognize: Unable to match single BinaryOp "
-                           "with constant in conditional recurrence\n");
-      return false;
-    }
+  if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && !ExtraConst) {
+    LLVM_DEBUG(dbgs() << "HashRecognize: Unable to match single BinaryOp "
+                         "with constant in conditional recurrence\n");
+    return false;
+  }
 
-    BO = FoundBO;
-    Start = FoundStart;
-    Step = FoundStep;
-    return true;
+  BO = FoundBO;
+  Start = FoundStart;
+  Step = FoundStep;
+  return true;
   }
   return false;
 }

>From 9da27b03c36820bcbbb59c6ccfc6921f4e955428 Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Fri, 24 Jul 2026 13:27:12 -0500
Subject: [PATCH 3/4] Use loop latch to determine step/start rather than
 iterating

---
 llvm/lib/Analysis/HashRecognize.cpp           | 11 ++++----
 .../HashRecognize/cyclic-redundancy-check.ll  | 25 +++++++++++++++++--
 2 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Analysis/HashRecognize.cpp b/llvm/lib/Analysis/HashRecognize.cpp
index 560e5566f5c9d..7357c9c21a1f9 100644
--- a/llvm/lib/Analysis/HashRecognize.cpp
+++ b/llvm/lib/Analysis/HashRecognize.cpp
@@ -290,14 +290,15 @@ bool RecurrenceInfo::matchConditionalRecurrence(
   if (Phi->getNumIncomingValues() != 2)
     return false;
 
-  for (unsigned Idx = 0; Idx != 2; ++Idx) {
-  Value *FoundStep = Phi->getIncomingValue(Idx);
-  Value *FoundStart = Phi->getIncomingValue(!Idx);
+  // Step comes from the loop latch, start comes from the other incoming value.
+  int LatchIdx = Phi->getBasicBlockIndex(L.getLoopLatch());
+  Value *FoundStep = Phi->getIncomingValue(LatchIdx);
+  Value *FoundStart = Phi->getIncomingValue(!LatchIdx);
 
   Instruction *TV, *FV;
   if (!match(FoundStep,
              m_Select(m_Cmp(), m_Instruction(TV), m_Instruction(FV))))
-    continue;
+    return false;
 
   // For a conditional recurrence, both the true and false values of the
   // select must ultimately end up in the same recurrent BinOp.
@@ -316,8 +317,6 @@ bool RecurrenceInfo::matchConditionalRecurrence(
   Start = FoundStart;
   Step = FoundStep;
   return true;
-  }
-  return false;
 }
 
 /// Iterates over all the phis in \p LoopLatch, and attempts to extract a
diff --git a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
index 4c0e51b67dd59..1f9bd52425455 100644
--- a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
+++ b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
@@ -337,8 +337,29 @@ exit:                                              ; preds = %loop
 
 define i16 @crc16.be.tc8.crc.init.select(i16 %a, i16 %b) {
 ; CHECK-LABEL: 'crc16.be.tc8.crc.init.select'
-; CHECK-NEXT:  Did not find a hash algorithm
-; CHECK-NEXT:  Reason: Unable to find conditional recurrence
+; CHECK-NEXT:  Found big-endian CRC-16 loop with trip count 8
+; CHECK-NEXT:    Initial CRC: %crc.init = select i1 %init.cond, i16 %a.inc, i16 %b.inc
+; CHECK-NEXT:    Generating polynomial: 4129
+; CHECK-NEXT:    Computed CRC: %crc.next = select i1 %check.sb, i16 %crc.xor, i16 %crc.shl
+; CHECK-NEXT:    Computed CRC lookup table:
+; CHECK-NEXT:  0 4129 8258 12387 16516 20645 24774 28903 33032 37161 41290 45419 49548 53677 57806 61935
+; CHECK-NEXT:  4657 528 12915 8786 21173 17044 29431 25302 37689 33560 45947 41818 54205 50076 62463 58334
+; CHECK-NEXT:  9314 13379 1056 5121 25830 29895 17572 21637 42346 46411 34088 38153 58862 62927 50604 54669
+; CHECK-NEXT:  13907 9842 5649 1584 30423 26358 22165 18100 46939 42874 38681 34616 63455 59390 55197 51132
+; CHECK-NEXT:  18628 22757 26758 30887 2112 6241 10242 14371 51660 55789 59790 63919 35144 39273 43274 47403
+; CHECK-NEXT:  23285 19156 31415 27286 6769 2640 14899 10770 56317 52188 64447 60318 39801 35672 47931 43802
+; CHECK-NEXT:  27814 31879 19684 23749 11298 15363 3168 7233 60846 64911 52716 56781 44330 48395 36200 40265
+; CHECK-NEXT:  32407 28342 24277 20212 15891 11826 7761 3696 65439 61374 57309 53244 48923 44858 40793 36728
+; CHECK-NEXT:  37256 33193 45514 41451 53516 49453 61774 57711 4224 161 12482 8419 20484 16421 28742 24679
+; CHECK-NEXT:  33721 37784 41979 46042 49981 54044 58239 62302 689 4752 8947 13010 16949 21012 25207 29270
+; CHECK-NEXT:  46570 42443 38312 34185 62830 58703 54572 50445 13538 9411 5280 1153 29798 25671 21540 17413
+; CHECK-NEXT:  42971 47098 34713 38840 59231 63358 50973 55100 9939 14066 1681 5808 26199 30326 17941 22068
+; CHECK-NEXT:  55628 51565 63758 59695 39368 35305 47498 43435 22596 18533 30726 26663 6336 2273 14466 10403
+; CHECK-NEXT:  52093 56156 60223 64286 35833 39896 43963 48026 19061 23124 27191 31254 2801 6864 10931 14994
+; CHECK-NEXT:  64814 60687 56684 52557 48554 44427 40424 36297 31782 27655 23652 19525 15522 11395 7392 3265
+; CHECK-NEXT:  61215 65342 53085 57212 44955 49082 36825 40952 28183 32310 20053 24180 11923 16050 3793 7920
+; CHECK-NEXT:    Computed CRC Barrett constants:
+; CHECK-NEXT:  Mu = 273, FullGenPoly = 69665
 ;
 entry:
   %a.inc = add i16 %a, 1

>From ee013c36efc04c1978da7a2d4cefd82faf1e5721 Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Mon, 27 Jul 2026 09:16:09 -0500
Subject: [PATCH 4/4] Add guard for invalid LatchIdx

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

diff --git a/llvm/lib/Analysis/HashRecognize.cpp b/llvm/lib/Analysis/HashRecognize.cpp
index 7357c9c21a1f9..c2cb6c44763a2 100644
--- a/llvm/lib/Analysis/HashRecognize.cpp
+++ b/llvm/lib/Analysis/HashRecognize.cpp
@@ -292,6 +292,8 @@ bool RecurrenceInfo::matchConditionalRecurrence(
 
   // Step comes from the loop latch, start comes from the other incoming value.
   int LatchIdx = Phi->getBasicBlockIndex(L.getLoopLatch());
+  if (LatchIdx < 0)
+    return false;
   Value *FoundStep = Phi->getIncomingValue(LatchIdx);
   Value *FoundStart = Phi->getIncomingValue(!LatchIdx);
 



More information about the llvm-commits mailing list