1 //===------ Simplify.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // Simplify a SCoP by removing unnecessary statements and accesses.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "polly/Simplify.h"
15 #include "polly/ScopInfo.h"
16 #include "polly/ScopPass.h"
17 #include "polly/Support/GICHelper.h"
18 #include "polly/Support/ISLOStream.h"
19 #include "llvm/ADT/Statistic.h"
20 #include "llvm/Support/Debug.h"
21 #define DEBUG_TYPE "polly-simplify"
22 
23 using namespace llvm;
24 using namespace polly;
25 
26 namespace {
27 
28 STATISTIC(ScopsProcessed, "Number of SCoPs processed");
29 STATISTIC(ScopsModified, "Number of SCoPs simplified");
30 
31 STATISTIC(PairUnequalAccRels, "Number of Load-Store pairs NOT removed because "
32                               "of different access relations");
33 STATISTIC(InBetweenStore, "Number of Load-Store pairs NOT removed because "
34                           "there is another store between them");
35 STATISTIC(TotalOverwritesRemoved, "Number of removed overwritten writes");
36 STATISTIC(TotalRedundantWritesRemoved,
37           "Number of writes of same value removed in any SCoP");
38 STATISTIC(TotalStmtsRemoved, "Number of statements removed in any SCoP");
39 
40 static bool isImplicitRead(MemoryAccess *MA) {
41   return MA->isRead() && MA->isOriginalScalarKind();
42 }
43 
44 static bool isExplicitAccess(MemoryAccess *MA) {
45   return MA->isOriginalArrayKind();
46 }
47 
48 static bool isImplicitWrite(MemoryAccess *MA) {
49   return MA->isWrite() && MA->isOriginalScalarKind();
50 }
51 
52 /// Return a vector that contains MemoryAccesses in the order in
53 /// which they are executed.
54 ///
55 /// The order is:
56 /// - Implicit reads (BlockGenerator::generateScalarLoads)
57 /// - Explicit reads and writes (BlockGenerator::generateArrayLoad,
58 ///   BlockGenerator::generateArrayStore)
59 ///   - In block statements, the accesses are in order in which their
60 ///     instructions are executed.
61 ///   - In region statements, that order of execution is not predictable at
62 ///     compile-time.
63 /// - Implicit writes (BlockGenerator::generateScalarStores)
64 ///   The order in which implicit writes are executed relative to each other is
65 ///   undefined.
66 static SmallVector<MemoryAccess *, 32> getAccessesInOrder(ScopStmt &Stmt) {
67 
68   SmallVector<MemoryAccess *, 32> Accesses;
69 
70   for (MemoryAccess *MemAcc : Stmt)
71     if (isImplicitRead(MemAcc))
72       Accesses.push_back(MemAcc);
73 
74   for (MemoryAccess *MemAcc : Stmt)
75     if (isExplicitAccess(MemAcc))
76       Accesses.push_back(MemAcc);
77 
78   for (MemoryAccess *MemAcc : Stmt)
79     if (isImplicitWrite(MemAcc))
80       Accesses.push_back(MemAcc);
81 
82   return Accesses;
83 }
84 
85 class Simplify : public ScopPass {
86 private:
87   /// The last/current SCoP that is/has been processed.
88   Scop *S;
89 
90   /// Number of writes that are overwritten anyway.
91   int OverwritesRemoved = 0;
92 
93   /// Number of redundant writes removed from this SCoP.
94   int RedundantWritesRemoved = 0;
95 
96   /// Number of unnecessary statements removed from the SCoP.
97   int StmtsRemoved = 0;
98 
99   /// Return whether at least one simplification has been applied.
100   bool isModified() const {
101     return OverwritesRemoved > 0 || RedundantWritesRemoved > 0 ||
102            StmtsRemoved > 0;
103   }
104 
105   MemoryAccess *getReadAccessForValue(ScopStmt *Stmt, llvm::Value *Val) {
106     if (!isa<Instruction>(Val))
107       return nullptr;
108 
109     for (auto *MA : *Stmt) {
110       if (!MA->isRead())
111         continue;
112       if (MA->getAccessValue() != Val)
113         continue;
114 
115       return MA;
116     }
117 
118     return nullptr;
119   }
120 
121   /// Return a write access that occurs between @p From and @p To.
122   ///
123   /// In region statements the order is ignored because we cannot predict it.
124   ///
125   /// @param Stmt    Statement of both writes.
126   /// @param From    Start looking after this access.
127   /// @param To      Stop looking at this access, with the access itself.
128   /// @param Targets Look for an access that may wrote to one of these elements.
129   ///
130   /// @return A write access between @p From and @p To that writes to at least
131   ///         one element in @p Targets.
132   MemoryAccess *hasWriteBetween(ScopStmt *Stmt, MemoryAccess *From,
133                                 MemoryAccess *To, isl::map Targets) {
134     auto TargetsSpace = Targets.get_space();
135 
136     bool Started = Stmt->isRegionStmt();
137     for (auto *Acc : *Stmt) {
138       if (Acc->isLatestScalarKind())
139         continue;
140 
141       if (Stmt->isBlockStmt() && From == Acc) {
142         assert(!Started);
143         Started = true;
144         continue;
145       }
146       if (Stmt->isBlockStmt() && To == Acc) {
147         assert(Started);
148         return nullptr;
149       }
150       if (!Started)
151         continue;
152 
153       if (!Acc->isWrite())
154         continue;
155 
156       auto AccRel = give(Acc->getAccessRelation());
157       auto AccRelSpace = AccRel.get_space();
158 
159       // Spaces being different means that they access different arrays.
160       if (!TargetsSpace.has_equal_tuples(AccRelSpace))
161         continue;
162 
163       AccRel = AccRel.intersect_domain(give(Acc->getStatement()->getDomain()));
164       AccRel = AccRel.intersect_params(give(S->getContext()));
165       auto CommonElt = Targets.intersect(AccRel);
166       if (!CommonElt.is_empty())
167         return Acc;
168     }
169     assert(Stmt->isRegionStmt() &&
170            "To must be encountered in block statements");
171     return nullptr;
172   }
173 
174   /// Remove writes that are overwritten unconditionally later in the same
175   /// statement.
176   ///
177   /// There must be no read of the same value between the write (that is to be
178   /// removed) and the overwrite.
179   void removeOverwrites() {
180     for (auto &Stmt : *S) {
181       auto Domain = give(Stmt.getDomain());
182       isl::union_map WillBeOverwritten =
183           isl::union_map::empty(give(S->getParamSpace()));
184 
185       SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt));
186 
187       // Iterate in reverse order, so the overwrite comes before the write that
188       // is to be removed.
189       for (auto *MA : reverse(Accesses)) {
190 
191         // In region statements, the explicit accesses can be in blocks that are
192         // can be executed in any order. We therefore process only the implicit
193         // writes and stop after that.
194         if (Stmt.isRegionStmt() && isExplicitAccess(MA))
195           break;
196 
197         auto AccRel = give(MA->getAccessRelation());
198         AccRel = AccRel.intersect_domain(Domain);
199         AccRel = AccRel.intersect_params(give(S->getContext()));
200 
201         // If a value is read in-between, do not consider it as overwritten.
202         if (MA->isRead()) {
203           WillBeOverwritten = WillBeOverwritten.subtract(AccRel);
204           continue;
205         }
206 
207         // If all of a write's elements are overwritten, remove it.
208         isl::union_map AccRelUnion = AccRel;
209         if (AccRelUnion.is_subset(WillBeOverwritten)) {
210           DEBUG(dbgs() << "Removing " << MA
211                        << " which will be overwritten anyway\n");
212 
213           Stmt.removeSingleMemoryAccess(MA);
214           OverwritesRemoved++;
215           TotalOverwritesRemoved++;
216         }
217 
218         // Unconditional writes overwrite other values.
219         if (MA->isMustWrite())
220           WillBeOverwritten = WillBeOverwritten.add_map(AccRel);
221       }
222     }
223   }
224 
225   /// Remove writes that just write the same value already stored in the
226   /// element.
227   void removeRedundantWrites() {
228     // Delay actual removal to not invalidate iterators.
229     SmallVector<MemoryAccess *, 8> StoresToRemove;
230 
231     for (auto &Stmt : *S) {
232       for (auto *WA : Stmt) {
233         if (!WA->isMustWrite())
234           continue;
235         if (!WA->isLatestArrayKind())
236           continue;
237         if (!isa<StoreInst>(WA->getAccessInstruction()))
238           continue;
239 
240         auto ReadingValue = WA->getAccessValue();
241         if (!ReadingValue)
242           continue;
243 
244         auto RA = getReadAccessForValue(&Stmt, ReadingValue);
245         if (!RA)
246           continue;
247         if (!RA->isLatestArrayKind())
248           continue;
249 
250         auto WARel = give(WA->getLatestAccessRelation());
251         WARel = WARel.intersect_domain(give(WA->getStatement()->getDomain()));
252         WARel = WARel.intersect_params(give(S->getContext()));
253         auto RARel = give(RA->getLatestAccessRelation());
254         RARel = RARel.intersect_domain(give(RA->getStatement()->getDomain()));
255         RARel = RARel.intersect_params(give(S->getContext()));
256 
257         if (!RARel.is_equal(WARel)) {
258           PairUnequalAccRels++;
259           DEBUG(dbgs() << "Not cleaning up " << WA
260                        << " because of unequal access relations:\n");
261           DEBUG(dbgs() << "      RA: " << RARel << "\n");
262           DEBUG(dbgs() << "      WA: " << WARel << "\n");
263           continue;
264         }
265 
266         if (auto *Conflicting = hasWriteBetween(&Stmt, RA, WA, WARel)) {
267           (void)Conflicting;
268           InBetweenStore++;
269           DEBUG(dbgs() << "Not cleaning up " << WA
270                        << " because there is another store to the same element "
271                           "between\n");
272           DEBUG(Conflicting->print(dbgs()));
273           continue;
274         }
275 
276         StoresToRemove.push_back(WA);
277       }
278     }
279 
280     for (auto *WA : StoresToRemove) {
281       auto Stmt = WA->getStatement();
282       auto AccRel = give(WA->getAccessRelation());
283       auto AccVal = WA->getAccessValue();
284 
285       DEBUG(dbgs() << "Cleanup of " << WA << ":\n");
286       DEBUG(dbgs() << "      Scalar: " << *AccVal << "\n");
287       DEBUG(dbgs() << "      AccRel: " << AccRel << "\n");
288       (void)AccVal;
289       (void)AccRel;
290 
291       Stmt->removeSingleMemoryAccess(WA);
292 
293       RedundantWritesRemoved++;
294       TotalRedundantWritesRemoved++;
295     }
296   }
297 
298   /// Remove statements without side effects.
299   void removeUnnecessayStmts() {
300     auto NumStmtsBefore = S->getSize();
301     S->simplifySCoP(true);
302     assert(NumStmtsBefore >= S->getSize());
303     StmtsRemoved = NumStmtsBefore - S->getSize();
304     DEBUG(dbgs() << "Removed " << StmtsRemoved << " (of " << NumStmtsBefore
305                  << ") statements\n");
306     TotalStmtsRemoved += StmtsRemoved;
307   }
308 
309   /// Print simplification statistics to @p OS.
310   void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const {
311     OS.indent(Indent) << "Statistics {\n";
312     OS.indent(Indent + 4) << "Overwrites removed: " << OverwritesRemoved
313                           << '\n';
314     OS.indent(Indent + 4) << "Redundant writes removed: "
315                           << RedundantWritesRemoved << "\n";
316     OS.indent(Indent + 4) << "Stmts removed: " << StmtsRemoved << "\n";
317     OS.indent(Indent) << "}\n";
318   }
319 
320   /// Print the current state of all MemoryAccesses to @p OS.
321   void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const {
322     OS.indent(Indent) << "After accesses {\n";
323     for (auto &Stmt : *S) {
324       OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
325       for (auto *MA : Stmt)
326         MA->print(OS);
327     }
328     OS.indent(Indent) << "}\n";
329   }
330 
331 public:
332   static char ID;
333   explicit Simplify() : ScopPass(ID) {}
334 
335   virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
336     AU.addRequiredTransitive<ScopInfoRegionPass>();
337     AU.setPreservesAll();
338   }
339 
340   virtual bool runOnScop(Scop &S) override {
341     // Reset statistics of last processed SCoP.
342     releaseMemory();
343 
344     // Prepare processing of this SCoP.
345     this->S = &S;
346     ScopsProcessed++;
347 
348     DEBUG(dbgs() << "Removing overwrites...\n");
349     removeOverwrites();
350 
351     DEBUG(dbgs() << "Removing redundant writes...\n");
352     removeRedundantWrites();
353 
354     DEBUG(dbgs() << "Removing statements without side effects...\n");
355     removeUnnecessayStmts();
356 
357     if (isModified())
358       ScopsModified++;
359     DEBUG(dbgs() << "\nFinal Scop:\n");
360     DEBUG(S.print(dbgs()));
361 
362     return false;
363   }
364 
365   virtual void printScop(raw_ostream &OS, Scop &S) const override {
366     assert(&S == this->S &&
367            "Can only print analysis for the last processed SCoP");
368     printStatistics(OS);
369 
370     if (!isModified()) {
371       OS << "SCoP could not be simplified\n";
372       return;
373     }
374     printAccesses(OS);
375   }
376 
377   virtual void releaseMemory() override {
378     S = nullptr;
379 
380     OverwritesRemoved = 0;
381     RedundantWritesRemoved = 0;
382     StmtsRemoved = 0;
383   }
384 };
385 
386 char Simplify::ID;
387 } // anonymous namespace
388 
389 Pass *polly::createSimplifyPass() { return new Simplify(); }
390 
391 INITIALIZE_PASS_BEGIN(Simplify, "polly-simplify", "Polly - Simplify", false,
392                       false)
393 INITIALIZE_PASS_END(Simplify, "polly-simplify", "Polly - Simplify", false,
394                     false)
395