1 //===------ Simplify.cpp ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Simplify a SCoP by removing unnecessary statements and accesses.
12 //===----------------------------------------------------------------------===//
14 #include "polly/Simplify.h"
15 #include "polly/ScopInfo.h"
16 #include "polly/ScopPass.h"
17 #include "polly/Support/GICHelper.h"
18 #include "llvm/ADT/Statistic.h"
19 #include "llvm/Support/Debug.h"
20 #define DEBUG_TYPE "polly-simplify"
23 using namespace polly
;
27 STATISTIC(ScopsProcessed
, "Number of SCoPs processed");
28 STATISTIC(ScopsModified
, "Number of SCoPs simplified");
30 STATISTIC(PairUnequalAccRels
, "Number of Load-Store pairs NOT removed because "
31 "of different access relations");
32 STATISTIC(InBetweenStore
, "Number of Load-Store pairs NOT removed because "
33 "there is another store between them");
34 STATISTIC(TotalRedundantWritesRemoved
,
35 "Number of writes of same value removed in any SCoP");
36 STATISTIC(TotalStmtsRemoved
, "Number of statements removed in any SCoP");
38 class Simplify
: public ScopPass
{
40 /// The last/current SCoP that is/has been processed.
43 /// Number of redundant writes removed from this SCoP.
44 int RedundantWritesRemoved
= 0;
46 /// Number of unnecessary statements removed from the SCoP.
49 /// Return whether at least one simplification has been applied.
50 bool isModified() const {
51 return RedundantWritesRemoved
> 0 || StmtsRemoved
> 0;
54 MemoryAccess
*getReadAccessForValue(ScopStmt
*Stmt
, llvm::Value
*Val
) {
55 if (!isa
<Instruction
>(Val
))
58 for (auto *MA
: *Stmt
) {
61 if (MA
->getAccessValue() != Val
)
70 /// Return a write access that occurs between @p From and @p To.
72 /// In region statements the order is ignored because we cannot predict it.
74 /// @param Stmt Statement of both writes.
75 /// @param From Start looking after this access.
76 /// @param To Stop looking at this access, with the access itself.
77 /// @param Targets Look for an access that may wrote to one of these elements.
79 /// @return A write access between @p From and @p To that writes to at least
80 /// one element in @p Targets.
81 MemoryAccess
*hasWriteBetween(ScopStmt
*Stmt
, MemoryAccess
*From
,
82 MemoryAccess
*To
, isl::map Targets
) {
83 auto TargetsSpace
= give(isl_map_get_space(Targets
.keep()));
85 bool Started
= Stmt
->isRegionStmt();
86 for (auto *Acc
: *Stmt
) {
87 if (Acc
->isLatestScalarKind())
90 if (Stmt
->isBlockStmt() && From
== Acc
) {
95 if (Stmt
->isBlockStmt() && To
== Acc
) {
105 auto AccRel
= give(Acc
->getAccessRelation());
106 auto AccRelSpace
= give(isl_map_get_space(AccRel
.keep()));
108 // Spaces being different means that they access different arrays.
109 if (isl_space_has_equal_tuples(TargetsSpace
.keep(), AccRelSpace
.keep()) ==
113 AccRel
= give(isl_map_intersect_domain(AccRel
.take(),
114 Acc
->getStatement()->getDomain()));
115 AccRel
= give(isl_map_intersect_params(AccRel
.take(), S
->getContext()));
116 auto CommonElt
= give(isl_map_intersect(Targets
.copy(), AccRel
.copy()));
117 if (isl_map_is_empty(CommonElt
.keep()) != isl_bool_true
)
120 assert(Stmt
->isRegionStmt() &&
121 "To must be encountered in block statements");
125 /// Remove writes that just write the same value already stored in the
127 void removeRedundantWrites() {
128 // Delay actual removal to not invalidate iterators.
129 SmallVector
<MemoryAccess
*, 8> StoresToRemove
;
131 for (auto &Stmt
: *S
) {
132 for (auto *WA
: Stmt
) {
133 if (!WA
->isMustWrite())
135 if (!WA
->isLatestArrayKind())
137 if (!isa
<StoreInst
>(WA
->getAccessInstruction()))
140 auto ReadingValue
= WA
->getAccessValue();
144 auto RA
= getReadAccessForValue(&Stmt
, ReadingValue
);
147 if (!RA
->isLatestArrayKind())
150 auto WARel
= give(WA
->getLatestAccessRelation());
151 WARel
= give(isl_map_intersect_domain(WARel
.take(),
152 WA
->getStatement()->getDomain()));
153 WARel
= give(isl_map_intersect_params(WARel
.take(), S
->getContext()));
154 auto RARel
= give(RA
->getLatestAccessRelation());
155 RARel
= give(isl_map_intersect_domain(RARel
.take(),
156 RA
->getStatement()->getDomain()));
157 RARel
= give(isl_map_intersect_params(RARel
.take(), S
->getContext()));
159 if (isl_map_is_equal(RARel
.keep(), WARel
.keep()) != isl_bool_true
) {
160 PairUnequalAccRels
++;
161 DEBUG(dbgs() << "Not cleaning up " << WA
162 << " because of unequal access relations:\n");
163 DEBUG(dbgs() << " RA: " << RARel
<< "\n");
164 DEBUG(dbgs() << " WA: " << WARel
<< "\n");
168 if (auto *Conflicting
= hasWriteBetween(&Stmt
, RA
, WA
, WARel
)) {
171 DEBUG(dbgs() << "Not cleaning up " << WA
172 << " because there is another store to the same element "
174 DEBUG(Conflicting
->print(dbgs()));
178 StoresToRemove
.push_back(WA
);
182 for (auto *WA
: StoresToRemove
) {
183 auto Stmt
= WA
->getStatement();
184 auto AccRel
= give(WA
->getAccessRelation());
185 auto AccVal
= WA
->getAccessValue();
187 DEBUG(dbgs() << "Cleanup of " << WA
<< ":\n");
188 DEBUG(dbgs() << " Scalar: " << *AccVal
<< "\n");
189 DEBUG(dbgs() << " AccRel: " << AccRel
<< "\n");
192 Stmt
->removeSingleMemoryAccess(WA
);
194 RedundantWritesRemoved
++;
195 TotalRedundantWritesRemoved
++;
199 /// Remove statements without side effects.
200 void removeUnnecessayStmts() {
201 auto NumStmtsBefore
= S
->getSize();
202 S
->simplifySCoP(true);
203 assert(NumStmtsBefore
>= S
->getSize());
204 StmtsRemoved
= NumStmtsBefore
- S
->getSize();
205 DEBUG(dbgs() << "Removed " << StmtsRemoved
<< " (of " << NumStmtsBefore
206 << ") statements\n");
207 TotalStmtsRemoved
+= StmtsRemoved
;
210 /// Print simplification statistics to @p OS.
211 void printStatistics(llvm::raw_ostream
&OS
, int Indent
= 0) const {
212 OS
.indent(Indent
) << "Statistics {\n";
213 OS
.indent(Indent
+ 4) << "Redundant writes removed: "
214 << RedundantWritesRemoved
<< "\n";
215 OS
.indent(Indent
+ 4) << "Stmts removed: " << StmtsRemoved
<< "\n";
216 OS
.indent(Indent
) << "}\n";
219 /// Print the current state of all MemoryAccesses to @p OS.
220 void printAccesses(llvm::raw_ostream
&OS
, int Indent
= 0) const {
221 OS
.indent(Indent
) << "After accesses {\n";
222 for (auto &Stmt
: *S
) {
223 OS
.indent(Indent
+ 4) << Stmt
.getBaseName() << "\n";
224 for (auto *MA
: Stmt
)
227 OS
.indent(Indent
) << "}\n";
232 explicit Simplify() : ScopPass(ID
) {}
234 virtual void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
235 AU
.addRequiredTransitive
<ScopInfoRegionPass
>();
236 AU
.setPreservesAll();
239 virtual bool runOnScop(Scop
&S
) override
{
240 // Reset statistics of last processed SCoP.
243 // Prepare processing of this SCoP.
247 DEBUG(dbgs() << "Removing redundant writes...\n");
248 removeRedundantWrites();
250 DEBUG(dbgs() << "Removing statements without side effects...\n");
251 removeUnnecessayStmts();
255 DEBUG(dbgs() << "\nFinal Scop:\n");
256 DEBUG(S
.print(dbgs()));
261 virtual void printScop(raw_ostream
&OS
, Scop
&S
) const override
{
262 assert(&S
== this->S
&&
263 "Can only print analysis for the last processed SCoP");
267 OS
<< "SCoP could not be simplified\n";
273 virtual void releaseMemory() override
{
280 } // anonymous namespace
282 Pass
*polly::createSimplifyPass() { return new Simplify(); }
284 INITIALIZE_PASS_BEGIN(Simplify
, "polly-simplify", "Polly - Simplify", false,
286 INITIALIZE_PASS_END(Simplify
, "polly-simplify", "Polly - Simplify", false,