forked from OSchip/llvm-project
[SCEV] Simplify tracking ExitNotTakenInfo instances; NFC
This change simplifies a data structure optimization in the `BackedgeTakenInfo` class for loops with exactly one computable exit. I've sanity checked that this does not regress compile time performance, using sqlite3's amalgamated build. llvm-svn: 282365
This commit is contained in:
parent
89eea6b2ed
commit
d1eb62ad11
|
@ -574,143 +574,44 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/// Forward declaration of ExitNotTakenExtras
|
||||
struct ExitNotTakenExtras;
|
||||
typedef std::pair<BasicBlock *, ExitLimit> EdgeExitInfo;
|
||||
|
||||
/// Information about the number of times a particular loop exit may be
|
||||
/// reached before exiting the loop.
|
||||
struct ExitNotTakenInfo {
|
||||
AssertingVH<BasicBlock> ExitingBlock;
|
||||
const SCEV *ExactNotTaken;
|
||||
|
||||
ExitNotTakenExtras *ExtraInfo;
|
||||
bool Complete;
|
||||
|
||||
ExitNotTakenInfo()
|
||||
: ExitingBlock(nullptr), ExactNotTaken(nullptr), ExtraInfo(nullptr),
|
||||
Complete(true) {}
|
||||
|
||||
ExitNotTakenInfo(BasicBlock *ExitBlock, const SCEV *Expr,
|
||||
ExitNotTakenExtras *Ptr)
|
||||
: ExitingBlock(ExitBlock), ExactNotTaken(Expr), ExtraInfo(Ptr),
|
||||
Complete(true) {}
|
||||
|
||||
/// Return true if all loop exits are computable.
|
||||
bool isCompleteList() const { return Complete; }
|
||||
|
||||
/// Sets the incomplete property, indicating that one of the loop exits
|
||||
/// doesn't have a corresponding ExitNotTakenInfo entry.
|
||||
void setIncomplete() { Complete = false; }
|
||||
|
||||
/// Returns a pointer to the predicate associated with this information,
|
||||
/// or nullptr if this doesn't exist (meaning always true).
|
||||
SCEVUnionPredicate *getPred() const {
|
||||
if (ExtraInfo)
|
||||
return &ExtraInfo->Pred;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Return true if the SCEV predicate associated with this information
|
||||
/// is always true.
|
||||
bool hasAlwaysTruePred() const {
|
||||
return !getPred() || getPred()->isAlwaysTrue();
|
||||
}
|
||||
|
||||
/// Defines a simple forward iterator for ExitNotTakenInfo.
|
||||
class ExitNotTakenInfoIterator
|
||||
: public std::iterator<std::forward_iterator_tag, ExitNotTakenInfo> {
|
||||
const ExitNotTakenInfo *Start;
|
||||
unsigned Position;
|
||||
|
||||
public:
|
||||
ExitNotTakenInfoIterator(const ExitNotTakenInfo *Start, unsigned Position)
|
||||
: Start(Start), Position(Position) {}
|
||||
|
||||
const ExitNotTakenInfo &operator*() const {
|
||||
if (Position == 0)
|
||||
return *Start;
|
||||
|
||||
return Start->ExtraInfo->Exits[Position - 1];
|
||||
}
|
||||
|
||||
const ExitNotTakenInfo *operator->() const {
|
||||
if (Position == 0)
|
||||
return Start;
|
||||
|
||||
return &Start->ExtraInfo->Exits[Position - 1];
|
||||
}
|
||||
|
||||
bool operator==(const ExitNotTakenInfoIterator &RHS) const {
|
||||
return Start == RHS.Start && Position == RHS.Position;
|
||||
}
|
||||
|
||||
bool operator!=(const ExitNotTakenInfoIterator &RHS) const {
|
||||
return Start != RHS.Start || Position != RHS.Position;
|
||||
}
|
||||
|
||||
ExitNotTakenInfoIterator &operator++() { // Preincrement
|
||||
if (!Start)
|
||||
return *this;
|
||||
|
||||
unsigned Elements =
|
||||
Start->ExtraInfo ? Start->ExtraInfo->Exits.size() + 1 : 1;
|
||||
|
||||
++Position;
|
||||
|
||||
// We've run out of elements.
|
||||
if (Position == Elements) {
|
||||
Start = nullptr;
|
||||
Position = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
ExitNotTakenInfoIterator operator++(int) { // Postincrement
|
||||
ExitNotTakenInfoIterator Tmp = *this;
|
||||
++*this;
|
||||
return Tmp;
|
||||
}
|
||||
};
|
||||
|
||||
/// Iterators
|
||||
ExitNotTakenInfoIterator begin() const {
|
||||
return ExitNotTakenInfoIterator(this, 0);
|
||||
}
|
||||
ExitNotTakenInfoIterator end() const {
|
||||
return ExitNotTakenInfoIterator(nullptr, 0);
|
||||
SCEVUnionPredicate Predicate;
|
||||
bool hasAlwaysTruePredicate() const {
|
||||
return Predicate.isAlwaysTrue();
|
||||
}
|
||||
};
|
||||
|
||||
/// Describes the extra information that a ExitNotTakenInfo can have.
|
||||
struct ExitNotTakenExtras {
|
||||
/// The predicate associated with the ExitNotTakenInfo struct.
|
||||
SCEVUnionPredicate Pred;
|
||||
|
||||
/// The extra exits in the loop. Only the ExitNotTakenExtras structure
|
||||
/// pointed to by the first ExitNotTakenInfo struct (associated with the
|
||||
/// first loop exit) will populate this vector to prevent having
|
||||
/// redundant information.
|
||||
SmallVector<ExitNotTakenInfo, 4> Exits;
|
||||
};
|
||||
|
||||
typedef std::pair<BasicBlock *, ExitLimit> EdgeExitInfo;
|
||||
|
||||
/// Information about the backedge-taken count of a loop. This currently
|
||||
/// includes an exact count and a maximum count.
|
||||
///
|
||||
class BackedgeTakenInfo {
|
||||
/// A list of computable exits and their not-taken counts. Loops almost
|
||||
/// never have more than one computable exit.
|
||||
ExitNotTakenInfo ExitNotTaken;
|
||||
SmallVector<ExitNotTakenInfo, 1> ExitNotTaken;
|
||||
|
||||
/// An expression indicating the least maximum backedge-taken count of the
|
||||
/// loop that is known, or a SCEVCouldNotCompute. This expression is only
|
||||
/// valid if the predicates associated with all loop exits are true.
|
||||
const SCEV *Max;
|
||||
/// The pointer part of \c MaxAndComplete is an expression indicating the
|
||||
/// least maximum backedge-taken count of the loop that is known, or a
|
||||
/// SCEVCouldNotCompute. This expression is only valid if the predicates
|
||||
/// associated with all loop exits are true.
|
||||
///
|
||||
/// The integer part of \c MaxAndComplete is a boolean indicating if \c
|
||||
/// ExitNotTaken has an element for every exiting block in the loop.
|
||||
PointerIntPair<const SCEV *, 1> MaxAndComplete;
|
||||
|
||||
/// \name Helper projection functions on \c MaxAndComplete.
|
||||
/// @{
|
||||
bool isComplete() const { return MaxAndComplete.getInt(); }
|
||||
const SCEV *getMax() const { return MaxAndComplete.getPointer(); }
|
||||
/// @}
|
||||
|
||||
public:
|
||||
BackedgeTakenInfo() : Max(nullptr) {}
|
||||
BackedgeTakenInfo() : MaxAndComplete(nullptr, 0) {}
|
||||
|
||||
/// Initialize BackedgeTakenInfo from a list of exact exit counts.
|
||||
BackedgeTakenInfo(ArrayRef<EdgeExitInfo> ExitCounts, bool Complete,
|
||||
|
@ -719,11 +620,11 @@ private:
|
|||
/// Test whether this BackedgeTakenInfo contains any computed information,
|
||||
/// or whether it's all SCEVCouldNotCompute values.
|
||||
bool hasAnyInfo() const {
|
||||
return ExitNotTaken.ExitingBlock || !isa<SCEVCouldNotCompute>(Max);
|
||||
return !ExitNotTaken.empty() || !isa<SCEVCouldNotCompute>(getMax());
|
||||
}
|
||||
|
||||
/// Test whether this BackedgeTakenInfo contains complete information.
|
||||
bool hasFullInfo() const { return ExitNotTaken.isCompleteList(); }
|
||||
bool hasFullInfo() const { return isComplete(); }
|
||||
|
||||
/// Return an expression indicating the exact backedge-taken count of the
|
||||
/// loop if it is known or SCEVCouldNotCompute otherwise. This is the
|
||||
|
|
|
@ -5601,14 +5601,11 @@ void ScalarEvolution::forgetValue(Value *V) {
|
|||
/// caller's responsibility to specify the relevant loop exit using
|
||||
/// getExact(ExitingBlock, SE).
|
||||
const SCEV *
|
||||
ScalarEvolution::BackedgeTakenInfo::getExact(
|
||||
ScalarEvolution *SE, SCEVUnionPredicate *Preds) const {
|
||||
ScalarEvolution::BackedgeTakenInfo::getExact(ScalarEvolution *SE,
|
||||
SCEVUnionPredicate *Preds) const {
|
||||
// If any exits were not computable, the loop is not computable.
|
||||
if (!ExitNotTaken.isCompleteList()) return SE->getCouldNotCompute();
|
||||
|
||||
// We need exactly one computable exit.
|
||||
if (!ExitNotTaken.ExitingBlock) return SE->getCouldNotCompute();
|
||||
assert(ExitNotTaken.ExactNotTaken && "uninitialized not-taken info");
|
||||
if (!isComplete() || ExitNotTaken.empty())
|
||||
return SE->getCouldNotCompute();
|
||||
|
||||
const SCEV *BECount = nullptr;
|
||||
for (auto &ENT : ExitNotTaken) {
|
||||
|
@ -5618,10 +5615,10 @@ ScalarEvolution::BackedgeTakenInfo::getExact(
|
|||
BECount = ENT.ExactNotTaken;
|
||||
else if (BECount != ENT.ExactNotTaken)
|
||||
return SE->getCouldNotCompute();
|
||||
if (Preds && ENT.getPred())
|
||||
Preds->add(ENT.getPred());
|
||||
if (Preds)
|
||||
Preds->add(&ENT.Predicate);
|
||||
|
||||
assert((Preds || ENT.hasAlwaysTruePred()) &&
|
||||
assert((Preds || ENT.hasAlwaysTruePredicate()) &&
|
||||
"Predicate should be always true!");
|
||||
}
|
||||
|
||||
|
@ -5634,7 +5631,7 @@ const SCEV *
|
|||
ScalarEvolution::BackedgeTakenInfo::getExact(BasicBlock *ExitingBlock,
|
||||
ScalarEvolution *SE) const {
|
||||
for (auto &ENT : ExitNotTaken)
|
||||
if (ENT.ExitingBlock == ExitingBlock && ENT.hasAlwaysTruePred())
|
||||
if (ENT.ExitingBlock == ExitingBlock && ENT.hasAlwaysTruePredicate())
|
||||
return ENT.ExactNotTaken;
|
||||
|
||||
return SE->getCouldNotCompute();
|
||||
|
@ -5643,21 +5640,22 @@ ScalarEvolution::BackedgeTakenInfo::getExact(BasicBlock *ExitingBlock,
|
|||
/// getMax - Get the max backedge taken count for the loop.
|
||||
const SCEV *
|
||||
ScalarEvolution::BackedgeTakenInfo::getMax(ScalarEvolution *SE) const {
|
||||
// TODO: use any_of
|
||||
for (auto &ENT : ExitNotTaken)
|
||||
if (!ENT.hasAlwaysTruePred())
|
||||
if (!ENT.hasAlwaysTruePredicate())
|
||||
return SE->getCouldNotCompute();
|
||||
|
||||
return Max ? Max : SE->getCouldNotCompute();
|
||||
if (auto *Max = getMax())
|
||||
return Max;
|
||||
return SE->getCouldNotCompute();
|
||||
}
|
||||
|
||||
bool ScalarEvolution::BackedgeTakenInfo::hasOperand(const SCEV *S,
|
||||
ScalarEvolution *SE) const {
|
||||
if (Max && Max != SE->getCouldNotCompute() && SE->hasOperand(Max, S))
|
||||
if (getMax() && getMax() != SE->getCouldNotCompute() &&
|
||||
SE->hasOperand(getMax(), S))
|
||||
return true;
|
||||
|
||||
if (!ExitNotTaken.ExitingBlock)
|
||||
return false;
|
||||
|
||||
for (auto &ENT : ExitNotTaken)
|
||||
if (ENT.ExactNotTaken != SE->getCouldNotCompute() &&
|
||||
SE->hasOperand(ENT.ExactNotTaken, S))
|
||||
|
@ -5671,65 +5669,19 @@ bool ScalarEvolution::BackedgeTakenInfo::hasOperand(const SCEV *S,
|
|||
ScalarEvolution::BackedgeTakenInfo::BackedgeTakenInfo(
|
||||
ArrayRef<ScalarEvolution::EdgeExitInfo> ExitCounts, bool Complete,
|
||||
const SCEV *MaxCount)
|
||||
: Max(MaxCount) {
|
||||
|
||||
if (!Complete)
|
||||
ExitNotTaken.setIncomplete();
|
||||
|
||||
unsigned NumExits = ExitCounts.size();
|
||||
if (NumExits == 0)
|
||||
return;
|
||||
|
||||
ExitNotTaken.ExitingBlock = ExitCounts[0].first;
|
||||
ExitNotTaken.ExactNotTaken = ExitCounts[0].second.ExactNotTaken;
|
||||
|
||||
// Determine the number of ExitNotTakenExtras structures that we need.
|
||||
unsigned ExtraInfoSize = 0;
|
||||
if (NumExits > 1) {
|
||||
auto HasNonTrivialPredicate =
|
||||
[](const ScalarEvolution::EdgeExitInfo &Entry) {
|
||||
return !Entry.second.Predicate.isAlwaysTrue();
|
||||
};
|
||||
ExtraInfoSize = 1 + std::count_if(std::next(ExitCounts.begin()),
|
||||
ExitCounts.end(), HasNonTrivialPredicate);
|
||||
} else if (!ExitCounts[0].second.Predicate.isAlwaysTrue())
|
||||
ExtraInfoSize = 1;
|
||||
|
||||
ExitNotTakenExtras *ENT = nullptr;
|
||||
|
||||
// Allocate the ExitNotTakenExtras structures and initialize the first
|
||||
// element (ExitNotTaken).
|
||||
if (ExtraInfoSize > 0) {
|
||||
ENT = new ExitNotTakenExtras[ExtraInfoSize];
|
||||
ExitNotTaken.ExtraInfo = &ENT[0];
|
||||
*ExitNotTaken.getPred() = std::move(ExitCounts[0].second.Predicate);
|
||||
}
|
||||
|
||||
if (NumExits == 1)
|
||||
return;
|
||||
|
||||
assert(ENT && "ExitNotTakenExtras is NULL while having more than one exit");
|
||||
|
||||
auto &Exits = ExitNotTaken.ExtraInfo->Exits;
|
||||
|
||||
// Handle the rare case of multiple computable exits.
|
||||
for (unsigned i = 1, PredPos = 1; i < NumExits; ++i) {
|
||||
ExitNotTakenExtras *Ptr = nullptr;
|
||||
if (!ExitCounts[i].second.Predicate.isAlwaysTrue()) {
|
||||
Ptr = &ENT[PredPos++];
|
||||
Ptr->Pred = std::move(ExitCounts[i].second.Predicate);
|
||||
}
|
||||
|
||||
Exits.emplace_back(ExitCounts[i].first, ExitCounts[i].second.ExactNotTaken,
|
||||
Ptr);
|
||||
}
|
||||
: MaxAndComplete(MaxCount, Complete) {
|
||||
std::transform(ExitCounts.begin(), ExitCounts.end(),
|
||||
std::back_inserter(ExitNotTaken),
|
||||
[&](const ScalarEvolution::EdgeExitInfo &EEI) {
|
||||
BasicBlock *ExitBB = EEI.first;
|
||||
const ExitLimit &EL = EEI.second;
|
||||
return ExitNotTakenInfo({ExitBB, EL.ExactNotTaken, EL.Predicate});
|
||||
});
|
||||
}
|
||||
|
||||
/// Invalidate this result and free the ExitNotTakenInfo array.
|
||||
void ScalarEvolution::BackedgeTakenInfo::clear() {
|
||||
ExitNotTaken.ExitingBlock = nullptr;
|
||||
ExitNotTaken.ExactNotTaken = nullptr;
|
||||
delete[] ExitNotTaken.ExtraInfo;
|
||||
ExitNotTaken.clear();
|
||||
}
|
||||
|
||||
/// Compute the number of times the backedge of the specified loop will execute.
|
||||
|
|
Loading…
Reference in New Issue