74#define DEBUG_TYPE "hash-recognize"
85 while (!Worklist.
empty()) {
92 for (
const Use &U :
I->operands()) {
100 return Latch->
size() != Visited.
size();
118 OS.
indent(Indent) <<
"Phi: ";
121 OS.
indent(Indent) <<
"BinaryOperator: ";
124 OS.
indent(Indent) <<
"Start: ";
127 OS.
indent(Indent) <<
"Step: ";
131 OS.
indent(Indent) <<
"ExtraConst: ";
137#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
197 if (AllowedByR == CheckAllowedByR)
198 return TV == BitShift &&
201 if (AllowedByR.inverse() == CheckAllowedByR)
202 return FV == BitShift &&
239 while (!Worklist.
empty()) {
255 if (
I->getOpcode() == BOWithConstOpToMatch) {
264 for (Use &U :
I->operands())
290 if (
Phi->getNumIncomingValues() != 2)
293 for (
unsigned Idx = 0; Idx != 2; ++Idx) {
294 Value *FoundStep =
Phi->getIncomingValue(Idx);
295 Value *FoundStart =
Phi->getIncomingValue(!Idx);
298 if (!
match(FoundStep,
304 BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);
306 if (!FoundBO || FoundBO != AltBO)
309 if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && !
ExtraConst) {
310 LLVM_DEBUG(
dbgs() <<
"HashRecognize: Unable to match single BinaryOp "
311 "with constant in conditional recurrence\n");
325static std::optional<std::pair<RecurrenceInfo, RecurrenceInfo>>
327 auto Phis = LoopLatch->
phis();
328 unsigned NumPhis = std::distance(Phis.begin(), Phis.end());
329 if (NumPhis != 2 && NumPhis != 3)
337 if (!SimpleRecurrence)
339 if (!ConditionalRecurrence)
341 &
P, Instruction::BinaryOps::Xor);
343 if (NumPhis == 3 && (!SimpleRecurrence || !ConditionalRecurrence))
345 return std::make_pair(SimpleRecurrence, ConditionalRecurrence);
365 for (
unsigned I = 1;
I < 256;
I <<= 1) {
366 CRCInit = CRCInit.
shl(1) ^
368 for (
unsigned J = 0; J <
I; ++J)
369 Table[
I + J] = CRCInit ^ Table[J];
374 APInt CRCInit(BW, 1);
375 for (
unsigned I = 128;
I;
I >>= 1) {
377 for (
unsigned J = 0; J < 256; J += (
I << 1))
378 Table[
I + J] = CRCInit ^ Table[J];
405 unsigned Shift = Dividend.
getActiveBits() - DivisorActiveBits;
409 Dividend ^= Divisor.
shl(Shift);
417std::pair<APInt, APInt>
420 unsigned TC = Info.TripCount;
427 (Info.IsBigEndian ? Info.RHS : Info.RHS.reverseBits()).
zext(BW + 1);
433 unsigned DivBW = BW + TC + 1;
440 if (!Info.IsBigEndian) {
445 return {Mu, FullGenPoly};
470 while (!Worklist.
empty()) {
483 for (
const Use &U :
I->operands())
496 if (!V->getType()->isIntegerTy())
510 if (!L.isInnermost())
511 return "Loop is not innermost";
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);
519 return "Unable to find a small constant trip count";
523 return "Found stray PHI";
524 auto [SimpleRecurrence, ConditionalRecurrence] = *R;
525 if (!ConditionalRecurrence)
526 return "Unable to find conditional recurrence";
530 std::optional<bool> IsBigEndian =
533 return "Loop with non-unit bitshifts";
534 if (SimpleRecurrence) {
536 return "Loop with non-unit bitshifts";
542 if (!ConditionalRecurrence.Phi->hasNUses(2) ||
543 !SimpleRecurrence.Phi->hasNUses(2) ||
544 SimpleRecurrence.BO->getUniqueUndroppableUser() != SimpleRecurrence.Phi)
545 return "Recurrences have stray uses";
550 SimpleRecurrence.Phi,
551 ConditionalRecurrence.Phi, L))
552 return "Recurrences not intertwined with XOR";
555 Value *LHS = ConditionalRecurrence.Start;
556 Value *LHSAux = SimpleRecurrence ? SimpleRecurrence.Start :
nullptr;
563 if (*IsBigEndian && LHSAux &&
565 LHS->getType()->getIntegerBitWidth())
570 : LHS->getType()->getIntegerBitWidth()))
571 return "Loop iterations exceed bitwidth of data";
577 if (
none_of(ComputedValue->users(), [Exit](
User *U) {
578 auto *UI = dyn_cast<Instruction>(U);
579 return UI && UI->getParent() == Exit;
581 return "Unable to find use of computed value in loop exit block";
583 assert(ConditionalRecurrence.ExtraConst &&
584 "Expected ExtraConst in conditional recurrence");
585 const APInt &GenPoly = *ConditionalRecurrence.ExtraConst;
589 return "Malformed significant-bit check";
595 if (SimpleRecurrence)
598 return "Found stray unvisited instructions";
600 return PolynomialInfo(TC, LHS, GenPoly, ComputedValue, *IsBigEndian, LHSAux);
604 for (
unsigned I = 0;
I < 256;
I++) {
605 (*this)[
I].print(OS,
false);
606 OS << (
I % 16 == 15 ?
'\n' :
' ');
610#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
615 if (!L.isInnermost())
617 OS <<
"HashRecognize: Checking a loop in '"
618 << L.getHeader()->getParent()->getName() <<
"' from " << L.getLocStr()
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";
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: ";
635 OS.
indent(2) <<
"Generating polynomial: ";
636 Info.RHS.print(OS,
false);
638 OS.
indent(2) <<
"Computed CRC: ";
639 Info.ComputedValue->print(OS);
642 OS.
indent(2) <<
"Auxiliary data: ";
643 Info.LHSAux->print(OS);
646 OS.
indent(2) <<
"Computed CRC lookup table:\n";
648 OS.
indent(2) <<
"Computed CRC Barrett constants:\n";
652 OS <<
", FullGenPoly = ";
653 FullGenPoly.print(OS,
false);
657#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
663 if (std::holds_alternative<PolynomialInfo>(Res))
664 return std::get<PolynomialInfo>(Res);
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.
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.
Class for arbitrary precision integers.
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
unsigned getActiveBits() const
Compute the number of active bits in the value.
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
unsigned getBitWidth() const
Return the number of bits in the APInt.
LLVM_ABI APInt reverseBits() const
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
APInt shl(unsigned shiftAmt) const
Left-shift function.
bool isSignBitSet() const
Determine if sign bit of this APInt is set.
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
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.
Value * getIncomingValueForBlock(const BasicBlock *BB) const
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
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.
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.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
@ C
The default llvm calling convention, compatible with C.
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.
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.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
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...
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
A structure that can hold either a Simple Recurrence or a Conditional Recurrence.
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.
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.
unsigned getBitWidth() const
Get the bit width of this value.
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)