[Polly] Hide Simplify implementation from header. NFC.

Move SimplifiyVisitor from Simplify.h to Simplify.cpp. It is not
relevant for applying the pass in either the NewPM or the legacyPM.
Rename it to SimplifyImpl to account for that.

This is possible due its state not being necessary to be preserved
between runs and thefore SimplifyImpl not needed to be held in the
pass object. Instead, SimplifyImpl is only instatiated for the
current Scop. In the NewPM as a function-local variable, and in the
legacy PM inside a llvm::Optional object because the state must be
preserved between the printScop (invoked by opt -analyze) and the most
recent runOnScop calls.
This commit is contained in:
Michael Kruse 2021-02-10 21:59:25 -06:00
parent c5e90a8857
commit 23753c6088
2 changed files with 147 additions and 159 deletions

View file

@ -15,7 +15,6 @@
#include "polly/ScopPass.h" #include "polly/ScopPass.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/IR/PassManager.h"
namespace llvm { namespace llvm {
class PassRegistry; class PassRegistry;
@ -23,101 +22,6 @@ class Pass;
} // namespace llvm } // namespace llvm
namespace polly { namespace polly {
class SimplifyVisitor {
private:
/// The invocation id (if there are multiple instances in the pass manager's
/// pipeline) to determine which statistics to update.
int CallNo;
/// The last/current SCoP that is/has been processed.
Scop *S;
/// Number of statements with empty domains removed from the SCoP.
int EmptyDomainsRemoved = 0;
/// Number of writes that are overwritten anyway.
int OverwritesRemoved = 0;
/// Number of combined writes.
int WritesCoalesced = 0;
/// Number of redundant writes removed from this SCoP.
int RedundantWritesRemoved = 0;
/// Number of writes with empty access domain removed.
int EmptyPartialAccessesRemoved = 0;
/// Number of unused accesses removed from this SCoP.
int DeadAccessesRemoved = 0;
/// Number of unused instructions removed from this SCoP.
int DeadInstructionsRemoved = 0;
/// Number of unnecessary statements removed from the SCoP.
int StmtsRemoved = 0;
/// Return whether at least one simplification has been applied.
bool isModified() const;
/// Remove statements that are never executed due to their domains being
/// empty.
///
/// In contrast to Scop::simplifySCoP, this removes based on the SCoP's
/// effective domain, i.e. including the SCoP's context as used by some other
/// simplification methods in this pass. This is necessary because the
/// analysis on empty domains is unreliable, e.g. remove a scalar value
/// definition MemoryAccesses, but not its use.
void removeEmptyDomainStmts();
/// Remove writes that are overwritten unconditionally later in the same
/// statement.
///
/// There must be no read of the same value between the write (that is to be
/// removed) and the overwrite.
void removeOverwrites();
/// Combine writes that write the same value if possible.
///
/// This function is able to combine:
/// - Partial writes with disjoint domain.
/// - Writes that write to the same array element.
///
/// In all cases, both writes must write the same values.
void coalesceWrites();
/// Remove writes that just write the same value already stored in the
/// element.
void removeRedundantWrites();
/// Remove statements without side effects.
void removeUnnecessaryStmts();
/// Remove accesses that have an empty domain.
void removeEmptyPartialAccesses();
/// Mark all reachable instructions and access, and sweep those that are not
/// reachable.
void markAndSweep(LoopInfo *LI);
/// Print simplification statistics to @p OS.
void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const;
/// Print the current state of all MemoryAccesses to @p OS.
void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const;
public:
explicit SimplifyVisitor(int CallNo = 0) : CallNo(CallNo) {}
bool visit(Scop &S, LoopInfo *LI);
void printScop(raw_ostream &OS, Scop &S) const;
void releaseMemory();
};
} // namespace polly
namespace polly {
class MemoryAccess; class MemoryAccess;
class ScopStmt; class ScopStmt;
@ -148,22 +52,25 @@ llvm::SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt);
llvm::Pass *createSimplifyWrapperPass(int CallNo = 0); llvm::Pass *createSimplifyWrapperPass(int CallNo = 0);
struct SimplifyPass : public PassInfoMixin<SimplifyPass> { struct SimplifyPass : public PassInfoMixin<SimplifyPass> {
SimplifyPass(int CallNo = 0) : Imp(CallNo) {} SimplifyPass(int CallNo = 0) : CallNo(CallNo) {}
llvm::PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM, llvm::PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &AR, SPMUpdater &U); ScopStandardAnalysisResults &AR, SPMUpdater &U);
SimplifyVisitor Imp; private:
int CallNo;
}; };
struct SimplifyPrinterPass : public PassInfoMixin<SimplifyPrinterPass> { struct SimplifyPrinterPass : public PassInfoMixin<SimplifyPrinterPass> {
SimplifyPrinterPass(raw_ostream &OS, int CallNo = 0) : OS(OS), Imp(CallNo) {} SimplifyPrinterPass(raw_ostream &OS, int CallNo = 0)
: OS(OS), CallNo(CallNo) {}
PreservedAnalyses run(Scop &S, ScopAnalysisManager &, PreservedAnalyses run(Scop &S, ScopAnalysisManager &,
ScopStandardAnalysisResults &, SPMUpdater &); ScopStandardAnalysisResults &, SPMUpdater &);
private:
raw_ostream &OS; raw_ostream &OS;
SimplifyVisitor Imp; int CallNo;
}; };
} // namespace polly } // namespace polly

