[llvm] [HashRecognize] Recognize trunc-to-i1 little-endian bit check (PR #213883)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 4 02:29:50 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-analysis

Author: Vito Kortbeek (vkortbeek-gf)

<details>
<summary>Changes</summary>

InstCombine may rewrite `icmp ne (X & 1), 0` to `trunc X to i1` (#<!-- -->178977). Accept that spelling in the CRC significant-bit matcher.

Fixes: #<!-- -->213881 
Assisted-by: AI

---
Full diff: https://github.com/llvm/llvm-project/pull/213883.diff


2 Files Affected:

- (modified) llvm/lib/Analysis/HashRecognize.cpp (+16-6) 
- (modified) llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll (+73) 


``````````diff
diff --git a/llvm/lib/Analysis/HashRecognize.cpp b/llvm/lib/Analysis/HashRecognize.cpp
index ade4be565ee11..840b97aaccab7 100644
--- a/llvm/lib/Analysis/HashRecognize.cpp
+++ b/llvm/lib/Analysis/HashRecognize.cpp
@@ -155,7 +155,8 @@ struct RecurrenceInfo {
 /// ConditionalRecurrence, \p SimpleRecurrence, depending on \p IsBigEndian. We
 /// check that ConditionalRecurrence.Step is a Select(Cmp()) where the compare
 /// is `>= 0` in the big-endian case, and `== 0` in the little-endian case (or
-/// the inverse, in which case the branches of the compare are swapped). We
+/// the inverse, in which case the branches of the compare are swapped). For
+/// little-endian, we also accept a trunc to i1 (extracting bit zero). We
 /// check that the LHS is (ConditionalRecurrence.Phi [xor SimpleRecurrence.Phi])
 /// in the big-endian case, and additionally check for an AND with one in the
 /// little-endian case. We then check AllowedByR against CheckAllowedByR, which
@@ -172,9 +173,6 @@ isSignificantBitCheckWellFormed(const RecurrenceInfo &ConditionalRecurrence,
   const Value *L;
   const APInt *R;
   Instruction *TV, *FV;
-  if (!match(SI, m_Select(m_ICmp(Pred, m_Value(L), m_APInt(R)),
-                          m_Instruction(TV), m_Instruction(FV))))
-    return false;
 
   // Match predicate with or without a SimpleRecurrence (the corresponding data
   // is LHSAux).
@@ -182,6 +180,18 @@ isSignificantBitCheckWellFormed(const RecurrenceInfo &ConditionalRecurrence,
       m_Specific(ConditionalRecurrence.Phi),
       m_c_Xor(m_ZExtOrTruncOrSelf(m_Specific(ConditionalRecurrence.Phi)),
               m_ZExtOrTruncOrSelf(m_Specific(SimpleRecurrence.Phi))));
+  BinaryOperator *BitShift = ConditionalRecurrence.BO;
+  if (!IsBigEndian &&
+      match(SI, m_Select(m_Trunc(m_Value(L)), m_Instruction(TV),
+                         m_Instruction(FV))))
+    return match(L, MatchPred) && FV == BitShift &&
+           match(TV, m_c_Xor(m_Specific(BitShift),
+                             m_SpecificInt(*ConditionalRecurrence.ExtraConst)));
+
+  if (!match(SI, m_Select(m_ICmp(Pred, m_Value(L), m_APInt(R)),
+                          m_Instruction(TV), m_Instruction(FV))))
+    return false;
+
   bool LWellFormed =
       IsBigEndian ? match(L, MatchPred) : match(L, m_c_And(MatchPred, m_One()));
   if (!LWellFormed)
@@ -195,7 +205,6 @@ isSignificantBitCheckWellFormed(const RecurrenceInfo &ConditionalRecurrence,
                                 IsBigEndian ? APInt::getSignedMinValue(BW)
                                             : APInt(BW, 1));
 
-  BinaryOperator *BitShift = ConditionalRecurrence.BO;
   if (AllowedByR == CheckAllowedByR)
     return TV == BitShift &&
            match(FV, m_c_Xor(m_Specific(BitShift),
@@ -301,7 +310,8 @@ bool RecurrenceInfo::matchConditionalRecurrence(
 
   Instruction *TV, *FV;
   if (!match(FoundStep,
-             m_Select(m_Cmp(), m_Instruction(TV), m_Instruction(FV))))
+             m_Select(m_CombineOr(m_Cmp(), m_Trunc(m_Value())),
+                      m_Instruction(TV), m_Instruction(FV))))
     return false;
 
   // For a conditional recurrence, both the true and false values of the
diff --git a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
index 1a17a82f1bff1..02eadff5765db 100644
--- a/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
+++ b/llvm/test/Analysis/HashRecognize/cyclic-redundancy-check.ll
@@ -51,6 +51,56 @@ exit:                                              ; preds = %loop
   ret i16 %crc.next
 }
 
+; A direct trunc to i1 tests whether bit zero is set.
+define i16 @crc16.le.tc8.trunc.i1(i8 %msg, i16 %checksum) {
+; CHECK-LABEL: 'crc16.le.tc8.trunc.i1'
+; CHECK-NEXT:  Found little-endian CRC-16 loop with trip count 8
+; CHECK-NEXT:    Initial CRC: i16 %checksum
+; CHECK-NEXT:    Generating polynomial: 40961
+; CHECK-NEXT:    Computed CRC: %crc.next = select i1 %check.sb, i16 %xor, i16 %crc.lshr
+; CHECK-NEXT:    Auxiliary data: i8 %msg
+; CHECK-NEXT:    Computed CRC lookup table:
+; CHECK-NEXT:  0 49345 49537 320 49921 960 640 49729 50689 1728 1920 51009 1280 50625 50305 1088
+; CHECK-NEXT:  52225 3264 3456 52545 3840 53185 52865 3648 2560 51905 52097 2880 51457 2496 2176 51265
+; CHECK-NEXT:  55297 6336 6528 55617 6912 56257 55937 6720 7680 57025 57217 8000 56577 7616 7296 56385
+; CHECK-NEXT:  5120 54465 54657 5440 55041 6080 5760 54849 53761 4800 4992 54081 4352 53697 53377 4160
+; CHECK-NEXT:  61441 12480 12672 61761 13056 62401 62081 12864 13824 63169 63361 14144 62721 13760 13440 62529
+; CHECK-NEXT:  15360 64705 64897 15680 65281 16320 16000 65089 64001 15040 15232 64321 14592 63937 63617 14400
+; CHECK-NEXT:  10240 59585 59777 10560 60161 11200 10880 59969 60929 11968 12160 61249 11520 60865 60545 11328
+; CHECK-NEXT:  58369 9408 9600 58689 9984 59329 59009 9792 8704 58049 58241 9024 57601 8640 8320 57409
+; CHECK-NEXT:  40961 24768 24960 41281 25344 41921 41601 25152 26112 42689 42881 26432 42241 26048 25728 42049
+; CHECK-NEXT:  27648 44225 44417 27968 44801 28608 28288 44609 43521 27328 27520 43841 26880 43457 43137 26688
+; CHECK-NEXT:  30720 47297 47489 31040 47873 31680 31360 47681 48641 32448 32640 48961 32000 48577 48257 31808
+; CHECK-NEXT:  46081 29888 30080 46401 30464 47041 46721 30272 29184 45761 45953 29504 45313 29120 28800 45121
+; CHECK-NEXT:  20480 37057 37249 20800 37633 21440 21120 37441 38401 22208 22400 38721 21760 38337 38017 21568
+; CHECK-NEXT:  39937 23744 23936 40257 24320 40897 40577 24128 23040 39617 39809 23360 39169 22976 22656 38977
+; CHECK-NEXT:  34817 18624 18816 35137 19200 35777 35457 19008 19968 36545 36737 20288 36097 19904 19584 35905
+; CHECK-NEXT:  17408 33985 34177 17728 34561 18368 18048 34369 33281 17088 17280 33601 16640 33217 32897 16448
+; CHECK-NEXT:    Computed CRC Barrett constants:
+; CHECK-NEXT:  Mu = 511, FullGenPoly = 81923
+;
+entry:
+  br label %loop
+
+loop:                                              ; preds = %loop, %entry
+  %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+  %crc = phi i16 [ %checksum, %entry ], [ %crc.next, %loop ]
+  %data = phi i8 [ %msg, %entry ], [ %data.next, %loop ]
+  %crc.trunc = trunc i16 %crc to i8
+  %xor.data.crc = xor i8 %data, %crc.trunc
+  %data.next = lshr i8 %data, 1
+  %check.sb = trunc i8 %xor.data.crc to i1
+  %crc.lshr = lshr i16 %crc, 1
+  %xor = xor i16 %crc.lshr, -24575
+  %crc.next = select i1 %check.sb, i16 %xor, i16 %crc.lshr
+  %iv.next = add nuw nsw i8 %iv, 1
+  %exit.cond = icmp samesign ult i8 %iv, 7
+  br i1 %exit.cond, label %loop, label %exit
+
+exit:                                              ; preds = %loop
+  ret i16 %crc.next
+}
+
 define i16 @crc16.le.tc8.udiv(i8 %msg, i16 %checksum) {
 ; CHECK-LABEL: 'crc16.le.tc8.udiv'
 ; CHECK-NEXT:  Found little-endian CRC-16 loop with trip count 8
@@ -1313,6 +1363,29 @@ exit:                                              ; preds = %loop
   ret i16 %crc.next
 }
 
+define i16 @not.crc.init.arg.trunc.i1.inverted.select(i16 %crc.init) {
+; CHECK-LABEL: 'not.crc.init.arg.trunc.i1.inverted.select'
+; CHECK-NEXT:  Did not find a hash algorithm
+; CHECK-NEXT:  Reason: Malformed significant-bit check
+;
+entry:
+  br label %loop
+
+loop:                                              ; preds = %loop, %entry
+  %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+  %crc = phi i16 [ %crc.init, %entry ], [ %crc.next, %loop ]
+  %check.sb = trunc i16 %crc to i1
+  %crc.lshr = lshr i16 %crc, 1
+  %crc.xor = xor i16 %crc.lshr, -24575
+  %crc.next = select i1 %check.sb, i16 %crc.lshr, i16 %crc.xor
+  %iv.next = add nuw nsw i8 %iv, 1
+  %exit.cond = icmp samesign ult i8 %iv, 7
+  br i1 %exit.cond, label %loop, label %exit
+
+exit:                                              ; preds = %loop
+  ret i16 %crc.next
+}
+
 define i16 @not.crc.bad.endian.swapped.sb.check(i8 %msg, i16 %checksum) {
 ; CHECK-LABEL: 'not.crc.bad.endian.swapped.sb.check'
 ; CHECK-NEXT:  Did not find a hash algorithm

``````````

</details>


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


More information about the llvm-commits mailing list