-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[HashRecognize] Track visited in ValueEvolution #147812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -102,9 +102,10 @@ class ValueEvolution { | |
|
||
public: | ||
// ValueEvolution is meant to be constructed with the TripCount of the loop, | ||
// and whether the polynomial algorithm is big-endian, for the significant-bit | ||
// check. | ||
ValueEvolution(unsigned TripCount, bool ByteOrderSwapped); | ||
// whether the polynomial algorithm is big-endian for the significant-bit | ||
// check, and an initial value for the Visited set. | ||
ValueEvolution(unsigned TripCount, bool ByteOrderSwapped, | ||
ArrayRef<const Instruction *> InitVisited); | ||
|
||
// Given a list of PHI nodes along with their incoming value from within the | ||
// loop, computeEvolutions computes the KnownBits of each of the PHI nodes on | ||
|
@@ -115,13 +116,19 @@ class ValueEvolution { | |
// precise error message. | ||
StringRef getError() const { return ErrStr; } | ||
|
||
// A set of instructions visited by ValueEvolution. Anything that's not in the | ||
// use-def chain of the PHIs' evolution will not be visited. | ||
SmallPtrSet<const Instruction *, 16> Visited; | ||
|
||
// The computed KnownBits for each PHI node, which is populated after | ||
// computeEvolutions is called. | ||
KnownPhiMap KnownPhis; | ||
}; | ||
|
||
ValueEvolution::ValueEvolution(unsigned TripCount, bool ByteOrderSwapped) | ||
: TripCount(TripCount), ByteOrderSwapped(ByteOrderSwapped) {} | ||
ValueEvolution::ValueEvolution(unsigned TripCount, bool ByteOrderSwapped, | ||
ArrayRef<const Instruction *> InitVisited) | ||
: TripCount(TripCount), ByteOrderSwapped(ByteOrderSwapped), | ||
Visited(InitVisited.begin(), InitVisited.end()) {} | ||
|
||
KnownBits ValueEvolution::computeBinOp(const BinaryOperator *I) { | ||
KnownBits KnownL(compute(I->getOperand(0))); | ||
|
@@ -177,6 +184,9 @@ KnownBits ValueEvolution::computeBinOp(const BinaryOperator *I) { | |
KnownBits ValueEvolution::computeInstr(const Instruction *I) { | ||
unsigned BitWidth = I->getType()->getScalarSizeInBits(); | ||
|
||
// computeInstr is the only entry-point that needs to update the Visited set. | ||
Visited.insert(I); | ||
|
||
// We look up in the map that contains the KnownBits of the PHI from the | ||
// previous iteration. | ||
if (const PHINode *P = dyn_cast<PHINode>(I)) | ||
|
@@ -185,9 +195,14 @@ KnownBits ValueEvolution::computeInstr(const Instruction *I) { | |
// Compute the KnownBits for a Select(Cmp()), forcing it to take the branch | ||
// that is predicated on the (least|most)-significant-bit check. | ||
CmpPredicate Pred; | ||
Value *L, *R, *TV, *FV; | ||
if (match(I, m_Select(m_ICmp(Pred, m_Value(L), m_Value(R)), m_Value(TV), | ||
m_Value(FV)))) { | ||
Value *L, *R; | ||
Instruction *TV, *FV; | ||
if (match(I, m_Select(m_ICmp(Pred, m_Value(L), m_Value(R)), m_Instruction(TV), | ||
m_Instruction(FV)))) { | ||
Visited.insert(cast<Instruction>(I->getOperand(0))); | ||
Visited.insert(TV); | ||
Visited.insert(FV); | ||
|
||
// We need to check LCR against [0, 2) in the little-endian case, because | ||
// the RCR check is insufficient: it is simply [0, 1). | ||
if (!ByteOrderSwapped) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The opposite ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test not.crc.bad.endian.swapped.sb.check fails. It took me some time to figure out why it was failing, but it is precisely due to this reason. |
||
|
@@ -209,6 +224,9 @@ KnownBits ValueEvolution::computeInstr(const Instruction *I) { | |
ConstantRange CheckRCR(APInt::getZero(ICmpBW), | ||
ByteOrderSwapped ? APInt::getSignedMinValue(ICmpBW) | ||
: APInt(ICmpBW, 1)); | ||
|
||
// We only compute KnownBits of either TV or FV, as the other value would | ||
// just be a bit-shift as checked by isBigEndianBitShift. | ||
if (AllowedR == CheckRCR) | ||
return compute(TV); | ||
if (AllowedR.inverse() == CheckRCR) | ||
|
@@ -629,11 +647,23 @@ HashRecognize::recognizeCRC() const { | |
if (SimpleRecurrence) | ||
PhiEvolutions.emplace_back(SimpleRecurrence.Phi, SimpleRecurrence.BO); | ||
|
||
ValueEvolution VE(TC, *ByteOrderSwapped); | ||
// Initialize the Visited set in ValueEvolution with the IndVar-related | ||
// instructions. | ||
std::initializer_list<const Instruction *> InitVisited = { | ||
IndVar, Latch->getTerminator(), L.getLatchCmpInst(), | ||
cast<Instruction>(IndVar->getIncomingValueForBlock(Latch))}; | ||
|
||
ValueEvolution VE(TC, *ByteOrderSwapped, InitVisited); | ||
if (!VE.computeEvolutions(PhiEvolutions)) | ||
return VE.getError(); | ||
KnownBits ResultBits = VE.KnownPhis.at(ConditionalRecurrence.Phi); | ||
|
||
// Any unvisited instructions from the KnownBits propagation can complicate | ||
// the optimization, which would just replace the entire loop with the | ||
// table-lookup version of the hash algorithm. | ||
if (std::distance(Latch->begin(), Latch->end()) != VE.Visited.size()) | ||
return "Found stray unvisited instructions"; | ||
|
||
unsigned N = std::min(TC, ResultBits.getBitWidth()); | ||
auto IsZero = [](const KnownBits &K) { return K.isZero(); }; | ||
if (!checkExtractBits(ResultBits, N, IsZero, *ByteOrderSwapped)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we rather rely on
compute(TV)
andcompute(FV)
below?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We only compute either TV or FV, with the other being a trivial bit-shift: we force the select-cmp to take the branch which is not a trivial bit-shift. I added a clarifying comment near that code.