View file

@ -20,6 +20,7 @@
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
#include "llvm/InitializePasses.h" #include "llvm/InitializePasses.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#define DEBUG_TYPE "polly-simplify" #define DEBUG_TYPE "polly-simplify"
using namespace llvm; using namespace llvm;
@ -116,10 +117,99 @@ static isl::union_map underapproximatedAddMap(isl::union_map UMap,
return UResult; return UResult;
} }
} // namespace
class SimplifyImpl {
private:
/// The invocation id (if there are multiple instances in the pass manager's
/// pipeline) to determine which statistics to update.
int CallNo;
/// The last/current SCoP that is/has been processed.
Scop *S = nullptr;
/// Number of statements with empty domains removed from the SCoP.
int EmptyDomainsRemoved = 0;
/// Number of writes that are overwritten anyway.
int OverwritesRemoved = 0;
/// Number of combined writes.
int WritesCoalesced = 0;
/// Number of redundant writes removed from this SCoP.
int RedundantWritesRemoved = 0;
/// Number of writes with empty access domain removed.
int EmptyPartialAccessesRemoved = 0;
/// Number of unused accesses removed from this SCoP.
int DeadAccessesRemoved = 0;
/// Number of unused instructions removed from this SCoP.
int DeadInstructionsRemoved = 0;
/// Number of unnecessary statements removed from the SCoP.
int StmtsRemoved = 0;
/// Remove statements that are never executed due to their domains being
/// empty.
///
/// In contrast to Scop::simplifySCoP, this removes based on the SCoP's
/// effective domain, i.e. including the SCoP's context as used by some other
/// simplification methods in this pass. This is necessary because the
/// analysis on empty domains is unreliable, e.g. remove a scalar value
/// definition MemoryAccesses, but not its use.
void removeEmptyDomainStmts();
/// Remove writes that are overwritten unconditionally later in the same
/// statement.
///
/// There must be no read of the same value between the write (that is to be
/// removed) and the overwrite.
void removeOverwrites();
/// Combine writes that write the same value if possible.
///
/// This function is able to combine:
/// - Partial writes with disjoint domain.
/// - Writes that write to the same array element.
///
/// In all cases, both writes must write the same values.
void coalesceWrites();
/// Remove writes that just write the same value already stored in the
/// element.
void removeRedundantWrites();
/// Remove statements without side effects.
void removeUnnecessaryStmts();
/// Remove accesses that have an empty domain.
void removeEmptyPartialAccesses();
/// Mark all reachable instructions and access, and sweep those that are not
/// reachable.
void markAndSweep(LoopInfo *LI);
/// Print simplification statistics to @p OS.
void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const;
/// Print the current state of all MemoryAccesses to @p OS.
void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const;
public:
explicit SimplifyImpl(int CallNo = 0) : CallNo(CallNo) {}
void run(Scop &S, LoopInfo *LI);
void printScop(raw_ostream &OS, Scop &S) const;
/// Return whether at least one simplification has been applied.
bool isModified() const;
};
/// Return whether at least one simplification has been applied. /// Return whether at least one simplification has been applied.
bool SimplifyVisitor::isModified() const { bool SimplifyImpl::isModified() const {
return EmptyDomainsRemoved > 0 || OverwritesRemoved > 0 || return EmptyDomainsRemoved > 0 || OverwritesRemoved > 0 ||
WritesCoalesced > 0 || RedundantWritesRemoved > 0 || WritesCoalesced > 0 || RedundantWritesRemoved > 0 ||
EmptyPartialAccessesRemoved > 0 || DeadAccessesRemoved > 0 || EmptyPartialAccessesRemoved > 0 || DeadAccessesRemoved > 0 ||
@ -134,7 +224,7 @@ bool SimplifyVisitor::isModified() const {
/// simplification methods in this pass. This is necessary because the /// simplification methods in this pass. This is necessary because the
/// analysis on empty domains is unreliable, e.g. remove a scalar value /// analysis on empty domains is unreliable, e.g. remove a scalar value
/// definition MemoryAccesses, but not its use. /// definition MemoryAccesses, but not its use.
void SimplifyVisitor::removeEmptyDomainStmts() { void SimplifyImpl::removeEmptyDomainStmts() {
size_t NumStmtsBefore = S->getSize(); size_t NumStmtsBefore = S->getSize();
S->removeStmts([](ScopStmt &Stmt) -> bool { S->removeStmts([](ScopStmt &Stmt) -> bool {
@ -155,7 +245,7 @@ void SimplifyVisitor::removeEmptyDomainStmts() {
/// ///
/// There must be no read of the same value between the write (that is to be /// There must be no read of the same value between the write (that is to be
/// removed) and the overwrite. /// removed) and the overwrite.
void SimplifyVisitor::removeOverwrites() { void SimplifyImpl::removeOverwrites() {
for (auto &Stmt : *S) { for (auto &Stmt : *S) {
isl::set Domain = Stmt.getDomain(); isl::set Domain = Stmt.getDomain();
isl::union_map WillBeOverwritten = isl::union_map WillBeOverwritten =
@ -214,7 +304,7 @@ void SimplifyVisitor::removeOverwrites() {
/// - Writes that write to the same array element. /// - Writes that write to the same array element.
/// ///
/// In all cases, both writes must write the same values. /// In all cases, both writes must write the same values.
void SimplifyVisitor::coalesceWrites() { void SimplifyImpl::coalesceWrites() {
for (auto &Stmt : *S) { for (auto &Stmt : *S) {
isl::set Domain = Stmt.getDomain().intersect_params(S->getContext()); isl::set Domain = Stmt.getDomain().intersect_params(S->getContext());
@ -386,7 +476,7 @@ void SimplifyVisitor::coalesceWrites() {
/// Remove writes that just write the same value already stored in the /// Remove writes that just write the same value already stored in the
/// element. /// element.
void SimplifyVisitor::removeRedundantWrites() { void SimplifyImpl::removeRedundantWrites() {
for (auto &Stmt : *S) { for (auto &Stmt : *S) {
SmallDenseMap<Value *, isl::set> ValueSets; SmallDenseMap<Value *, isl::set> ValueSets;
auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set { auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set {
@ -480,7 +570,7 @@ void SimplifyVisitor::removeRedundantWrites() {
} }
/// Remove statements without side effects. /// Remove statements without side effects.
void SimplifyVisitor::removeUnnecessaryStmts() { void SimplifyImpl::removeUnnecessaryStmts() {
auto NumStmtsBefore = S->getSize(); auto NumStmtsBefore = S->getSize();
S->simplifySCoP(true); S->simplifySCoP(true);
assert(NumStmtsBefore >= S->getSize()); assert(NumStmtsBefore >= S->getSize());
@ -491,7 +581,7 @@ void SimplifyVisitor::removeUnnecessaryStmts() {
} }
/// Remove accesses that have an empty domain. /// Remove accesses that have an empty domain.
void SimplifyVisitor::removeEmptyPartialAccesses() { void SimplifyImpl::removeEmptyPartialAccesses() {
for (ScopStmt &Stmt : *S) { for (ScopStmt &Stmt : *S) {
// Defer the actual removal to not invalidate iterators. // Defer the actual removal to not invalidate iterators.
SmallVector<MemoryAccess *, 8> DeferredRemove; SmallVector<MemoryAccess *, 8> DeferredRemove;
@ -520,7 +610,7 @@ void SimplifyVisitor::removeEmptyPartialAccesses() {
/// Mark all reachable instructions and access, and sweep those that are not /// Mark all reachable instructions and access, and sweep those that are not
/// reachable. /// reachable.
void SimplifyVisitor::markAndSweep(LoopInfo *LI) { void SimplifyImpl::markAndSweep(LoopInfo *LI) {
DenseSet<MemoryAccess *> UsedMA; DenseSet<MemoryAccess *> UsedMA;
DenseSet<VirtualInstruction> UsedInsts; DenseSet<VirtualInstruction> UsedInsts;
@ -578,7 +668,7 @@ void SimplifyVisitor::markAndSweep(LoopInfo *LI) {
} }
/// Print simplification statistics to @p OS. /// Print simplification statistics to @p OS.
void SimplifyVisitor::printStatistics(llvm::raw_ostream &OS, int Indent) const { void SimplifyImpl::printStatistics(llvm::raw_ostream &OS, int Indent) const {
OS.indent(Indent) << "Statistics {\n"; OS.indent(Indent) << "Statistics {\n";
OS.indent(Indent + 4) << "Empty domains removed: " << EmptyDomainsRemoved OS.indent(Indent + 4) << "Empty domains removed: " << EmptyDomainsRemoved
<< '\n'; << '\n';
@ -598,7 +688,7 @@ void SimplifyVisitor::printStatistics(llvm::raw_ostream &OS, int Indent) const {
} }
/// Print the current state of all MemoryAccesses to @p OS. /// Print the current state of all MemoryAccesses to @p OS.
void SimplifyVisitor::printAccesses(llvm::raw_ostream &OS, int Indent) const { void SimplifyImpl::printAccesses(llvm::raw_ostream &OS, int Indent) const {
OS.indent(Indent) << "After accesses {\n"; OS.indent(Indent) << "After accesses {\n";
for (auto &Stmt : *S) { for (auto &Stmt : *S) {
OS.indent(Indent + 4) << Stmt.getBaseName() << "\n"; OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
@ -608,9 +698,9 @@ void SimplifyVisitor::printAccesses(llvm::raw_ostream &OS, int Indent) const {
OS.indent(Indent) << "}\n"; OS.indent(Indent) << "}\n";
} }
bool SimplifyVisitor::visit(Scop &S, LoopInfo *LI) { void SimplifyImpl::run(Scop &S, LoopInfo *LI) {
// Reset statistics of last processed SCoP. // Must not have run before.
releaseMemory(); assert(!this->S);
assert(!isModified()); assert(!isModified());
// Prepare processing of this SCoP. // Prepare processing of this SCoP.
@ -650,11 +740,9 @@ bool SimplifyVisitor::visit(Scop &S, LoopInfo *LI) {
NumPHIWritesInLoops[CallNo] += ScopStats.NumPHIWritesInLoops; NumPHIWritesInLoops[CallNo] += ScopStats.NumPHIWritesInLoops;
NumSingletonWrites[CallNo] += ScopStats.NumSingletonWrites; NumSingletonWrites[CallNo] += ScopStats.NumSingletonWrites;
NumSingletonWritesInLoops[CallNo] += ScopStats.NumSingletonWritesInLoops; NumSingletonWritesInLoops[CallNo] += ScopStats.NumSingletonWritesInLoops;
return false;
} }
void SimplifyVisitor::printScop(raw_ostream &OS, Scop &S) const { void SimplifyImpl::printScop(raw_ostream &OS, Scop &S) const {
assert(&S == this->S && assert(&S == this->S &&
"Can only print analysis for the last processed SCoP"); "Can only print analysis for the last processed SCoP");
printStatistics(OS); printStatistics(OS);
@ -666,26 +754,13 @@ void SimplifyVisitor::printScop(raw_ostream &OS, Scop &S) const {
printAccesses(OS); printAccesses(OS);
} }
void SimplifyVisitor::releaseMemory() {
S = nullptr;
EmptyDomainsRemoved = 0;
OverwritesRemoved = 0;
WritesCoalesced = 0;
RedundantWritesRemoved = 0;
EmptyPartialAccessesRemoved = 0;
DeadAccessesRemoved = 0;
DeadInstructionsRemoved = 0;
StmtsRemoved = 0;
}
namespace {
class SimplifyWrapperPass : public ScopPass { class SimplifyWrapperPass : public ScopPass {
public: public:
static char ID; static char ID;
SimplifyVisitor Imp; int CallNo;
Optional<SimplifyImpl> Impl;
explicit SimplifyWrapperPass(int CallNo = 0) : ScopPass(ID), Imp(CallNo) {} explicit SimplifyWrapperPass(int CallNo = 0) : ScopPass(ID), CallNo(CallNo) {}
virtual void getAnalysisUsage(AnalysisUsage &AU) const override { virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequiredTransitive<ScopInfoRegionPass>(); AU.addRequiredTransitive<ScopInfoRegionPass>();
@ -694,24 +769,37 @@ public:
} }
virtual bool runOnScop(Scop &S) override { virtual bool runOnScop(Scop &S) override {
return Imp.visit(S, &getAnalysis<LoopInfoWrapperPass>().getLoopInfo()); LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
Impl.emplace(CallNo);
Impl->run(S, LI);
return false;
} }
virtual void printScop(raw_ostream &OS, Scop &S) const override { virtual void printScop(raw_ostream &OS, Scop &S) const override {
Imp.printScop(OS, S); if (Impl)
Impl->printScop(OS, S);
} }
virtual void releaseMemory() override { Imp.releaseMemory(); } virtual void releaseMemory() override { Impl.reset(); }
}; };
char SimplifyWrapperPass::ID; char SimplifyWrapperPass::ID;
} // anonymous namespace
namespace polly { static llvm::PreservedAnalyses
llvm::PreservedAnalyses SimplifyPass::run(Scop &S, ScopAnalysisManager &SAM, runSimplifyUsingNPM(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &SAR, ScopStandardAnalysisResults &SAR, SPMUpdater &U, int CallNo,
SPMUpdater &U) { raw_ostream *OS) {
if (!Imp.visit(S, &SAR.LI)) SimplifyImpl Impl(CallNo);
Impl.run(S, &SAR.LI);
if (OS) {
*OS << "Printing analysis 'Polly - Simplify' for region: '" << S.getName()
<< "' in function '" << S.getFunction().getName() << "':\n";
Impl.printScop(*OS, S);
}
if (!Impl.isModified())
return llvm::PreservedAnalyses::all(); return llvm::PreservedAnalyses::all();
PreservedAnalyses PA; PreservedAnalyses PA;
@ -721,27 +809,21 @@ llvm::PreservedAnalyses SimplifyPass::run(Scop &S, ScopAnalysisManager &SAM,
return PA; return PA;
} }
} // anonymous namespace
llvm::PreservedAnalyses SimplifyPass::run(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &SAR,
SPMUpdater &U) {
return runSimplifyUsingNPM(S, SAM, SAR, U, CallNo, nullptr);
}
llvm::PreservedAnalyses llvm::PreservedAnalyses
SimplifyPrinterPass::run(Scop &S, ScopAnalysisManager &SAM, SimplifyPrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
ScopStandardAnalysisResults &SAR, SPMUpdater &U) { ScopStandardAnalysisResults &SAR, SPMUpdater &U) {
bool Changed = Imp.visit(S, &SAR.LI); return runSimplifyUsingNPM(S, SAM, SAR, U, CallNo, &OS);
OS << "Printing analysis 'Polly - Simplify' for region: '" << S.getName()
<< "' in function '" << S.getFunction().getName() << "':\n";
Imp.printScop(OS, S);
if (!Changed)
return llvm::PreservedAnalyses::all();
PreservedAnalyses PA;
PA.preserveSet<AllAnalysesOn<Module>>();
PA.preserveSet<AllAnalysesOn<Function>>();
PA.preserveSet<AllAnalysesOn<Loop>>();
return PA;
} }
SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt) { SmallVector<MemoryAccess *, 32> polly::getAccessesInOrder(ScopStmt &Stmt) {
SmallVector<MemoryAccess *, 32> Accesses; SmallVector<MemoryAccess *, 32> Accesses;
for (MemoryAccess *MemAcc : Stmt) for (MemoryAccess *MemAcc : Stmt)
@ -758,7 +840,6 @@ SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt) {
return Accesses; return Accesses;
} }
} // namespace polly
Pass *polly::createSimplifyWrapperPass(int CallNo) { Pass *polly::createSimplifyWrapperPass(int CallNo) {
return new SimplifyWrapperPass(CallNo); return new SimplifyWrapperPass(CallNo);