1a32707d5SEugene Zelenko //===- MaximalStaticExpansion.cpp -----------------------------------------===//
281fb6b3eSAndreas Simbuerger //
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
681fb6b3eSAndreas Simbuerger //
781fb6b3eSAndreas Simbuerger //===----------------------------------------------------------------------===//
881fb6b3eSAndreas Simbuerger //
981fb6b3eSAndreas Simbuerger // This pass fully expand the memory accesses of a Scop to get rid of
1081fb6b3eSAndreas Simbuerger // dependencies.
1181fb6b3eSAndreas Simbuerger //
1281fb6b3eSAndreas Simbuerger //===----------------------------------------------------------------------===//
1381fb6b3eSAndreas Simbuerger 
1402f64067SYang Keao #include "polly/MaximalStaticExpansion.h"
1581fb6b3eSAndreas Simbuerger #include "polly/DependenceInfo.h"
1681fb6b3eSAndreas Simbuerger #include "polly/LinkAllPasses.h"
1781fb6b3eSAndreas Simbuerger #include "polly/ScopInfo.h"
18a32707d5SEugene Zelenko #include "polly/ScopPass.h"
1977e871aaSTobias Grosser #include "polly/Support/ISLTools.h"
20a32707d5SEugene Zelenko #include "llvm/ADT/SmallPtrSet.h"
21a32707d5SEugene Zelenko #include "llvm/ADT/StringRef.h"
22e0f1541fSAdam Nemet #include "llvm/Analysis/OptimizationRemarkEmitter.h"
2305da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
24a32707d5SEugene Zelenko #include "isl/isl-noexceptions.h"
25a32707d5SEugene Zelenko #include "isl/union_map.h"
26a32707d5SEugene Zelenko #include <cassert>
27a32707d5SEugene Zelenko #include <limits>
28a32707d5SEugene Zelenko #include <string>
29a32707d5SEugene Zelenko #include <vector>
3081fb6b3eSAndreas Simbuerger 
3181fb6b3eSAndreas Simbuerger using namespace llvm;
3281fb6b3eSAndreas Simbuerger using namespace polly;
3381fb6b3eSAndreas Simbuerger 
3481fb6b3eSAndreas Simbuerger #define DEBUG_TYPE "polly-mse"
3581fb6b3eSAndreas Simbuerger 
3681fb6b3eSAndreas Simbuerger namespace {
37a32707d5SEugene Zelenko 
3802f64067SYang Keao class MaximalStaticExpanderWrapperPass final : public ScopPass {
3981fb6b3eSAndreas Simbuerger public:
4081fb6b3eSAndreas Simbuerger   static char ID;
41a32707d5SEugene Zelenko 
MaximalStaticExpanderWrapperPass()4202f64067SYang Keao   explicit MaximalStaticExpanderWrapperPass() : ScopPass(ID) {}
4381fb6b3eSAndreas Simbuerger 
4402f64067SYang Keao   ~MaximalStaticExpanderWrapperPass() override = default;
4581fb6b3eSAndreas Simbuerger 
4681fb6b3eSAndreas Simbuerger   /// Expand the accesses of the SCoP.
4781fb6b3eSAndreas Simbuerger   ///
4881fb6b3eSAndreas Simbuerger   /// @param S The SCoP that must be expanded.
4981fb6b3eSAndreas Simbuerger   bool runOnScop(Scop &S) override;
5081fb6b3eSAndreas Simbuerger 
5181fb6b3eSAndreas Simbuerger   /// Print the SCoP.
5281fb6b3eSAndreas Simbuerger   ///
5381fb6b3eSAndreas Simbuerger   /// @param OS The stream where to print.
5481fb6b3eSAndreas Simbuerger   /// @param S The SCop that must be printed.
5581fb6b3eSAndreas Simbuerger   void printScop(raw_ostream &OS, Scop &S) const override;
5681fb6b3eSAndreas Simbuerger 
5781fb6b3eSAndreas Simbuerger   /// Register all analyses and transformations required.
5881fb6b3eSAndreas Simbuerger   void getAnalysisUsage(AnalysisUsage &AU) const override;
5981fb6b3eSAndreas Simbuerger };
6081fb6b3eSAndreas Simbuerger 
61a1579aabSMichael Kruse #ifndef NDEBUG
6281fb6b3eSAndreas Simbuerger /// Whether a dimension of a set is bounded (lower and upper) by a constant,
6381fb6b3eSAndreas Simbuerger /// i.e. there are two constants Min and Max, such that every value x of the
6481fb6b3eSAndreas Simbuerger /// chosen dimensions is Min <= x <= Max.
isDimBoundedByConstant(isl::set Set,unsigned dim)65a32707d5SEugene Zelenko static bool isDimBoundedByConstant(isl::set Set, unsigned dim) {
6644596fe6SRiccardo Mori   auto ParamDims = unsignedFromIslSize(Set.dim(isl::dim::param));
6781fb6b3eSAndreas Simbuerger   Set = Set.project_out(isl::dim::param, 0, ParamDims);
6881fb6b3eSAndreas Simbuerger   Set = Set.project_out(isl::dim::set, 0, dim);
6944596fe6SRiccardo Mori   auto SetDims = unsignedFromIslSize(Set.tuple_dim());
7044596fe6SRiccardo Mori   assert(SetDims >= 1);
7181fb6b3eSAndreas Simbuerger   Set = Set.project_out(isl::dim::set, 1, SetDims - 1);
7281fb6b3eSAndreas Simbuerger   return bool(Set.is_bounded());
7381fb6b3eSAndreas Simbuerger }
74a1579aabSMichael Kruse #endif
7581fb6b3eSAndreas Simbuerger 
7602f64067SYang Keao class MaximalStaticExpansionImpl {
7702f64067SYang Keao   OptimizationRemarkEmitter &ORE;
7802f64067SYang Keao   Scop &S;
7902f64067SYang Keao   isl::union_map &Dependences;
8081fb6b3eSAndreas Simbuerger 
8102f64067SYang Keao   /// Emit remark
emitRemark(StringRef Msg,Instruction * Inst)8202f64067SYang Keao   void emitRemark(StringRef Msg, Instruction *Inst) {
8302f64067SYang Keao     ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ExpansionRejection", Inst)
8402f64067SYang Keao              << Msg);
8502f64067SYang Keao   }
8602f64067SYang Keao 
8702f64067SYang Keao   /// Filter the dependences to have only one related to current memory access.
8802f64067SYang Keao   ///
8902f64067SYang Keao   /// @param S The SCop in which the memory access appears in.
9002f64067SYang Keao   /// @param MapDependences The dependences to filter.
9102f64067SYang Keao   /// @param MA The memory access that need to be expanded.
filterDependences(const isl::union_map & Dependences,MemoryAccess * MA)9202f64067SYang Keao   isl::union_map filterDependences(const isl::union_map &Dependences,
9302f64067SYang Keao                                    MemoryAccess *MA) {
948d5b257dSAndreas Simbuerger     auto SAI = MA->getLatestScopArrayInfo();
958d5b257dSAndreas Simbuerger 
968d5b257dSAndreas Simbuerger     auto AccessDomainSet = MA->getAccessRelation().domain();
978d5b257dSAndreas Simbuerger     auto AccessDomainId = AccessDomainSet.get_tuple_id();
988d5b257dSAndreas Simbuerger 
99bad3ebbaSRiccardo Mori     isl::union_map MapDependences = isl::union_map::empty(S.getIslCtx());
1008d5b257dSAndreas Simbuerger 
1013867bae7STobias Grosser     for (isl::map Map : Dependences.get_map_list()) {
1028d5b257dSAndreas Simbuerger       // Filter out Statement to Statement dependences.
1038d5b257dSAndreas Simbuerger       if (!Map.can_curry())
1043867bae7STobias Grosser         continue;
1058d5b257dSAndreas Simbuerger 
1068d5b257dSAndreas Simbuerger       // Intersect with the relevant SAI.
1078d5b257dSAndreas Simbuerger       auto TmpMapDomainId =
1088d5b257dSAndreas Simbuerger           Map.get_space().domain().unwrap().range().get_tuple_id(isl::dim::set);
1098d5b257dSAndreas Simbuerger 
1108d5b257dSAndreas Simbuerger       ScopArrayInfo *UserSAI =
1118d5b257dSAndreas Simbuerger           static_cast<ScopArrayInfo *>(TmpMapDomainId.get_user());
1128d5b257dSAndreas Simbuerger 
1138d5b257dSAndreas Simbuerger       if (SAI != UserSAI)
1143867bae7STobias Grosser         continue;
1158d5b257dSAndreas Simbuerger 
1168d5b257dSAndreas Simbuerger       // Get the correct S1[] -> S2[] dependence.
1178d5b257dSAndreas Simbuerger       auto NewMap = Map.factor_domain();
1188d5b257dSAndreas Simbuerger       auto NewMapDomainId = NewMap.domain().get_tuple_id();
1198d5b257dSAndreas Simbuerger 
120d3d3d6b7STobias Grosser       if (AccessDomainId.get() != NewMapDomainId.get())
1213867bae7STobias Grosser         continue;
1228d5b257dSAndreas Simbuerger 
1238d5b257dSAndreas Simbuerger       // Add the corresponding map to MapDependences.
124d5ee355fSRiccardo Mori       MapDependences = MapDependences.unite(NewMap);
1253867bae7STobias Grosser     }
1268d5b257dSAndreas Simbuerger 
1278d5b257dSAndreas Simbuerger     return MapDependences;
1288d5b257dSAndreas Simbuerger   }
1298d5b257dSAndreas Simbuerger 
13002f64067SYang Keao   /// Return true if the SAI in parameter is expandable.
13102f64067SYang Keao   ///
13202f64067SYang Keao   /// @param SAI the SAI that need to be checked.
13302f64067SYang Keao   /// @param Writes A set that will contains all the write accesses.
13402f64067SYang Keao   /// @param Reads A set that will contains all the read accesses.
13502f64067SYang Keao   /// @param S The SCop in which the SAI is in.
13602f64067SYang Keao   /// @param Dependences The RAW dependences of the SCop.
isExpandable(const ScopArrayInfo * SAI,SmallPtrSetImpl<MemoryAccess * > & Writes,SmallPtrSetImpl<MemoryAccess * > & Reads,Scop & S)13702f64067SYang Keao   bool isExpandable(const ScopArrayInfo *SAI,
13802f64067SYang Keao                     SmallPtrSetImpl<MemoryAccess *> &Writes,
13902f64067SYang Keao                     SmallPtrSetImpl<MemoryAccess *> &Reads, Scop &S) {
140e478e2deSAndreas Simbuerger     if (SAI->isValueKind()) {
141e478e2deSAndreas Simbuerger       Writes.insert(S.getValueDef(SAI));
142e478e2deSAndreas Simbuerger       for (auto MA : S.getValueUses(SAI))
143e478e2deSAndreas Simbuerger         Reads.insert(MA);
144e478e2deSAndreas Simbuerger       return true;
145e478e2deSAndreas Simbuerger     } else if (SAI->isPHIKind()) {
146e478e2deSAndreas Simbuerger       auto Read = S.getPHIRead(SAI);
147e478e2deSAndreas Simbuerger 
148e478e2deSAndreas Simbuerger       auto StmtDomain = isl::union_set(Read->getStatement()->getDomain());
149e478e2deSAndreas Simbuerger 
150e478e2deSAndreas Simbuerger       auto Writes = S.getPHIIncomings(SAI);
151e478e2deSAndreas Simbuerger 
152e478e2deSAndreas Simbuerger       // Get the domain where all the writes are writing to.
153bad3ebbaSRiccardo Mori       auto WriteDomain = isl::union_set::empty(S.getIslCtx());
154e478e2deSAndreas Simbuerger 
155e478e2deSAndreas Simbuerger       for (auto Write : Writes) {
15602f64067SYang Keao         auto MapDeps = filterDependences(Dependences, Write);
1573867bae7STobias Grosser         for (isl::map Map : MapDeps.get_map_list())
158b55aedd0Spatacca           WriteDomain = WriteDomain.unite(Map.range());
159e478e2deSAndreas Simbuerger       }
160e478e2deSAndreas Simbuerger 
161e478e2deSAndreas Simbuerger       // For now, read from original scalar is not possible.
162e478e2deSAndreas Simbuerger       if (!StmtDomain.is_equal(WriteDomain)) {
163e478e2deSAndreas Simbuerger         emitRemark(SAI->getName() + " read from its original value.",
164e478e2deSAndreas Simbuerger                    Read->getAccessInstruction());
165e478e2deSAndreas Simbuerger         return false;
166e478e2deSAndreas Simbuerger       }
167e478e2deSAndreas Simbuerger 
168e478e2deSAndreas Simbuerger       return true;
169e478e2deSAndreas Simbuerger     } else if (SAI->isExitPHIKind()) {
170e478e2deSAndreas Simbuerger       // For now, we are not able to expand ExitPhi.
171e478e2deSAndreas Simbuerger       emitRemark(SAI->getName() + " is a ExitPhi node.",
172e478e2deSAndreas Simbuerger                  S.getEnteringBlock()->getFirstNonPHI());
173e478e2deSAndreas Simbuerger       return false;
174e478e2deSAndreas Simbuerger     }
175e478e2deSAndreas Simbuerger 
17681fb6b3eSAndreas Simbuerger     int NumberWrites = 0;
17781fb6b3eSAndreas Simbuerger     for (ScopStmt &Stmt : S) {
178bad3ebbaSRiccardo Mori       auto StmtReads = isl::union_map::empty(S.getIslCtx());
179bad3ebbaSRiccardo Mori       auto StmtWrites = isl::union_map::empty(S.getIslCtx());
1808d5b257dSAndreas Simbuerger 
18181fb6b3eSAndreas Simbuerger       for (MemoryAccess *MA : Stmt) {
18281fb6b3eSAndreas Simbuerger         // Check if the current MemoryAccess involved the current SAI.
18381fb6b3eSAndreas Simbuerger         if (SAI != MA->getLatestScopArrayInfo())
18481fb6b3eSAndreas Simbuerger           continue;
18581fb6b3eSAndreas Simbuerger 
1868d5b257dSAndreas Simbuerger         // For now, we are not able to expand array where read come after write
1878d5b257dSAndreas Simbuerger         // (to the same location) in a same statement.
1888d5b257dSAndreas Simbuerger         auto AccRel = isl::union_map(MA->getAccessRelation());
1898d5b257dSAndreas Simbuerger         if (MA->isRead()) {
1908d5b257dSAndreas Simbuerger           // Reject load after store to same location.
1918d5b257dSAndreas Simbuerger           if (!StmtWrites.is_disjoint(AccRel)) {
1928d5b257dSAndreas Simbuerger             emitRemark(SAI->getName() + " has read after write to the same "
1938d5b257dSAndreas Simbuerger                                         "element in same statement. The "
1948d5b257dSAndreas Simbuerger                                         "dependences found during analysis may "
1958d5b257dSAndreas Simbuerger                                         "be wrong because Polly is not able to "
1968d5b257dSAndreas Simbuerger                                         "handle such case for now.",
1978d5b257dSAndreas Simbuerger                        MA->getAccessInstruction());
1988d5b257dSAndreas Simbuerger             return false;
1998d5b257dSAndreas Simbuerger           }
2008d5b257dSAndreas Simbuerger 
201da3e8c4bSTobias Grosser           StmtReads = StmtReads.unite(AccRel);
2028d5b257dSAndreas Simbuerger         } else {
203da3e8c4bSTobias Grosser           StmtWrites = StmtWrites.unite(AccRel);
2048d5b257dSAndreas Simbuerger         }
2058d5b257dSAndreas Simbuerger 
20681fb6b3eSAndreas Simbuerger         // For now, we are not able to expand MayWrite.
20781fb6b3eSAndreas Simbuerger         if (MA->isMayWrite()) {
20881fb6b3eSAndreas Simbuerger           emitRemark(SAI->getName() + " has a maywrite access.",
20981fb6b3eSAndreas Simbuerger                      MA->getAccessInstruction());
21081fb6b3eSAndreas Simbuerger           return false;
21181fb6b3eSAndreas Simbuerger         }
21281fb6b3eSAndreas Simbuerger 
21381fb6b3eSAndreas Simbuerger         // For now, we are not able to expand SAI with more than one write.
21481fb6b3eSAndreas Simbuerger         if (MA->isMustWrite()) {
21581fb6b3eSAndreas Simbuerger           Writes.insert(MA);
21681fb6b3eSAndreas Simbuerger           NumberWrites++;
21781fb6b3eSAndreas Simbuerger           if (NumberWrites > 1) {
21881fb6b3eSAndreas Simbuerger             emitRemark(SAI->getName() + " has more than 1 write access.",
21981fb6b3eSAndreas Simbuerger                        MA->getAccessInstruction());
22081fb6b3eSAndreas Simbuerger             return false;
22181fb6b3eSAndreas Simbuerger           }
22281fb6b3eSAndreas Simbuerger         }
22381fb6b3eSAndreas Simbuerger 
22481fb6b3eSAndreas Simbuerger         // Check if it is possible to expand this read.
22581fb6b3eSAndreas Simbuerger         if (MA->isRead()) {
22681fb6b3eSAndreas Simbuerger           // Get the domain of the current ScopStmt.
22781fb6b3eSAndreas Simbuerger           auto StmtDomain = Stmt.getDomain();
22881fb6b3eSAndreas Simbuerger 
22981fb6b3eSAndreas Simbuerger           // Get the domain of the future Read access.
23081fb6b3eSAndreas Simbuerger           auto ReadDomainSet = MA->getAccessRelation().domain();
23181fb6b3eSAndreas Simbuerger           auto ReadDomain = isl::union_set(ReadDomainSet);
23281fb6b3eSAndreas Simbuerger 
2338d5b257dSAndreas Simbuerger           // Get the dependences relevant for this MA
23402f64067SYang Keao           auto MapDependences = filterDependences(Dependences.reverse(), MA);
2358d5b257dSAndreas Simbuerger           unsigned NumberElementMap = isl_union_map_n_map(MapDependences.get());
23681fb6b3eSAndreas Simbuerger 
237e478e2deSAndreas Simbuerger           if (NumberElementMap == 0) {
238e478e2deSAndreas Simbuerger             emitRemark("The expansion of " + SAI->getName() +
239e478e2deSAndreas Simbuerger                            " would lead to a read from the original array.",
240e478e2deSAndreas Simbuerger                        MA->getAccessInstruction());
241e478e2deSAndreas Simbuerger             return false;
242e478e2deSAndreas Simbuerger           }
243e478e2deSAndreas Simbuerger 
244e478e2deSAndreas Simbuerger           auto DepsDomain = MapDependences.domain();
245e478e2deSAndreas Simbuerger 
24681fb6b3eSAndreas Simbuerger           // If there are multiple maps in the Deps, we cannot handle this case
24781fb6b3eSAndreas Simbuerger           // for now.
24881fb6b3eSAndreas Simbuerger           if (NumberElementMap != 1) {
24981fb6b3eSAndreas Simbuerger             emitRemark(SAI->getName() +
25081fb6b3eSAndreas Simbuerger                            " has too many dependences to be handle for now.",
25181fb6b3eSAndreas Simbuerger                        MA->getAccessInstruction());
25281fb6b3eSAndreas Simbuerger             return false;
25381fb6b3eSAndreas Simbuerger           }
25481fb6b3eSAndreas Simbuerger 
25581fb6b3eSAndreas Simbuerger           auto DepsDomainSet = isl::set(DepsDomain);
25681fb6b3eSAndreas Simbuerger 
25781fb6b3eSAndreas Simbuerger           // For now, read from the original array is not possible.
25881fb6b3eSAndreas Simbuerger           if (!StmtDomain.is_subset(DepsDomainSet)) {
25981fb6b3eSAndreas Simbuerger             emitRemark("The expansion of " + SAI->getName() +
26081fb6b3eSAndreas Simbuerger                            " would lead to a read from the original array.",
26181fb6b3eSAndreas Simbuerger                        MA->getAccessInstruction());
26281fb6b3eSAndreas Simbuerger             return false;
26381fb6b3eSAndreas Simbuerger           }
26481fb6b3eSAndreas Simbuerger 
26581fb6b3eSAndreas Simbuerger           Reads.insert(MA);
26681fb6b3eSAndreas Simbuerger         }
26781fb6b3eSAndreas Simbuerger       }
26881fb6b3eSAndreas Simbuerger     }
26981fb6b3eSAndreas Simbuerger 
27081fb6b3eSAndreas Simbuerger     // No need to expand SAI with no write.
27181fb6b3eSAndreas Simbuerger     if (NumberWrites == 0) {
27281fb6b3eSAndreas Simbuerger       emitRemark(SAI->getName() + " has 0 write access.",
27381fb6b3eSAndreas Simbuerger                  S.getEnteringBlock()->getFirstNonPHI());
27481fb6b3eSAndreas Simbuerger       return false;
27581fb6b3eSAndreas Simbuerger     }
27681fb6b3eSAndreas Simbuerger 
27781fb6b3eSAndreas Simbuerger     return true;
27881fb6b3eSAndreas Simbuerger   }
27981fb6b3eSAndreas Simbuerger 
28002f64067SYang Keao   /// Expand the MemoryAccess according to Dependences and already expanded
28102f64067SYang Keao   /// MemoryAccesses.
28202f64067SYang Keao   ///
28302f64067SYang Keao   /// @param The SCop in which the memory access appears in.
28402f64067SYang Keao   /// @param The memory access that need to be expanded.
28502f64067SYang Keao   /// @param Dependences The RAW dependences of the SCop.
28602f64067SYang Keao   /// @param ExpandedSAI The expanded SAI created during write expansion.
28702f64067SYang Keao   /// @param Reverse if true, the Dependences union_map is reversed before
28802f64067SYang Keao   /// intersection.
mapAccess(SmallPtrSetImpl<MemoryAccess * > & Accesses,const isl::union_map & Dependences,ScopArrayInfo * ExpandedSAI,bool Reverse)28902f64067SYang Keao   void mapAccess(SmallPtrSetImpl<MemoryAccess *> &Accesses,
29002f64067SYang Keao                  const isl::union_map &Dependences, ScopArrayInfo *ExpandedSAI,
291e478e2deSAndreas Simbuerger                  bool Reverse) {
292e478e2deSAndreas Simbuerger     for (auto MA : Accesses) {
29381fb6b3eSAndreas Simbuerger       // Get the current AM.
29481fb6b3eSAndreas Simbuerger       auto CurrentAccessMap = MA->getAccessRelation();
29581fb6b3eSAndreas Simbuerger 
29681fb6b3eSAndreas Simbuerger       // Get RAW dependences for the current WA.
297e478e2deSAndreas Simbuerger       auto DomainSet = MA->getAccessRelation().domain();
298e478e2deSAndreas Simbuerger       auto Domain = isl::union_set(DomainSet);
29981fb6b3eSAndreas Simbuerger 
300e478e2deSAndreas Simbuerger       // Get the dependences relevant for this MA.
301b0c7dee0SDavide Italiano       isl::union_map MapDependences =
30202f64067SYang Keao           filterDependences(Reverse ? Dependences.reverse() : Dependences, MA);
30381fb6b3eSAndreas Simbuerger 
30481fb6b3eSAndreas Simbuerger       // If no dependences, no need to modify anything.
3058d5b257dSAndreas Simbuerger       if (MapDependences.is_empty())
30681fb6b3eSAndreas Simbuerger         return;
30781fb6b3eSAndreas Simbuerger 
3088d5b257dSAndreas Simbuerger       assert(isl_union_map_n_map(MapDependences.get()) == 1 &&
30981fb6b3eSAndreas Simbuerger              "There are more than one RAW dependencies in the union map.");
3108d5b257dSAndreas Simbuerger       auto NewAccessMap = isl::map::from_union_map(MapDependences);
31181fb6b3eSAndreas Simbuerger 
31281fb6b3eSAndreas Simbuerger       auto Id = ExpandedSAI->getBasePtrId();
31381fb6b3eSAndreas Simbuerger 
31481fb6b3eSAndreas Simbuerger       // Replace the out tuple id with the one of the access array.
31581fb6b3eSAndreas Simbuerger       NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, Id);
31681fb6b3eSAndreas Simbuerger 
31781fb6b3eSAndreas Simbuerger       // Set the new access relation.
31881fb6b3eSAndreas Simbuerger       MA->setNewAccessRelation(NewAccessMap);
31981fb6b3eSAndreas Simbuerger     }
320e478e2deSAndreas Simbuerger   }
32181fb6b3eSAndreas Simbuerger 
32202f64067SYang Keao   /// Expand the MemoryAccess according to its domain.
32302f64067SYang Keao   ///
32402f64067SYang Keao   /// @param S The SCop in which the memory access appears in.
32502f64067SYang Keao   /// @param MA The memory access that need to be expanded.
expandAccess(MemoryAccess * MA)32602f64067SYang Keao   ScopArrayInfo *expandAccess(MemoryAccess *MA) {
32781fb6b3eSAndreas Simbuerger     // Get the current AM.
32881fb6b3eSAndreas Simbuerger     auto CurrentAccessMap = MA->getAccessRelation();
32981fb6b3eSAndreas Simbuerger 
33044596fe6SRiccardo Mori     unsigned in_dimensions =
33144596fe6SRiccardo Mori         unsignedFromIslSize(CurrentAccessMap.domain_tuple_dim());
33281fb6b3eSAndreas Simbuerger 
33381fb6b3eSAndreas Simbuerger     // Get domain from the current AM.
33481fb6b3eSAndreas Simbuerger     auto Domain = CurrentAccessMap.domain();
33581fb6b3eSAndreas Simbuerger 
33681fb6b3eSAndreas Simbuerger     // Create a new AM from the domain.
33781fb6b3eSAndreas Simbuerger     auto NewAccessMap = isl::map::from_domain(Domain);
33881fb6b3eSAndreas Simbuerger 
33981fb6b3eSAndreas Simbuerger     // Add dimensions to the new AM according to the current in_dim.
34081fb6b3eSAndreas Simbuerger     NewAccessMap = NewAccessMap.add_dims(isl::dim::out, in_dimensions);
34181fb6b3eSAndreas Simbuerger 
34281fb6b3eSAndreas Simbuerger     // Create the string representing the name of the new SAI.
34302f64067SYang Keao     // One new SAI for each statement so that each write go to a different
34402f64067SYang Keao     // memory cell.
34581fb6b3eSAndreas Simbuerger     auto CurrentStmtDomain = MA->getStatement()->getDomain();
34681fb6b3eSAndreas Simbuerger     auto CurrentStmtName = CurrentStmtDomain.get_tuple_name();
34781fb6b3eSAndreas Simbuerger     auto CurrentOutId = CurrentAccessMap.get_tuple_id(isl::dim::out);
34881fb6b3eSAndreas Simbuerger     std::string CurrentOutIdString =
34981fb6b3eSAndreas Simbuerger         MA->getScopArrayInfo()->getName() + "_" + CurrentStmtName + "_expanded";
35081fb6b3eSAndreas Simbuerger 
35181fb6b3eSAndreas Simbuerger     // Set the tuple id for the out dimension.
35281fb6b3eSAndreas Simbuerger     NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, CurrentOutId);
35381fb6b3eSAndreas Simbuerger 
35481fb6b3eSAndreas Simbuerger     // Create the size vector.
35581fb6b3eSAndreas Simbuerger     std::vector<unsigned> Sizes;
35681fb6b3eSAndreas Simbuerger     for (unsigned i = 0; i < in_dimensions; i++) {
35781fb6b3eSAndreas Simbuerger       assert(isDimBoundedByConstant(CurrentStmtDomain, i) &&
35881fb6b3eSAndreas Simbuerger              "Domain boundary are not constant.");
35981fb6b3eSAndreas Simbuerger       auto UpperBound = getConstant(CurrentStmtDomain.dim_max(i), true, false);
36081fb6b3eSAndreas Simbuerger       assert(!UpperBound.is_null() && UpperBound.is_pos() &&
36181fb6b3eSAndreas Simbuerger              !UpperBound.is_nan() &&
36281fb6b3eSAndreas Simbuerger              "The upper bound is not a positive integer.");
3630813bd16SRiccardo Mori       assert(UpperBound.le(isl::val(CurrentAccessMap.ctx(),
36481fb6b3eSAndreas Simbuerger                                     std::numeric_limits<int>::max() - 1)) &&
36581fb6b3eSAndreas Simbuerger              "The upper bound overflow a int.");
36681fb6b3eSAndreas Simbuerger       Sizes.push_back(UpperBound.get_num_si() + 1);
36781fb6b3eSAndreas Simbuerger     }
36881fb6b3eSAndreas Simbuerger 
36981fb6b3eSAndreas Simbuerger     // Get the ElementType of the current SAI.
37081fb6b3eSAndreas Simbuerger     auto ElementType = MA->getLatestScopArrayInfo()->getElementType();
37181fb6b3eSAndreas Simbuerger 
37281fb6b3eSAndreas Simbuerger     // Create (or get if already existing) the new expanded SAI.
37381fb6b3eSAndreas Simbuerger     auto ExpandedSAI =
37481fb6b3eSAndreas Simbuerger         S.createScopArrayInfo(ElementType, CurrentOutIdString, Sizes);
37581fb6b3eSAndreas Simbuerger     ExpandedSAI->setIsOnHeap(true);
37681fb6b3eSAndreas Simbuerger 
37781fb6b3eSAndreas Simbuerger     // Get the out Id of the expanded Array.
37881fb6b3eSAndreas Simbuerger     auto NewOutId = ExpandedSAI->getBasePtrId();
37981fb6b3eSAndreas Simbuerger 
38081fb6b3eSAndreas Simbuerger     // Set the out id of the new AM to the new SAI id.
38181fb6b3eSAndreas Simbuerger     NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, NewOutId);
38281fb6b3eSAndreas Simbuerger 
38381fb6b3eSAndreas Simbuerger     // Add constraints to linked output with input id.
38481fb6b3eSAndreas Simbuerger     auto SpaceMap = NewAccessMap.get_space();
38544596fe6SRiccardo Mori     auto ConstraintBasicMap = isl::basic_map::equal(
38644596fe6SRiccardo Mori         SpaceMap, unsignedFromIslSize(SpaceMap.dim(isl::dim::in)));
38781fb6b3eSAndreas Simbuerger     NewAccessMap = isl::map(ConstraintBasicMap);
38881fb6b3eSAndreas Simbuerger 
38981fb6b3eSAndreas Simbuerger     // Set the new access relation map.
39081fb6b3eSAndreas Simbuerger     MA->setNewAccessRelation(NewAccessMap);
39181fb6b3eSAndreas Simbuerger 
39281fb6b3eSAndreas Simbuerger     return ExpandedSAI;
39381fb6b3eSAndreas Simbuerger   }
39481fb6b3eSAndreas Simbuerger 
39502f64067SYang Keao   /// Expand PHI memory accesses.
39602f64067SYang Keao   ///
39702f64067SYang Keao   /// @param The SCop in which the memory access appears in.
39802f64067SYang Keao   /// @param The ScopArrayInfo representing the PHI accesses to expand.
39902f64067SYang Keao   /// @param Dependences The RAW dependences of the SCop.
expandPhi(Scop & S,const ScopArrayInfo * SAI,const isl::union_map & Dependences)40002f64067SYang Keao   void expandPhi(Scop &S, const ScopArrayInfo *SAI,
401e478e2deSAndreas Simbuerger                  const isl::union_map &Dependences) {
402e478e2deSAndreas Simbuerger     SmallPtrSet<MemoryAccess *, 4> Writes;
403e478e2deSAndreas Simbuerger     for (auto MA : S.getPHIIncomings(SAI))
404e478e2deSAndreas Simbuerger       Writes.insert(MA);
405e478e2deSAndreas Simbuerger     auto Read = S.getPHIRead(SAI);
40602f64067SYang Keao     auto ExpandedSAI = expandAccess(Read);
407e478e2deSAndreas Simbuerger 
40802f64067SYang Keao     mapAccess(Writes, Dependences, ExpandedSAI, false);
409e478e2deSAndreas Simbuerger   }
410e478e2deSAndreas Simbuerger 
41102f64067SYang Keao public:
MaximalStaticExpansionImpl(Scop & S,isl::union_map & Dependences,OptimizationRemarkEmitter & ORE)41202f64067SYang Keao   MaximalStaticExpansionImpl(Scop &S, isl::union_map &Dependences,
41302f64067SYang Keao                              OptimizationRemarkEmitter &ORE)
414*8d3dda76SFangrui Song       : ORE(ORE), S(S), Dependences(Dependences) {}
41581fb6b3eSAndreas Simbuerger 
41602f64067SYang Keao   /// Expand the accesses of the SCoP
41702f64067SYang Keao   ///
41802f64067SYang Keao   /// @param S The SCoP that must be expanded
41902f64067SYang Keao   /// @param D The dependencies information of SCoP
expand()42002f64067SYang Keao   void expand() {
421c2774a54SMandeep Singh Grang     SmallVector<ScopArrayInfo *, 4> CurrentSAI(S.arrays().begin(),
42281fb6b3eSAndreas Simbuerger                                                S.arrays().end());
42381fb6b3eSAndreas Simbuerger     for (auto SAI : CurrentSAI) {
42481fb6b3eSAndreas Simbuerger       SmallPtrSet<MemoryAccess *, 4> AllWrites;
42581fb6b3eSAndreas Simbuerger       SmallPtrSet<MemoryAccess *, 4> AllReads;
42602f64067SYang Keao       if (!isExpandable(SAI, AllWrites, AllReads, S))
42781fb6b3eSAndreas Simbuerger         continue;
42881fb6b3eSAndreas Simbuerger 
429e478e2deSAndreas Simbuerger       if (SAI->isValueKind() || SAI->isArrayKind()) {
430e478e2deSAndreas Simbuerger         assert(AllWrites.size() == 1 || SAI->isValueKind());
43181fb6b3eSAndreas Simbuerger 
43281fb6b3eSAndreas Simbuerger         auto TheWrite = *(AllWrites.begin());
43302f64067SYang Keao         ScopArrayInfo *ExpandedArray = expandAccess(TheWrite);
43481fb6b3eSAndreas Simbuerger 
43502f64067SYang Keao         mapAccess(AllReads, Dependences, ExpandedArray, true);
436e478e2deSAndreas Simbuerger       } else if (SAI->isPHIKind()) {
437e478e2deSAndreas Simbuerger         expandPhi(S, SAI, Dependences);
438e478e2deSAndreas Simbuerger       }
43981fb6b3eSAndreas Simbuerger     }
44002f64067SYang Keao   }
44102f64067SYang Keao 
44202f64067SYang Keao   /// Dump the internal information about a performed MSE to @p OS.
print(llvm::raw_ostream & OS)44302f64067SYang Keao   void print(llvm::raw_ostream &OS) {
44402f64067SYang Keao     OS << "After arrays {\n";
44502f64067SYang Keao 
44602f64067SYang Keao     for (auto &Array : S.arrays())
44702f64067SYang Keao       Array->print(OS);
44802f64067SYang Keao 
44902f64067SYang Keao     OS << "}\n";
45002f64067SYang Keao 
45102f64067SYang Keao     OS << "After accesses {\n";
45202f64067SYang Keao     for (auto &Stmt : S) {
45302f64067SYang Keao       OS.indent(4) << Stmt.getBaseName() << "{\n";
45402f64067SYang Keao       for (auto *MA : Stmt)
45502f64067SYang Keao         MA->print(OS);
45602f64067SYang Keao       OS.indent(4) << "}\n";
45702f64067SYang Keao     }
45802f64067SYang Keao     OS << "}\n";
45902f64067SYang Keao   }
46002f64067SYang Keao };
46102f64067SYang Keao 
46202f64067SYang Keao static std::unique_ptr<MaximalStaticExpansionImpl>
runMaximalStaticExpansion(Scop & S,OptimizationRemarkEmitter & ORE,const Dependences & D)46302f64067SYang Keao runMaximalStaticExpansion(Scop &S, OptimizationRemarkEmitter &ORE,
46402f64067SYang Keao                           const Dependences &D) {
46502f64067SYang Keao   auto Dependences = D.getDependences(Dependences::TYPE_RAW);
46602f64067SYang Keao 
46702f64067SYang Keao   std::unique_ptr<MaximalStaticExpansionImpl> Impl =
46802f64067SYang Keao       std::make_unique<MaximalStaticExpansionImpl>(S, Dependences, ORE);
46902f64067SYang Keao 
47002f64067SYang Keao   Impl->expand();
47102f64067SYang Keao   return Impl;
47202f64067SYang Keao }
47302f64067SYang Keao 
runMSEUsingNPM(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,raw_ostream * OS)47402f64067SYang Keao static PreservedAnalyses runMSEUsingNPM(Scop &S, ScopAnalysisManager &SAM,
47502f64067SYang Keao                                         ScopStandardAnalysisResults &SAR,
47602f64067SYang Keao                                         raw_ostream *OS) {
47702f64067SYang Keao   OptimizationRemarkEmitter ORE(&S.getFunction());
47802f64067SYang Keao 
47902f64067SYang Keao   auto &DI = SAM.getResult<DependenceAnalysis>(S, SAR);
48002f64067SYang Keao   auto &D = DI.getDependences(Dependences::AL_Reference);
48102f64067SYang Keao 
48202f64067SYang Keao   std::unique_ptr<MaximalStaticExpansionImpl> Impl =
48302f64067SYang Keao       runMaximalStaticExpansion(S, ORE, D);
48402f64067SYang Keao 
48502f64067SYang Keao   if (OS) {
48602f64067SYang Keao     *OS << "Printing analysis 'Polly - Maximal static expansion of SCoP' for "
48702f64067SYang Keao            "region: '"
48802f64067SYang Keao         << S.getName() << "' in function '" << S.getFunction().getName()
48902f64067SYang Keao         << "':\n";
49002f64067SYang Keao 
49102f64067SYang Keao     if (Impl) {
49202f64067SYang Keao       *OS << "MSE result:\n";
49302f64067SYang Keao       Impl->print(*OS);
49402f64067SYang Keao     }
49502f64067SYang Keao   }
49602f64067SYang Keao 
49702f64067SYang Keao   return PreservedAnalyses::all();
49802f64067SYang Keao }
49902f64067SYang Keao 
50002f64067SYang Keao } // namespace
50102f64067SYang Keao 
50202f64067SYang Keao PreservedAnalyses
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater &)50302f64067SYang Keao MaximalStaticExpansionPass::run(Scop &S, ScopAnalysisManager &SAM,
50402f64067SYang Keao                                 ScopStandardAnalysisResults &SAR,
50502f64067SYang Keao                                 SPMUpdater &) {
50602f64067SYang Keao   return runMSEUsingNPM(S, SAM, SAR, nullptr);
50702f64067SYang Keao }
50802f64067SYang Keao 
50902f64067SYang Keao PreservedAnalyses
run(Scop & S,ScopAnalysisManager & SAM,ScopStandardAnalysisResults & SAR,SPMUpdater &)51002f64067SYang Keao MaximalStaticExpansionPrinterPass::run(Scop &S, ScopAnalysisManager &SAM,
51102f64067SYang Keao                                        ScopStandardAnalysisResults &SAR,
51202f64067SYang Keao                                        SPMUpdater &) {
51302f64067SYang Keao   return runMSEUsingNPM(S, SAM, SAR, &OS);
51402f64067SYang Keao }
51502f64067SYang Keao 
51602f64067SYang Keao char MaximalStaticExpanderWrapperPass::ID = 0;
51702f64067SYang Keao 
runOnScop(Scop & S)51802f64067SYang Keao bool MaximalStaticExpanderWrapperPass::runOnScop(Scop &S) {
51902f64067SYang Keao   // Get the ORE from OptimizationRemarkEmitterWrapperPass.
52002f64067SYang Keao   OptimizationRemarkEmitter *ORE =
52102f64067SYang Keao       &getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
52202f64067SYang Keao 
52302f64067SYang Keao   // Get the RAW Dependences.
52402f64067SYang Keao   auto &DI = getAnalysis<DependenceInfo>();
52502f64067SYang Keao   auto &D = DI.getDependences(Dependences::AL_Reference);
52602f64067SYang Keao 
52702f64067SYang Keao   std::unique_ptr<MaximalStaticExpansionImpl> Impl =
52802f64067SYang Keao       runMaximalStaticExpansion(S, *ORE, D);
52981fb6b3eSAndreas Simbuerger 
53081fb6b3eSAndreas Simbuerger   return false;
53181fb6b3eSAndreas Simbuerger }
53281fb6b3eSAndreas Simbuerger 
printScop(raw_ostream & OS,Scop & S) const53302f64067SYang Keao void MaximalStaticExpanderWrapperPass::printScop(raw_ostream &OS,
53402f64067SYang Keao                                                  Scop &S) const {
53581fb6b3eSAndreas Simbuerger   S.print(OS, false);
53681fb6b3eSAndreas Simbuerger }
53781fb6b3eSAndreas Simbuerger 
getAnalysisUsage(AnalysisUsage & AU) const53802f64067SYang Keao void MaximalStaticExpanderWrapperPass::getAnalysisUsage(
53902f64067SYang Keao     AnalysisUsage &AU) const {
54081fb6b3eSAndreas Simbuerger   ScopPass::getAnalysisUsage(AU);
54181fb6b3eSAndreas Simbuerger   AU.addRequired<DependenceInfo>();
54281fb6b3eSAndreas Simbuerger   AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
54381fb6b3eSAndreas Simbuerger }
54481fb6b3eSAndreas Simbuerger 
createMaximalStaticExpansionPass()54581fb6b3eSAndreas Simbuerger Pass *polly::createMaximalStaticExpansionPass() {
54602f64067SYang Keao   return new MaximalStaticExpanderWrapperPass();
54781fb6b3eSAndreas Simbuerger }
54881fb6b3eSAndreas Simbuerger 
54902f64067SYang Keao INITIALIZE_PASS_BEGIN(MaximalStaticExpanderWrapperPass, "polly-mse",
55081fb6b3eSAndreas Simbuerger                       "Polly - Maximal static expansion of SCoP", false, false);
55181fb6b3eSAndreas Simbuerger INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
55281fb6b3eSAndreas Simbuerger INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass);
55302f64067SYang Keao INITIALIZE_PASS_END(MaximalStaticExpanderWrapperPass, "polly-mse",
55481fb6b3eSAndreas Simbuerger                     "Polly - Maximal static expansion of SCoP", false, false)
555