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 // Skip this instruction if we have already visited it before.
88 if (!Visited.insert(I).second)
89 continue;
90
91 if (isa<PHINode>(I))
92 continue;
93
94 for (const Use &U : I->operands()) {
95 if (auto *UI = dyn_cast<Instruction>(U)) {
96 if (!L.contains(UI))
97 return true;
98 Worklist.push_back(UI);
99 }
100 }
101 }
102 return Latch->size() != Visited.size();
103}
104
105/// A structure that can hold either a Simple Recurrence or a Conditional
106/// Recurrence. Note that in the case of a Simple Recurrence, Step is an operand
107/// of the BO, while in a Conditional Recurrence, it is a SelectInst.
109 const Loop &L;
110 const PHINode *Phi = nullptr;
111 BinaryOperator *BO = nullptr;
112 Value *Start = nullptr;
113 Value *Step = nullptr;
114 std::optional<APInt> ExtraConst;
115
116 RecurrenceInfo(const Loop &L) : L(L) {}
117 operator bool() const { return BO; }
118
119 void print(raw_ostream &OS, unsigned Indent = 0) const {
120 OS.indent(Indent) << "Phi: ";
121 Phi->print(OS);
122 OS << "\n";
123 OS.indent(Indent) << "BinaryOperator: ";
124 BO->print(OS);
125 OS << "\n";
126 OS.indent(Indent) << "Start: ";
127 Start->print(OS);
128 OS << "\n";
129 OS.indent(Indent) << "Step: ";
130 Step->print(OS);
131 OS << "\n";
132 if (ExtraConst) {
133 OS.indent(Indent) << "ExtraConst: ";
134 ExtraConst->print(OS, false);
135 OS << "\n";
136 }
137 }
138
139#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
140 LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
141#endif
142
143 bool matchSimpleRecurrence(const PHINode *P);
145 const PHINode *P,
146 Instruction::BinaryOps BOWithConstOpToMatch = Instruction::BinaryOpsEnd);
147
148private:
149 BinaryOperator *digRecurrence(
150 Instruction *V,
151 Instruction::BinaryOps BOWithConstOpToMatch = Instruction::BinaryOpsEnd);
152};
153
154/// Check the well-formedness of the (most|least) significant bit check given \p
155/// ConditionalRecurrence, \p SimpleRecurrence, depending on \p IsBigEndian. We
156/// check that ConditionalRecurrence.Step is a Select(Cmp()) where the compare
157/// is `>= 0` in the big-endian case, and `== 0` in the little-endian case (or
158/// the inverse, in which case the branches of the compare are swapped). For
159/// little-endian, we also accept a trunc to i1 (extracting bit zero). We
160/// check that the LHS is (ConditionalRecurrence.Phi [xor SimpleRecurrence.Phi])
161/// in the big-endian case, and additionally check for an AND with one in the
162/// little-endian case. We then check AllowedByR against CheckAllowedByR, which
163/// is [0, smin) in the big-endian case, and is [0, 1) in the little-endian
164/// case. CheckAllowedByR checks for significant-bit-clear, and we match the
165/// corresponding arms of the select against bit-shift and
166/// bit-shift-and-xor-gen-poly.
167static bool
169 const RecurrenceInfo &SimpleRecurrence,
170 bool IsBigEndian) {
171 auto *SI = cast<SelectInst>(ConditionalRecurrence.Step);
172
173 // Match predicate with or without a SimpleRecurrence (the corresponding data
174 // is LHSAux).
175 auto MatchPred = m_CombineOr(
176 m_Specific(ConditionalRecurrence.Phi),
177 m_c_Xor(m_ZExtOrTruncOrSelf(m_Specific(ConditionalRecurrence.Phi)),
178 m_ZExtOrTruncOrSelf(m_Specific(SimpleRecurrence.Phi))));
179
180 BinaryOperator *BitShift = ConditionalRecurrence.BO;
181 auto MatchBitShiftXorGenPoly = m_c_Xor(
182 m_Specific(BitShift), m_SpecificInt(*ConditionalRecurrence.ExtraConst));
183 if (!IsBigEndian &&
184 match(SI, m_Select(m_Trunc(MatchPred), MatchBitShiftXorGenPoly,
185 m_Specific(BitShift))))
186 return true;
187
188 CmpPredicate Pred;
189 const Value *L;
190 const APInt *R;
191 Instruction *TV, *FV;
192 if (!match(SI, m_Select(m_ICmp(Pred, m_Value(L), m_APInt(R)),
193 m_Instruction(TV), m_Instruction(FV))))
194 return false;
195
196 bool LWellFormed =
197 IsBigEndian ? match(L, MatchPred) : match(L, m_c_And(MatchPred, m_One()));
198 if (!LWellFormed)
199 return false;
200
202 unsigned BW = KnownR.getBitWidth();
203 auto RCR = ConstantRange::fromKnownBits(KnownR, false);
204 auto AllowedByR = ConstantRange::makeAllowedICmpRegion(Pred, RCR);
205 ConstantRange CheckAllowedByR(APInt::getZero(BW),
206 IsBigEndian ? APInt::getSignedMinValue(BW)
207 : APInt(BW, 1));
208
209 if (AllowedByR == CheckAllowedByR)
210 return TV == BitShift && match(FV, MatchBitShiftXorGenPoly);
211 if (AllowedByR.inverse() == CheckAllowedByR)
212 return FV == BitShift && match(TV, MatchBitShiftXorGenPoly);
213 return false;
214}
215
216/// Wraps llvm::matchSimpleRecurrence. Match a simple first order recurrence
217/// cycle of the form:
218///
219/// loop:
220/// %rec = phi [%start, %entry], [%BO, %loop]
221/// ...
222/// %BO = binop %rec, %step
223///
224/// or
225///
226/// loop:
227/// %rec = phi [%start, %entry], [%BO, %loop]
228/// ...
229/// %BO = binop %step, %rec
230///
233 Phi = P;
234 return true;
235 }
236 return false;
237}
238
239/// Digs for a recurrence starting with \p V hitting the PHI node in a use-def
240/// chain. Used by matchConditionalRecurrence.
242RecurrenceInfo::digRecurrence(Instruction *V,
243 Instruction::BinaryOps BOWithConstOpToMatch) {
246 Worklist.push_back(V);
247 while (!Worklist.empty()) {
248 Instruction *I = Worklist.pop_back_val();
249 // Skip this instruction if we have already visited it before.
250 if (!Visited.insert(I).second)
251 continue;
252
253 // Don't add a PHI's operands to the Worklist.
254 if (isa<PHINode>(I))
255 continue;
256
257 // Find a recurrence over a BinOp, by matching either of its operands
258 // with with the PHINode.
260 return cast<BinaryOperator>(I);
261
262 // Bind to ExtraConst, if we match exactly one.
263 if (I->getOpcode() == BOWithConstOpToMatch) {
264 if (ExtraConst)
265 return nullptr;
266 const APInt *C = nullptr;
267 if (match(I, m_c_BinOp(m_APInt(C), m_Value())))
268 ExtraConst = *C;
269 }
270
271 // Continue along the use-def chain.
272 for (Use &U : I->operands())
273 if (auto *UI = dyn_cast<Instruction>(U))
274 if (L.contains(UI))
275 Worklist.push_back(UI);
276 }
277 return nullptr;
278}
279
280/// A Conditional Recurrence is a recurrence of the form:
281///
282/// loop:
283/// %rec = phi [%start, %entry], [%step, %loop]
284/// ...
285/// %step = select _, %tv, %fv
286///
287/// where %tv and %fv ultimately end up using %rec via the same %BO instruction,
288/// after digging through the use-def chain.
289///
290/// ExtraConst is relevant if \p BOWithConstOpToMatch is supplied: when digging
291/// the use-def chain, a BinOp with opcode \p BOWithConstOpToMatch is matched,
292/// and ExtraConst is a constant operand of that BinOp. This peculiarity exists,
293/// because in a CRC algorithm, the \p BOWithConstOpToMatch is an XOR, and the
294/// ExtraConst ends up being the generating polynomial.
296 const PHINode *P, Instruction::BinaryOps BOWithConstOpToMatch) {
297 Phi = P;
298 if (Phi->getNumIncomingValues() != 2)
299 return false;
300
301 // Step comes from the loop latch, start comes from the other incoming value.
302 int LatchIdx = Phi->getBasicBlockIndex(L.getLoopLatch());
303 if (LatchIdx < 0)
304 return false;
305 Value *FoundStep = Phi->getIncomingValue(LatchIdx);
306 Value *FoundStart = Phi->getIncomingValue(!LatchIdx);
307
308 Instruction *TV, *FV;
310 m_Instruction(FV))))
311 return false;
312
313 // For a conditional recurrence, both the true and false values of the
314 // select must ultimately end up in the same recurrent BinOp.
315 BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);
316 BinaryOperator *AltBO = digRecurrence(FV, BOWithConstOpToMatch);
317 if (!FoundBO || FoundBO != AltBO)
318 return false;
319
320 if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && !ExtraConst) {
321 LLVM_DEBUG(dbgs() << "HashRecognize: Unable to match single BinaryOp "
322 "with constant in conditional recurrence\n");
323 return false;
324 }
325
326 BO = FoundBO;
327 Start = FoundStart;
328 Step = FoundStep;
329 return true;
330}
331
332/// Iterates over all the phis in \p LoopLatch, and attempts to extract a
333/// Conditional Recurrence and an optional Simple Recurrence.
334static std::optional<std::pair<RecurrenceInfo, RecurrenceInfo>>
335getRecurrences(BasicBlock *LoopLatch, const PHINode *IndVar, const Loop &L) {
336 auto Phis = LoopLatch->phis();
337 unsigned NumPhis = std::distance(Phis.begin(), Phis.end());
338 if (NumPhis != 2 && NumPhis != 3)
339 return {};
340
341 RecurrenceInfo SimpleRecurrence(L);
342 RecurrenceInfo ConditionalRecurrence(L);
343 for (PHINode &P : Phis) {
344 if (&P == IndVar)
345 continue;
346 if (!SimpleRecurrence)
347 SimpleRecurrence.matchSimpleRecurrence(&P);
348 if (!ConditionalRecurrence)
349 ConditionalRecurrence.matchConditionalRecurrence(
350 &P, Instruction::BinaryOps::Xor);
351 }
352 if (NumPhis == 3 && (!SimpleRecurrence || !ConditionalRecurrence))
353 return {};
354 return std::make_pair(SimpleRecurrence, ConditionalRecurrence);
355}
356
362
363/// Generate a lookup table of 256 entries by interleaving the generating
364/// polynomial. The optimization technique of table-lookup for CRC is also
365/// called the Sarwate algorithm.
367 bool IsBigEndian) {
368 unsigned BW = GenPoly.getBitWidth();
370 Table[0] = APInt::getZero(BW);
371
372 if (IsBigEndian) {
373 APInt CRCInit = APInt::getSignedMinValue(BW);
374 for (unsigned I = 1; I < 256; I <<= 1) {
375 CRCInit = CRCInit.shl(1) ^
376 (CRCInit.isSignBitSet() ? GenPoly : APInt::getZero(BW));
377 for (unsigned J = 0; J < I; ++J)
378 Table[I + J] = CRCInit ^ Table[J];
379 }
380 return Table;
381 }
382
383 APInt CRCInit(BW, 1);
384 for (unsigned I = 128; I; I >>= 1) {
385 CRCInit = CRCInit.lshr(1) ^ (CRCInit[0] ? GenPoly : APInt::getZero(BW));
386 for (unsigned J = 0; J < 256; J += (I << 1))
387 Table[I + J] = CRCInit ^ Table[J];
388 }
389 return Table;
390}
391
392/// Perform polynomial (GF(2)) floor division. This is based on the
393/// floor_division(S, P) algorithm in
394/// https://www.corsix.org/content/barrett-reduction-polynomials. Note that the
395/// maximum degree of the returned polynomial is
396/// max(0, deg(Dividend) - deg(Divisor)), but the bit width will be the same as
397/// that of Dividend.
398static APInt floorDivideGF2(APInt Dividend, APInt Divisor) {
399 assert(!Divisor.isZero() && "Cannot divide by zero");
400
401 // Extend the divisor bit width to match the dividend.
402 Divisor = Divisor.zext(Dividend.getBitWidth());
403
404 // Note that getActiveBits returns deg+1, but the computation below
405 // still holds.
406 unsigned DivisorActiveBits = Divisor.getActiveBits();
407
408 // Q = 0
409 APInt Quotient = APInt::getZero(Dividend.getBitWidth());
410 // S != 0 and deg(S) >= deg(P)
411 // (S != 0 implied by DivisorActiveBits > 0)
412 while (Dividend.getActiveBits() >= DivisorActiveBits) {
413 // T = S[deg(S)] / P[deg(P)]
414 unsigned Shift = Dividend.getActiveBits() - DivisorActiveBits;
415 // Q = Q + T
416 Quotient.setBit(Shift);
417 // S = S - T * P
418 Dividend ^= Divisor.shl(Shift);
419 }
420 return Quotient;
421}
422
423/// Generate the constants for performing a Polynomial (GF(2)) Barrett Reduction
424/// according to Intel's Fast CRC Computation white paper with some adjustments
425/// to account for the fact that bit width and trip count can vary.
426std::pair<APInt, APInt>
428 unsigned BW = Info.RHS.getBitWidth();
429 unsigned TC = Info.TripCount;
430
431 // Recover the full generating polynomial in normal form by reflecting the LE
432 // case and adding the implied x^BW term.
433 // deg(P(x)) = BW due to the implied term, and thus P(x) must fit in exactly
434 // BW+1 bits.
435 APInt FullGenPoly =
436 (Info.IsBigEndian ? Info.RHS : Info.RHS.reverseBits()).zext(BW + 1);
437 FullGenPoly.setBit(BW);
438
439 // Calculate mu = floor(x^(BW+TC) / P(x)).
440 // deg(mu) <= deg(x^(BW+TC)) - deg(P(x)) = BW+TC - BW = TC, and thus mu must
441 // fit in at most TC+1 bits.
442 unsigned DivBW = BW + TC + 1;
443 APInt Mu = floorDivideGF2(APInt::getOneBitSet(DivBW, BW + TC), FullGenPoly)
444 .trunc(TC + 1);
445
446 // In the bit-reflected (little-endian) case, mu and P(x) must be
447 // bit-reflected across their respective widths for the corresponding Barrett
448 // reduction steps.
449 if (!Info.IsBigEndian) {
450 Mu = Mu.reverseBits();
451 FullGenPoly = FullGenPoly.reverseBits();
452 }
453
454 return {Mu, FullGenPoly};
455}
456
457/// Checks that \p P1 and \p P2 are used together in an XOR in the use-def chain
458/// of \p SI's condition, ignoring any casts. The purpose of this function is to
459/// ensure that LHSAux from the SimpleRecurrence is used correctly in the CRC
460/// computation.
461///
462/// In other words, it checks for the following pattern:
463///
464/// loop:
465/// %P1 = phi [_, %entry], [%P1.next, %loop]
466/// %P2 = phi [_, %entry], [%P2.next, %loop]
467/// ...
468/// %xor = xor (CastOrSelf %P1), (CastOrSelf %P2)
469///
470/// where %xor is in the use-def chain of \p SI's condition.
471static bool isConditionalOnXorOfPHIs(const SelectInst *SI, const PHINode *P1,
472 const PHINode *P2, const Loop &L) {
475
476 // matchConditionalRecurrence has already ensured that the SelectInst's
477 // condition is an Instruction.
478 Worklist.push_back(cast<Instruction>(SI->getCondition()));
479
480 while (!Worklist.empty()) {
481 const Instruction *I = Worklist.pop_back_val();
482 // Skip this instruction if we have already visited it before.
483 if (!Visited.insert(I).second)
484 continue;
485
486 // Don't add a PHI's operands to the Worklist.
487 if (isa<PHINode>(I))
488 continue;
489
490 // If we match an XOR of the two PHIs ignoring casts, we're done.
493 return true;
494
495 // Continue along the use-def chain.
496 for (const Use &U : I->operands())
497 if (auto *UI = dyn_cast<Instruction>(U))
498 if (L.contains(UI))
499 Worklist.push_back(UI);
500 }
501 return false;
502}
503
504// Recognizes a multiplication or division by the constant two, using SCEV. By
505// doing this, we're immune to whether the IR expression is mul/udiv or
506// equivalently shl/lshr. Return false when it is a UDiv, true when it is a Mul,
507// and std::nullopt otherwise.
508static std::optional<bool> isBigEndianBitShift(Value *V, ScalarEvolution &SE) {
509 if (!V->getType()->isIntegerTy())
510 return {};
511
512 const SCEV *E = SE.getSCEV(V);
514 return false;
516 return true;
517 return {};
518}
519
520/// The main entry point for analyzing a loop and recognizing the CRC algorithm.
521/// Returns a PolynomialInfo on success, and a StringRef on failure.
522std::variant<PolynomialInfo, StringRef> HashRecognize::recognizeCRC() const {
523 if (!L.isInnermost())
524 return "Loop is not innermost";
525 BasicBlock *Latch = L.getLoopLatch();
526 BasicBlock *Exit = L.getExitBlock();
527 const PHINode *IndVar = L.getCanonicalInductionVariable();
528 if (!Latch || !Exit || !IndVar || L.getNumBlocks() != 1 ||
529 !L.getLatchCmpInst())
530 return "Loop not in canonical form";
531 unsigned TC = SE.getSmallConstantTripCount(&L);
532 if (!TC)
533 return "Unable to find a small constant trip count";
534
535 auto R = getRecurrences(Latch, IndVar, L);
536 if (!R)
537 return "Found stray PHI";
538 auto [SimpleRecurrence, ConditionalRecurrence] = *R;
539 if (!ConditionalRecurrence)
540 return "Unable to find conditional recurrence";
541
542 // Make sure that all recurrences are either all SCEVMul with two or SCEVDiv
543 // with two, or in other words, that they're single bit-shifts.
544 std::optional<bool> IsBigEndian =
545 isBigEndianBitShift(ConditionalRecurrence.BO, SE);
546 if (!IsBigEndian)
547 return "Loop with non-unit bitshifts";
548 if (SimpleRecurrence) {
549 if (isBigEndianBitShift(SimpleRecurrence.BO, SE) != IsBigEndian)
550 return "Loop with non-unit bitshifts";
551
552 // Ensure that the PHIs have exactly two uses:
553 // the bit-shift, and the XOR (or a cast feeding into the XOR).
554 // Also ensure that the SimpleRecurrence's evolution doesn't have stray
555 // users.
556 if (!ConditionalRecurrence.Phi->hasNUses(2) ||
557 !SimpleRecurrence.Phi->hasNUses(2) ||
558 SimpleRecurrence.BO->getUniqueUndroppableUser() != SimpleRecurrence.Phi)
559 return "Recurrences have stray uses";
560
561 // Check that the SelectInst ConditionalRecurrence.Step is conditional on
562 // the XOR of SimpleRecurrence.Phi and ConditionalRecurrence.Phi.
563 if (!isConditionalOnXorOfPHIs(cast<SelectInst>(ConditionalRecurrence.Step),
564 SimpleRecurrence.Phi,
565 ConditionalRecurrence.Phi, L))
566 return "Recurrences not intertwined with XOR";
567 }
568
569 Value *LHS = ConditionalRecurrence.Start;
570 Value *LHSAux = SimpleRecurrence ? SimpleRecurrence.Start : nullptr;
571
572 // In the big-endian case where LHSAux is narrower than LHS, the most
573 // significant bit check will never be influenced by LHSAux. In this case,
574 // SimpleRecurrence must still be well-formed, but LHSAux is effectively dead.
575 // This also averts a possible miscompile later where LHSAux gets shifted by
576 // its entire bit width, creating poison.
577 if (*IsBigEndian && LHSAux &&
578 LHSAux->getType()->getIntegerBitWidth() <
579 LHS->getType()->getIntegerBitWidth())
580 LHSAux = nullptr;
581
582 // Make sure that the TC doesn't exceed the bitwidth of LHSAux, or LHS.
583 if (TC > (LHSAux ? LHSAux->getType()->getIntegerBitWidth()
584 : LHS->getType()->getIntegerBitWidth()))
585 return "Loop iterations exceed bitwidth of data";
586
587 // Ensure nothing other than the computed value makes its way out of the loop.
588 // Since the loop is in LCSSA form, this is as simple as checking the PHI
589 // nodes in the exit block.
590 auto *ComputedValue = cast<SelectInst>(ConditionalRecurrence.Step);
591 if (any_of(Exit->phis(), [Latch, ComputedValue](PHINode &PN) {
592 return PN.getIncomingValueForBlock(Latch) != ComputedValue;
593 }))
594 return "Found stray incoming values in loop exit block";
595
596 assert(ConditionalRecurrence.ExtraConst &&
597 "Expected ExtraConst in conditional recurrence");
598 const APInt &GenPoly = *ConditionalRecurrence.ExtraConst;
599
600 if (!isSignificantBitCheckWellFormed(ConditionalRecurrence, SimpleRecurrence,
601 *IsBigEndian))
602 return "Malformed significant-bit check";
603
605 {ComputedValue,
607 L.getLatchCmpInst(), Latch->getTerminator()});
608 if (SimpleRecurrence)
609 Roots.push_back(SimpleRecurrence.BO);
610 if (containsUnreachable(L, Roots))
611 return "Found stray unvisited instructions";
612
613 return PolynomialInfo(TC, LHS, GenPoly, ComputedValue, *IsBigEndian, LHSAux);
614}
615
617 for (unsigned I = 0; I < 256; I++) {
618 (*this)[I].print(OS, false);
619 OS << (I % 16 == 15 ? '\n' : ' ');
620 }
621}
622
623#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
624void CRCTable::dump() const { print(dbgs()); }
625#endif
626
628 if (!L.isInnermost())
629 return;
630 OS << "HashRecognize: Checking a loop in '"
631 << L.getHeader()->getParent()->getName() << "' from " << L.getLocStr()
632 << "\n";
633 auto Ret = recognizeCRC();
634 if (!std::holds_alternative<PolynomialInfo>(Ret)) {
635 OS << "Did not find a hash algorithm\n";
636 if (std::holds_alternative<StringRef>(Ret))
637 OS << "Reason: " << std::get<StringRef>(Ret) << "\n";
638 return;
639 }
640
641 auto Info = std::get<PolynomialInfo>(Ret);
642 OS << "Found" << (Info.IsBigEndian ? " big-endian " : " little-endian ")
643 << "CRC-" << Info.RHS.getBitWidth() << " loop with trip count "
644 << Info.TripCount << "\n";
645 OS.indent(2) << "Initial CRC: ";
646 Info.LHS->print(OS);
647 OS << "\n";
648 OS.indent(2) << "Generating polynomial: ";
649 Info.RHS.print(OS, false);
650 OS << "\n";
651 OS.indent(2) << "Computed CRC: ";
652 Info.ComputedValue->print(OS);
653 OS << "\n";
654 if (Info.LHSAux) {
655 OS.indent(2) << "Auxiliary data: ";
656 Info.LHSAux->print(OS);
657 OS << "\n";
658 }
659 OS.indent(2) << "Computed CRC lookup table:\n";
660 genSarwateTable(Info.RHS, Info.IsBigEndian).print(OS);
661 OS.indent(2) << "Computed CRC Barrett constants:\n";
662 auto [Mu, FullGenPoly] = genBarrettConstants(Info);
663 OS << "Mu = ";
664 Mu.print(OS, false);
665 OS << ", FullGenPoly = ";
666 FullGenPoly.print(OS, false);
667 OS << "\n";
668}
669
670#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
671void HashRecognize::dump() const { print(dbgs()); }
672#endif
673
674std::optional<PolynomialInfo> HashRecognize::getResult() const {
675 auto Res = HashRecognize(L, SE).recognizeCRC();
676 if (std::holds_alternative<PolynomialInfo>(Res))
677 return std::get<PolynomialInfo>(Res);
678 return std::nullopt;
679}
680
682 : L(L), SE(SE) {}
683
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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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:678
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:1050
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1533
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:963
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Definition APInt.h:1351
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:377
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1509
LLVM_ABI APInt reverseBits() const
Definition APInt.cpp:785
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
Definition APInt.h:216
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:876
bool isSignBitSet() const
Determine if sign bit of this APInt is set.
Definition APInt.h:338
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:197
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:236
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:854
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:515
size_t size() const
Definition BasicBlock.h:467
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.
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
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.
CastInst_match< OpTy, TruncInst > m_Trunc(const OpTy &Op)
Matches Trunc.
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,...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1746
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
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)