10446d81eSMichael Kruse //===------ Simplify.cpp ----------------------------------------*- C++ -*-===//
20446d81eSMichael Kruse //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60446d81eSMichael Kruse //
70446d81eSMichael Kruse //===----------------------------------------------------------------------===//
80446d81eSMichael Kruse //
90446d81eSMichael Kruse // Simplify a SCoP by removing unnecessary statements and accesses.
100446d81eSMichael Kruse //
110446d81eSMichael Kruse //===----------------------------------------------------------------------===//
120446d81eSMichael Kruse
130446d81eSMichael Kruse #include "polly/Simplify.h"
140446d81eSMichael Kruse #include "polly/ScopInfo.h"
150446d81eSMichael Kruse #include "polly/ScopPass.h"
160446d81eSMichael Kruse #include "polly/Support/GICHelper.h"
1733204859STobias Grosser #include "polly/Support/ISLOStream.h"
18ce9617f4SMichael Kruse #include "polly/Support/ISLTools.h"
1922058c3fSMichael Kruse #include "polly/Support/VirtualInstruction.h"
200446d81eSMichael Kruse #include "llvm/ADT/Statistic.h"
2105da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
220446d81eSMichael Kruse #include "llvm/Support/Debug.h"
2323753c60SMichael Kruse
240446d81eSMichael Kruse #define DEBUG_TYPE "polly-simplify"
250446d81eSMichael Kruse
260446d81eSMichael Kruse using namespace llvm;
270446d81eSMichael Kruse using namespace polly;
280446d81eSMichael Kruse
290446d81eSMichael Kruse namespace {
300446d81eSMichael Kruse
3106ed5292SMichael Kruse #define TWO_STATISTICS(VARNAME, DESC) \
3206ed5292SMichael Kruse static llvm::Statistic VARNAME[2] = { \
33126158f0SVolodymyr Sapsai {DEBUG_TYPE, #VARNAME "0", DESC " (first)"}, \
34126158f0SVolodymyr Sapsai {DEBUG_TYPE, #VARNAME "1", DESC " (second)"}}
3506ed5292SMichael Kruse
36693ef999SMichael Kruse /// Number of max disjuncts we allow in removeOverwrites(). This is to avoid
37693ef999SMichael Kruse /// that the analysis of accesses in a statement is becoming too complex. Chosen
38693ef999SMichael Kruse /// to be relatively small because all the common cases should access only few
39693ef999SMichael Kruse /// array elements per statement.
4044596fe6SRiccardo Mori static unsigned const SimplifyMaxDisjuncts = 4;
41693ef999SMichael Kruse
4206ed5292SMichael Kruse TWO_STATISTICS(ScopsProcessed, "Number of SCoPs processed");
4306ed5292SMichael Kruse TWO_STATISTICS(ScopsModified, "Number of SCoPs simplified");
440446d81eSMichael Kruse
456983741eSMichael Kruse TWO_STATISTICS(TotalEmptyDomainsRemoved,
466983741eSMichael Kruse "Number of statement with empty domains removed in any SCoP");
4706ed5292SMichael Kruse TWO_STATISTICS(TotalOverwritesRemoved, "Number of removed overwritten writes");
4806ed5292SMichael Kruse TWO_STATISTICS(TotalWritesCoalesced, "Number of writes coalesced with another");
4906ed5292SMichael Kruse TWO_STATISTICS(TotalRedundantWritesRemoved,
500446d81eSMichael Kruse "Number of writes of same value removed in any SCoP");
5106ed5292SMichael Kruse TWO_STATISTICS(TotalEmptyPartialAccessesRemoved,
52ab8f0d57SMichael Kruse "Number of empty partial accesses removed");
5306ed5292SMichael Kruse TWO_STATISTICS(TotalDeadAccessesRemoved, "Number of dead accesses removed");
5406ed5292SMichael Kruse TWO_STATISTICS(TotalDeadInstructionsRemoved,
5522058c3fSMichael Kruse "Number of unused instructions removed");
5606ed5292SMichael Kruse TWO_STATISTICS(TotalStmtsRemoved, "Number of statements removed in any SCoP");
5706ed5292SMichael Kruse
5806ed5292SMichael Kruse TWO_STATISTICS(NumValueWrites, "Number of scalar value writes after Simplify");
5906ed5292SMichael Kruse TWO_STATISTICS(
6006ed5292SMichael Kruse NumValueWritesInLoops,
6106ed5292SMichael Kruse "Number of scalar value writes nested in affine loops after Simplify");
6206ed5292SMichael Kruse TWO_STATISTICS(NumPHIWrites,
6306ed5292SMichael Kruse "Number of scalar phi writes after the first simplification");
6406ed5292SMichael Kruse TWO_STATISTICS(
6506ed5292SMichael Kruse NumPHIWritesInLoops,
6606ed5292SMichael Kruse "Number of scalar phi writes nested in affine loops after Simplify");
6706ed5292SMichael Kruse TWO_STATISTICS(NumSingletonWrites, "Number of singleton writes after Simplify");
6806ed5292SMichael Kruse TWO_STATISTICS(
6906ed5292SMichael Kruse NumSingletonWritesInLoops,
7006ed5292SMichael Kruse "Number of singleton writes nested in affine loops after Simplify");
710446d81eSMichael Kruse
isImplicitRead(MemoryAccess * MA)72f263610bSMichael Kruse static bool isImplicitRead(MemoryAccess *MA) {
73f263610bSMichael Kruse return MA->isRead() && MA->isOriginalScalarKind();
74f263610bSMichael Kruse }
75f263610bSMichael Kruse
isExplicitAccess(MemoryAccess * MA)76f263610bSMichael Kruse static bool isExplicitAccess(MemoryAccess *MA) {
77f263610bSMichael Kruse return MA->isOriginalArrayKind();
78f263610bSMichael Kruse }
79f263610bSMichael Kruse
isImplicitWrite(MemoryAccess * MA)80f263610bSMichael Kruse static bool isImplicitWrite(MemoryAccess *MA) {
81f263610bSMichael Kruse return MA->isWrite() && MA->isOriginalScalarKind();
82f263610bSMichael Kruse }
83f263610bSMichael Kruse
84d5ee355fSRiccardo Mori /// Like isl::union_map::unite, but may also return an underapproximated
85693ef999SMichael Kruse /// result if getting too complex.
86693ef999SMichael Kruse ///
87693ef999SMichael Kruse /// This is implemented by adding disjuncts to the results until the limit is
88693ef999SMichael Kruse /// reached.
underapproximatedAddMap(isl::union_map UMap,isl::map Map)89693ef999SMichael Kruse static isl::union_map underapproximatedAddMap(isl::union_map UMap,
90693ef999SMichael Kruse isl::map Map) {
91693ef999SMichael Kruse if (UMap.is_null() || Map.is_null())
92693ef999SMichael Kruse return {};
93693ef999SMichael Kruse
94693ef999SMichael Kruse isl::map PrevMap = UMap.extract_map(Map.get_space());
95693ef999SMichael Kruse
96693ef999SMichael Kruse // Fast path: If known that we cannot exceed the disjunct limit, just add
97693ef999SMichael Kruse // them.
9844596fe6SRiccardo Mori if (unsignedFromIslSize(PrevMap.n_basic_map()) +
9944596fe6SRiccardo Mori unsignedFromIslSize(Map.n_basic_map()) <=
100693ef999SMichael Kruse SimplifyMaxDisjuncts)
101d5ee355fSRiccardo Mori return UMap.unite(Map);
102693ef999SMichael Kruse
103693ef999SMichael Kruse isl::map Result = isl::map::empty(PrevMap.get_space());
104a3387168STobias Grosser for (isl::basic_map BMap : PrevMap.get_basic_map_list()) {
10544596fe6SRiccardo Mori if (unsignedFromIslSize(Result.n_basic_map()) > SimplifyMaxDisjuncts)
106a3387168STobias Grosser break;
107693ef999SMichael Kruse Result = Result.unite(BMap);
108a3387168STobias Grosser }
109a3387168STobias Grosser for (isl::basic_map BMap : Map.get_basic_map_list()) {
11044596fe6SRiccardo Mori if (unsignedFromIslSize(Result.n_basic_map()) > SimplifyMaxDisjuncts)
111a3387168STobias Grosser break;
112693ef999SMichael Kruse Result = Result.unite(BMap);
113a3387168STobias Grosser }
114693ef999SMichael Kruse
115693ef999SMichael Kruse isl::union_map UResult =
116693ef999SMichael Kruse UMap.subtract(isl::map::universe(PrevMap.get_space()));
117d5ee355fSRiccardo Mori UResult.unite(Result);
118693ef999SMichael Kruse
119693ef999SMichael Kruse return UResult;
120693ef999SMichael Kruse }
12123753c60SMichael Kruse
122bd93df93SMichael Kruse class SimplifyImpl final {
12323753c60SMichael Kruse private:
12423753c60SMichael Kruse /// The invocation id (if there are multiple instances in the pass manager's
12523753c60SMichael Kruse /// pipeline) to determine which statistics to update.
12623753c60SMichael Kruse int CallNo;
12723753c60SMichael Kruse
12823753c60SMichael Kruse /// The last/current SCoP that is/has been processed.
12923753c60SMichael Kruse Scop *S = nullptr;
13023753c60SMichael Kruse
13123753c60SMichael Kruse /// Number of statements with empty domains removed from the SCoP.
13223753c60SMichael Kruse int EmptyDomainsRemoved = 0;
13323753c60SMichael Kruse
13423753c60SMichael Kruse /// Number of writes that are overwritten anyway.
13523753c60SMichael Kruse int OverwritesRemoved = 0;
13623753c60SMichael Kruse
13723753c60SMichael Kruse /// Number of combined writes.
13823753c60SMichael Kruse int WritesCoalesced = 0;
13923753c60SMichael Kruse
14023753c60SMichael Kruse /// Number of redundant writes removed from this SCoP.
14123753c60SMichael Kruse int RedundantWritesRemoved = 0;
14223753c60SMichael Kruse
14323753c60SMichael Kruse /// Number of writes with empty access domain removed.
14423753c60SMichael Kruse int EmptyPartialAccessesRemoved = 0;
14523753c60SMichael Kruse
14623753c60SMichael Kruse /// Number of unused accesses removed from this SCoP.
14723753c60SMichael Kruse int DeadAccessesRemoved = 0;
14823753c60SMichael Kruse
14923753c60SMichael Kruse /// Number of unused instructions removed from this SCoP.
15023753c60SMichael Kruse int DeadInstructionsRemoved = 0;
15123753c60SMichael Kruse
15223753c60SMichael Kruse /// Number of unnecessary statements removed from the SCoP.
15323753c60SMichael Kruse int StmtsRemoved = 0;
15423753c60SMichael Kruse
15523753c60SMichael Kruse /// Remove statements that are never executed due to their domains being
15623753c60SMichael Kruse /// empty.
15723753c60SMichael Kruse ///
15823753c60SMichael Kruse /// In contrast to Scop::simplifySCoP, this removes based on the SCoP's
15923753c60SMichael Kruse /// effective domain, i.e. including the SCoP's context as used by some other
16023753c60SMichael Kruse /// simplification methods in this pass. This is necessary because the
16123753c60SMichael Kruse /// analysis on empty domains is unreliable, e.g. remove a scalar value
16223753c60SMichael Kruse /// definition MemoryAccesses, but not its use.
16323753c60SMichael Kruse void removeEmptyDomainStmts();
16423753c60SMichael Kruse
16523753c60SMichael Kruse /// Remove writes that are overwritten unconditionally later in the same
16623753c60SMichael Kruse /// statement.
16723753c60SMichael Kruse ///
16823753c60SMichael Kruse /// There must be no read of the same value between the write (that is to be
16923753c60SMichael Kruse /// removed) and the overwrite.
17023753c60SMichael Kruse void removeOverwrites();
17123753c60SMichael Kruse
17223753c60SMichael Kruse /// Combine writes that write the same value if possible.
17323753c60SMichael Kruse ///
17423753c60SMichael Kruse /// This function is able to combine:
17523753c60SMichael Kruse /// - Partial writes with disjoint domain.
17623753c60SMichael Kruse /// - Writes that write to the same array element.
17723753c60SMichael Kruse ///
17823753c60SMichael Kruse /// In all cases, both writes must write the same values.
17923753c60SMichael Kruse void coalesceWrites();
18023753c60SMichael Kruse
18123753c60SMichael Kruse /// Remove writes that just write the same value already stored in the
18223753c60SMichael Kruse /// element.
18323753c60SMichael Kruse void removeRedundantWrites();
18423753c60SMichael Kruse
18523753c60SMichael Kruse /// Remove statements without side effects.
18623753c60SMichael Kruse void removeUnnecessaryStmts();
18723753c60SMichael Kruse
18823753c60SMichael Kruse /// Remove accesses that have an empty domain.
18923753c60SMichael Kruse void removeEmptyPartialAccesses();
19023753c60SMichael Kruse
19123753c60SMichael Kruse /// Mark all reachable instructions and access, and sweep those that are not
19223753c60SMichael Kruse /// reachable.
19323753c60SMichael Kruse void markAndSweep(LoopInfo *LI);
19423753c60SMichael Kruse
19523753c60SMichael Kruse /// Print simplification statistics to @p OS.
19623753c60SMichael Kruse void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const;
19723753c60SMichael Kruse
19823753c60SMichael Kruse /// Print the current state of all MemoryAccesses to @p OS.
19923753c60SMichael Kruse void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const;
20023753c60SMichael Kruse
20123753c60SMichael Kruse public:
SimplifyImpl(int CallNo=0)20223753c60SMichael Kruse explicit SimplifyImpl(int CallNo = 0) : CallNo(CallNo) {}
20323753c60SMichael Kruse
20423753c60SMichael Kruse void run(Scop &S, LoopInfo *LI);
20523753c60SMichael Kruse
20623753c60SMichael Kruse void printScop(raw_ostream &OS, Scop &S) const;
207693ef999SMichael Kruse
2080446d81eSMichael Kruse /// Return whether at least one simplification has been applied.
20923753c60SMichael Kruse bool isModified() const;
21023753c60SMichael Kruse };
21123753c60SMichael Kruse
21223753c60SMichael Kruse /// Return whether at least one simplification has been applied.
isModified() const21323753c60SMichael Kruse bool SimplifyImpl::isModified() const {
2146983741eSMichael Kruse return EmptyDomainsRemoved > 0 || OverwritesRemoved > 0 ||
2156983741eSMichael Kruse WritesCoalesced > 0 || RedundantWritesRemoved > 0 ||
2166983741eSMichael Kruse EmptyPartialAccessesRemoved > 0 || DeadAccessesRemoved > 0 ||
2176983741eSMichael Kruse DeadInstructionsRemoved > 0 || StmtsRemoved > 0;
2186983741eSMichael Kruse }
2196983741eSMichael Kruse
2206983741eSMichael Kruse /// Remove statements that are never executed due to their domains being
2216983741eSMichael Kruse /// empty.
2226983741eSMichael Kruse ///
2236983741eSMichael Kruse /// In contrast to Scop::simplifySCoP, this removes based on the SCoP's
2246983741eSMichael Kruse /// effective domain, i.e. including the SCoP's context as used by some other
2256983741eSMichael Kruse /// simplification methods in this pass. This is necessary because the
2266983741eSMichael Kruse /// analysis on empty domains is unreliable, e.g. remove a scalar value
2276983741eSMichael Kruse /// definition MemoryAccesses, but not its use.
removeEmptyDomainStmts()22823753c60SMichael Kruse void SimplifyImpl::removeEmptyDomainStmts() {
2296983741eSMichael Kruse size_t NumStmtsBefore = S->getSize();
2306983741eSMichael Kruse
2316538fff3SMichael Kruse S->removeStmts([](ScopStmt &Stmt) -> bool {
2326983741eSMichael Kruse auto EffectiveDomain =
2336983741eSMichael Kruse Stmt.getDomain().intersect_params(Stmt.getParent()->getContext());
2346983741eSMichael Kruse return EffectiveDomain.is_empty();
2356538fff3SMichael Kruse });
2366983741eSMichael Kruse
2376983741eSMichael Kruse assert(NumStmtsBefore >= S->getSize());
2386983741eSMichael Kruse EmptyDomainsRemoved = NumStmtsBefore - S->getSize();
2396983741eSMichael Kruse LLVM_DEBUG(dbgs() << "Removed " << EmptyDomainsRemoved << " (of "
240deb00cf0SPengxuan Zheng << NumStmtsBefore << ") statements with empty domains \n");
2416983741eSMichael Kruse TotalEmptyDomainsRemoved[CallNo] += EmptyDomainsRemoved;
2420446d81eSMichael Kruse }
2430446d81eSMichael Kruse
244f263610bSMichael Kruse /// Remove writes that are overwritten unconditionally later in the same
245f263610bSMichael Kruse /// statement.
246f263610bSMichael Kruse ///
247f263610bSMichael Kruse /// There must be no read of the same value between the write (that is to be
248f263610bSMichael Kruse /// removed) and the overwrite.
removeOverwrites()24923753c60SMichael Kruse void SimplifyImpl::removeOverwrites() {
250f263610bSMichael Kruse for (auto &Stmt : *S) {
251dcf8d696STobias Grosser isl::set Domain = Stmt.getDomain();
252bad3ebbaSRiccardo Mori isl::union_map WillBeOverwritten = isl::union_map::empty(S->getIslCtx());
253f263610bSMichael Kruse
2549746f817SSiddharth Bhat SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt));
255f263610bSMichael Kruse
256f263610bSMichael Kruse // Iterate in reverse order, so the overwrite comes before the write that
257f263610bSMichael Kruse // is to be removed.
258f263610bSMichael Kruse for (auto *MA : reverse(Accesses)) {
259f263610bSMichael Kruse
260f263610bSMichael Kruse // In region statements, the explicit accesses can be in blocks that are
261f263610bSMichael Kruse // can be executed in any order. We therefore process only the implicit
262f263610bSMichael Kruse // writes and stop after that.
263f263610bSMichael Kruse if (Stmt.isRegionStmt() && isExplicitAccess(MA))
264f263610bSMichael Kruse break;
265f263610bSMichael Kruse
2661515f6b9STobias Grosser auto AccRel = MA->getAccessRelation();
267f263610bSMichael Kruse AccRel = AccRel.intersect_domain(Domain);
268b65ccc43STobias Grosser AccRel = AccRel.intersect_params(S->getContext());
269f263610bSMichael Kruse
270f263610bSMichael Kruse // If a value is read in-between, do not consider it as overwritten.
271f263610bSMichael Kruse if (MA->isRead()) {
272693ef999SMichael Kruse // Invalidate all overwrites for the array it accesses to avoid too
273693ef999SMichael Kruse // complex isl sets.
274693ef999SMichael Kruse isl::map AccRelUniv = isl::map::universe(AccRel.get_space());
275693ef999SMichael Kruse WillBeOverwritten = WillBeOverwritten.subtract(AccRelUniv);
276f263610bSMichael Kruse continue;
277f263610bSMichael Kruse }
278f263610bSMichael Kruse
279f263610bSMichael Kruse // If all of a write's elements are overwritten, remove it.
280f263610bSMichael Kruse isl::union_map AccRelUnion = AccRel;
281b5f61bdeSTobias Grosser if (AccRelUnion.is_subset(WillBeOverwritten)) {
282349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removing " << MA
283f263610bSMichael Kruse << " which will be overwritten anyway\n");
284f263610bSMichael Kruse
285f263610bSMichael Kruse Stmt.removeSingleMemoryAccess(MA);
286f263610bSMichael Kruse OverwritesRemoved++;
28706ed5292SMichael Kruse TotalOverwritesRemoved[CallNo]++;
288f263610bSMichael Kruse }
289f263610bSMichael Kruse
290f263610bSMichael Kruse // Unconditional writes overwrite other values.
291693ef999SMichael Kruse if (MA->isMustWrite()) {
292693ef999SMichael Kruse // Avoid too complex isl sets. If necessary, throw away some of the
293693ef999SMichael Kruse // knowledge.
294deb00cf0SPengxuan Zheng WillBeOverwritten = underapproximatedAddMap(WillBeOverwritten, AccRel);
295693ef999SMichael Kruse }
296f263610bSMichael Kruse }
297f263610bSMichael Kruse }
298f263610bSMichael Kruse }
299f263610bSMichael Kruse
300ce9617f4SMichael Kruse /// Combine writes that write the same value if possible.
301ce9617f4SMichael Kruse ///
302ce9617f4SMichael Kruse /// This function is able to combine:
303ce9617f4SMichael Kruse /// - Partial writes with disjoint domain.
304ce9617f4SMichael Kruse /// - Writes that write to the same array element.
305ce9617f4SMichael Kruse ///
306ce9617f4SMichael Kruse /// In all cases, both writes must write the same values.
coalesceWrites()30723753c60SMichael Kruse void SimplifyImpl::coalesceWrites() {
308ce9617f4SMichael Kruse for (auto &Stmt : *S) {
309b65ccc43STobias Grosser isl::set Domain = Stmt.getDomain().intersect_params(S->getContext());
310ce9617f4SMichael Kruse
311ce9617f4SMichael Kruse // We let isl do the lookup for the same-value condition. For this, we
312ce9617f4SMichael Kruse // wrap llvm::Value into an isl::set such that isl can do the lookup in
313ce9617f4SMichael Kruse // its hashtable implementation. llvm::Values are only compared within a
314ce9617f4SMichael Kruse // ScopStmt, so the map can be local to this scope. TODO: Refactor with
315ce9617f4SMichael Kruse // ZoneAlgorithm::makeValueSet()
316ce9617f4SMichael Kruse SmallDenseMap<Value *, isl::set> ValueSets;
317ce9617f4SMichael Kruse auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set {
318ce9617f4SMichael Kruse assert(V);
319ce9617f4SMichael Kruse isl::set &Result = ValueSets[V];
320ce9617f4SMichael Kruse if (Result.is_null()) {
32100fd43b3SPhilip Pfaffe isl::ctx Ctx = S->getIslCtx();
322deb00cf0SPengxuan Zheng std::string Name = getIslCompatibleName(
323deb00cf0SPengxuan Zheng "Val", V, ValueSets.size() - 1, std::string(), UseInstructionNames);
32400fd43b3SPhilip Pfaffe isl::id Id = isl::id::alloc(Ctx, Name, V);
325ce9617f4SMichael Kruse Result = isl::set::universe(
326ce9617f4SMichael Kruse isl::space(Ctx, 0, 0).set_tuple_id(isl::dim::set, Id));
327ce9617f4SMichael Kruse }
328ce9617f4SMichael Kruse return Result;
329ce9617f4SMichael Kruse };
330ce9617f4SMichael Kruse
331ce9617f4SMichael Kruse // List of all eligible (for coalescing) writes of the future.
332ce9617f4SMichael Kruse // { [Domain[] -> Element[]] -> [Value[] -> MemoryAccess[]] }
333bad3ebbaSRiccardo Mori isl::union_map FutureWrites = isl::union_map::empty(S->getIslCtx());
334ce9617f4SMichael Kruse
335ce9617f4SMichael Kruse // Iterate over accesses from the last to the first.
336ce9617f4SMichael Kruse SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt));
337ce9617f4SMichael Kruse for (MemoryAccess *MA : reverse(Accesses)) {
338ce9617f4SMichael Kruse // In region statements, the explicit accesses can be in blocks that can
339ce9617f4SMichael Kruse // be executed in any order. We therefore process only the implicit
340ce9617f4SMichael Kruse // writes and stop after that.
341ce9617f4SMichael Kruse if (Stmt.isRegionStmt() && isExplicitAccess(MA))
342ce9617f4SMichael Kruse break;
343ce9617f4SMichael Kruse
344ce9617f4SMichael Kruse // { Domain[] -> Element[] }
345deb00cf0SPengxuan Zheng isl::map AccRel = MA->getLatestAccessRelation().intersect_domain(Domain);
346ce9617f4SMichael Kruse
347ce9617f4SMichael Kruse // { [Domain[] -> Element[]] }
348ce9617f4SMichael Kruse isl::set AccRelWrapped = AccRel.wrap();
349ce9617f4SMichael Kruse
350ce9617f4SMichael Kruse // { Value[] }
351ce9617f4SMichael Kruse isl::set ValSet;
352ce9617f4SMichael Kruse
353ce9617f4SMichael Kruse if (MA->isMustWrite() && (MA->isOriginalScalarKind() ||
354ce9617f4SMichael Kruse isa<StoreInst>(MA->getAccessInstruction()))) {
355ce9617f4SMichael Kruse // Normally, tryGetValueStored() should be used to determine which
356ce9617f4SMichael Kruse // element is written, but it can return nullptr; For PHI accesses,
357ce9617f4SMichael Kruse // getAccessValue() returns the PHI instead of the PHI's incoming
358ce9617f4SMichael Kruse // value. In this case, where we only compare values of a single
359ce9617f4SMichael Kruse // statement, this is fine, because within a statement, a PHI in a
360ce9617f4SMichael Kruse // successor block has always the same value as the incoming write. We
361ce9617f4SMichael Kruse // still preferably use the incoming value directly so we also catch
362ce9617f4SMichael Kruse // direct uses of that.
363ce9617f4SMichael Kruse Value *StoredVal = MA->tryGetValueStored();
364ce9617f4SMichael Kruse if (!StoredVal)
365ce9617f4SMichael Kruse StoredVal = MA->getAccessValue();
366ce9617f4SMichael Kruse ValSet = makeValueSet(StoredVal);
367ce9617f4SMichael Kruse
368ce9617f4SMichael Kruse // { Domain[] }
369ce9617f4SMichael Kruse isl::set AccDomain = AccRel.domain();
370ce9617f4SMichael Kruse
371ce9617f4SMichael Kruse // Parts of the statement's domain that is not written by this access.
372ce9617f4SMichael Kruse isl::set UndefDomain = Domain.subtract(AccDomain);
373ce9617f4SMichael Kruse
374ce9617f4SMichael Kruse // { Element[] }
375ce9617f4SMichael Kruse isl::set ElementUniverse =
376ce9617f4SMichael Kruse isl::set::universe(AccRel.get_space().range());
377ce9617f4SMichael Kruse
378ce9617f4SMichael Kruse // { Domain[] -> Element[] }
379ce9617f4SMichael Kruse isl::map UndefAnything =
380ce9617f4SMichael Kruse isl::map::from_domain_and_range(UndefDomain, ElementUniverse);
381ce9617f4SMichael Kruse
382ce9617f4SMichael Kruse // We are looking a compatible write access. The other write can
383ce9617f4SMichael Kruse // access these elements...
384ce9617f4SMichael Kruse isl::map AllowedAccesses = AccRel.unite(UndefAnything);
385ce9617f4SMichael Kruse
386ce9617f4SMichael Kruse // ... and must write the same value.
387ce9617f4SMichael Kruse // { [Domain[] -> Element[]] -> Value[] }
388ce9617f4SMichael Kruse isl::map Filter =
389ce9617f4SMichael Kruse isl::map::from_domain_and_range(AllowedAccesses.wrap(), ValSet);
390ce9617f4SMichael Kruse
391ce9617f4SMichael Kruse // Lookup future write that fulfills these conditions.
392ce9617f4SMichael Kruse // { [[Domain[] -> Element[]] -> Value[]] -> MemoryAccess[] }
393ce9617f4SMichael Kruse isl::union_map Filtered =
394ce9617f4SMichael Kruse FutureWrites.uncurry().intersect_domain(Filter.wrap());
395ce9617f4SMichael Kruse
396ce9617f4SMichael Kruse // Iterate through the candidates.
397a3387168STobias Grosser for (isl::map Map : Filtered.get_map_list()) {
398ce9617f4SMichael Kruse MemoryAccess *OtherMA = (MemoryAccess *)Map.get_space()
399ce9617f4SMichael Kruse .get_tuple_id(isl::dim::out)
400ce9617f4SMichael Kruse .get_user();
401ce9617f4SMichael Kruse
402ce9617f4SMichael Kruse isl::map OtherAccRel =
403ce9617f4SMichael Kruse OtherMA->getLatestAccessRelation().intersect_domain(Domain);
404ce9617f4SMichael Kruse
405ce9617f4SMichael Kruse // The filter only guaranteed that some of OtherMA's accessed
406ce9617f4SMichael Kruse // elements are allowed. Verify that it only accesses allowed
407ce9617f4SMichael Kruse // elements. Otherwise, continue with the next candidate.
408ce9617f4SMichael Kruse if (!OtherAccRel.is_subset(AllowedAccesses).is_true())
409a3387168STobias Grosser continue;
410ce9617f4SMichael Kruse
411ce9617f4SMichael Kruse // The combined access relation.
412ce9617f4SMichael Kruse // { Domain[] -> Element[] }
413ce9617f4SMichael Kruse isl::map NewAccRel = AccRel.unite(OtherAccRel);
414ce9617f4SMichael Kruse simplify(NewAccRel);
415ce9617f4SMichael Kruse
416ce9617f4SMichael Kruse // Carry out the coalescing.
417ce9617f4SMichael Kruse Stmt.removeSingleMemoryAccess(MA);
4187b45af13STobias Grosser OtherMA->setNewAccessRelation(NewAccRel);
419ce9617f4SMichael Kruse
420ce9617f4SMichael Kruse // We removed MA, OtherMA takes its role.
421ce9617f4SMichael Kruse MA = OtherMA;
422ce9617f4SMichael Kruse
42306ed5292SMichael Kruse TotalWritesCoalesced[CallNo]++;
424ce9617f4SMichael Kruse WritesCoalesced++;
425ce9617f4SMichael Kruse
426ce9617f4SMichael Kruse // Don't look for more candidates.
427a3387168STobias Grosser break;
428a3387168STobias Grosser }
429ce9617f4SMichael Kruse }
430ce9617f4SMichael Kruse
431ce9617f4SMichael Kruse // Two writes cannot be coalesced if there is another access (to some of
432ce9617f4SMichael Kruse // the written elements) between them. Remove all visited write accesses
433ce9617f4SMichael Kruse // from the list of eligible writes. Don't just remove the accessed
434ce9617f4SMichael Kruse // elements, but any MemoryAccess that touches any of the invalidated
435ce9617f4SMichael Kruse // elements.
436693ef999SMichael Kruse SmallPtrSet<MemoryAccess *, 2> TouchedAccesses;
437a3387168STobias Grosser for (isl::map Map :
438a3387168STobias Grosser FutureWrites.intersect_domain(AccRelWrapped).get_map_list()) {
439693ef999SMichael Kruse MemoryAccess *MA = (MemoryAccess *)Map.get_space()
440ce9617f4SMichael Kruse .range()
441ce9617f4SMichael Kruse .unwrap()
442693ef999SMichael Kruse .get_tuple_id(isl::dim::out)
443693ef999SMichael Kruse .get_user();
444693ef999SMichael Kruse TouchedAccesses.insert(MA);
445a3387168STobias Grosser }
446693ef999SMichael Kruse isl::union_map NewFutureWrites =
447bad3ebbaSRiccardo Mori isl::union_map::empty(FutureWrites.ctx());
448a3387168STobias Grosser for (isl::map FutureWrite : FutureWrites.get_map_list()) {
449693ef999SMichael Kruse MemoryAccess *MA = (MemoryAccess *)FutureWrite.get_space()
450693ef999SMichael Kruse .range()
451693ef999SMichael Kruse .unwrap()
452693ef999SMichael Kruse .get_tuple_id(isl::dim::out)
453693ef999SMichael Kruse .get_user();
454693ef999SMichael Kruse if (!TouchedAccesses.count(MA))
455d5ee355fSRiccardo Mori NewFutureWrites = NewFutureWrites.unite(FutureWrite);
456a3387168STobias Grosser }
457693ef999SMichael Kruse FutureWrites = NewFutureWrites;
458ce9617f4SMichael Kruse
459ce9617f4SMichael Kruse if (MA->isMustWrite() && !ValSet.is_null()) {
460ce9617f4SMichael Kruse // { MemoryAccess[] }
461ce9617f4SMichael Kruse auto AccSet =
462ce9617f4SMichael Kruse isl::set::universe(isl::space(S->getIslCtx(), 0, 0)
463ce9617f4SMichael Kruse .set_tuple_id(isl::dim::set, MA->getId()));
464ce9617f4SMichael Kruse
465ce9617f4SMichael Kruse // { Val[] -> MemoryAccess[] }
466ce9617f4SMichael Kruse isl::map ValAccSet = isl::map::from_domain_and_range(ValSet, AccSet);
467ce9617f4SMichael Kruse
468ce9617f4SMichael Kruse // { [Domain[] -> Element[]] -> [Value[] -> MemoryAccess[]] }
469ce9617f4SMichael Kruse isl::map AccRelValAcc =
470ce9617f4SMichael Kruse isl::map::from_domain_and_range(AccRelWrapped, ValAccSet.wrap());
471d5ee355fSRiccardo Mori FutureWrites = FutureWrites.unite(AccRelValAcc);
472ce9617f4SMichael Kruse }
473ce9617f4SMichael Kruse }
474ce9617f4SMichael Kruse }
475ce9617f4SMichael Kruse }
476ce9617f4SMichael Kruse
4770446d81eSMichael Kruse /// Remove writes that just write the same value already stored in the
4780446d81eSMichael Kruse /// element.
removeRedundantWrites()47923753c60SMichael Kruse void SimplifyImpl::removeRedundantWrites() {
4800446d81eSMichael Kruse for (auto &Stmt : *S) {
481bc88a78cSMichael Kruse SmallDenseMap<Value *, isl::set> ValueSets;
482bc88a78cSMichael Kruse auto makeValueSet = [&ValueSets, this](Value *V) -> isl::set {
483bc88a78cSMichael Kruse assert(V);
484bc88a78cSMichael Kruse isl::set &Result = ValueSets[V];
485bc88a78cSMichael Kruse if (Result.is_null()) {
48600fd43b3SPhilip Pfaffe isl_ctx *Ctx = S->getIslCtx().get();
487deb00cf0SPengxuan Zheng std::string Name = getIslCompatibleName(
488deb00cf0SPengxuan Zheng "Val", V, ValueSets.size() - 1, std::string(), UseInstructionNames);
489da3e8c4bSTobias Grosser isl::id Id = isl::manage(isl_id_alloc(Ctx, Name.c_str(), V));
490bc88a78cSMichael Kruse Result = isl::set::universe(
491bc88a78cSMichael Kruse isl::space(Ctx, 0, 0).set_tuple_id(isl::dim::set, Id));
4920446d81eSMichael Kruse }
493bc88a78cSMichael Kruse return Result;
494bc88a78cSMichael Kruse };
4950446d81eSMichael Kruse
496dcf8d696STobias Grosser isl::set Domain = Stmt.getDomain();
497b65ccc43STobias Grosser Domain = Domain.intersect_params(S->getContext());
4980446d81eSMichael Kruse
499bc88a78cSMichael Kruse // List of element reads that still have the same value while iterating
500bc88a78cSMichael Kruse // through the MemoryAccesses.
501bc88a78cSMichael Kruse // { [Domain[] -> Element[]] -> Val[] }
502bad3ebbaSRiccardo Mori isl::union_map Known = isl::union_map::empty(S->getIslCtx());
5030446d81eSMichael Kruse
504bc88a78cSMichael Kruse SmallVector<MemoryAccess *, 32> Accesses(getAccessesInOrder(Stmt));
505bc88a78cSMichael Kruse for (MemoryAccess *MA : Accesses) {
506bc88a78cSMichael Kruse // Is the memory access in a defined order relative to the other
507bc88a78cSMichael Kruse // accesses? In region statements, only the first and the last accesses
508bc88a78cSMichael Kruse // have defined order. Execution of those in the middle may depend on
509bc88a78cSMichael Kruse // runtime conditions an therefore cannot be modified.
510bc88a78cSMichael Kruse bool IsOrdered =
511bc88a78cSMichael Kruse Stmt.isBlockStmt() || MA->isOriginalScalarKind() ||
512bc88a78cSMichael Kruse (!S->getBoxedLoops().size() && MA->getAccessInstruction() &&
513bc88a78cSMichael Kruse Stmt.getEntryBlock() == MA->getAccessInstruction()->getParent());
5140446d81eSMichael Kruse
515bc88a78cSMichael Kruse isl::map AccRel = MA->getAccessRelation();
516bc88a78cSMichael Kruse AccRel = AccRel.intersect_domain(Domain);
517bc88a78cSMichael Kruse isl::set AccRelWrapped = AccRel.wrap();
518bc88a78cSMichael Kruse
519bc88a78cSMichael Kruse // Determine whether a write is redundant (stores only values that are
520bc88a78cSMichael Kruse // already present in the written array elements) and remove it if this
521bc88a78cSMichael Kruse // is the case.
522bc88a78cSMichael Kruse if (IsOrdered && MA->isMustWrite() &&
523bc88a78cSMichael Kruse (isa<StoreInst>(MA->getAccessInstruction()) ||
524bc88a78cSMichael Kruse MA->isOriginalScalarKind())) {
525bc88a78cSMichael Kruse Value *StoredVal = MA->tryGetValueStored();
526bc88a78cSMichael Kruse if (!StoredVal)
527bc88a78cSMichael Kruse StoredVal = MA->getAccessValue();
528bc88a78cSMichael Kruse
529bc88a78cSMichael Kruse if (StoredVal) {
530bc88a78cSMichael Kruse // Lookup in the set of known values.
531bc88a78cSMichael Kruse isl::map AccRelStoredVal = isl::map::from_domain_and_range(
532bc88a78cSMichael Kruse AccRelWrapped, makeValueSet(StoredVal));
533bc88a78cSMichael Kruse if (isl::union_map(AccRelStoredVal).is_subset(Known)) {
534349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Cleanup of " << MA << ":\n");
535349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << " Scalar: " << *StoredVal << "\n");
536349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << " AccRel: " << AccRel << "\n");
5370446d81eSMichael Kruse
538bc88a78cSMichael Kruse Stmt.removeSingleMemoryAccess(MA);
5390446d81eSMichael Kruse
5400446d81eSMichael Kruse RedundantWritesRemoved++;
54106ed5292SMichael Kruse TotalRedundantWritesRemoved[CallNo]++;
5420446d81eSMichael Kruse }
5430446d81eSMichael Kruse }
544bc88a78cSMichael Kruse }
545bc88a78cSMichael Kruse
546bc88a78cSMichael Kruse // Update the know values set.
547bc88a78cSMichael Kruse if (MA->isRead()) {
548bc88a78cSMichael Kruse // Loaded values are the currently known values of the array element
549bc88a78cSMichael Kruse // it was loaded from.
550bc88a78cSMichael Kruse Value *LoadedVal = MA->getAccessValue();
551bc88a78cSMichael Kruse if (LoadedVal && IsOrdered) {
552bc88a78cSMichael Kruse isl::map AccRelVal = isl::map::from_domain_and_range(
553bc88a78cSMichael Kruse AccRelWrapped, makeValueSet(LoadedVal));
554bc88a78cSMichael Kruse
555d5ee355fSRiccardo Mori Known = Known.unite(AccRelVal);
556bc88a78cSMichael Kruse }
557bc88a78cSMichael Kruse } else if (MA->isWrite()) {
558bc88a78cSMichael Kruse // Remove (possibly) overwritten values from the known elements set.
559bc88a78cSMichael Kruse // We remove all elements of the accessed array to avoid too complex
560bc88a78cSMichael Kruse // isl sets.
561bc88a78cSMichael Kruse isl::set AccRelUniv = isl::set::universe(AccRelWrapped.get_space());
562bc88a78cSMichael Kruse Known = Known.subtract_domain(AccRelUniv);
563bc88a78cSMichael Kruse
564bc88a78cSMichael Kruse // At this point, we could add the written value of must-writes.
565bc88a78cSMichael Kruse // However, writing same values is already handled by
566bc88a78cSMichael Kruse // coalesceWrites().
567bc88a78cSMichael Kruse }
568bc88a78cSMichael Kruse }
569bc88a78cSMichael Kruse }
570bc88a78cSMichael Kruse }
5710446d81eSMichael Kruse
5720446d81eSMichael Kruse /// Remove statements without side effects.
removeUnnecessaryStmts()57323753c60SMichael Kruse void SimplifyImpl::removeUnnecessaryStmts() {
5740446d81eSMichael Kruse auto NumStmtsBefore = S->getSize();
5750446d81eSMichael Kruse S->simplifySCoP(true);
5760446d81eSMichael Kruse assert(NumStmtsBefore >= S->getSize());
5770446d81eSMichael Kruse StmtsRemoved = NumStmtsBefore - S->getSize();
578349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removed " << StmtsRemoved << " (of " << NumStmtsBefore
5790446d81eSMichael Kruse << ") statements\n");
58006ed5292SMichael Kruse TotalStmtsRemoved[CallNo] += StmtsRemoved;
5810446d81eSMichael Kruse }
5820446d81eSMichael Kruse
583ab8f0d57SMichael Kruse /// Remove accesses that have an empty domain.
removeEmptyPartialAccesses()58423753c60SMichael Kruse void SimplifyImpl::removeEmptyPartialAccesses() {
585ab8f0d57SMichael Kruse for (ScopStmt &Stmt : *S) {
586ab8f0d57SMichael Kruse // Defer the actual removal to not invalidate iterators.
587ab8f0d57SMichael Kruse SmallVector<MemoryAccess *, 8> DeferredRemove;
588ab8f0d57SMichael Kruse
589ab8f0d57SMichael Kruse for (MemoryAccess *MA : Stmt) {
590ab8f0d57SMichael Kruse if (!MA->isWrite())
591ab8f0d57SMichael Kruse continue;
592ab8f0d57SMichael Kruse
593325812acSTobias Grosser isl::map AccRel = MA->getAccessRelation();
594ab8f0d57SMichael Kruse if (!AccRel.is_empty().is_true())
595ab8f0d57SMichael Kruse continue;
596ab8f0d57SMichael Kruse
597349506a9SNicola Zaghen LLVM_DEBUG(
598349506a9SNicola Zaghen dbgs() << "Removing " << MA
599ab8f0d57SMichael Kruse << " because it's a partial access that never occurs\n");
600ab8f0d57SMichael Kruse DeferredRemove.push_back(MA);
601ab8f0d57SMichael Kruse }
602ab8f0d57SMichael Kruse
603ab8f0d57SMichael Kruse for (MemoryAccess *MA : DeferredRemove) {
604ab8f0d57SMichael Kruse Stmt.removeSingleMemoryAccess(MA);
605ab8f0d57SMichael Kruse EmptyPartialAccessesRemoved++;
60606ed5292SMichael Kruse TotalEmptyPartialAccessesRemoved[CallNo]++;
607ab8f0d57SMichael Kruse }
608ab8f0d57SMichael Kruse }
609ab8f0d57SMichael Kruse }
610ab8f0d57SMichael Kruse
61122058c3fSMichael Kruse /// Mark all reachable instructions and access, and sweep those that are not
61222058c3fSMichael Kruse /// reachable.
markAndSweep(LoopInfo * LI)61323753c60SMichael Kruse void SimplifyImpl::markAndSweep(LoopInfo *LI) {
61422058c3fSMichael Kruse DenseSet<MemoryAccess *> UsedMA;
61522058c3fSMichael Kruse DenseSet<VirtualInstruction> UsedInsts;
61622058c3fSMichael Kruse
61722058c3fSMichael Kruse // Get all reachable instructions and accesses.
61822058c3fSMichael Kruse markReachable(S, LI, UsedInsts, UsedMA);
61922058c3fSMichael Kruse
62022058c3fSMichael Kruse // Remove all non-reachable accesses.
62122058c3fSMichael Kruse // We need get all MemoryAccesses first, in order to not invalidate the
62222058c3fSMichael Kruse // iterators when removing them.
62322058c3fSMichael Kruse SmallVector<MemoryAccess *, 64> AllMAs;
62422058c3fSMichael Kruse for (ScopStmt &Stmt : *S)
62522058c3fSMichael Kruse AllMAs.append(Stmt.begin(), Stmt.end());
62622058c3fSMichael Kruse
62722058c3fSMichael Kruse for (MemoryAccess *MA : AllMAs) {
62822058c3fSMichael Kruse if (UsedMA.count(MA))
62922058c3fSMichael Kruse continue;
630349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removing " << MA
631349506a9SNicola Zaghen << " because its value is not used\n");
63222058c3fSMichael Kruse ScopStmt *Stmt = MA->getStatement();
63322058c3fSMichael Kruse Stmt->removeSingleMemoryAccess(MA);
63422058c3fSMichael Kruse
63522058c3fSMichael Kruse DeadAccessesRemoved++;
63606ed5292SMichael Kruse TotalDeadAccessesRemoved[CallNo]++;
63722058c3fSMichael Kruse }
63822058c3fSMichael Kruse
63922058c3fSMichael Kruse // Remove all non-reachable instructions.
64022058c3fSMichael Kruse for (ScopStmt &Stmt : *S) {
641420c4863SMichael Kruse // Note that for region statements, we can only remove the non-terminator
642420c4863SMichael Kruse // instructions of the entry block. All other instructions are not in the
643420c4863SMichael Kruse // instructions list, but implicitly always part of the statement.
644cedd7a74SMichael Kruse
64522058c3fSMichael Kruse SmallVector<Instruction *, 32> AllInsts(Stmt.insts_begin(),
64622058c3fSMichael Kruse Stmt.insts_end());
64722058c3fSMichael Kruse SmallVector<Instruction *, 32> RemainInsts;
64822058c3fSMichael Kruse
64922058c3fSMichael Kruse for (Instruction *Inst : AllInsts) {
65022058c3fSMichael Kruse auto It = UsedInsts.find({&Stmt, Inst});
65122058c3fSMichael Kruse if (It == UsedInsts.end()) {
652349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removing "; Inst->print(dbgs());
65322058c3fSMichael Kruse dbgs() << " because it is not used\n");
65422058c3fSMichael Kruse DeadInstructionsRemoved++;
65506ed5292SMichael Kruse TotalDeadInstructionsRemoved[CallNo]++;
65622058c3fSMichael Kruse continue;
65722058c3fSMichael Kruse }
65822058c3fSMichael Kruse
65922058c3fSMichael Kruse RemainInsts.push_back(Inst);
66022058c3fSMichael Kruse
66122058c3fSMichael Kruse // If instructions appear multiple times, keep only the first.
66222058c3fSMichael Kruse UsedInsts.erase(It);
66322058c3fSMichael Kruse }
66422058c3fSMichael Kruse
66522058c3fSMichael Kruse // Set the new instruction list to be only those we did not remove.
66622058c3fSMichael Kruse Stmt.setInstructions(RemainInsts);
66722058c3fSMichael Kruse }
66822058c3fSMichael Kruse }
66922058c3fSMichael Kruse
6700446d81eSMichael Kruse /// Print simplification statistics to @p OS.
printStatistics(llvm::raw_ostream & OS,int Indent) const67123753c60SMichael Kruse void SimplifyImpl::printStatistics(llvm::raw_ostream &OS, int Indent) const {
6720446d81eSMichael Kruse OS.indent(Indent) << "Statistics {\n";
6736983741eSMichael Kruse OS.indent(Indent + 4) << "Empty domains removed: " << EmptyDomainsRemoved
6746983741eSMichael Kruse << '\n';
675deb00cf0SPengxuan Zheng OS.indent(Indent + 4) << "Overwrites removed: " << OverwritesRemoved << '\n';
676ce9617f4SMichael Kruse OS.indent(Indent + 4) << "Partial writes coalesced: " << WritesCoalesced
677ce9617f4SMichael Kruse << "\n";
6780446d81eSMichael Kruse OS.indent(Indent + 4) << "Redundant writes removed: "
6790446d81eSMichael Kruse << RedundantWritesRemoved << "\n";
6806c8f91b9SMichael Kruse OS.indent(Indent + 4) << "Accesses with empty domains removed: "
681ab8f0d57SMichael Kruse << EmptyPartialAccessesRemoved << "\n";
68222058c3fSMichael Kruse OS.indent(Indent + 4) << "Dead accesses removed: " << DeadAccessesRemoved
68322058c3fSMichael Kruse << '\n';
68422058c3fSMichael Kruse OS.indent(Indent + 4) << "Dead instructions removed: "
68522058c3fSMichael Kruse << DeadInstructionsRemoved << '\n';
6860446d81eSMichael Kruse OS.indent(Indent + 4) << "Stmts removed: " << StmtsRemoved << "\n";
6870446d81eSMichael Kruse OS.indent(Indent) << "}\n";
6880446d81eSMichael Kruse }
6890446d81eSMichael Kruse
6900446d81eSMichael Kruse /// Print the current state of all MemoryAccesses to @p OS.
printAccesses(llvm::raw_ostream & OS,int Indent) const69123753c60SMichael Kruse void SimplifyImpl::printAccesses(llvm::raw_ostream &OS, int Indent) const {
6920446d81eSMichael Kruse OS.indent(Indent) << "After accesses {\n";
6930446d81eSMichael Kruse for (auto &Stmt : *S) {
6940446d81eSMichael Kruse OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
6950446d81eSMichael Kruse for (auto *MA : Stmt)
6960446d81eSMichael Kruse MA->print(OS);
6970446d81eSMichael Kruse }
6980446d81eSMichael Kruse OS.indent(Indent) << "}\n";
6990446d81eSMichael Kruse }
7000446d81eSMichael Kruse
run(Scop & S,LoopInfo * LI)70123753c60SMichael Kruse void SimplifyImpl::run(Scop &S, LoopInfo *LI) {
70223753c60SMichael Kruse // Must not have run before.
70323753c60SMichael Kruse assert(!this->S);
704629f9185SMichael Kruse assert(!isModified());
7050446d81eSMichael Kruse
7060446d81eSMichael Kruse // Prepare processing of this SCoP.
7070446d81eSMichael Kruse this->S = &S;
70806ed5292SMichael Kruse ScopsProcessed[CallNo]++;
7090446d81eSMichael Kruse
7106983741eSMichael Kruse LLVM_DEBUG(dbgs() << "Removing statements that are never executed...\n");
7116983741eSMichael Kruse removeEmptyDomainStmts();
7126983741eSMichael Kruse
713349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removing partial writes that never happen...\n");
71434a77780SMichael Kruse removeEmptyPartialAccesses();
71534a77780SMichael Kruse
716349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removing overwrites...\n");
717f263610bSMichael Kruse removeOverwrites();
718f263610bSMichael Kruse
719349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Coalesce partial writes...\n");
720ce9617f4SMichael Kruse coalesceWrites();
721ce9617f4SMichael Kruse
722349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removing redundant writes...\n");
7230446d81eSMichael Kruse removeRedundantWrites();
7240446d81eSMichael Kruse
725349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Cleanup unused accesses...\n");
72622058c3fSMichael Kruse markAndSweep(LI);
72722058c3fSMichael Kruse
728349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "Removing statements without side effects...\n");
7298e1280b8STobias Grosser removeUnnecessaryStmts();
7300446d81eSMichael Kruse
7310446d81eSMichael Kruse if (isModified())
73206ed5292SMichael Kruse ScopsModified[CallNo]++;
733349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << "\nFinal Scop:\n");
734349506a9SNicola Zaghen LLVM_DEBUG(dbgs() << S);
7350446d81eSMichael Kruse
73606ed5292SMichael Kruse auto ScopStats = S.getStatistics();
73706ed5292SMichael Kruse NumValueWrites[CallNo] += ScopStats.NumValueWrites;
73806ed5292SMichael Kruse NumValueWritesInLoops[CallNo] += ScopStats.NumValueWritesInLoops;
73906ed5292SMichael Kruse NumPHIWrites[CallNo] += ScopStats.NumPHIWrites;
74006ed5292SMichael Kruse NumPHIWritesInLoops[CallNo] += ScopStats.NumPHIWritesInLoops;
74106ed5292SMichael Kruse NumSingletonWrites[CallNo] += ScopStats.NumSingletonWrites;
74206ed5292SMichael Kruse NumSingletonWritesInLoops[CallNo] += ScopStats.NumSingletonWritesInLoops;
7430446d81eSMichael Kruse }
7440446d81eSMichael Kruse
printScop(raw_ostream & OS,Scop & S) const74523753c60SMichael Kruse void SimplifyImpl::printScop(raw_ostream &OS, Scop &S) const {
7460446d81eSMichael Kruse assert(&S == this->S &&
7470446d81eSMichael Kruse "Can only print analysis for the last processed SCoP");
7480446d81eSMichael Kruse printStatistics(OS);
7490446d81eSMichael Kruse
7500446d81eSMichael Kruse if (!isModified()) {
7510446d81eSMichael Kruse OS << "SCoP could not be simplified\n";
7520446d81eSMichael Kruse return;
7530446d81eSMichael Kruse }
7540446d81eSMichael Kruse printAccesses(OS);
7550446d81eSMichael Kruse }
7560446d81eSMichael Kruse
757bd93df93SMichael Kruse class SimplifyWrapperPass final : public ScopPass {
758deb00cf0SPengxuan Zheng public:
759deb00cf0SPengxuan Zheng static char ID;
76023753c60SMichael Kruse int CallNo;
76123753c60SMichael Kruse Optional<SimplifyImpl> Impl;
762deb00cf0SPengxuan Zheng
SimplifyWrapperPass(int CallNo=0)76323753c60SMichael Kruse explicit SimplifyWrapperPass(int CallNo = 0) : ScopPass(ID), CallNo(CallNo) {}
764deb00cf0SPengxuan Zheng
getAnalysisUsage(AnalysisUsage & AU) const765*3f3930a4SKazu Hirata void getAnalysisUsage(AnalysisUsage &AU) const override {
766deb00cf0SPengxuan Zheng AU.addRequiredTransitive<ScopInfoRegionPass>();
767deb00cf0SPengxuan Zheng AU.addRequired<LoopInfoWrapperPass>();
768deb00cf0SPengxuan Zheng AU.setPreservesAll();
769deb00cf0SPengxuan Zheng }
770deb00cf0SPengxuan Zheng
runOnScop(Scop & S)771*3f3930a4SKazu Hirata bool runOnScop(Scop &S) override {
77223753c60SMichael Kruse LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
77323753c60SMichael Kruse
77423753c60SMichael Kruse Impl.emplace(CallNo);
77523753c60SMichael Kruse Impl->run(S, LI);
77623753c60SMichael Kruse
77723753c60SMichael Kruse return false;
778deb00cf0SPengxuan Zheng }
779deb00cf0SPengxuan Zheng
printScop(raw_ostream & OS,Scop & S) const780*3f3930a4SKazu Hirata void printScop(raw_ostream &OS, Scop &S) const override {
78123753c60SMichael Kruse if (Impl)
78223753c60SMichael Kruse Impl->printScop(OS, S);
783deb00cf0SPengxuan Zheng }
784deb00cf0SPengxuan Zheng
releaseMemory()785*3f3930a4SKazu Hirata void releaseMemory() override { Impl.reset(); }
7860446d81eSMichael Kruse };
7870446d81eSMichael Kruse
78813f758a8SMichael Kruse char SimplifyWrapperPass::ID;
7890446d81eSMichael Kruse
79023753c60SMichael Kruse static llvm::PreservedAnalyses
runSimplifyUsingNPM(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U,int CallNo,raw_ostream * OS)79123753c60SMichael Kruse runSimplifyUsingNPM(Scop &S, ScopAnalysisManager &SAM,
79223753c60SMichael Kruse ScopStandardAnalysisResults &SAR, SPMUpdater &U, int CallNo,
79323753c60SMichael Kruse raw_ostream *OS) {
79423753c60SMichael Kruse SimplifyImpl Impl(CallNo);
79523753c60SMichael Kruse Impl.run(S, &SAR.LI);
79623753c60SMichael Kruse if (OS) {
79723753c60SMichael Kruse *OS << "Printing analysis 'Polly - Simplify' for region: '" << S.getName()
79823753c60SMichael Kruse << "' in function '" << S.getFunction().getName() << "':\n";
79923753c60SMichael Kruse Impl.printScop(*OS, S);
80023753c60SMichael Kruse }
80123753c60SMichael Kruse
80223753c60SMichael Kruse if (!Impl.isModified())
803deb00cf0SPengxuan Zheng return llvm::PreservedAnalyses::all();
804deb00cf0SPengxuan Zheng
80513f758a8SMichael Kruse PreservedAnalyses PA;
80613f758a8SMichael Kruse PA.preserveSet<AllAnalysesOn<Module>>();
80713f758a8SMichael Kruse PA.preserveSet<AllAnalysesOn<Function>>();
80813f758a8SMichael Kruse PA.preserveSet<AllAnalysesOn<Loop>>();
80913f758a8SMichael Kruse return PA;
810deb00cf0SPengxuan Zheng }
811deb00cf0SPengxuan Zheng
81223753c60SMichael Kruse } // anonymous namespace
81323753c60SMichael Kruse
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U)81423753c60SMichael Kruse llvm::PreservedAnalyses SimplifyPass::run(Scop &S, ScopAnalysisManager &SAM,
81523753c60SMichael Kruse ScopStandardAnalysisResults &SAR,
81623753c60SMichael Kruse SPMUpdater &U) {
81723753c60SMichael Kruse return runSimplifyUsingNPM(S, SAM, SAR, U, CallNo, nullptr);
81823753c60SMichael Kruse }
81923753c60SMichael Kruse
820deb00cf0SPengxuan Zheng llvm::PreservedAnalyses
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater & U)821deb00cf0SPengxuan Zheng SimplifyPrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
822deb00cf0SPengxuan Zheng ScopStandardAnalysisResults &SAR, SPMUpdater &U) {
82323753c60SMichael Kruse return runSimplifyUsingNPM(S, SAM, SAR, U, CallNo, &OS);
824deb00cf0SPengxuan Zheng }
825deb00cf0SPengxuan Zheng
getAccessesInOrder(ScopStmt & Stmt)82623753c60SMichael Kruse SmallVector<MemoryAccess *, 32> polly::getAccessesInOrder(ScopStmt &Stmt) {
827327e9ecbSTobias Grosser SmallVector<MemoryAccess *, 32> Accesses;
828327e9ecbSTobias Grosser
829327e9ecbSTobias Grosser for (MemoryAccess *MemAcc : Stmt)
830327e9ecbSTobias Grosser if (isImplicitRead(MemAcc))
831327e9ecbSTobias Grosser Accesses.push_back(MemAcc);
832327e9ecbSTobias Grosser
833327e9ecbSTobias Grosser for (MemoryAccess *MemAcc : Stmt)
834327e9ecbSTobias Grosser if (isExplicitAccess(MemAcc))
835327e9ecbSTobias Grosser Accesses.push_back(MemAcc);
836327e9ecbSTobias Grosser
837327e9ecbSTobias Grosser for (MemoryAccess *MemAcc : Stmt)
838327e9ecbSTobias Grosser if (isImplicitWrite(MemAcc))
839327e9ecbSTobias Grosser Accesses.push_back(MemAcc);
840327e9ecbSTobias Grosser
841327e9ecbSTobias Grosser return Accesses;
842327e9ecbSTobias Grosser }
843327e9ecbSTobias Grosser
createSimplifyWrapperPass(int CallNo)84413f758a8SMichael Kruse Pass *polly::createSimplifyWrapperPass(int CallNo) {
84513f758a8SMichael Kruse return new SimplifyWrapperPass(CallNo);
846deb00cf0SPengxuan Zheng }
8470446d81eSMichael Kruse
84813f758a8SMichael Kruse INITIALIZE_PASS_BEGIN(SimplifyWrapperPass, "polly-simplify", "Polly - Simplify",
849deb00cf0SPengxuan Zheng false, false)
85022058c3fSMichael Kruse INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
85113f758a8SMichael Kruse INITIALIZE_PASS_END(SimplifyWrapperPass, "polly-simplify", "Polly - Simplify",
852deb00cf0SPengxuan Zheng false, false)
8535c028081SMichael Kruse
8545c028081SMichael Kruse //===----------------------------------------------------------------------===//
8555c028081SMichael Kruse
8565c028081SMichael Kruse namespace {
8575c028081SMichael Kruse /// Print result from SimplifyWrapperPass.
858bd93df93SMichael Kruse class SimplifyPrinterLegacyPass final : public ScopPass {
8595c028081SMichael Kruse public:
8605c028081SMichael Kruse static char ID;
8615c028081SMichael Kruse
SimplifyPrinterLegacyPass()8625c028081SMichael Kruse SimplifyPrinterLegacyPass() : SimplifyPrinterLegacyPass(outs()) {}
SimplifyPrinterLegacyPass(llvm::raw_ostream & OS)8635c028081SMichael Kruse explicit SimplifyPrinterLegacyPass(llvm::raw_ostream &OS)
8645c028081SMichael Kruse : ScopPass(ID), OS(OS) {}
8655c028081SMichael Kruse
runOnScop(Scop & S)8665c028081SMichael Kruse bool runOnScop(Scop &S) override {
8675c028081SMichael Kruse SimplifyWrapperPass &P = getAnalysis<SimplifyWrapperPass>();
8685c028081SMichael Kruse
8695c028081SMichael Kruse OS << "Printing analysis '" << P.getPassName() << "' for region: '"
8705c028081SMichael Kruse << S.getRegion().getNameStr() << "' in function '"
8715c028081SMichael Kruse << S.getFunction().getName() << "':\n";
8725c028081SMichael Kruse P.printScop(OS, S);
8735c028081SMichael Kruse
8745c028081SMichael Kruse return false;
8755c028081SMichael Kruse }
8765c028081SMichael Kruse
getAnalysisUsage(AnalysisUsage & AU) const8775c028081SMichael Kruse void getAnalysisUsage(AnalysisUsage &AU) const override {
8785c028081SMichael Kruse ScopPass::getAnalysisUsage(AU);
8795c028081SMichael Kruse AU.addRequired<SimplifyWrapperPass>();
8805c028081SMichael Kruse AU.setPreservesAll();
8815c028081SMichael Kruse }
8825c028081SMichael Kruse
8835c028081SMichael Kruse private:
8845c028081SMichael Kruse llvm::raw_ostream &OS;
8855c028081SMichael Kruse };
8865c028081SMichael Kruse
8875c028081SMichael Kruse char SimplifyPrinterLegacyPass::ID = 0;
8885c028081SMichael Kruse } // namespace
8895c028081SMichael Kruse
createSimplifyPrinterLegacyPass(raw_ostream & OS)8905c028081SMichael Kruse Pass *polly::createSimplifyPrinterLegacyPass(raw_ostream &OS) {
8915c028081SMichael Kruse return new SimplifyPrinterLegacyPass(OS);
8925c028081SMichael Kruse }
8935c028081SMichael Kruse
8945c028081SMichael Kruse INITIALIZE_PASS_BEGIN(SimplifyPrinterLegacyPass, "polly-print-simplify",
8955c028081SMichael Kruse "Polly - Print Simplify actions", false, false)
8965c028081SMichael Kruse INITIALIZE_PASS_DEPENDENCY(SimplifyWrapperPass)
8975c028081SMichael Kruse INITIALIZE_PASS_END(SimplifyPrinterLegacyPass, "polly-print-simplify",
8985c028081SMichael Kruse "Polly - Print Simplify actions", false, false)
899