19#include "llvm/ADT/SmallPtrSet.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Analysis/OptimizationRemarkEmitter.h"
32#define DEBUG_TYPE "polly-mse"
37 PollyPrintMSE(
"polly-print-mse",
38 cl::desc(
"Polly - Print Maximal static expansion of SCoP"),
45static bool isDimBoundedByConstant(
isl::set Set,
unsigned dim) {
56class MaximalStaticExpansionImpl {
57 OptimizationRemarkEmitter &ORE;
62 void emitRemark(StringRef Msg, Instruction *Inst) {
63 ORE.emit(OptimizationRemarkAnalysis(
DEBUG_TYPE,
"ExpansionRejection", Inst)
88 Map.get_space().domain().unwrap().range().get_tuple_id(
isl::dim::set);
97 auto NewMap = Map.factor_domain();
98 auto NewMapDomainId = NewMap.domain().get_tuple_id();
100 if (AccessDomainId.get() != NewMapDomainId.get())
104 MapDependences = MapDependences.
unite(NewMap);
107 return MapDependences;
118 SmallPtrSetImpl<MemoryAccess *> &Writes,
119 SmallPtrSetImpl<MemoryAccess *> &Reads,
Scop &
S) {
121 Writes.insert(
S.getValueDef(SAI));
122 Reads.insert_range(
S.getValueUses(SAI));
125 auto Read =
S.getPHIRead(SAI);
127 auto StmtDomain =
isl::union_set(Read->getStatement()->getDomain());
129 auto Writes =
S.getPHIIncomings(SAI);
134 for (
auto Write : Writes) {
135 auto MapDeps = filterDependences(
Dependences, Write);
136 for (
isl::map Map : MapDeps.get_map_list())
137 WriteDomain = WriteDomain.unite(Map.range());
141 if (!StmtDomain.is_equal(WriteDomain)) {
142 emitRemark(SAI->
getName() +
" read from its original value.",
143 Read->getAccessInstruction());
150 emitRemark(SAI->
getName() +
" is a ExitPhi node.",
151 &*
S.getEnteringBlock()->getFirstNonPHIIt());
155 int NumberWrites = 0;
170 if (!StmtWrites.is_disjoint(AccRel)) {
171 emitRemark(SAI->
getName() +
" has read after write to the same "
172 "element in same statement. The "
173 "dependences found during analysis may "
174 "be wrong because Polly is not able to "
175 "handle such case for now.",
180 StmtReads = StmtReads.unite(AccRel);
182 StmtWrites = StmtWrites.unite(AccRel);
187 emitRemark(SAI->
getName() +
" has a maywrite access.",
196 if (NumberWrites > 1) {
197 emitRemark(SAI->
getName() +
" has more than 1 write access.",
206 auto StmtDomain = Stmt.getDomain();
213 auto MapDependences = filterDependences(
Dependences.reverse(), MA);
216 if (NumberElementMap == 0) {
217 emitRemark(
"The expansion of " + SAI->
getName() +
218 " would lead to a read from the original array.",
223 auto DepsDomain = MapDependences.domain();
227 if (NumberElementMap != 1) {
229 " has too many dependences to be handle for now.",
234 auto DepsDomainSet =
isl::set(DepsDomain);
237 if (!StmtDomain.is_subset(DepsDomainSet)) {
238 emitRemark(
"The expansion of " + SAI->
getName() +
239 " would lead to a read from the original array.",
250 if (NumberWrites == 0) {
251 emitRemark(SAI->
getName() +
" has 0 write access.",
252 &*
S.getEnteringBlock()->getFirstNonPHIIt());
268 void mapAccess(SmallPtrSetImpl<MemoryAccess *> &Accesses,
271 for (
auto MA : Accesses) {
288 "There are more than one RAW dependencies in the union map.");
309 unsigned in_dimensions =
313 auto Domain = CurrentAccessMap.domain();
319 NewAccessMap = NewAccessMap.add_dims(
isl::dim::out, in_dimensions);
326 auto CurrentOutId = CurrentAccessMap.get_tuple_id(
isl::dim::out);
327 std::string CurrentOutIdString =
331 NewAccessMap = NewAccessMap.set_tuple_id(
isl::dim::out, CurrentOutId);
334 std::vector<unsigned> Sizes;
335 for (
unsigned i = 0; i < in_dimensions; i++) {
336 assert(isDimBoundedByConstant(CurrentStmtDomain, i) &&
337 "Domain boundary are not constant.");
338 auto UpperBound =
getConstant(CurrentStmtDomain.dim_max(i),
true,
false);
339 assert(!UpperBound.is_null() && UpperBound.is_pos() &&
340 !UpperBound.is_nan() &&
341 "The upper bound is not a positive integer.");
343 std::numeric_limits<int>::max() - 1)) &&
344 "The upper bound overflow a int.");
345 Sizes.push_back(UpperBound.get_num_si() + 1);
353 S.createScopArrayInfo(ElementType, CurrentOutIdString, Sizes);
360 NewAccessMap = NewAccessMap.set_tuple_id(
isl::dim::out, NewOutId);
363 auto SpaceMap = NewAccessMap.get_space();
366 NewAccessMap =
isl::map(ConstraintBasicMap);
381 SmallPtrSet<MemoryAccess *, 4> Writes(llvm::from_range,
382 S.getPHIIncomings(SAI));
383 auto Read =
S.getPHIRead(SAI);
384 auto ExpandedSAI = expandAccess(Read);
386 mapAccess(Writes,
Dependences, ExpandedSAI,
false);
391 OptimizationRemarkEmitter &ORE)
399 SmallVector<ScopArrayInfo *, 4> CurrentSAI(
S.arrays().begin(),
401 for (
auto SAI : CurrentSAI) {
402 SmallPtrSet<MemoryAccess *, 4> AllWrites;
403 SmallPtrSet<MemoryAccess *, 4> AllReads;
404 if (!isExpandable(SAI, AllWrites, AllReads,
S))
410 auto TheWrite = *(AllWrites.begin());
413 mapAccess(AllReads,
Dependences, ExpandedArray,
true);
421 void print(llvm::raw_ostream &OS) {
422 OS <<
"After arrays {\n";
424 for (
auto &
Array :
S.arrays())
429 OS <<
"After accesses {\n";
430 for (
auto &Stmt :
S) {
431 OS.indent(4) << Stmt.getBaseName() <<
"{\n";
432 for (
auto *MA : Stmt)
434 OS.indent(4) <<
"}\n";
440static std::unique_ptr<MaximalStaticExpansionImpl>
441runMaximalStaticExpansionImpl(
Scop &
S, OptimizationRemarkEmitter &ORE,
445 std::unique_ptr<MaximalStaticExpansionImpl> Impl =
446 std::make_unique<MaximalStaticExpansionImpl>(
S,
Dependences, ORE);
454 OptimizationRemarkEmitter ORE(&
S.getFunction());
458 std::unique_ptr<MaximalStaticExpansionImpl> Impl =
459 runMaximalStaticExpansionImpl(
S, ORE, D);
463 <<
"Printing analysis 'Polly - Maximal static expansion of SCoP' for "
465 <<
S.getName() <<
"' in function '" <<
S.getFunction().getName()
469 outs() <<
"MSE result:\n";
470 Impl->print(llvm::outs());
llvm::cl::OptionCategory PollyCategory
static isl::basic_map equal(isl::space space, unsigned int n_equal)
static isl::map from_union_map(isl::union_map umap)
static isl::map from_domain(isl::set set)
isl::set project_out(isl::dim type, unsigned int first, unsigned int n) const
isl::id get_tuple_id() const
boolean is_bounded() const
class size tuple_dim() const
class size dim(isl::dim type) const
std::string get_tuple_name() const
isl::union_map unite(isl::union_map umap2) const
__isl_keep isl_union_map * get() const
static isl::union_map empty(isl::ctx ctx)
static isl::union_set empty(isl::ctx ctx)
The accumulated dependence information for a SCoP.
isl::union_map getDependences(int Kinds) const
Get the dependences of type Kinds.
Represent memory accesses in statements.
const ScopArrayInfo * getLatestScopArrayInfo() const
Get the ScopArrayInfo object for the base address, or the one set by setNewAccessRelation().
Instruction * getAccessInstruction() const
Return the access instruction of this memory access.
bool isRead() const
Is this a read memory access?
bool isMustWrite() const
Is this a must-write memory access?
void print(raw_ostream &OS) const
Print the MemoryAccess.
const ScopArrayInfo * getScopArrayInfo() const
Legacy name of getOriginalScopArrayInfo().
ScopStmt * getStatement() const
Get the statement that contains this memory access.
bool isMayWrite() const
Is this a may-write memory access?
isl::map getAccessRelation() const
Old name of getLatestAccessRelation().
void setNewAccessRelation(isl::map NewAccessRelation)
Set the updated access relation read from JSCOP file.
A class to store information about arrays in the SCoP.
bool isExitPHIKind() const
Is this array info modeling an MemoryKind::ExitPHI?
bool isArrayKind() const
Is this array info modeling an array?
bool isValueKind() const
Is this array info modeling an llvm::Value?
void setIsOnHeap(bool value)
std::string getName() const
Get the name of this memory reference.
bool isPHIKind() const
Is this array info modeling special PHI node memory?
isl::id getBasePtrId() const
Return the isl id for the base pointer.
Type * getElementType() const
Get the canonical element type of this array.
isl::set getDomain() const
Get the iteration domain of this ScopStmt.
static __isl_give isl_poly * expand(__isl_take isl_poly *poly, int *exp, int first)
@ Array
MemoryKind::Array: Models a one or multi-dimensional array.
isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min)
If PwAff maps to a constant, return said constant.
void runMaximalStaticExpansion(Scop &S, DependenceAnalysis::Result &DI)
const Dependences & getDependences(Dependences::AnalysisLevel Level)
Return the dependence information for the current SCoP.
static TupleKindPtr Domain("Domain")
isl_size isl_union_map_n_map(__isl_keep isl_union_map *umap)