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