[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