74#define DEBUG_TYPE "hash-recognize"
85 while (!Worklist.
empty()) {
94 for (
const Use &U :
I->operands()) {
102 return Latch->
size() != Visited.
size();
120 OS.
indent(Indent) <<
"Phi: ";
123 OS.
indent(Indent) <<
"BinaryOperator: ";
126 OS.
indent(Indent) <<
"Start: ";
129 OS.
indent(Indent) <<
"Step: ";
133 OS.
indent(Indent) <<
"ExtraConst: ";
139#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
199 if (AllowedByR == CheckAllowedByR)
200 return TV == BitShift &&
203 if (AllowedByR.inverse() == CheckAllowedByR)
204 return FV == BitShift &&
241 while (!Worklist.
empty()) {
257 if (
I->getOpcode() == BOWithConstOpToMatch) {
266 for (Use &U :
I->operands())
292 if (
Phi->getNumIncomingValues() != 2)
296 int LatchIdx =
Phi->getBasicBlockIndex(
L.getLoopLatch());
299 Value *FoundStep =
Phi->getIncomingValue(LatchIdx);
300 Value *FoundStart =
Phi->getIncomingValue(!LatchIdx);
303 if (!
match(FoundStep,
309 BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);
311 if (!FoundBO || FoundBO != AltBO)
314 if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && !
ExtraConst) {
315 LLVM_DEBUG(
dbgs() <<
"HashRecognize: Unable to match single BinaryOp "
316 "with constant in conditional recurrence\n");
328static std::optional<std::pair<RecurrenceInfo, RecurrenceInfo>>
330 auto Phis = LoopLatch->
phis();
331 unsigned NumPhis = std::distance(Phis.begin(), Phis.end());
332 if (NumPhis != 2 && NumPhis != 3)
340 if (!SimpleRecurrence)
342 if (!ConditionalRecurrence)
344 &
P, Instruction::BinaryOps::Xor);
346 if (NumPhis == 3 && (!SimpleRecurrence || !ConditionalRecurrence))
348 return std::make_pair(SimpleRecurrence, ConditionalRecurrence);
368 for (
unsigned I = 1;
I < 256;
I <<= 1) {
369 CRCInit = CRCInit.
shl(1) ^
371 for (
unsigned J = 0; J <
I; ++J)
377 APInt CRCInit(BW, 1);
378 for (
unsigned I = 128;
I;
I >>= 1) {
380 for (
unsigned J = 0; J < 256; J += (
I << 1))
408 unsigned Shift = Dividend.
getActiveBits() - DivisorActiveBits;
412 Dividend ^= Divisor.
shl(Shift);
420std::pair<APInt, APInt>
423 unsigned TC = Info.TripCount;
430 (Info.IsBigEndian ? Info.RHS : Info.RHS.reverseBits()).
zext(BW + 1);
436 unsigned DivBW = BW + TC + 1;
443 if (!Info.IsBigEndian) {
448 return {Mu, FullGenPoly};
474 while (!Worklist.
empty()) {
490 for (
const Use &U :
I->operands())
503 if (!V->getType()->isIntegerTy())
517 if (!L.isInnermost())
518 return "Loop is not innermost";
521 const PHINode *IndVar = L.getCanonicalInductionVariable();
522 if (!Latch || !Exit || !IndVar || L.getNumBlocks() != 1 ||
523 !L.getLatchCmpInst())
524 return "Loop not in canonical form";
525 unsigned TC = SE.getSmallConstantTripCount(&L);
527 return "Unable to find a small constant trip count";
531 return "Found stray PHI";
532 auto [SimpleRecurrence, ConditionalRecurrence] = *R;
533 if (!ConditionalRecurrence)
534 return "Unable to find conditional recurrence";
538 std::optional<bool> IsBigEndian =
541 return "Loop with non-unit bitshifts";
542 if (SimpleRecurrence) {
544 return "Loop with non-unit bitshifts";
550 if (!ConditionalRecurrence.Phi->hasNUses(2) ||
551 !SimpleRecurrence.Phi->hasNUses(2) ||
552 SimpleRecurrence.BO->getUniqueUndroppableUser() != SimpleRecurrence.Phi)
553 return "Recurrences have stray uses";
558 SimpleRecurrence.Phi,
559 ConditionalRecurrence.Phi, L))
560 return "Recurrences not intertwined with XOR";
563 Value *LHS = ConditionalRecurrence.Start;
564 Value *LHSAux = SimpleRecurrence ? SimpleRecurrence.Start :
nullptr;
571 if (*IsBigEndian && LHSAux &&
573 LHS->getType()->getIntegerBitWidth())
578 : LHS->getType()->getIntegerBitWidth()))
579 return "Loop iterations exceed bitwidth of data";
585 if (
any_of(Exit->phis(), [Latch, ComputedValue](
PHINode &PN) {
586 return PN.getIncomingValueForBlock(Latch) != ComputedValue;
588 return "Found stray incoming values in loop exit block";
590 assert(ConditionalRecurrence.ExtraConst &&
591 "Expected ExtraConst in conditional recurrence");
592 const APInt &GenPoly = *ConditionalRecurrence.ExtraConst;
596 return "Malformed significant-bit check";
602 if (SimpleRecurrence)
605 return "Found stray unvisited instructions";
607 return PolynomialInfo(TC, LHS, GenPoly, ComputedValue, *IsBigEndian, LHSAux);
611 for (
unsigned I = 0;
I < 256;
I++) {
612 (*this)[
I].print(OS,
false);
613 OS << (
I % 16 == 15 ?
'\n' :
' ');
617#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
622 if (!L.isInnermost())
624 OS <<
"HashRecognize: Checking a loop in '"
625 << L.getHeader()->getParent()->getName() <<
"' from " << L.getLocStr()
628 if (!std::holds_alternative<PolynomialInfo>(Ret)) {
629 OS <<
"Did not find a hash algorithm\n";
630 if (std::holds_alternative<StringRef>(Ret))
631 OS <<
"Reason: " << std::get<StringRef>(Ret) <<
"\n";
635 auto Info = std::get<PolynomialInfo>(Ret);
636 OS <<
"Found" << (Info.IsBigEndian ?
" big-endian " :
" little-endian ")
637 <<
"CRC-" << Info.RHS.getBitWidth() <<
" loop with trip count "
638 << Info.TripCount <<
"\n";
639 OS.
indent(2) <<
"Initial CRC: ";
642 OS.
indent(2) <<
"Generating polynomial: ";
643 Info.RHS.print(OS,
false);
645 OS.
indent(2) <<
"Computed CRC: ";
646 Info.ComputedValue->print(OS);
649 OS.
indent(2) <<
"Auxiliary data: ";
650 Info.LHSAux->print(OS);
653 OS.
indent(2) <<
"Computed CRC lookup table:\n";
655 OS.
indent(2) <<
"Computed CRC Barrett constants:\n";
659 OS <<
", FullGenPoly = ";
660 FullGenPoly.print(OS,
false);
664#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
670 if (std::holds_alternative<PolynomialInfo>(Res))
671 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< 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.
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.
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,...
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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)