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)
181 auto MatchBitShiftXorGenPoly =
m_c_Xor(
209 if (AllowedByR == CheckAllowedByR)
210 return TV == BitShift &&
match(FV, MatchBitShiftXorGenPoly);
211 if (AllowedByR.inverse() == CheckAllowedByR)
212 return FV == BitShift &&
match(TV, MatchBitShiftXorGenPoly);
247 while (!Worklist.
empty()) {
263 if (
I->getOpcode() == BOWithConstOpToMatch) {
272 for (Use &U :
I->operands())
298 if (
Phi->getNumIncomingValues() != 2)
302 int LatchIdx =
Phi->getBasicBlockIndex(
L.getLoopLatch());
305 Value *FoundStep =
Phi->getIncomingValue(LatchIdx);
306 Value *FoundStart =
Phi->getIncomingValue(!LatchIdx);
315 BinaryOperator *FoundBO = digRecurrence(TV, BOWithConstOpToMatch);
317 if (!FoundBO || FoundBO != AltBO)
320 if (BOWithConstOpToMatch != Instruction::BinaryOpsEnd && !
ExtraConst) {
321 LLVM_DEBUG(
dbgs() <<
"HashRecognize: Unable to match single BinaryOp "
322 "with constant in conditional recurrence\n");
334static std::optional<std::pair<RecurrenceInfo, RecurrenceInfo>>
336 auto Phis = LoopLatch->
phis();
337 unsigned NumPhis = std::distance(Phis.begin(), Phis.end());
338 if (NumPhis != 2 && NumPhis != 3)
346 if (!SimpleRecurrence)
348 if (!ConditionalRecurrence)
350 &
P, Instruction::BinaryOps::Xor);
352 if (NumPhis == 3 && (!SimpleRecurrence || !ConditionalRecurrence))
354 return std::make_pair(SimpleRecurrence, ConditionalRecurrence);
374 for (
unsigned I = 1;
I < 256;
I <<= 1) {
375 CRCInit = CRCInit.
shl(1) ^
377 for (
unsigned J = 0; J <
I; ++J)
383 APInt CRCInit(BW, 1);
384 for (
unsigned I = 128;
I;
I >>= 1) {
386 for (
unsigned J = 0; J < 256; J += (
I << 1))
414 unsigned Shift = Dividend.
getActiveBits() - DivisorActiveBits;
418 Dividend ^= Divisor.
shl(Shift);
426std::pair<APInt, APInt>
429 unsigned TC = Info.TripCount;
436 (Info.IsBigEndian ? Info.RHS : Info.RHS.reverseBits()).
zext(BW + 1);
442 unsigned DivBW = BW + TC + 1;
449 if (!Info.IsBigEndian) {
454 return {Mu, FullGenPoly};
480 while (!Worklist.
empty()) {
496 for (
const Use &U :
I->operands())
509 if (!V->getType()->isIntegerTy())
523 if (!L.isInnermost())
524 return "Loop is not innermost";
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);
533 return "Unable to find a small constant trip count";
537 return "Found stray PHI";
538 auto [SimpleRecurrence, ConditionalRecurrence] = *R;
539 if (!ConditionalRecurrence)
540 return "Unable to find conditional recurrence";
544 std::optional<bool> IsBigEndian =
547 return "Loop with non-unit bitshifts";
548 if (SimpleRecurrence) {
550 return "Loop with non-unit bitshifts";
556 if (!ConditionalRecurrence.Phi->hasNUses(2) ||
557 !SimpleRecurrence.Phi->hasNUses(2) ||
558 SimpleRecurrence.BO->getUniqueUndroppableUser() != SimpleRecurrence.Phi)
559 return "Recurrences have stray uses";
564 SimpleRecurrence.Phi,
565 ConditionalRecurrence.Phi, L))
566 return "Recurrences not intertwined with XOR";
569 Value *LHS = ConditionalRecurrence.Start;
570 Value *LHSAux = SimpleRecurrence ? SimpleRecurrence.Start :
nullptr;
577 if (*IsBigEndian && LHSAux &&
579 LHS->getType()->getIntegerBitWidth())
584 : LHS->getType()->getIntegerBitWidth()))
585 return "Loop iterations exceed bitwidth of data";
591 if (
any_of(Exit->phis(), [Latch, ComputedValue](
PHINode &PN) {
592 return PN.getIncomingValueForBlock(Latch) != ComputedValue;
594 return "Found stray incoming values in loop exit block";
596 assert(ConditionalRecurrence.ExtraConst &&
597 "Expected ExtraConst in conditional recurrence");
598 const APInt &GenPoly = *ConditionalRecurrence.ExtraConst;
602 return "Malformed significant-bit check";
608 if (SimpleRecurrence)
611 return "Found stray unvisited instructions";
613 return PolynomialInfo(TC, LHS, GenPoly, ComputedValue, *IsBigEndian, LHSAux);
617 for (
unsigned I = 0;
I < 256;
I++) {
618 (*this)[
I].print(OS,
false);
619 OS << (
I % 16 == 15 ?
'\n' :
' ');
623#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
628 if (!L.isInnermost())
630 OS <<
"HashRecognize: Checking a loop in '"
631 << L.getHeader()->getParent()->getName() <<
"' from " << L.getLocStr()
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";
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: ";
648 OS.
indent(2) <<
"Generating polynomial: ";
649 Info.RHS.print(OS,
false);
651 OS.
indent(2) <<
"Computed CRC: ";
652 Info.ComputedValue->print(OS);
655 OS.
indent(2) <<
"Auxiliary data: ";
656 Info.LHSAux->print(OS);
659 OS.
indent(2) <<
"Computed CRC lookup table:\n";
661 OS.
indent(2) <<
"Computed CRC Barrett constants:\n";
665 OS <<
", FullGenPoly = ";
666 FullGenPoly.print(OS,
false);
670#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
676 if (std::holds_alternative<PolynomialInfo>(Res))
677 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_isa< To... > m_Isa()
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.
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)