//===------ Simplify.h ------------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Simplify a SCoP by removing unnecessary statements and accesses. // //===----------------------------------------------------------------------===// #ifndef POLLY_TRANSFORM_SIMPLIFY_H #define POLLY_TRANSFORM_SIMPLIFY_H #include "polly/ScopPass.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/PassManager.h" namespace llvm { class PassRegistry; class Pass; } // namespace llvm 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 ScopStmt; /// Return a vector that contains MemoryAccesses in the order in /// which they are executed. /// /// The order is: /// - Implicit reads (BlockGenerator::generateScalarLoads) /// - Explicit reads and writes (BlockGenerator::generateArrayLoad, /// BlockGenerator::generateArrayStore) /// - In block statements, the accesses are in order in which their /// instructions are executed. /// - In region statements, that order of execution is not predictable at /// compile-time. /// - Implicit writes (BlockGenerator::generateScalarStores) /// The order in which implicit writes are executed relative to each other is /// undefined. llvm::SmallVector getAccessesInOrder(ScopStmt &Stmt); /// Create a Simplify pass /// /// @param CallNo Disambiguates this instance for when there are multiple /// instances of this pass in the pass manager. It is used only to /// keep the statistics apart and has no influence on the /// simplification itself. /// /// @return The Simplify pass. llvm::Pass *createSimplifyPass(int CallNo = 0); struct SimplifyPass : public PassInfoMixin { SimplifyPass(int CallNo = 0) : Imp(CallNo) {} llvm::PreservedAnalyses run(Scop &S, ScopAnalysisManager &SAM, ScopStandardAnalysisResults &AR, SPMUpdater &U); SimplifyVisitor Imp; }; struct SimplifyPrinterPass : public PassInfoMixin { SimplifyPrinterPass(raw_ostream &OS, int CallNo = 0) : OS(OS), Imp(CallNo) {} PreservedAnalyses run(Scop &S, ScopAnalysisManager &, ScopStandardAnalysisResults &, SPMUpdater &); raw_ostream &OS; SimplifyVisitor Imp; }; } // namespace polly namespace llvm { void initializeSimplifyLegacyPassPass(llvm::PassRegistry &); } // namespace llvm #endif /* POLLY_TRANSFORM_SIMPLIFY_H */