[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:
Sanjoy Das 2016-09-25 23:12:00 +00:00
parent 3b4c0c8086
commit 6bbb5f521c
2 changed files with 46 additions and 193 deletions

View File

@ -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

View File

@ -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.