20#include "llvm/ADT/Statistic.h"
21#include "llvm/Support/Debug.h"
25#define DEBUG_TYPE "polly-simplify"
33 PollyPrintSimplify(
"polly-print-simplify",
34 cl::desc(
"Polly - Print Simplify actions"),
37#define TWO_STATISTICS(VARNAME, DESC) \
38 static llvm::Statistic VARNAME[2] = { \
39 {DEBUG_TYPE, #VARNAME "0", DESC " (first)"}, \
40 {DEBUG_TYPE, #VARNAME "1", DESC " (second)"}}
46static unsigned const SimplifyMaxDisjuncts = 4;
52 "Number of statement with empty domains removed in any SCoP");
53TWO_STATISTICS(TotalOverwritesRemoved,
"Number of removed overwritten writes");
54TWO_STATISTICS(TotalWritesCoalesced,
"Number of writes coalesced with another");
56 "Number of writes of same value removed in any SCoP");
58 "Number of empty partial accesses removed");
59TWO_STATISTICS(TotalDeadAccessesRemoved,
"Number of dead accesses removed");
61 "Number of unused instructions removed");
62TWO_STATISTICS(TotalStmtsRemoved,
"Number of statements removed in any SCoP");
64TWO_STATISTICS(NumValueWrites,
"Number of scalar value writes after Simplify");
66 NumValueWritesInLoops,
67 "Number of scalar value writes nested in affine loops after Simplify");
69 "Number of scalar phi writes after the first simplification");
72 "Number of scalar phi writes nested in affine loops after Simplify");
73TWO_STATISTICS(NumSingletonWrites,
"Number of singleton writes after Simplify");
75 NumSingletonWritesInLoops,
76 "Number of singleton writes nested in affine loops after Simplify");
106 SimplifyMaxDisjuncts)
107 return UMap.
unite(Map);
113 Result = Result.
unite(BMap);
118 Result = Result.
unite(BMap);
123 UResult.
unite(Result);
128class SimplifyImpl final {
138 int EmptyDomainsRemoved = 0;
141 int OverwritesRemoved = 0;
144 int WritesCoalesced = 0;
147 int RedundantWritesRemoved = 0;
150 int EmptyPartialAccessesRemoved = 0;
153 int DeadAccessesRemoved = 0;
156 int DeadInstructionsRemoved = 0;
159 int StmtsRemoved = 0;
169 void removeEmptyDomainStmts();
176 void removeOverwrites();
185 void coalesceWrites();
189 void removeRedundantWrites();
192 void removeUnnecessaryStmts();
195 void removeEmptyPartialAccesses();
199 void markAndSweep(LoopInfo *LI);
202 void printStatistics(llvm::raw_ostream &OS,
int Indent = 0)
const;
205 void printAccesses(llvm::raw_ostream &OS,
int Indent = 0)
const;
208 explicit SimplifyImpl(
int CallNo = 0) : CallNo(CallNo) {}
210 void run(Scop &S, LoopInfo *LI);
212 void printScop(raw_ostream &OS, Scop &S)
const;
215 bool isModified()
const;
219bool SimplifyImpl::isModified()
const {
220 return EmptyDomainsRemoved > 0 || OverwritesRemoved > 0 ||
221 WritesCoalesced > 0 || RedundantWritesRemoved > 0 ||
222 EmptyPartialAccessesRemoved > 0 || DeadAccessesRemoved > 0 ||
223 DeadInstructionsRemoved > 0 || StmtsRemoved > 0;
234void SimplifyImpl::removeEmptyDomainStmts() {
235 size_t NumStmtsBefore =
S->getSize();
237 S->removeStmts([](ScopStmt &Stmt) ->
bool {
238 auto EffectiveDomain =
243 assert(NumStmtsBefore >=
S->getSize());
244 EmptyDomainsRemoved = NumStmtsBefore -
S->getSize();
245 POLLY_DEBUG(dbgs() <<
"Removed " << EmptyDomainsRemoved <<
" (of "
246 << NumStmtsBefore <<
") statements with empty domains \n");
247 TotalEmptyDomainsRemoved[CallNo] += EmptyDomainsRemoved;
255void SimplifyImpl::removeOverwrites() {
256 for (
auto &Stmt : *
S) {
264 for (
auto *MA : reverse(Accesses)) {
281 WillBeOverwritten = WillBeOverwritten.
subtract(AccRelUniv);
286 isl::union_map AccRelUnion = AccRel;
287 if (AccRelUnion.
is_subset(WillBeOverwritten)) {
289 <<
" which will be overwritten anyway\n");
293 TotalOverwritesRemoved[CallNo]++;
300 WillBeOverwritten = underapproximatedAddMap(WillBeOverwritten, AccRel);
313void SimplifyImpl::coalesceWrites() {
314 for (
auto &Stmt : *
S) {
322 SmallDenseMap<Value *, isl::set> ValueSets;
323 auto makeValueSet = [&ValueSets,
this](
Value *V) ->
isl::set {
327 isl::ctx
Ctx =
S->getIslCtx();
343 for (MemoryAccess *MA : reverse(Accesses)) {
372 ValSet = makeValueSet(StoredVal);
385 isl::map UndefAnything =
390 isl::map AllowedAccesses = AccRel.
unite(UndefAnything);
399 isl::union_map Filtered =
404 MemoryAccess *OtherMA = (MemoryAccess *)Map.
get_space()
408 isl::map OtherAccRel =
419 isl::map NewAccRel = AccRel.
unite(OtherAccRel);
429 TotalWritesCoalesced[CallNo]++;
442 SmallPtrSet<MemoryAccess *, 2> TouchedAccesses;
445 MemoryAccess *MA = (MemoryAccess *)Map.
get_space()
450 TouchedAccesses.insert(MA);
452 isl::union_map NewFutureWrites =
454 for (isl::map FutureWrite : FutureWrites.
get_map_list()) {
455 MemoryAccess *MA = (MemoryAccess *)FutureWrite.get_space()
460 if (!TouchedAccesses.count(MA))
461 NewFutureWrites = NewFutureWrites.
unite(FutureWrite);
463 FutureWrites = NewFutureWrites;
475 isl::map AccRelValAcc =
477 FutureWrites = FutureWrites.
unite(AccRelValAcc);
485void SimplifyImpl::removeRedundantWrites() {
486 for (
auto &Stmt : *
S) {
487 SmallDenseMap<Value *, isl::set> ValueSets;
488 auto makeValueSet = [&ValueSets,
this](
Value *V) ->
isl::set {
511 for (MemoryAccess *MA : Accesses) {
538 AccRelWrapped, makeValueSet(StoredVal));
539 if (isl::union_map(AccRelStoredVal).is_subset(Known)) {
540 POLLY_DEBUG(dbgs() <<
"Cleanup of " << MA <<
":\n");
541 POLLY_DEBUG(dbgs() <<
" Scalar: " << *StoredVal <<
"\n");
542 POLLY_DEBUG(dbgs() <<
" AccRel: " << AccRel <<
"\n");
546 RedundantWritesRemoved++;
547 TotalRedundantWritesRemoved[CallNo]++;
557 if (LoadedVal && IsOrdered) {
559 AccRelWrapped, makeValueSet(LoadedVal));
561 Known = Known.
unite(AccRelVal);
579void SimplifyImpl::removeUnnecessaryStmts() {
580 auto NumStmtsBefore =
S->getSize();
581 S->simplifySCoP(
true);
582 assert(NumStmtsBefore >=
S->getSize());
583 StmtsRemoved = NumStmtsBefore -
S->getSize();
584 POLLY_DEBUG(dbgs() <<
"Removed " << StmtsRemoved <<
" (of " << NumStmtsBefore
585 <<
") statements\n");
586 TotalStmtsRemoved[CallNo] += StmtsRemoved;
590void SimplifyImpl::removeEmptyPartialAccesses() {
591 for (ScopStmt &Stmt : *
S) {
593 SmallVector<MemoryAccess *, 8> DeferredRemove;
595 for (MemoryAccess *MA : Stmt) {
604 dbgs() <<
"Removing " << MA
605 <<
" because it's a partial access that never occurs\n");
606 DeferredRemove.push_back(MA);
609 for (MemoryAccess *MA : DeferredRemove) {
610 Stmt.removeSingleMemoryAccess(MA);
611 EmptyPartialAccessesRemoved++;
612 TotalEmptyPartialAccessesRemoved[CallNo]++;
619void SimplifyImpl::markAndSweep(LoopInfo *LI) {
620 DenseSet<MemoryAccess *> UsedMA;
621 DenseSet<VirtualInstruction> UsedInsts;
629 SmallVector<MemoryAccess *, 64> AllMAs;
630 for (ScopStmt &Stmt : *
S)
631 AllMAs.append(Stmt.begin(), Stmt.end());
633 for (MemoryAccess *MA : AllMAs) {
634 if (UsedMA.count(MA))
637 <<
" because its value is not used\n");
641 DeadAccessesRemoved++;
642 TotalDeadAccessesRemoved[CallNo]++;
646 for (ScopStmt &Stmt : *
S) {
651 SmallVector<Instruction *, 32> AllInsts(Stmt.
insts_begin(),
653 SmallVector<Instruction *, 32> RemainInsts;
655 for (Instruction *Inst : AllInsts) {
656 auto It = UsedInsts.find({&Stmt, Inst});
657 if (It == UsedInsts.end()) {
658 POLLY_DEBUG(dbgs() <<
"Removing "; Inst->print(dbgs());
659 dbgs() <<
" because it is not used\n");
660 DeadInstructionsRemoved++;
661 TotalDeadInstructionsRemoved[CallNo]++;
665 RemainInsts.push_back(Inst);
677void SimplifyImpl::printStatistics(llvm::raw_ostream &OS,
int Indent)
const {
678 OS.indent(Indent) <<
"Statistics {\n";
679 OS.indent(Indent + 4) <<
"Empty domains removed: " << EmptyDomainsRemoved
681 OS.indent(Indent + 4) <<
"Overwrites removed: " << OverwritesRemoved <<
'\n';
682 OS.indent(Indent + 4) <<
"Partial writes coalesced: " << WritesCoalesced
684 OS.indent(Indent + 4) <<
"Redundant writes removed: "
685 << RedundantWritesRemoved <<
"\n";
686 OS.indent(Indent + 4) <<
"Accesses with empty domains removed: "
687 << EmptyPartialAccessesRemoved <<
"\n";
688 OS.indent(Indent + 4) <<
"Dead accesses removed: " << DeadAccessesRemoved
690 OS.indent(Indent + 4) <<
"Dead instructions removed: "
691 << DeadInstructionsRemoved <<
'\n';
692 OS.indent(Indent + 4) <<
"Stmts removed: " << StmtsRemoved <<
"\n";
693 OS.indent(Indent) <<
"}\n";
697void SimplifyImpl::printAccesses(llvm::raw_ostream &OS,
int Indent)
const {
698 OS.indent(Indent) <<
"After accesses {\n";
699 for (
auto &Stmt : *
S) {
700 OS.indent(Indent + 4) << Stmt.
getBaseName() <<
"\n";
701 for (
auto *MA : Stmt)
704 OS.indent(Indent) <<
"}\n";
707void SimplifyImpl::run(Scop &
S, LoopInfo *LI) {
714 ScopsProcessed[CallNo]++;
716 POLLY_DEBUG(dbgs() <<
"Removing statements that are never executed...\n");
717 removeEmptyDomainStmts();
719 POLLY_DEBUG(dbgs() <<
"Removing partial writes that never happen...\n");
720 removeEmptyPartialAccesses();
725 POLLY_DEBUG(dbgs() <<
"Coalesce partial writes...\n");
728 POLLY_DEBUG(dbgs() <<
"Removing redundant writes...\n");
729 removeRedundantWrites();
731 POLLY_DEBUG(dbgs() <<
"Cleanup unused accesses...\n");
734 POLLY_DEBUG(dbgs() <<
"Removing statements without side effects...\n");
735 removeUnnecessaryStmts();
738 ScopsModified[CallNo]++;
742 auto ScopStats =
S.getStatistics();
743 NumValueWrites[CallNo] += ScopStats.NumValueWrites;
744 NumValueWritesInLoops[CallNo] += ScopStats.NumValueWritesInLoops;
745 NumPHIWrites[CallNo] += ScopStats.NumPHIWrites;
746 NumPHIWritesInLoops[CallNo] += ScopStats.NumPHIWritesInLoops;
747 NumSingletonWrites[CallNo] += ScopStats.NumSingletonWrites;
748 NumSingletonWritesInLoops[CallNo] += ScopStats.NumSingletonWritesInLoops;
751void SimplifyImpl::printScop(raw_ostream &OS, Scop &
S)
const {
753 "Can only print analysis for the last processed SCoP");
757 OS <<
"SCoP could not be simplified\n";
766 SmallVector<MemoryAccess *, 32> Accesses;
769 if (isImplicitRead(
MemAcc))
770 Accesses.push_back(
MemAcc);
773 if (isExplicitAccess(
MemAcc))
774 Accesses.push_back(
MemAcc);
777 if (isImplicitWrite(
MemAcc))
778 Accesses.push_back(
MemAcc);
784 SimplifyImpl Impl(CallNo);
785 Impl.run(
S,
S.getLI());
786 if (PollyPrintSimplify) {
787 outs() <<
"Printing analysis 'Polly - Simplify' for region: '"
788 <<
S.getName() <<
"' in function '" <<
S.getFunction().getName()
790 Impl.printScop(outs(),
S);
793 return Impl.isModified();
llvm::cl::OptionCategory PollyCategory
#define TWO_STATISTICS(VARNAME, DESC)
static isl::id alloc(isl::ctx ctx, const std::string &name, void *user)
isl::basic_map_list get_basic_map_list() const
static isl::map universe(isl::space space)
isl::map intersect_params(isl::set params) const
boolean is_subset(const isl::map &map2) const
class size n_basic_map() const
static isl::map from_domain_and_range(isl::set domain, isl::set range)
isl::map unite(isl::map map2) const
isl::space get_space() const
static isl::map empty(isl::space space)
isl::map intersect_domain(isl::set set) const
static isl::set universe(isl::space space)
isl::set intersect_params(isl::set params) const
isl::space get_space() const
isl::id get_tuple_id(isl::dim type) const
isl::space unwrap() const
isl::map extract_map(isl::space space) const
isl::union_map uncurry() const
isl::union_map unite(isl::union_map umap2) const
isl::map_list get_map_list() const
isl::union_map subtract_domain(isl::union_set dom) const
boolean is_subset(const isl::union_map &umap2) const
static isl::union_map empty(isl::ctx ctx)
isl::union_map subtract(isl::union_map umap2) const
isl::union_map intersect_domain(isl::space space) const
Represent memory accesses in statements.
bool isOriginalArrayKind() const
Whether this is an access of an explicit load or store in the IR.
isl::map getLatestAccessRelation() const
Return the newest access relation of this access.
bool isWrite() const
Is this a write memory access?
Instruction * getAccessInstruction() const
Return the access instruction of this memory access.
Value * tryGetValueStored()
Return llvm::Value that is stored by this access, if available.
bool isRead() const
Is this a read memory access?
isl::id getId() const
Get identifier for the memory access.
bool isMustWrite() const
Is this a must-write memory access?
void print(raw_ostream &OS) const
Print the MemoryAccess.
bool isOriginalScalarKind() const
Whether this access is an array to a scalar memory object, without considering changes by setNewAcces...
ScopStmt * getStatement() const
Get the statement that contains this memory access.
isl::map getAccessRelation() const
Old name of getLatestAccessRelation().
Value * getAccessValue() const
Return the access value of this memory access.
void setNewAccessRelation(isl::map NewAccessRelation)
Set the updated access relation read from JSCOP file.
BasicBlock * getEntryBlock() const
Return a BasicBlock from this statement.
std::vector< Instruction * >::const_iterator insts_end() const
bool isBlockStmt() const
Return true if this statement represents a single basic block.
void removeSingleMemoryAccess(MemoryAccess *MA, bool AfterHoisting=true)
Remove MA from this statement.
void setInstructions(ArrayRef< Instruction * > Range)
Set the list of instructions for this statement.
std::vector< Instruction * >::const_iterator insts_begin() const
const char * getBaseName() const
bool isRegionStmt() const
Return true if this statement represents a whole region.
isl::set getDomain() const
Get the iteration domain of this ScopStmt.
isl::set getContext() const
Get the constraint on parameter of this Scop.
__isl_give isl_id * isl_id_alloc(isl_ctx *ctx, __isl_keep const char *name, void *user)
boolean manage(isl_bool val)
std::string getIslCompatibleName(const std::string &Prefix, const llvm::Value *Val, long Number, const std::string &Suffix, bool UseInstructionNames)
Combine Prefix, Val (or Number) and Suffix to an isl-compatible name.
llvm::SmallVector< MemoryAccess *, 32 > getAccessesInOrder(ScopStmt &Stmt)
Return a vector that contains MemoryAccesses in the order in which they are executed.
@ Value
MemoryKind::Value: Models an llvm::Value.
void markReachable(Scop *S, LoopInfo *LI, DenseSet< VirtualInstruction > &UsedInsts, DenseSet< MemoryAccess * > &UsedAccs, ScopStmt *OnlyLocal=nullptr)
Find all reachable instructions and accesses.
bool runSimplify(Scop &S, int CallNo)
void simplify(isl::set &Set)
Simplify a set inplace.
static TupleKindPtr Domain("Domain")