[llvm] [HashRecognize] Apply byte-multiple trip count requirement only to table lookup optimization (PR #210086)
Sean Clarke via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 08:53:40 PDT 2026
https://github.com/xarkenz created https://github.com/llvm/llvm-project/pull/210086
The newly added carryless-multiply CRC loop optimization (#203405) does not require a byte-multiple trip count unlike the Sarwate method which was previously implemented. Loosen this requirement in HashRecognize and reapply it in `optimizeCRCLoop`.
>From 3258a3ea330f8d0f8195fba33510cdf95dfca46d Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Tue, 14 Jul 2026 10:47:49 -0500
Subject: [PATCH 1/3] Add baseline tests
---
.../LoopIdiom/cyclic-redundancy-check.ll | 94 ++++++++++++++++++-
1 file changed, 92 insertions(+), 2 deletions(-)
diff --git a/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll b/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll
index 299a84099cb54..efa33c75de1df 100644
--- a/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll
+++ b/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll
@@ -1033,9 +1033,99 @@ exit: ; preds = %loop
ret i16 %crc.next
}
+define i32 @crc32.le.tc4.data32(i32 %checksum, i32 %msg) optsize {
+; ALL-LABEL: define i32 @crc32.le.tc4.data32(
+; ALL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0:[0-9]+]] {
+; ALL-NEXT: [[ENTRY:.*]]:
+; ALL-NEXT: br label %[[LOOP:.*]]
+; ALL: [[LOOP]]:
+; ALL-NEXT: [[CRC:%.*]] = phi i32 [ [[CHECKSUM]], %[[ENTRY]] ], [ [[CRC_NEXT:%.*]], %[[LOOP]] ]
+; ALL-NEXT: [[DATA:%.*]] = phi i32 [ [[MSG]], %[[ENTRY]] ], [ [[DATA_NEXT:%.*]], %[[LOOP]] ]
+; ALL-NEXT: [[IV:%.*]] = phi i8 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; ALL-NEXT: [[XOR_CRC_DATA:%.*]] = xor i32 [[CRC]], [[DATA]]
+; ALL-NEXT: [[SB_CRC_DATA:%.*]] = and i32 [[XOR_CRC_DATA]], 1
+; ALL-NEXT: [[CHECK_SB:%.*]] = icmp eq i32 [[SB_CRC_DATA]], 0
+; ALL-NEXT: [[CRC_LSHR:%.*]] = lshr i32 [[CRC]], 1
+; ALL-NEXT: [[CRC_XOR:%.*]] = xor i32 [[CRC_LSHR]], 33800
+; ALL-NEXT: [[CRC_NEXT]] = select i1 [[CHECK_SB]], i32 [[CRC_LSHR]], i32 [[CRC_XOR]]
+; ALL-NEXT: [[IV_NEXT]] = add nuw nsw i8 [[IV]], 1
+; ALL-NEXT: [[DATA_NEXT]] = lshr i32 [[DATA]], 1
+; ALL-NEXT: [[EXIT_COND:%.*]] = icmp samesign ult i8 [[IV]], 3
+; ALL-NEXT: br i1 [[EXIT_COND]], label %[[LOOP]], label %[[EXIT:.*]]
+; ALL: [[EXIT]]:
+; ALL-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT]], %[[LOOP]] ]
+; ALL-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
+;
+entry:
+ br label %loop
+
+loop: ; preds = %loop, %entry
+ %crc = phi i32 [ %checksum, %entry ], [ %crc.next, %loop ]
+ %data = phi i32 [ %msg, %entry ], [ %data.next, %loop ]
+ %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+ %xor.crc.data = xor i32 %crc, %data
+ %sb.crc.data = and i32 %xor.crc.data, 1
+ %check.sb = icmp eq i32 %sb.crc.data, 0
+ %crc.lshr = lshr i32 %crc, 1
+ %crc.xor = xor i32 %crc.lshr, 33800
+ %crc.next = select i1 %check.sb, i32 %crc.lshr, i32 %crc.xor
+ %iv.next = add nuw nsw i8 %iv, 1
+ %data.next = lshr i32 %data, 1
+ %exit.cond = icmp samesign ult i8 %iv, 3
+ br i1 %exit.cond, label %loop, label %exit
+
+exit: ; preds = %loop
+ ret i32 %crc.next
+}
+
+define i32 @crc32.le.tc30.data32(i32 %checksum, i32 %msg) optsize {
+; ALL-LABEL: define i32 @crc32.le.tc30.data32(
+; ALL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0]] {
+; ALL-NEXT: [[ENTRY:.*]]:
+; ALL-NEXT: br label %[[LOOP:.*]]
+; ALL: [[LOOP]]:
+; ALL-NEXT: [[CRC:%.*]] = phi i32 [ [[CHECKSUM]], %[[ENTRY]] ], [ [[CRC_NEXT:%.*]], %[[LOOP]] ]
+; ALL-NEXT: [[DATA:%.*]] = phi i32 [ [[MSG]], %[[ENTRY]] ], [ [[DATA_NEXT:%.*]], %[[LOOP]] ]
+; ALL-NEXT: [[IV:%.*]] = phi i8 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; ALL-NEXT: [[XOR_CRC_DATA:%.*]] = xor i32 [[CRC]], [[DATA]]
+; ALL-NEXT: [[SB_CRC_DATA:%.*]] = and i32 [[XOR_CRC_DATA]], 1
+; ALL-NEXT: [[CHECK_SB:%.*]] = icmp eq i32 [[SB_CRC_DATA]], 0
+; ALL-NEXT: [[CRC_LSHR:%.*]] = lshr i32 [[CRC]], 1
+; ALL-NEXT: [[CRC_XOR:%.*]] = xor i32 [[CRC_LSHR]], 33800
+; ALL-NEXT: [[CRC_NEXT]] = select i1 [[CHECK_SB]], i32 [[CRC_LSHR]], i32 [[CRC_XOR]]
+; ALL-NEXT: [[IV_NEXT]] = add nuw nsw i8 [[IV]], 1
+; ALL-NEXT: [[DATA_NEXT]] = lshr i32 [[DATA]], 1
+; ALL-NEXT: [[EXIT_COND:%.*]] = icmp samesign ult i8 [[IV]], 29
+; ALL-NEXT: br i1 [[EXIT_COND]], label %[[LOOP]], label %[[EXIT:.*]]
+; ALL: [[EXIT]]:
+; ALL-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT]], %[[LOOP]] ]
+; ALL-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
+;
+entry:
+ br label %loop
+
+loop: ; preds = %loop, %entry
+ %crc = phi i32 [ %checksum, %entry ], [ %crc.next, %loop ]
+ %data = phi i32 [ %msg, %entry ], [ %data.next, %loop ]
+ %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+ %xor.crc.data = xor i32 %crc, %data
+ %sb.crc.data = and i32 %xor.crc.data, 1
+ %check.sb = icmp eq i32 %sb.crc.data, 0
+ %crc.lshr = lshr i32 %crc, 1
+ %crc.xor = xor i32 %crc.lshr, 33800
+ %crc.next = select i1 %check.sb, i32 %crc.lshr, i32 %crc.xor
+ %iv.next = add nuw nsw i8 %iv, 1
+ %data.next = lshr i32 %data, 1
+ %exit.cond = icmp samesign ult i8 %iv, 29
+ br i1 %exit.cond, label %loop, label %exit
+
+exit: ; preds = %loop
+ ret i32 %crc.next
+}
+
define i32 @crc.disabled.optsize(i32 %checksum, i32 %msg) optsize {
; TABLE-LABEL: define i32 @crc.disabled.optsize(
-; TABLE-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0:[0-9]+]] {
+; TABLE-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0]] {
; TABLE-NEXT: [[ENTRY:.*]]:
; TABLE-NEXT: br label %[[LOOP:.*]]
; TABLE: [[LOOP]]:
@@ -1057,7 +1147,7 @@ define i32 @crc.disabled.optsize(i32 %checksum, i32 %msg) optsize {
; TABLE-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
;
; CLMUL-LABEL: define i32 @crc.disabled.optsize(
-; CLMUL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CLMUL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0]] {
; CLMUL-NEXT: [[ENTRY:.*:]]
; CLMUL-NEXT: [[CRC_CAST:%.*]] = zext i32 [[CHECKSUM]] to i40
; CLMUL-NEXT: [[DATA_CAST:%.*]] = zext i32 [[MSG]] to i40
>From 612bfaedbb04981aec9e255d3c0d1cc61bd0286e Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Tue, 14 Jul 2026 10:57:23 -0500
Subject: [PATCH 2/3] Move byte-multiple TC restriction from HashRecognize to
optimizeCRCLoop
---
llvm/lib/Analysis/HashRecognize.cpp | 4 +-
.../Transforms/Scalar/LoopIdiomRecognize.cpp | 4 +-
.../HashRecognize/cyclic-redundancy-check.ll | 27 +++-
.../LoopIdiom/cyclic-redundancy-check.ll | 124 ++++++++++++------
4 files changed, 111 insertions(+), 48 deletions(-)
diff --git a/llvm/lib/Analysis/HashRecognize.cpp b/llvm/lib/Analysis/HashRecognize.cpp
index 3846c822432e1..d29742ef571bd 100644
--- a/llvm/lib/Analysis/HashRecognize.cpp
+++ b/llvm/lib/Analysis/HashRecognize.cpp
@@ -511,8 +511,8 @@ std::variant<PolynomialInfo, StringRef> HashRecognize::recognizeCRC() const {
if (!Latch || !Exit || !IndVar || L.getNumBlocks() != 1)
return "Loop not in canonical form";
unsigned TC = SE.getSmallConstantTripCount(&L);
- if (!TC || TC % 8)
- return "Unable to find a small constant byte-multiple trip count";
+ if (!TC)
+ return "Unable to find a small constant trip count";
auto R = getRecurrences(Latch, IndVar, L);
if (!R)
diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
index e831a89a79113..e674143099a53 100644
--- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
@@ -1608,7 +1608,7 @@ bool LoopIdiomRecognize::optimizeCRCLoop(const PolynomialInfo &Info) {
// be used to determine which optimization to use. Until then, only apply the
// clmul optimization when optimizing for size, since a lookup table is not
// viable in that case.
- if (!ApplyCodeSizeHeuristics) {
+ if (!ApplyCodeSizeHeuristics && Info.TripCount % 8 == 0) {
optimizeCRCLoopUsingTableLookup(Info);
return true;
}
@@ -1743,6 +1743,8 @@ void LoopIdiomRecognize::optimizeCRCLoopUsingClmul(const PolynomialInfo &Info,
void LoopIdiomRecognize::optimizeCRCLoopUsingTableLookup(
const PolynomialInfo &Info) {
+ assert(Info.TripCount % 8 == 0 && "A byte-multiple trip count is required");
+
// First, create a new GlobalVariable corresponding to the
// Sarwate-lookup-table.
Type *CRCTy = Info.LHS->getType();
diff --git a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
index e3dc53a3e66ed..cf3831e3d0537 100644
--- a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
+++ b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
@@ -742,7 +742,7 @@ exit: ; preds = %loop
define i16 @not.crc.non.const.tc(i16 %crc.init, i32 %loop.limit) {
; CHECK-LABEL: 'not.crc.non.const.tc'
; CHECK-NEXT: Did not find a hash algorithm
-; CHECK-NEXT: Reason: Unable to find a small constant byte-multiple trip count
+; CHECK-NEXT: Reason: Unable to find a small constant trip count
;
entry:
br label %loop
@@ -764,8 +764,29 @@ exit: ; preds = %loop
define i16 @not.crc.non.canonical.not.multiple.8(i16 %crc.init) {
; CHECK-LABEL: 'not.crc.non.canonical.not.multiple.8'
-; CHECK-NEXT: Did not find a hash algorithm
-; CHECK-NEXT: Reason: Unable to find a small constant byte-multiple trip count
+; CHECK-NEXT: Found big-endian CRC-16 loop with trip count 4
+; CHECK-NEXT: Initial CRC: i16 %crc.init
+; 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 = 17, FullGenPoly = 69665
;
entry:
br label %loop
diff --git a/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll b/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll
index efa33c75de1df..d4c2f59e9003a 100644
--- a/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll
+++ b/llvm/test/Transforms/LoopIdiom/cyclic-redundancy-check.ll
@@ -1034,27 +1034,47 @@ exit: ; preds = %loop
}
define i32 @crc32.le.tc4.data32(i32 %checksum, i32 %msg) optsize {
-; ALL-LABEL: define i32 @crc32.le.tc4.data32(
-; ALL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0:[0-9]+]] {
-; ALL-NEXT: [[ENTRY:.*]]:
-; ALL-NEXT: br label %[[LOOP:.*]]
-; ALL: [[LOOP]]:
-; ALL-NEXT: [[CRC:%.*]] = phi i32 [ [[CHECKSUM]], %[[ENTRY]] ], [ [[CRC_NEXT:%.*]], %[[LOOP]] ]
-; ALL-NEXT: [[DATA:%.*]] = phi i32 [ [[MSG]], %[[ENTRY]] ], [ [[DATA_NEXT:%.*]], %[[LOOP]] ]
-; ALL-NEXT: [[IV:%.*]] = phi i8 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; ALL-NEXT: [[XOR_CRC_DATA:%.*]] = xor i32 [[CRC]], [[DATA]]
-; ALL-NEXT: [[SB_CRC_DATA:%.*]] = and i32 [[XOR_CRC_DATA]], 1
-; ALL-NEXT: [[CHECK_SB:%.*]] = icmp eq i32 [[SB_CRC_DATA]], 0
-; ALL-NEXT: [[CRC_LSHR:%.*]] = lshr i32 [[CRC]], 1
-; ALL-NEXT: [[CRC_XOR:%.*]] = xor i32 [[CRC_LSHR]], 33800
-; ALL-NEXT: [[CRC_NEXT]] = select i1 [[CHECK_SB]], i32 [[CRC_LSHR]], i32 [[CRC_XOR]]
-; ALL-NEXT: [[IV_NEXT]] = add nuw nsw i8 [[IV]], 1
-; ALL-NEXT: [[DATA_NEXT]] = lshr i32 [[DATA]], 1
-; ALL-NEXT: [[EXIT_COND:%.*]] = icmp samesign ult i8 [[IV]], 3
-; ALL-NEXT: br i1 [[EXIT_COND]], label %[[LOOP]], label %[[EXIT:.*]]
-; ALL: [[EXIT]]:
-; ALL-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT]], %[[LOOP]] ]
-; ALL-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
+; TABLE-LABEL: define i32 @crc32.le.tc4.data32(
+; TABLE-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0:[0-9]+]] {
+; TABLE-NEXT: [[ENTRY:.*]]:
+; TABLE-NEXT: br label %[[LOOP:.*]]
+; TABLE: [[LOOP]]:
+; TABLE-NEXT: [[CRC:%.*]] = phi i32 [ [[CHECKSUM]], %[[ENTRY]] ], [ [[CRC_NEXT:%.*]], %[[LOOP]] ]
+; TABLE-NEXT: [[DATA:%.*]] = phi i32 [ [[MSG]], %[[ENTRY]] ], [ [[DATA_NEXT:%.*]], %[[LOOP]] ]
+; TABLE-NEXT: [[IV:%.*]] = phi i8 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; TABLE-NEXT: [[XOR_CRC_DATA:%.*]] = xor i32 [[CRC]], [[DATA]]
+; TABLE-NEXT: [[SB_CRC_DATA:%.*]] = and i32 [[XOR_CRC_DATA]], 1
+; TABLE-NEXT: [[CHECK_SB:%.*]] = icmp eq i32 [[SB_CRC_DATA]], 0
+; TABLE-NEXT: [[CRC_LSHR:%.*]] = lshr i32 [[CRC]], 1
+; TABLE-NEXT: [[CRC_XOR:%.*]] = xor i32 [[CRC_LSHR]], 33800
+; TABLE-NEXT: [[CRC_NEXT]] = select i1 [[CHECK_SB]], i32 [[CRC_LSHR]], i32 [[CRC_XOR]]
+; TABLE-NEXT: [[IV_NEXT]] = add nuw nsw i8 [[IV]], 1
+; TABLE-NEXT: [[DATA_NEXT]] = lshr i32 [[DATA]], 1
+; TABLE-NEXT: [[EXIT_COND:%.*]] = icmp samesign ult i8 [[IV]], 3
+; TABLE-NEXT: br i1 [[EXIT_COND]], label %[[LOOP]], label %[[EXIT:.*]]
+; TABLE: [[EXIT]]:
+; TABLE-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT]], %[[LOOP]] ]
+; TABLE-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
+;
+; CLMUL-LABEL: define i32 @crc32.le.tc4.data32(
+; CLMUL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0:[0-9]+]] {
+; CLMUL-NEXT: [[ENTRY:.*:]]
+; CLMUL-NEXT: [[CRC_CAST:%.*]] = zext i32 [[CHECKSUM]] to i36
+; CLMUL-NEXT: [[DATA_CAST:%.*]] = zext i32 [[MSG]] to i36
+; CLMUL-NEXT: [[XOR_CRC_DATA1:%.*]] = xor i36 [[CRC_CAST]], [[DATA_CAST]]
+; CLMUL-NEXT: [[CRC_TCBITS:%.*]] = and i36 [[XOR_CRC_DATA1]], 15
+; CLMUL-NEXT: [[CLMUL_MU:%.*]] = call i36 @llvm.clmul.i36(i36 [[CRC_TCBITS]], i36 17)
+; CLMUL-NEXT: [[QUOT_MASK:%.*]] = and i36 [[CLMUL_MU]], 15
+; CLMUL-NEXT: [[CLMUL_GP:%.*]] = call i36 @llvm.clmul.i36(i36 [[QUOT_MASK]], i36 67601)
+; CLMUL-NEXT: [[XOR_CRC_MULT:%.*]] = xor i36 [[CRC_CAST]], [[CLMUL_GP]]
+; CLMUL-NEXT: [[CRC_LSHR2:%.*]] = lshr i36 [[XOR_CRC_MULT]], 4
+; CLMUL-NEXT: [[CRC_NEXT3:%.*]] = trunc i36 [[CRC_LSHR2]] to i32
+; CLMUL-NEXT: br label %[[LOOP:.*]]
+; CLMUL: [[LOOP]]:
+; CLMUL-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT:.*]]
+; CLMUL: [[EXIT]]:
+; CLMUL-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT3]], %[[LOOP]] ]
+; CLMUL-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
;
entry:
br label %loop
@@ -1079,27 +1099,47 @@ exit: ; preds = %loop
}
define i32 @crc32.le.tc30.data32(i32 %checksum, i32 %msg) optsize {
-; ALL-LABEL: define i32 @crc32.le.tc30.data32(
-; ALL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0]] {
-; ALL-NEXT: [[ENTRY:.*]]:
-; ALL-NEXT: br label %[[LOOP:.*]]
-; ALL: [[LOOP]]:
-; ALL-NEXT: [[CRC:%.*]] = phi i32 [ [[CHECKSUM]], %[[ENTRY]] ], [ [[CRC_NEXT:%.*]], %[[LOOP]] ]
-; ALL-NEXT: [[DATA:%.*]] = phi i32 [ [[MSG]], %[[ENTRY]] ], [ [[DATA_NEXT:%.*]], %[[LOOP]] ]
-; ALL-NEXT: [[IV:%.*]] = phi i8 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; ALL-NEXT: [[XOR_CRC_DATA:%.*]] = xor i32 [[CRC]], [[DATA]]
-; ALL-NEXT: [[SB_CRC_DATA:%.*]] = and i32 [[XOR_CRC_DATA]], 1
-; ALL-NEXT: [[CHECK_SB:%.*]] = icmp eq i32 [[SB_CRC_DATA]], 0
-; ALL-NEXT: [[CRC_LSHR:%.*]] = lshr i32 [[CRC]], 1
-; ALL-NEXT: [[CRC_XOR:%.*]] = xor i32 [[CRC_LSHR]], 33800
-; ALL-NEXT: [[CRC_NEXT]] = select i1 [[CHECK_SB]], i32 [[CRC_LSHR]], i32 [[CRC_XOR]]
-; ALL-NEXT: [[IV_NEXT]] = add nuw nsw i8 [[IV]], 1
-; ALL-NEXT: [[DATA_NEXT]] = lshr i32 [[DATA]], 1
-; ALL-NEXT: [[EXIT_COND:%.*]] = icmp samesign ult i8 [[IV]], 29
-; ALL-NEXT: br i1 [[EXIT_COND]], label %[[LOOP]], label %[[EXIT:.*]]
-; ALL: [[EXIT]]:
-; ALL-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT]], %[[LOOP]] ]
-; ALL-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
+; TABLE-LABEL: define i32 @crc32.le.tc30.data32(
+; TABLE-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0]] {
+; TABLE-NEXT: [[ENTRY:.*]]:
+; TABLE-NEXT: br label %[[LOOP:.*]]
+; TABLE: [[LOOP]]:
+; TABLE-NEXT: [[CRC:%.*]] = phi i32 [ [[CHECKSUM]], %[[ENTRY]] ], [ [[CRC_NEXT:%.*]], %[[LOOP]] ]
+; TABLE-NEXT: [[DATA:%.*]] = phi i32 [ [[MSG]], %[[ENTRY]] ], [ [[DATA_NEXT:%.*]], %[[LOOP]] ]
+; TABLE-NEXT: [[IV:%.*]] = phi i8 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
+; TABLE-NEXT: [[XOR_CRC_DATA:%.*]] = xor i32 [[CRC]], [[DATA]]
+; TABLE-NEXT: [[SB_CRC_DATA:%.*]] = and i32 [[XOR_CRC_DATA]], 1
+; TABLE-NEXT: [[CHECK_SB:%.*]] = icmp eq i32 [[SB_CRC_DATA]], 0
+; TABLE-NEXT: [[CRC_LSHR:%.*]] = lshr i32 [[CRC]], 1
+; TABLE-NEXT: [[CRC_XOR:%.*]] = xor i32 [[CRC_LSHR]], 33800
+; TABLE-NEXT: [[CRC_NEXT]] = select i1 [[CHECK_SB]], i32 [[CRC_LSHR]], i32 [[CRC_XOR]]
+; TABLE-NEXT: [[IV_NEXT]] = add nuw nsw i8 [[IV]], 1
+; TABLE-NEXT: [[DATA_NEXT]] = lshr i32 [[DATA]], 1
+; TABLE-NEXT: [[EXIT_COND:%.*]] = icmp samesign ult i8 [[IV]], 29
+; TABLE-NEXT: br i1 [[EXIT_COND]], label %[[LOOP]], label %[[EXIT:.*]]
+; TABLE: [[EXIT]]:
+; TABLE-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT]], %[[LOOP]] ]
+; TABLE-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
+;
+; CLMUL-LABEL: define i32 @crc32.le.tc30.data32(
+; CLMUL-SAME: i32 [[CHECKSUM:%.*]], i32 [[MSG:%.*]]) #[[ATTR0]] {
+; CLMUL-NEXT: [[ENTRY:.*:]]
+; CLMUL-NEXT: [[CRC_CAST:%.*]] = zext i32 [[CHECKSUM]] to i62
+; CLMUL-NEXT: [[DATA_CAST:%.*]] = zext i32 [[MSG]] to i62
+; CLMUL-NEXT: [[XOR_CRC_DATA1:%.*]] = xor i62 [[CRC_CAST]], [[DATA_CAST]]
+; CLMUL-NEXT: [[CRC_TCBITS:%.*]] = and i62 [[XOR_CRC_DATA1]], 1073741823
+; CLMUL-NEXT: [[CLMUL_MU:%.*]] = call i62 @llvm.clmul.i62(i62 [[CRC_TCBITS]], i62 475535633)
+; CLMUL-NEXT: [[QUOT_MASK:%.*]] = and i62 [[CLMUL_MU]], 1073741823
+; CLMUL-NEXT: [[CLMUL_GP:%.*]] = call i62 @llvm.clmul.i62(i62 [[QUOT_MASK]], i62 67601)
+; CLMUL-NEXT: [[XOR_CRC_MULT:%.*]] = xor i62 [[CRC_CAST]], [[CLMUL_GP]]
+; CLMUL-NEXT: [[CRC_LSHR2:%.*]] = lshr i62 [[XOR_CRC_MULT]], 30
+; CLMUL-NEXT: [[CRC_NEXT3:%.*]] = trunc i62 [[CRC_LSHR2]] to i32
+; CLMUL-NEXT: br label %[[LOOP:.*]]
+; CLMUL: [[LOOP]]:
+; CLMUL-NEXT: br i1 false, label %[[LOOP]], label %[[EXIT:.*]]
+; CLMUL: [[EXIT]]:
+; CLMUL-NEXT: [[CRC_NEXT_LCSSA:%.*]] = phi i32 [ [[CRC_NEXT3]], %[[LOOP]] ]
+; CLMUL-NEXT: ret i32 [[CRC_NEXT_LCSSA]]
;
entry:
br label %loop
>From e87533fc6c0bc7d190c0832c3df447f06ab1671c Mon Sep 17 00:00:00 2001
From: Sean Clarke <sclarke at tenstorrent.com>
Date: Tue, 14 Jul 2026 11:01:51 -0500
Subject: [PATCH 3/3] Rename now-positive test
---
.../HashRecognize/cyclic-redundancy-check.ll | 54 +++++++++----------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
index cf3831e3d0537..b7139a7367829 100644
--- a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
+++ b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
@@ -737,33 +737,8 @@ exit: ; preds = %loop
ret i16 %crc.next
}
-; Negative tests
-
-define i16 @not.crc.non.const.tc(i16 %crc.init, i32 %loop.limit) {
-; CHECK-LABEL: 'not.crc.non.const.tc'
-; CHECK-NEXT: Did not find a hash algorithm
-; CHECK-NEXT: Reason: Unable to find a small constant trip count
-;
-entry:
- 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 sge i16 %crc, 0
- %crc.next = select i1 %check.sb, i16 %crc.shl, i16 %crc.xor
- %iv.next = add nuw nsw i32 %iv, 1
- %exit.cond = icmp samesign ult i32 %iv, %loop.limit
- br i1 %exit.cond, label %loop, label %exit
-
-exit: ; preds = %loop
- ret i16 %crc.next
-}
-
-define i16 @not.crc.non.canonical.not.multiple.8(i16 %crc.init) {
-; CHECK-LABEL: 'not.crc.non.canonical.not.multiple.8'
+define i16 @crc16.be.tc4.crc.init.arg(i16 %crc.init) {
+; CHECK-LABEL: 'crc16.be.tc4.crc.init.arg'
; CHECK-NEXT: Found big-endian CRC-16 loop with trip count 4
; CHECK-NEXT: Initial CRC: i16 %crc.init
; CHECK-NEXT: Generating polynomial: 4129
@@ -806,6 +781,31 @@ exit: ; preds = %loop
ret i16 %crc.next
}
+; Negative tests
+
+define i16 @not.crc.non.const.tc(i16 %crc.init, i32 %loop.limit) {
+; CHECK-LABEL: 'not.crc.non.const.tc'
+; CHECK-NEXT: Did not find a hash algorithm
+; CHECK-NEXT: Reason: Unable to find a small constant trip count
+;
+entry:
+ 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 sge i16 %crc, 0
+ %crc.next = select i1 %check.sb, i16 %crc.shl, i16 %crc.xor
+ %iv.next = add nuw nsw i32 %iv, 1
+ %exit.cond = icmp samesign ult i32 %iv, %loop.limit
+ br i1 %exit.cond, label %loop, label %exit
+
+exit: ; preds = %loop
+ ret i16 %crc.next
+}
+
define i16 @not.crc.non.canonical.loop.countdown(i16 %crc.init) {
; CHECK-LABEL: 'not.crc.non.canonical.loop.countdown'
; CHECK-NEXT: Did not find a hash algorithm
More information about the llvm-commits
mailing list