LLVM 24.0.0git
HashRecognize.cpp
Go to the documentation of this file.
1//===- HashRecognize.cpp ----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// The HashRecognize analysis recognizes unoptimized polynomial hash functions
10// with operations over a Galois field of characteristic 2, also called binary
11// fields, or GF(2^n). 2^n is termed the order of the Galois field. This class
12// of hash functions can be optimized using a lookup-table-driven
13// implementation, or with target-specific instructions.
14//
15// Examples:
16//
17// 1. Cyclic redundancy check (CRC), which is a polynomial division in GF(2).
18// 2. Rabin fingerprint, a component of the Rabin-Karp algorithm, which is a
19// rolling hash polynomial division in GF(2).
20// 3. Rijndael MixColumns, a step in AES computation, which is a polynomial
21// multiplication in GF(2^3).
22// 4. GHASH, the authentication mechanism in AES Galois/Counter Mode (GCM),
23// which is a polynomial evaluation in GF(2^128).
24//
25// All of them use an irreducible generating polynomial of degree m,
26//
27// c_m * x^m + c_(m-1) * x^(m-1) + ... + c_0 * x^0
28//
29// where each coefficient c is can take values 0 or 1. The polynomial is simply
30// represented by m+1 bits, corresponding to the coefficients. The different
31// variants of CRC are named by degree of generating polynomial used: so CRC-32
32// would use a polynomial of degree 32.
33//
34// The reason algorithms on GF(2^n) can be optimized with a lookup-table is the
35// following: in such fields, polynomial addition and subtraction are identical
36// and equivalent to XOR, polynomial multiplication is an AND, and polynomial
37// division is identity: the XOR and AND operations in unoptimized
38// implementations are performed bit-wise, and can be optimized to be performed
39// chunk-wise, by interleaving copies of the generating polynomial, and storing
40// the pre-computed values in a table.
41//
42// A generating polynomial of m bits always has the MSB set, so we usually
43// omit it. An example of a 16-bit polynomial is the CRC-16-CCITT polynomial:
44//
45// (x^16) + x^12 + x^5 + 1 = (1) 0001 0000 0010 0001 = 0x1021
46//
47// Transmissions are either in big-endian or little-endian form, and hash
48// algorithms are written according to this. For example, IEEE 802 and RS-232
49// specify little-endian transmission.
50//
51//===----------------------------------------------------------------------===//
52//
53// At the moment, we only recognize the CRC algorithm.
54// Documentation on CRC32 from the kernel:
55// https://www.kernel.org/doc/Documentation/crc32.txt
56//
57//
58//===----------------------------------------------------------------------===//
59
61#include "llvm/ADT/APInt.h"
69
70using namespace llvm;
71using namespace PatternMatch;
72using namespace SCEVPatternMatch;
73
74#define DEBUG_TYPE "hash-recognize"
75
76/// Checks if there's a stray instruction in the loop \p L outside of the
77/// use-def chains from \p Roots, or if we escape the loop during the use-def
78/// walk.
79static bool containsUnreachable(const Loop &L,
82 BasicBlock *Latch = L.getLoopLatch();
83
85 while (!Worklist.empty()) {
86 const Instruction *I = Worklist.pop_back_val();
87 Visited.insert(I);
88
89 if (isa<PHINode>(I))
90 continue;
91
92 for (const Use &U : I->operands()) {
93 if (auto *UI = dyn_cast<Instruction>(U)) {
94 if (!L.contains(UI))
95 return true;
96 Worklist.push_back(UI);
97 }
98 }
99 }
100 return Latch->size() != Visited.size();
101}
102
103/// A structure that can hold either a Simple Recurrence or a Conditional
104/// Recurrence. Note that in the case of a Simple Recurrence, Step is an operand
105/// of the BO, while in a Conditional Recurrence, it is a SelectInst.
107 const Loop &L;
108 const PHINode *Phi = nullptr;
109 BinaryOperator *BO = nullptr;
110 Value *Start = nullptr;
111 Value *Step = nullptr;
112 std::optional<APInt> ExtraConst;
113
114 RecurrenceInfo(const Loop &L) : L(L) {}
115 operator bool() const { return BO; }
116
117 void print(raw_ostream &OS, unsigned Indent = 0) const {
118 OS.indent(Indent) << "Phi: ";
119 Phi->print(OS);
120 OS << "\n";
121 OS.indent(Indent) << "BinaryOperator: ";
122 BO->print(OS);
123 OS << "\n";
124 OS.indent(Indent) << "Start: ";
125 Start->print(OS);
126 OS << "\n";
127 OS.indent(Indent) << "Step: ";
128 Step->print(OS);
129 OS << "\n";
130 if (ExtraConst) {
131 OS.indent(Indent) << "ExtraConst: ";
132 ExtraConst->print(OS, false);
133 OS << "\n";
134 }
135 }
136
137#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
138 LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
139#endif
140
141 bool matchSimpleRecurrence(const PHINode *P);
143 const PHINode *P,
144 Instruction::BinaryOps BOWithConstOpToMatch = Instruction::BinaryOpsEnd);
145
146private:
147 BinaryOperator *digRecurrence(
148 Instruction *V,
149 Instruction::BinaryOps BOWithConstOpToMatch = Instruction::BinaryOpsEnd);
150};
151
152/// Check the well-formedness of the (most|least) significant bit check given \p
153/// ConditionalRecurrence, \p SimpleRecurrence, depending on \p IsBigEndian. We
154/// check that ConditionalRecurrence.Step is a Select(Cmp()) where the compare
155/// is `>= 0` in the big-endian case, and `== 0` in the little-endian case (or
156/// the inverse, in which case the branches of the compare are swapped). We
157/// check that the LHS is (ConditionalRecurrence.Phi [xor SimpleRecurrence.Phi])
158/// in the big-endian case, and additionally check for an AND with one in the
159/// little-endian case. We then check AllowedByR against CheckAllowedByR, which
160/// is [0, smin) in the big-endian case, and is [0, 1) in the little-endian
161/// case. CheckAllowedByR checks for significant-bit-clear, and we match the
162/// corresponding arms of the select against bit-shift and
163/// bit-shift-and-xor-gen-poly.
164static bool
166 const RecurrenceInfo &SimpleRecurrence,
167 bool IsBigEndian) {
168 auto *SI = cast<SelectInst>(ConditionalRecurrence.Step);
169 CmpPredicate Pred;
170 const Value *L;
171 const APInt *R;
172 Instruction *TV, *FV;
173 if (!match(SI, m_Select(m_ICmp(Pred, m_Value(L), m_APInt(R)),
174 m_Instruction(TV), m_Instruction(FV))))
175 return false;
176
177 // Match predicate with or without a SimpleRecurrence (the corresponding data
178 // is LHSAux).
179 auto MatchPred = m_CombineOr(
180 m_Specific(ConditionalRecurrence.Phi),
181 m_c_Xor(m_ZExtOrTruncOrSelf(m_Specific(ConditionalRecurrence.Phi)),
182 m_ZExtOrTruncOrSelf(m_Specific(SimpleRecurrence.Phi))));
183 bool LWellFormed =
184 IsBigEndian ? match(L, MatchPred) : match(L, m_c_And(MatchPred, m_One()));
185 if (!LWellFormed)
186 return false;
187
189 unsigned BW = KnownR.getBitWidth();
190 auto RCR = ConstantRange::fromKnownBits(KnownR, false);
191 auto AllowedByR = ConstantRange::makeAllowedICmpRegion(Pred, RCR);
192 ConstantRange CheckAllowedByR(APInt::getZero(BW),
193 IsBigEndian ? APInt::getSignedMinValue(BW)
194 : APInt(BW, 1));
195
196 BinaryOperator *BitShift = ConditionalRecurrence.BO;
197 if (AllowedByR == CheckAllowedByR)
198 return TV == BitShift &&
199 match(FV, m_c_Xor(m_Specific(BitShift),
200 m_SpecificInt(*ConditionalRecurrence.ExtraConst)));
201 if (AllowedByR.inverse() == CheckAllowedByR)
202 return FV == BitShift &&
203 match(TV, m_c_Xor(m_Specific(BitShift),
204 m_SpecificInt(*ConditionalRecurrence.ExtraConst)));
205 return false;
206}
207
208/// Wraps llvm::matchSimpleRecurrence. Match a simple first order recurrence
209/// cycle of the form:
210///
211/// loop:
212/// %rec = phi [%start, %entry], [%BO, %loop]
213/// ...
214/// %BO = binop %rec, %step
215///
216/// or
217///
218/// loop:
219/// %rec = phi [%start, %entry], [%BO, %loop]
220/// ...
221/// %BO = binop %step, %rec
222///
225 Phi = P;
226 return true;
227 }
228 return false;
229}
230
231/// Digs for a recurrence starting with \p V hitting the PHI node in a use-def
232/// chain. Used by matchConditionalRecurrence.
234RecurrenceInfo::digRecurrence(Instruction *V,
235 Instruction::BinaryOps BOWithConstOpToMatch) {
238 Worklist.push_back(V);
239 while (!Worklist.empty()) {
240 Instruction *I = Worklist.pop_back_val();
241 // Skip this instruction if we have already visited it before.
242 if (!Visited.insert(I).second)
243 continue;
244
245 // Don't add a PHI's operands to the Worklist.
246 if (isa<PHINode>(I))
247 continue;
248
249 // Find a recurrence over a BinOp, by matching either of its operands
250 // with with the PHINode.
252 return cast<BinaryOperator>(I);
253
254 // Bind to ExtraConst, if we match exactly one.
255 if (I->getOpcode() == BOWithConstOpToMatch) {
256 if (ExtraConst)
257 return nullptr;
258 const APInt *C = nullptr;
259 if (match(I, m_c_BinOp(m_APInt(C), m_Value())))
260 ExtraConst = *C;
261 }
262
263 // Continue along the use-def chain.
264 for (Use &U : I->operands())
265 if (auto *UI = dyn_cast<Instruction>(U))
266 if (L.contains(UI))
267 Worklist.push_back(UI);
268 }
269 return nullptr;
270}
271
272/// A Conditional Recurrence is a recurrence of the form:
273///
274/// loop:
275/// %rec = phi [%start, %entry], [%step, %loop]
276/// ...
277/// %step = select _, %tv, %fv
278///
279/// where %tv and %fv ultimately end up using %rec via the same %BO instruction,
280/// after digging through the use-def chain.
281///
282/// ExtraConst is relevant if \p BOWithConstOpToMatch is supplied: when digging
283/// the use-def chain, a BinOp with opcode \p BOWithConstOpToMatch is matched,
284/// and ExtraConst is a constant operand of that BinOp. This peculiarity exists,
285/// because in a CRC algorithm, the \p BOWithConstOpToMatch is an XOR, and the
286/// ExtraConst ends up being the generating polynomial.
288 const PHINode *P, Instruction::BinaryOps BOWithConstOpToMatch) {
289 Phi = P;
290 if (Phi->getNumIncomingValues() != 2)
291 return false;
292
293 for (unsigned Idx = 0; Idx != 2; ++Idx) {
294 Value *FoundStep = Phi->getIncomingValue(Idx);
295 Value *FoundStart = Phi->getIncomingValue(!Idx);
296
297 Instruction *TV, *FV;
298 if (!match(FoundStep,
300 continue;
301
302 // For a conditional recurrence, both the true and false values of the
303 // select must ultimately end up in the same recurrent BinOp.
304 BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);
305 BinaryOperator *AltBO = digRecurrence(FV, BOWithConstOpToMatch);
306 if (!FoundBO || FoundBO != AltBO)
307 return false;
308
309 if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && !ExtraConst) {
310 LLVM_DEBUG(dbgs() << "HashRecognize: Unable to match single BinaryOp "
311 "with constant in conditional recurrence\n");
312 return false;
313 }
314
315 BO = FoundBO;
316 Start = FoundStart;
317 Step = FoundStep;
318 return true;
319 }
320 return false;
321}
322
323/// Iterates over all the phis in \p LoopLatch, and attempts to extract a
324/// Conditional Recurrence and an optional Simple Recurrence.
325static std::optional<std::pair<RecurrenceInfo, RecurrenceInfo>>
326getRecurrences(BasicBlock *LoopLatch, const PHINode *IndVar, const Loop &L) {
327 auto Phis = LoopLatch->phis();
328 unsigned NumPhis = std::distance(Phis.begin(), Phis.end());
329 if (NumPhis != 2 && NumPhis != 3)
330 return {};
331
332 RecurrenceInfo SimpleRecurrence(L);
333 RecurrenceInfo ConditionalRecurrence(L);
334 for (PHINode &P : Phis) {
335 if (&P == IndVar)
336 continue;
337 if (!SimpleRecurrence)
338 SimpleRecurrence.matchSimpleRecurrence(&P);
339 if (!ConditionalRecurrence)
340 ConditionalRecurrence.matchConditionalRecurrence(
341 &P, Instruction::BinaryOps::Xor);
342 }
343 if (NumPhis == 3 && (!SimpleRecurrence || !ConditionalRecurrence))
344 return {};
345 return std::make_pair(SimpleRecurrence, ConditionalRecurrence);
346}
347
353
354/// Generate a lookup table of 256 entries by interleaving the generating
355/// polynomial. The optimization technique of table-lookup for CRC is also
356/// called the Sarwate algorithm.
358 bool IsBigEndian) {
359 unsigned BW = GenPoly.getBitWidth();
360 CRCTable Table;
361 Table[0] = APInt::getZero(BW);
362
363 if (IsBigEndian) {
364 APInt CRCInit = APInt::getSignedMinValue(BW);
365 for (unsigned I = 1; I < 256; I <<= 1) {
366 CRCInit = CRCInit.shl(1) ^
367 (CRCInit.isSignBitSet() ? GenPoly : APInt::getZero(BW));
368 for (unsigned J = 0; J < I; ++J)
369 Table[I + J] = CRCInit ^ Table[J];
370 }
371 return Table;
372 }
373
374 APInt CRCInit(BW, 1);
375 for (unsigned I = 128; I; I >>= 1) {
376 CRCInit = CRCInit.lshr(1) ^ (CRCInit[0] ? GenPoly : APInt::getZero(BW));
377 for (unsigned J = 0; J < 256; J += (I << 1))
378 Table[I + J] = CRCInit ^ Table[J];
379 }
380 return Table;
381}
382
383/// Perform polynomial (GF(2)) floor division. This is based on the
384/// floor_division(S, P) algorithm in
385/// https://www.corsix.org/content/barrett-reduction-polynomials. Note that the
386/// maximum degree of the returned polynomial is
387/// max(0, deg(Dividend) - deg(Divisor)), but the bit width will be the same as
388/// that of Dividend.
389static APInt floorDivideGF2(APInt Dividend, APInt Divisor) {
390 assert(!Divisor.isZero() && "Cannot divide by zero");
391
392 // Extend the divisor bit width to match the dividend.
393 Divisor = Divisor.zext(Dividend.getBitWidth());
394
395 // Note that getActiveBits returns deg+1, but the computation below
396 // still holds.
397 unsigned DivisorActiveBits = Divisor.getActiveBits();
398
399 // Q = 0
400 APInt Quotient = APInt::getZero(Dividend.getBitWidth());
401 // S != 0 and deg(S) >= deg(P)
402 // (S != 0 implied by DivisorActiveBits > 0)
403 while (Dividend.getActiveBits() >= DivisorActiveBits) {
404 // T = S[deg(S)] / P[deg(P)]
405 unsigned Shift = Dividend.getActiveBits() - DivisorActiveBits;
406 // Q = Q + T
407 Quotient.setBit(Shift);
408 // S = S - T * P
409 Dividend ^= Divisor.shl(Shift);
410 }
411 return Quotient;
412}
413
414/// Generate the constants for performing a Polynomial (GF(2)) Barrett Reduction
415/// according to Intel's Fast CRC Computation white paper with some adjustments
416/// to account for the fact that bit width and trip count can vary.
417std::pair<APInt, APInt>
419 unsigned BW = Info.RHS.getBitWidth();
420 unsigned TC = Info.TripCount;
421
422 // Recover the full generating polynomial in normal form by reflecting the LE
423 // case and adding the implied x^BW term.
424 // deg(P(x)) = BW due to the implied term, and thus P(x) must fit in exactly
425 // BW+1 bits.
426 APInt FullGenPoly =
427 (Info.IsBigEndian ? Info.RHS : Info.RHS.reverseBits()).zext(BW + 1);
428 FullGenPoly.setBit(BW);
429
430 // Calculate mu = floor(x^(BW+TC) / P(x)).
431 // deg(mu) <= deg(x^(BW+TC)) - deg(P(x)) = BW+TC - BW = TC, and thus mu must
432 // fit in at most TC+1 bits.
433 unsigned DivBW = BW + TC + 1;
434 APInt Mu = floorDivideGF2(APInt::getOneBitSet(DivBW, BW + TC), FullGenPoly)
435 .trunc(TC + 1);
436
437 // In the bit-reflected (little-endian) case, mu and P(x) must be
438 // bit-reflected across their respective widths for the corresponding Barrett
439 // reduction steps.
440 if (!Info.IsBigEndian) {
441 Mu = Mu.reverseBits();
442 FullGenPoly = FullGenPoly.reverseBits();
443 }
444
445 return {Mu, FullGenPoly};
446}
447
448/// Checks that \p P1 and \p P2 are used together in an XOR in the use-def chain
449/// of \p SI's condition, ignoring any casts. The purpose of this function is to
450/// ensure that LHSAux from the SimpleRecurrence is used correctly in the CRC
451/// computation.
452///
453/// In other words, it checks for the following pattern:
454///
455/// loop:
456/// %P1 = phi [_, %entry], [%P1.next, %loop]
457/// %P2 = phi [_, %entry], [%P2.next, %loop]
458/// ...
459/// %xor = xor (CastOrSelf %P1), (CastOrSelf %P2)
460///
461/// where %xor is in the use-def chain of \p SI's condition.
462static bool isConditionalOnXorOfPHIs(const SelectInst *SI, const PHINode *P1,
463 const PHINode *P2, const Loop &L) {
465
466 // matchConditionalRecurrence has already ensured that the SelectInst's
467 // condition is an Instruction.
468 Worklist.push_back(cast<Instruction>(SI->getCondition()));
469
470 while (!Worklist.empty()) {
471 const Instruction *I = Worklist.pop_back_val();
472
473 // Don't add a PHI's operands to the Worklist.
474 if (isa<PHINode>(I))
475 continue;
476
477 // If we match an XOR of the two PHIs ignoring casts, we're done.
480 return true;
481
482 // Continue along the use-def chain.
483 for (const Use &U : I->operands())
484 if (auto *UI = dyn_cast<Instruction>(U))
485 if (L.contains(UI))
486 Worklist.push_back(UI);
487 }
488 return false;
489}
490
491// Recognizes a multiplication or division by the constant two, using SCEV. By
492// doing this, we're immune to whether the IR expression is mul/udiv or
493// equivalently shl/lshr. Return false when it is a UDiv, true when it is a Mul,
494// and std::nullopt otherwise.
495static std::optional<bool> isBigEndianBitShift(Value *V, ScalarEvolution &SE) {
496 if (!V->getType()->isIntegerTy())
497 return {};
498
499 const SCEV *E = SE.getSCEV(V);
501 return false;
503 return true;
504 return {};
505}
506
507/// The main entry point for analyzing a loop and recognizing the CRC algorithm.
508/// Returns a PolynomialInfo on success, and a StringRef on failure.
509std::variant<PolynomialInfo, StringRef> HashRecognize::recognizeCRC() const {
510 if (!L.isInnermost())
511 return "Loop is not innermost";
512 BasicBlock *Latch = L.getLoopLatch();
513 BasicBlock *Exit = L.getExitBlock();
514 const PHINode *IndVar = L.getCanonicalInductionVariable();
515 if (!Latch || !Exit || !IndVar || L.getNumBlocks() != 1)
516 return "Loop not in canonical form";
517 unsigned TC = SE.getSmallConstantTripCount(&L);
518 if (!TC)
519 return "Unable to find a small constant trip count";
520
521 auto R = getRecurrences(Latch, IndVar, L);
522 if (!R)
523 return "Found stray PHI";
524 auto [SimpleRecurrence, ConditionalRecurrence] = *R;
525 if (!ConditionalRecurrence)
526 return "Unable to find conditional recurrence";
527
528 // Make sure that all recurrences are either all SCEVMul with two or SCEVDiv
529 // with two, or in other words, that they're single bit-shifts.
530 std::optional<bool> IsBigEndian =
531 isBigEndianBitShift(ConditionalRecurrence.BO, SE);
532 if (!IsBigEndian)
533 return "Loop with non-unit bitshifts";
534 if (SimpleRecurrence) {
535 if (isBigEndianBitShift(SimpleRecurrence.BO, SE) != IsBigEndian)
536 return "Loop with non-unit bitshifts";
537
538 // Ensure that the PHIs have exactly two uses:
539 // the bit-shift, and the XOR (or a cast feeding into the XOR).
540 // Also ensure that the SimpleRecurrence's evolution doesn't have stray
541 // users.
542 if (!ConditionalRecurrence.Phi->hasNUses(2) ||
543 !SimpleRecurrence.Phi->hasNUses(2) ||
544 SimpleRecurrence.BO->getUniqueUndroppableUser() != SimpleRecurrence.Phi)
545 return "Recurrences have stray uses";
546
547 // Check that the SelectInst ConditionalRecurrence.Step is conditional on
548 // the XOR of SimpleRecurrence.Phi and ConditionalRecurrence.Phi.
549 if (!isConditionalOnXorOfPHIs(cast<SelectInst>(ConditionalRecurrence.Step),
550 SimpleRecurrence.Phi,
551 ConditionalRecurrence.Phi, L))
552 return "Recurrences not intertwined with XOR";
553 }
554
555 Value *LHS = ConditionalRecurrence.Start;
556 Value *LHSAux = SimpleRecurrence ? SimpleRecurrence.Start : nullptr;
557
558 // In the big-endian case where LHSAux is narrower than LHS, the most
559 // significant bit check will never be influenced by LHSAux. In this case,
560 // SimpleRecurrence must still be well-formed, but LHSAux is effectively dead.
561 // This also averts a possible miscompile later where LHSAux gets shifted by
562 // its entire bit width, creating poison.
563 if (*IsBigEndian && LHSAux &&
564 LHSAux->getType()->getIntegerBitWidth() <
565 LHS->getType()->getIntegerBitWidth())
566 LHSAux = nullptr;
567
568 // Make sure that the TC doesn't exceed the bitwidth of LHSAux, or LHS.
569 if (TC > (LHSAux ? LHSAux->getType()->getIntegerBitWidth()
570 : LHS->getType()->getIntegerBitWidth()))
571 return "Loop iterations exceed bitwidth of data";
572
573 // Make sure that the computed value is used in the exit block: this should be
574 // true even if it is only really used in an outer loop's exit block, since
575 // the loop is in LCSSA form.
576 auto *ComputedValue = cast<SelectInst>(ConditionalRecurrence.Step);
577 if (none_of(ComputedValue->users(), [Exit](User *U) {
578 auto *UI = dyn_cast<Instruction>(U);
579 return UI && UI->getParent() == Exit;
580 }))
581 return "Unable to find use of computed value in loop exit block";
582
583 assert(ConditionalRecurrence.ExtraConst &&
584 "Expected ExtraConst in conditional recurrence");
585 const APInt &GenPoly = *ConditionalRecurrence.ExtraConst;
586
587 if (!isSignificantBitCheckWellFormed(ConditionalRecurrence, SimpleRecurrence,
588 *IsBigEndian))
589 return "Malformed significant-bit check";
590
592 {ComputedValue,
594 L.getLatchCmpInst(), Latch->getTerminator()});
595 if (SimpleRecurrence)
596 Roots.push_back(SimpleRecurrence.BO);
597 if (containsUnreachable(L, Roots))
598 return "Found stray unvisited instructions";
599
600 return PolynomialInfo(TC, LHS, GenPoly, ComputedValue, *IsBigEndian, LHSAux);
601}
602
604 for (unsigned I = 0; I < 256; I++) {
605 (*this)[I].print(OS, false);
606 OS << (I % 16 == 15 ? '\n' : ' ');
607 }
608}
609
610#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
611void CRCTable::dump() const { print(dbgs()); }
612#endif
613
615 if (!L.isInnermost())
616 return;
617 OS << "HashRecognize: Checking a loop in '"
618 << L.getHeader()->getParent()->getName() << "' from " << L.getLocStr()
619 << "\n";
620 auto Ret = recognizeCRC();
621 if (!std::holds_alternative<PolynomialInfo>(Ret)) {
622 OS << "Did not find a hash algorithm\n";
623 if (std::holds_alternative<StringRef>(Ret))
624 OS << "Reason: " << std::get<StringRef>(Ret) << "\n";
625 return;
626 }
627
628 auto Info = std::get<PolynomialInfo>(Ret);
629 OS << "Found" << (Info.IsBigEndian ? " big-endian " : " little-endian ")
630 << "CRC-" << Info.RHS.getBitWidth() << " loop with trip count "
631 << Info.TripCount << "\n";
632 OS.indent(2) << "Initial CRC: ";
633 Info.LHS->print(OS);
634 OS << "\n";
635 OS.indent(2) << "Generating polynomial: ";
636 Info.RHS.print(OS, false);
637 OS << "\n";
638 OS.indent(2) << "Computed CRC: ";
639 Info.ComputedValue->print(OS);
640 OS << "\n";
641 if (Info.LHSAux) {
642 OS.indent(2) << "Auxiliary data: ";
643 Info.LHSAux->print(OS);
644 OS << "\n";
645 }
646 OS.indent(2) << "Computed CRC lookup table:\n";
647 genSarwateTable(Info.RHS, Info.IsBigEndian).print(OS);
648 OS.indent(2) << "Computed CRC Barrett constants:\n";
649 auto [Mu, FullGenPoly] = genBarrettConstants(Info);
650 OS << "Mu = ";
651 Mu.print(OS, false);
652 OS << ", FullGenPoly = ";
653 FullGenPoly.print(OS, false);
654 OS << "\n";
655}
656
657#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
658void HashRecognize::dump() const { print(dbgs()); }
659#endif
660
661std::optional<PolynomialInfo> HashRecognize::getResult() const {
662 auto Res = HashRecognize(L, SE).recognizeCRC();
663 if (std::holds_alternative<PolynomialInfo>(Res))
664 return std::get<PolynomialInfo>(Res);
665 return std::nullopt;
666}
667
669 : L(L), SE(SE) {}
670
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition Compiler.h:672
static bool containsUnreachable(const Loop &L, ArrayRef< const Instruction * > Roots)
Checks if there's a stray instruction in the loop L outside of the use-def chains from Roots,...
static bool isSignificantBitCheckWellFormed(const RecurrenceInfo &ConditionalRecurrence, const RecurrenceInfo &SimpleRecurrence, bool IsBigEndian)
Check the well-formedness of the (most|least) significant bit check given ConditionalRecurrence,...
static bool isConditionalOnXorOfPHIs(const SelectInst *SI, const PHINode *P1, const PHINode *P2, const Loop &L)
Checks that P1 and P2 are used together in an XOR in the use-def chain of SI's condition,...
static std::optional< std::pair< RecurrenceInfo, RecurrenceInfo > > getRecurrences(BasicBlock *LoopLatch, const PHINode *IndVar, const Loop &L)
Iterates over all the phis in LoopLatch, and attempts to extract a Conditional Recurrence and an opti...
static std::optional< bool > isBigEndianBitShift(Value *V, ScalarEvolution &SE)
static APInt floorDivideGF2(APInt Dividend, APInt Divisor)
Perform polynomial (GF(2)) floor division.
This header provides classes for managing per-loop analyses.
#define I(x, y, z)
Definition MD5.cpp:57
#define P(N)
#define LLVM_DEBUG(...)
Definition Debug.h:119
Class for arbitrary precision integers.
Definition APInt.h:78
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1055
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1537
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:968
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1355
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:381
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1513
LLVM_ABI APInt reverseBits() const
Definition APInt.cpp:790
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
Definition APInt.h:220
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:880
bool isSignBitSet() const
Determine if sign bit of this APInt is set.
Definition APInt.h:342
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:201
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:240
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:858
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
LLVM Basic Block Representation.
Definition BasicBlock.h:62
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
Definition BasicBlock.h:530
size_t size() const
Definition BasicBlock.h:482
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...
This class represents a range of values.
static LLVM_ABI ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned)
Initialize a range based on a known bits constraint.
static LLVM_ABI ConstantRange makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other)
Produce the smallest range such that all values that may satisfy the given predicate with any value c...
LLVM_ABI PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &)
static LLVM_ABI CRCTable genSarwateTable(const APInt &GenPoly, bool IsBigEndian)
Generate a lookup table of 256 entries by interleaving the generating polynomial.
static LLVM_ABI std::pair< APInt, APInt > genBarrettConstants(const PolynomialInfo &Info)
Auxilary entry point after analysis to generate constants for a GF(2) Barrett Reduction.
LLVM_ABI std::optional< PolynomialInfo > getResult() const
LLVM_DUMP_METHOD void dump() const
LLVM_ABI HashRecognize(const Loop &L, ScalarEvolution &SE)
LLVM_ABI void print(raw_ostream &OS) const
LLVM_ABI std::variant< PolynomialInfo, StringRef > recognizeCRC() const
The main entry point for analyzing a loop and recognizing the CRC algorithm.
This class provides an interface for updating the loop pass manager based on mutations to the loop ne...
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
Value * getIncomingValueForBlock(const BasicBlock *BB) const
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
This class represents an analyzed expression in the program.
The main scalar evolution driver.
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
This class represents the LLVM 'select' instruction.
size_type size() const
Definition SmallPtrSet.h:99
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM_ABI unsigned getIntegerBitWidth() const
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
auto m_Cmp()
Matches any compare instruction and ignore it.
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
BinaryOp_match< LHS, RHS, Instruction::And, true > m_c_And(const LHS &L, const RHS &R)
Matches an And with LHS and RHS in either order.
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
cst_pred_ty< is_one > m_One()
Match an integer 1 or a vector with all elements equal to 1.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Xor, true > m_c_Xor(const LHS &L, const RHS &R)
Matches an Xor with LHS and RHS in either order.
auto m_ZExtOrTruncOrSelf(const OpTy &Op)
AnyBinaryOp_match< LHS, RHS, true > m_c_BinOp(const LHS &L, const RHS &R)
Matches a BinaryOperator with LHS and RHS in either order.
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
match_bind< const SCEVMulExpr > m_scev_Mul(const SCEVMulExpr *&V)
bool match(const SCEV *S, const Pattern &P)
SCEVBinaryExpr_match< SCEVUDivExpr, Op0_t, Op1_t > m_scev_UDiv(const Op0_t &Op0, const Op1_t &Op1)
cst_pred_ty< is_specific_cst > m_scev_SpecificInt(uint64_t V)
Match an SCEV constant with a plain unsigned integer.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
AnalysisManager< Loop, LoopStandardAnalysisResults & > LoopAnalysisManager
The loop analysis manager.
LLVM_ABI bool matchSimpleRecurrence(const PHINode *P, BinaryOperator *&BO, Value *&Start, Value *&Step)
Attempt to match a simple first order recurrence cycle of the form: iv = phi Ty [Start,...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1753
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
A structure that can hold either a Simple Recurrence or a Conditional Recurrence.
const PHINode * Phi
LLVM_DUMP_METHOD void dump() const
bool matchConditionalRecurrence(const PHINode *P, Instruction::BinaryOps BOWithConstOpToMatch=Instruction::BinaryOpsEnd)
A Conditional Recurrence is a recurrence of the form:
void print(raw_ostream &OS, unsigned Indent=0) const
std::optional< APInt > ExtraConst
bool matchSimpleRecurrence(const PHINode *P)
Wraps llvm::matchSimpleRecurrence.
BinaryOperator * BO
RecurrenceInfo(const Loop &L)
A custom std::array with 256 entries, that also has a print function.
LLVM_ABI LLVM_DUMP_METHOD void dump() const
LLVM_ABI void print(raw_ostream &OS) const
static KnownBits makeConstant(const APInt &C)
Create known bits from a known constant.
Definition KnownBits.h:315
unsigned getBitWidth() const
Get the bit width of this value.
Definition KnownBits.h:44
The adaptor from a function pass to a loop pass computes these analyses and makes them available to t...
The structure that is returned when a polynomial algorithm was recognized by the analysis.
LLVM_ABI PolynomialInfo(unsigned TripCount, Value *LHS, const APInt &RHS, Value *ComputedValue, bool IsBigEndian, Value *LHSAux=nullptr)