1 //===- ScopInfo.cpp -------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Create a polyhedral description for a static control flow region.
10 //
11 // The pass creates a polyhedral description of the Scops detected by the Scop
12 // detection derived from their LLVM-IR code.
13 //
14 // This representation is shared among several tools in the polyhedral
15 // community, which are e.g. Cloog, Pluto, Loopo, Graphite.
16 //
17 //===----------------------------------------------------------------------===//
18
19 #include "polly/ScopInfo.h"
20 #include "polly/LinkAllPasses.h"
21 #include "polly/Options.h"
22 #include "polly/ScopBuilder.h"
23 #include "polly/ScopDetection.h"
24 #include "polly/Support/GICHelper.h"
25 #include "polly/Support/ISLOStream.h"
26 #include "polly/Support/ISLTools.h"
27 #include "polly/Support/SCEVAffinator.h"
28 #include "polly/Support/SCEVValidator.h"
29 #include "polly/Support/ScopHelper.h"
30 #include "llvm/ADT/APInt.h"
31 #include "llvm/ADT/ArrayRef.h"
32 #include "llvm/ADT/PostOrderIterator.h"
33 #include "llvm/ADT/Sequence.h"
34 #include "llvm/ADT/SmallPtrSet.h"
35 #include "llvm/ADT/SmallSet.h"
36 #include "llvm/ADT/Statistic.h"
37 #include "llvm/Analysis/AliasAnalysis.h"
38 #include "llvm/Analysis/AssumptionCache.h"
39 #include "llvm/Analysis/Loads.h"
40 #include "llvm/Analysis/LoopInfo.h"
41 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
42 #include "llvm/Analysis/RegionInfo.h"
43 #include "llvm/Analysis/RegionIterator.h"
44 #include "llvm/Analysis/ScalarEvolution.h"
45 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
46 #include "llvm/IR/BasicBlock.h"
47 #include "llvm/IR/ConstantRange.h"
48 #include "llvm/IR/DataLayout.h"
49 #include "llvm/IR/DebugLoc.h"
50 #include "llvm/IR/Dominators.h"
51 #include "llvm/IR/Function.h"
52 #include "llvm/IR/InstrTypes.h"
53 #include "llvm/IR/Instruction.h"
54 #include "llvm/IR/Instructions.h"
55 #include "llvm/IR/Module.h"
56 #include "llvm/IR/PassManager.h"
57 #include "llvm/IR/Type.h"
58 #include "llvm/IR/Value.h"
59 #include "llvm/InitializePasses.h"
60 #include "llvm/Support/Compiler.h"
61 #include "llvm/Support/Debug.h"
62 #include "llvm/Support/ErrorHandling.h"
63 #include "llvm/Support/raw_ostream.h"
64 #include "isl/aff.h"
65 #include "isl/local_space.h"
66 #include "isl/map.h"
67 #include "isl/options.h"
68 #include "isl/set.h"
69 #include <cassert>
70
71 using namespace llvm;
72 using namespace polly;
73
74 #define DEBUG_TYPE "polly-scops"
75
76 STATISTIC(AssumptionsAliasing, "Number of aliasing assumptions taken.");
77 STATISTIC(AssumptionsInbounds, "Number of inbounds assumptions taken.");
78 STATISTIC(AssumptionsWrapping, "Number of wrapping assumptions taken.");
79 STATISTIC(AssumptionsUnsigned, "Number of unsigned assumptions taken.");
80 STATISTIC(AssumptionsComplexity, "Number of too complex SCoPs.");
81 STATISTIC(AssumptionsUnprofitable, "Number of unprofitable SCoPs.");
82 STATISTIC(AssumptionsErrorBlock, "Number of error block assumptions taken.");
83 STATISTIC(AssumptionsInfiniteLoop, "Number of bounded loop assumptions taken.");
84 STATISTIC(AssumptionsInvariantLoad,
85 "Number of invariant loads assumptions taken.");
86 STATISTIC(AssumptionsDelinearization,
87 "Number of delinearization assumptions taken.");
88
89 STATISTIC(NumScops, "Number of feasible SCoPs after ScopInfo");
90 STATISTIC(NumLoopsInScop, "Number of loops in scops");
91 STATISTIC(NumBoxedLoops, "Number of boxed loops in SCoPs after ScopInfo");
92 STATISTIC(NumAffineLoops, "Number of affine loops in SCoPs after ScopInfo");
93
94 STATISTIC(NumScopsDepthZero, "Number of scops with maximal loop depth 0");
95 STATISTIC(NumScopsDepthOne, "Number of scops with maximal loop depth 1");
96 STATISTIC(NumScopsDepthTwo, "Number of scops with maximal loop depth 2");
97 STATISTIC(NumScopsDepthThree, "Number of scops with maximal loop depth 3");
98 STATISTIC(NumScopsDepthFour, "Number of scops with maximal loop depth 4");
99 STATISTIC(NumScopsDepthFive, "Number of scops with maximal loop depth 5");
100 STATISTIC(NumScopsDepthLarger,
101 "Number of scops with maximal loop depth 6 and larger");
102 STATISTIC(MaxNumLoopsInScop, "Maximal number of loops in scops");
103
104 STATISTIC(NumValueWrites, "Number of scalar value writes after ScopInfo");
105 STATISTIC(
106 NumValueWritesInLoops,
107 "Number of scalar value writes nested in affine loops after ScopInfo");
108 STATISTIC(NumPHIWrites, "Number of scalar phi writes after ScopInfo");
109 STATISTIC(NumPHIWritesInLoops,
110 "Number of scalar phi writes nested in affine loops after ScopInfo");
111 STATISTIC(NumSingletonWrites, "Number of singleton writes after ScopInfo");
112 STATISTIC(NumSingletonWritesInLoops,
113 "Number of singleton writes nested in affine loops after ScopInfo");
114
115 unsigned const polly::MaxDisjunctsInDomain = 20;
116
117 // The number of disjunct in the context after which we stop to add more
118 // disjuncts. This parameter is there to avoid exponential growth in the
119 // number of disjunct when adding non-convex sets to the context.
120 static int const MaxDisjunctsInContext = 4;
121
122 // Be a bit more generous for the defined behavior context which is used less
123 // often.
124 static int const MaxDisjunktsInDefinedBehaviourContext = 8;
125
126 static cl::opt<bool> PollyRemarksMinimal(
127 "polly-remarks-minimal",
128 cl::desc("Do not emit remarks about assumptions that are known"),
129 cl::Hidden, cl::cat(PollyCategory));
130
131 static cl::opt<bool>
132 IslOnErrorAbort("polly-on-isl-error-abort",
133 cl::desc("Abort if an isl error is encountered"),
134 cl::init(true), cl::cat(PollyCategory));
135
136 static cl::opt<bool> PollyPreciseInbounds(
137 "polly-precise-inbounds",
138 cl::desc("Take more precise inbounds assumptions (do not scale well)"),
139 cl::Hidden, cl::init(false), cl::cat(PollyCategory));
140
141 static cl::opt<bool> PollyIgnoreParamBounds(
142 "polly-ignore-parameter-bounds",
143 cl::desc(
144 "Do not add parameter bounds and do no gist simplify sets accordingly"),
145 cl::Hidden, cl::init(false), cl::cat(PollyCategory));
146
147 static cl::opt<bool> PollyPreciseFoldAccesses(
148 "polly-precise-fold-accesses",
149 cl::desc("Fold memory accesses to model more possible delinearizations "
150 "(does not scale well)"),
151 cl::Hidden, cl::init(false), cl::cat(PollyCategory));
152
153 bool polly::UseInstructionNames;
154
155 static cl::opt<bool, true> XUseInstructionNames(
156 "polly-use-llvm-names",
157 cl::desc("Use LLVM-IR names when deriving statement names"),
158 cl::location(UseInstructionNames), cl::Hidden, cl::cat(PollyCategory));
159
160 static cl::opt<bool> PollyPrintInstructions(
161 "polly-print-instructions", cl::desc("Output instructions per ScopStmt"),
162 cl::Hidden, cl::Optional, cl::init(false), cl::cat(PollyCategory));
163
164 static cl::list<std::string> IslArgs("polly-isl-arg",
165 cl::value_desc("argument"),
166 cl::desc("Option passed to ISL"),
167 cl::cat(PollyCategory));
168
169 //===----------------------------------------------------------------------===//
170
addRangeBoundsToSet(isl::set S,const ConstantRange & Range,int dim,isl::dim type)171 static isl::set addRangeBoundsToSet(isl::set S, const ConstantRange &Range,
172 int dim, isl::dim type) {
173 isl::val V;
174 isl::ctx Ctx = S.ctx();
175
176 // The upper and lower bound for a parameter value is derived either from
177 // the data type of the parameter or from the - possibly more restrictive -
178 // range metadata.
179 V = valFromAPInt(Ctx.get(), Range.getSignedMin(), true);
180 S = S.lower_bound_val(type, dim, V);
181 V = valFromAPInt(Ctx.get(), Range.getSignedMax(), true);
182 S = S.upper_bound_val(type, dim, V);
183
184 if (Range.isFullSet())
185 return S;
186
187 if (S.n_basic_set().release() > MaxDisjunctsInContext)
188 return S;
189
190 // In case of signed wrapping, we can refine the set of valid values by
191 // excluding the part not covered by the wrapping range.
192 if (Range.isSignWrappedSet()) {
193 V = valFromAPInt(Ctx.get(), Range.getLower(), true);
194 isl::set SLB = S.lower_bound_val(type, dim, V);
195
196 V = valFromAPInt(Ctx.get(), Range.getUpper(), true);
197 V = V.sub(1);
198 isl::set SUB = S.upper_bound_val(type, dim, V);
199 S = SLB.unite(SUB);
200 }
201
202 return S;
203 }
204
identifyBasePtrOriginSAI(Scop * S,Value * BasePtr)205 static const ScopArrayInfo *identifyBasePtrOriginSAI(Scop *S, Value *BasePtr) {
206 LoadInst *BasePtrLI = dyn_cast<LoadInst>(BasePtr);
207 if (!BasePtrLI)
208 return nullptr;
209
210 if (!S->contains(BasePtrLI))
211 return nullptr;
212
213 ScalarEvolution &SE = *S->getSE();
214
215 auto *OriginBaseSCEV =
216 SE.getPointerBase(SE.getSCEV(BasePtrLI->getPointerOperand()));
217 if (!OriginBaseSCEV)
218 return nullptr;
219
220 auto *OriginBaseSCEVUnknown = dyn_cast<SCEVUnknown>(OriginBaseSCEV);
221 if (!OriginBaseSCEVUnknown)
222 return nullptr;
223
224 return S->getScopArrayInfo(OriginBaseSCEVUnknown->getValue(),
225 MemoryKind::Array);
226 }
227
ScopArrayInfo(Value * BasePtr,Type * ElementType,isl::ctx Ctx,ArrayRef<const SCEV * > Sizes,MemoryKind Kind,const DataLayout & DL,Scop * S,const char * BaseName)228 ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl::ctx Ctx,
229 ArrayRef<const SCEV *> Sizes, MemoryKind Kind,
230 const DataLayout &DL, Scop *S,
231 const char *BaseName)
232 : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) {
233 std::string BasePtrName =
234 BaseName ? BaseName
235 : getIslCompatibleName("MemRef", BasePtr, S->getNextArrayIdx(),
236 Kind == MemoryKind::PHI ? "__phi" : "",
237 UseInstructionNames);
238 Id = isl::id::alloc(Ctx, BasePtrName, this);
239
240 updateSizes(Sizes);
241
242 if (!BasePtr || Kind != MemoryKind::Array) {
243 BasePtrOriginSAI = nullptr;
244 return;
245 }
246
247 BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr);
248 if (BasePtrOriginSAI)
249 const_cast<ScopArrayInfo *>(BasePtrOriginSAI)->addDerivedSAI(this);
250 }
251
252 ScopArrayInfo::~ScopArrayInfo() = default;
253
getSpace() const254 isl::space ScopArrayInfo::getSpace() const {
255 auto Space = isl::space(Id.ctx(), 0, getNumberOfDimensions());
256 Space = Space.set_tuple_id(isl::dim::set, Id);
257 return Space;
258 }
259
isReadOnly()260 bool ScopArrayInfo::isReadOnly() {
261 isl::union_set WriteSet = S.getWrites().range();
262 isl::space Space = getSpace();
263 WriteSet = WriteSet.extract_set(Space);
264
265 return bool(WriteSet.is_empty());
266 }
267
isCompatibleWith(const ScopArrayInfo * Array) const268 bool ScopArrayInfo::isCompatibleWith(const ScopArrayInfo *Array) const {
269 if (Array->getElementType() != getElementType())
270 return false;
271
272 if (Array->getNumberOfDimensions() != getNumberOfDimensions())
273 return false;
274
275 for (unsigned i = 0; i < getNumberOfDimensions(); i++)
276 if (Array->getDimensionSize(i) != getDimensionSize(i))
277 return false;
278
279 return true;
280 }
281
updateElementType(Type * NewElementType)282 void ScopArrayInfo::updateElementType(Type *NewElementType) {
283 if (NewElementType == ElementType)
284 return;
285
286 auto OldElementSize = DL.getTypeAllocSizeInBits(ElementType);
287 auto NewElementSize = DL.getTypeAllocSizeInBits(NewElementType);
288
289 if (NewElementSize == OldElementSize || NewElementSize == 0)
290 return;
291
292 if (NewElementSize % OldElementSize == 0 && NewElementSize < OldElementSize) {
293 ElementType = NewElementType;
294 } else {
295 auto GCD = GreatestCommonDivisor64(NewElementSize, OldElementSize);
296 ElementType = IntegerType::get(ElementType->getContext(), GCD);
297 }
298 }
299
updateSizes(ArrayRef<const SCEV * > NewSizes,bool CheckConsistency)300 bool ScopArrayInfo::updateSizes(ArrayRef<const SCEV *> NewSizes,
301 bool CheckConsistency) {
302 int SharedDims = std::min(NewSizes.size(), DimensionSizes.size());
303 int ExtraDimsNew = NewSizes.size() - SharedDims;
304 int ExtraDimsOld = DimensionSizes.size() - SharedDims;
305
306 if (CheckConsistency) {
307 for (int i = 0; i < SharedDims; i++) {
308 auto *NewSize = NewSizes[i + ExtraDimsNew];
309 auto *KnownSize = DimensionSizes[i + ExtraDimsOld];
310 if (NewSize && KnownSize && NewSize != KnownSize)
311 return false;
312 }
313
314 if (DimensionSizes.size() >= NewSizes.size())
315 return true;
316 }
317
318 DimensionSizes.clear();
319 DimensionSizes.insert(DimensionSizes.begin(), NewSizes.begin(),
320 NewSizes.end());
321 DimensionSizesPw.clear();
322 for (const SCEV *Expr : DimensionSizes) {
323 if (!Expr) {
324 DimensionSizesPw.push_back(isl::pw_aff());
325 continue;
326 }
327 isl::pw_aff Size = S.getPwAffOnly(Expr);
328 DimensionSizesPw.push_back(Size);
329 }
330 return true;
331 }
332
getName() const333 std::string ScopArrayInfo::getName() const { return Id.get_name(); }
334
getElemSizeInBytes() const335 int ScopArrayInfo::getElemSizeInBytes() const {
336 return DL.getTypeAllocSize(ElementType);
337 }
338
getBasePtrId() const339 isl::id ScopArrayInfo::getBasePtrId() const { return Id; }
340
341 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const342 LLVM_DUMP_METHOD void ScopArrayInfo::dump() const { print(errs()); }
343 #endif
344
print(raw_ostream & OS,bool SizeAsPwAff) const345 void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const {
346 OS.indent(8) << *getElementType() << " " << getName();
347 unsigned u = 0;
348
349 if (getNumberOfDimensions() > 0 && !getDimensionSize(0)) {
350 OS << "[*]";
351 u++;
352 }
353 for (; u < getNumberOfDimensions(); u++) {
354 OS << "[";
355
356 if (SizeAsPwAff) {
357 isl::pw_aff Size = getDimensionSizePw(u);
358 OS << " " << Size << " ";
359 } else {
360 OS << *getDimensionSize(u);
361 }
362
363 OS << "]";
364 }
365
366 OS << ";";
367
368 if (BasePtrOriginSAI)
369 OS << " [BasePtrOrigin: " << BasePtrOriginSAI->getName() << "]";
370
371 OS << " // Element size " << getElemSizeInBytes() << "\n";
372 }
373
374 const ScopArrayInfo *
getFromAccessFunction(isl::pw_multi_aff PMA)375 ScopArrayInfo::getFromAccessFunction(isl::pw_multi_aff PMA) {
376 isl::id Id = PMA.get_tuple_id(isl::dim::out);
377 assert(!Id.is_null() && "Output dimension didn't have an ID");
378 return getFromId(Id);
379 }
380
getFromId(isl::id Id)381 const ScopArrayInfo *ScopArrayInfo::getFromId(isl::id Id) {
382 void *User = Id.get_user();
383 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
384 return SAI;
385 }
386
wrapConstantDimensions()387 void MemoryAccess::wrapConstantDimensions() {
388 auto *SAI = getScopArrayInfo();
389 isl::space ArraySpace = SAI->getSpace();
390 isl::ctx Ctx = ArraySpace.ctx();
391 unsigned DimsArray = SAI->getNumberOfDimensions();
392
393 isl::multi_aff DivModAff = isl::multi_aff::identity(
394 ArraySpace.map_from_domain_and_range(ArraySpace));
395 isl::local_space LArraySpace = isl::local_space(ArraySpace);
396
397 // Begin with last dimension, to iteratively carry into higher dimensions.
398 for (int i = DimsArray - 1; i > 0; i--) {
399 auto *DimSize = SAI->getDimensionSize(i);
400 auto *DimSizeCst = dyn_cast<SCEVConstant>(DimSize);
401
402 // This transformation is not applicable to dimensions with dynamic size.
403 if (!DimSizeCst)
404 continue;
405
406 // This transformation is not applicable to dimensions of size zero.
407 if (DimSize->isZero())
408 continue;
409
410 isl::val DimSizeVal =
411 valFromAPInt(Ctx.get(), DimSizeCst->getAPInt(), false);
412 isl::aff Var = isl::aff::var_on_domain(LArraySpace, isl::dim::set, i);
413 isl::aff PrevVar =
414 isl::aff::var_on_domain(LArraySpace, isl::dim::set, i - 1);
415
416 // Compute: index % size
417 // Modulo must apply in the divide of the previous iteration, if any.
418 isl::aff Modulo = Var.mod(DimSizeVal);
419 Modulo = Modulo.pullback(DivModAff);
420
421 // Compute: floor(index / size)
422 isl::aff Divide = Var.div(isl::aff(LArraySpace, DimSizeVal));
423 Divide = Divide.floor();
424 Divide = Divide.add(PrevVar);
425 Divide = Divide.pullback(DivModAff);
426
427 // Apply Modulo and Divide.
428 DivModAff = DivModAff.set_aff(i, Modulo);
429 DivModAff = DivModAff.set_aff(i - 1, Divide);
430 }
431
432 // Apply all modulo/divides on the accesses.
433 isl::map Relation = AccessRelation;
434 Relation = Relation.apply_range(isl::map::from_multi_aff(DivModAff));
435 Relation = Relation.detect_equalities();
436 AccessRelation = Relation;
437 }
438
updateDimensionality()439 void MemoryAccess::updateDimensionality() {
440 auto *SAI = getScopArrayInfo();
441 isl::space ArraySpace = SAI->getSpace();
442 isl::space AccessSpace = AccessRelation.get_space().range();
443 isl::ctx Ctx = ArraySpace.ctx();
444
445 unsigned DimsArray = unsignedFromIslSize(ArraySpace.dim(isl::dim::set));
446 unsigned DimsAccess = unsignedFromIslSize(AccessSpace.dim(isl::dim::set));
447 assert(DimsArray >= DimsAccess);
448 unsigned DimsMissing = DimsArray - DimsAccess;
449
450 auto *BB = getStatement()->getEntryBlock();
451 auto &DL = BB->getModule()->getDataLayout();
452 unsigned ArrayElemSize = SAI->getElemSizeInBytes();
453 unsigned ElemBytes = DL.getTypeAllocSize(getElementType());
454
455 isl::map Map = isl::map::from_domain_and_range(
456 isl::set::universe(AccessSpace), isl::set::universe(ArraySpace));
457
458 for (auto i : seq<unsigned>(0, DimsMissing))
459 Map = Map.fix_si(isl::dim::out, i, 0);
460
461 for (auto i : seq<unsigned>(DimsMissing, DimsArray))
462 Map = Map.equate(isl::dim::in, i - DimsMissing, isl::dim::out, i);
463
464 AccessRelation = AccessRelation.apply_range(Map);
465
466 // For the non delinearized arrays, divide the access function of the last
467 // subscript by the size of the elements in the array.
468 //
469 // A stride one array access in C expressed as A[i] is expressed in
470 // LLVM-IR as something like A[i * elementsize]. This hides the fact that
471 // two subsequent values of 'i' index two values that are stored next to
472 // each other in memory. By this division we make this characteristic
473 // obvious again. If the base pointer was accessed with offsets not divisible
474 // by the accesses element size, we will have chosen a smaller ArrayElemSize
475 // that divides the offsets of all accesses to this base pointer.
476 if (DimsAccess == 1) {
477 isl::val V = isl::val(Ctx, ArrayElemSize);
478 AccessRelation = AccessRelation.floordiv_val(V);
479 }
480
481 // We currently do this only if we added at least one dimension, which means
482 // some dimension's indices have not been specified, an indicator that some
483 // index values have been added together.
484 // TODO: Investigate general usefulness; Effect on unit tests is to make index
485 // expressions more complicated.
486 if (DimsMissing)
487 wrapConstantDimensions();
488
489 if (!isAffine())
490 computeBoundsOnAccessRelation(ArrayElemSize);
491
492 // Introduce multi-element accesses in case the type loaded by this memory
493 // access is larger than the canonical element type of the array.
494 //
495 // An access ((float *)A)[i] to an array char *A is modeled as
496 // {[i] -> A[o] : 4 i <= o <= 4 i + 3
497 if (ElemBytes > ArrayElemSize) {
498 assert(ElemBytes % ArrayElemSize == 0 &&
499 "Loaded element size should be multiple of canonical element size");
500 assert(DimsArray >= 1);
501 isl::map Map = isl::map::from_domain_and_range(
502 isl::set::universe(ArraySpace), isl::set::universe(ArraySpace));
503 for (auto i : seq<unsigned>(0, DimsArray - 1))
504 Map = Map.equate(isl::dim::in, i, isl::dim::out, i);
505
506 isl::constraint C;
507 isl::local_space LS;
508
509 LS = isl::local_space(Map.get_space());
510 int Num = ElemBytes / getScopArrayInfo()->getElemSizeInBytes();
511
512 C = isl::constraint::alloc_inequality(LS);
513 C = C.set_constant_val(isl::val(Ctx, Num - 1));
514 C = C.set_coefficient_si(isl::dim::in, DimsArray - 1, 1);
515 C = C.set_coefficient_si(isl::dim::out, DimsArray - 1, -1);
516 Map = Map.add_constraint(C);
517
518 C = isl::constraint::alloc_inequality(LS);
519 C = C.set_coefficient_si(isl::dim::in, DimsArray - 1, -1);
520 C = C.set_coefficient_si(isl::dim::out, DimsArray - 1, 1);
521 C = C.set_constant_val(isl::val(Ctx, 0));
522 Map = Map.add_constraint(C);
523 AccessRelation = AccessRelation.apply_range(Map);
524 }
525 }
526
527 const std::string
getReductionOperatorStr(MemoryAccess::ReductionType RT)528 MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) {
529 switch (RT) {
530 case MemoryAccess::RT_NONE:
531 llvm_unreachable("Requested a reduction operator string for a memory "
532 "access which isn't a reduction");
533 case MemoryAccess::RT_ADD:
534 return "+";
535 case MemoryAccess::RT_MUL:
536 return "*";
537 case MemoryAccess::RT_BOR:
538 return "|";
539 case MemoryAccess::RT_BXOR:
540 return "^";
541 case MemoryAccess::RT_BAND:
542 return "&";
543 }
544 llvm_unreachable("Unknown reduction type");
545 }
546
getOriginalScopArrayInfo() const547 const ScopArrayInfo *MemoryAccess::getOriginalScopArrayInfo() const {
548 isl::id ArrayId = getArrayId();
549 void *User = ArrayId.get_user();
550 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
551 return SAI;
552 }
553
getLatestScopArrayInfo() const554 const ScopArrayInfo *MemoryAccess::getLatestScopArrayInfo() const {
555 isl::id ArrayId = getLatestArrayId();
556 void *User = ArrayId.get_user();
557 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
558 return SAI;
559 }
560
getOriginalArrayId() const561 isl::id MemoryAccess::getOriginalArrayId() const {
562 return AccessRelation.get_tuple_id(isl::dim::out);
563 }
564
getLatestArrayId() const565 isl::id MemoryAccess::getLatestArrayId() const {
566 if (!hasNewAccessRelation())
567 return getOriginalArrayId();
568 return NewAccessRelation.get_tuple_id(isl::dim::out);
569 }
570
getAddressFunction() const571 isl::map MemoryAccess::getAddressFunction() const {
572 return getAccessRelation().lexmin();
573 }
574
575 isl::pw_multi_aff
applyScheduleToAccessRelation(isl::union_map USchedule) const576 MemoryAccess::applyScheduleToAccessRelation(isl::union_map USchedule) const {
577 isl::map Schedule, ScheduledAccRel;
578 isl::union_set UDomain;
579
580 UDomain = getStatement()->getDomain();
581 USchedule = USchedule.intersect_domain(UDomain);
582 Schedule = isl::map::from_union_map(USchedule);
583 ScheduledAccRel = getAddressFunction().apply_domain(Schedule);
584 return isl::pw_multi_aff::from_map(ScheduledAccRel);
585 }
586
getOriginalAccessRelation() const587 isl::map MemoryAccess::getOriginalAccessRelation() const {
588 return AccessRelation;
589 }
590
getOriginalAccessRelationStr() const591 std::string MemoryAccess::getOriginalAccessRelationStr() const {
592 return stringFromIslObj(AccessRelation);
593 }
594
getOriginalAccessRelationSpace() const595 isl::space MemoryAccess::getOriginalAccessRelationSpace() const {
596 return AccessRelation.get_space();
597 }
598
getNewAccessRelation() const599 isl::map MemoryAccess::getNewAccessRelation() const {
600 return NewAccessRelation;
601 }
602
getNewAccessRelationStr() const603 std::string MemoryAccess::getNewAccessRelationStr() const {
604 return stringFromIslObj(NewAccessRelation);
605 }
606
getAccessRelationStr() const607 std::string MemoryAccess::getAccessRelationStr() const {
608 return stringFromIslObj(getAccessRelation());
609 }
610
createBasicAccessMap(ScopStmt * Statement)611 isl::basic_map MemoryAccess::createBasicAccessMap(ScopStmt *Statement) {
612 isl::space Space = isl::space(Statement->getIslCtx(), 0, 1);
613 Space = Space.align_params(Statement->getDomainSpace());
614
615 return isl::basic_map::from_domain_and_range(
616 isl::basic_set::universe(Statement->getDomainSpace()),
617 isl::basic_set::universe(Space));
618 }
619
620 // Formalize no out-of-bound access assumption
621 //
622 // When delinearizing array accesses we optimistically assume that the
623 // delinearized accesses do not access out of bound locations (the subscript
624 // expression of each array evaluates for each statement instance that is
625 // executed to a value that is larger than zero and strictly smaller than the
626 // size of the corresponding dimension). The only exception is the outermost
627 // dimension for which we do not need to assume any upper bound. At this point
628 // we formalize this assumption to ensure that at code generation time the
629 // relevant run-time checks can be generated.
630 //
631 // To find the set of constraints necessary to avoid out of bound accesses, we
632 // first build the set of data locations that are not within array bounds. We
633 // then apply the reverse access relation to obtain the set of iterations that
634 // may contain invalid accesses and reduce this set of iterations to the ones
635 // that are actually executed by intersecting them with the domain of the
636 // statement. If we now project out all loop dimensions, we obtain a set of
637 // parameters that may cause statement instances to be executed that may
638 // possibly yield out of bound memory accesses. The complement of these
639 // constraints is the set of constraints that needs to be assumed to ensure such
640 // statement instances are never executed.
assumeNoOutOfBound()641 isl::set MemoryAccess::assumeNoOutOfBound() {
642 auto *SAI = getScopArrayInfo();
643 isl::space Space = getOriginalAccessRelationSpace().range();
644 isl::set Outside = isl::set::empty(Space);
645 for (int i = 1, Size = Space.dim(isl::dim::set).release(); i < Size; ++i) {
646 isl::local_space LS(Space);
647 isl::pw_aff Var = isl::pw_aff::var_on_domain(LS, isl::dim::set, i);
648 isl::pw_aff Zero = isl::pw_aff(LS);
649
650 isl::set DimOutside = Var.lt_set(Zero);
651 isl::pw_aff SizeE = SAI->getDimensionSizePw(i);
652 SizeE = SizeE.add_dims(isl::dim::in, Space.dim(isl::dim::set).release());
653 SizeE = SizeE.set_tuple_id(isl::dim::in, Space.get_tuple_id(isl::dim::set));
654 DimOutside = DimOutside.unite(SizeE.le_set(Var));
655
656 Outside = Outside.unite(DimOutside);
657 }
658
659 Outside = Outside.apply(getAccessRelation().reverse());
660 Outside = Outside.intersect(Statement->getDomain());
661 Outside = Outside.params();
662
663 // Remove divs to avoid the construction of overly complicated assumptions.
664 // Doing so increases the set of parameter combinations that are assumed to
665 // not appear. This is always save, but may make the resulting run-time check
666 // bail out more often than strictly necessary.
667 Outside = Outside.remove_divs();
668 Outside = Outside.complement();
669
670 if (!PollyPreciseInbounds)
671 Outside = Outside.gist_params(Statement->getDomain().params());
672 return Outside;
673 }
674
buildMemIntrinsicAccessRelation()675 void MemoryAccess::buildMemIntrinsicAccessRelation() {
676 assert(isMemoryIntrinsic());
677 assert(Subscripts.size() == 2 && Sizes.size() == 1);
678
679 isl::pw_aff SubscriptPWA = getPwAff(Subscripts[0]);
680 isl::map SubscriptMap = isl::map::from_pw_aff(SubscriptPWA);
681
682 isl::map LengthMap;
683 if (Subscripts[1] == nullptr) {
684 LengthMap = isl::map::universe(SubscriptMap.get_space());
685 } else {
686 isl::pw_aff LengthPWA = getPwAff(Subscripts[1]);
687 LengthMap = isl::map::from_pw_aff(LengthPWA);
688 isl::space RangeSpace = LengthMap.get_space().range();
689 LengthMap = LengthMap.apply_range(isl::map::lex_gt(RangeSpace));
690 }
691 LengthMap = LengthMap.lower_bound_si(isl::dim::out, 0, 0);
692 LengthMap = LengthMap.align_params(SubscriptMap.get_space());
693 SubscriptMap = SubscriptMap.align_params(LengthMap.get_space());
694 LengthMap = LengthMap.sum(SubscriptMap);
695 AccessRelation =
696 LengthMap.set_tuple_id(isl::dim::in, getStatement()->getDomainId());
697 }
698
computeBoundsOnAccessRelation(unsigned ElementSize)699 void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) {
700 ScalarEvolution *SE = Statement->getParent()->getSE();
701
702 auto MAI = MemAccInst(getAccessInstruction());
703 if (isa<MemIntrinsic>(MAI))
704 return;
705
706 Value *Ptr = MAI.getPointerOperand();
707 if (!Ptr || !SE->isSCEVable(Ptr->getType()))
708 return;
709
710 auto *PtrSCEV = SE->getSCEV(Ptr);
711 if (isa<SCEVCouldNotCompute>(PtrSCEV))
712 return;
713
714 auto *BasePtrSCEV = SE->getPointerBase(PtrSCEV);
715 if (BasePtrSCEV && !isa<SCEVCouldNotCompute>(BasePtrSCEV))
716 PtrSCEV = SE->getMinusSCEV(PtrSCEV, BasePtrSCEV);
717
718 const ConstantRange &Range = SE->getSignedRange(PtrSCEV);
719 if (Range.isFullSet())
720 return;
721
722 if (Range.isUpperWrapped() || Range.isSignWrappedSet())
723 return;
724
725 bool isWrapping = Range.isSignWrappedSet();
726
727 unsigned BW = Range.getBitWidth();
728 const auto One = APInt(BW, 1);
729 const auto LB = isWrapping ? Range.getLower() : Range.getSignedMin();
730 const auto UB = isWrapping ? (Range.getUpper() - One) : Range.getSignedMax();
731
732 auto Min = LB.sdiv(APInt(BW, ElementSize));
733 auto Max = UB.sdiv(APInt(BW, ElementSize)) + One;
734
735 assert(Min.sle(Max) && "Minimum expected to be less or equal than max");
736
737 isl::map Relation = AccessRelation;
738 isl::set AccessRange = Relation.range();
739 AccessRange = addRangeBoundsToSet(AccessRange, ConstantRange(Min, Max), 0,
740 isl::dim::set);
741 AccessRelation = Relation.intersect_range(AccessRange);
742 }
743
foldAccessRelation()744 void MemoryAccess::foldAccessRelation() {
745 if (Sizes.size() < 2 || isa<SCEVConstant>(Sizes[1]))
746 return;
747
748 int Size = Subscripts.size();
749
750 isl::map NewAccessRelation = AccessRelation;
751
752 for (int i = Size - 2; i >= 0; --i) {
753 isl::space Space;
754 isl::map MapOne, MapTwo;
755 isl::pw_aff DimSize = getPwAff(Sizes[i + 1]);
756
757 isl::space SpaceSize = DimSize.get_space();
758 isl::id ParamId = SpaceSize.get_dim_id(isl::dim::param, 0);
759
760 Space = AccessRelation.get_space();
761 Space = Space.range().map_from_set();
762 Space = Space.align_params(SpaceSize);
763
764 int ParamLocation = Space.find_dim_by_id(isl::dim::param, ParamId);
765
766 MapOne = isl::map::universe(Space);
767 for (int j = 0; j < Size; ++j)
768 MapOne = MapOne.equate(isl::dim::in, j, isl::dim::out, j);
769 MapOne = MapOne.lower_bound_si(isl::dim::in, i + 1, 0);
770
771 MapTwo = isl::map::universe(Space);
772 for (int j = 0; j < Size; ++j)
773 if (j < i || j > i + 1)
774 MapTwo = MapTwo.equate(isl::dim::in, j, isl::dim::out, j);
775
776 isl::local_space LS(Space);
777 isl::constraint C;
778 C = isl::constraint::alloc_equality(LS);
779 C = C.set_constant_si(-1);
780 C = C.set_coefficient_si(isl::dim::in, i, 1);
781 C = C.set_coefficient_si(isl::dim::out, i, -1);
782 MapTwo = MapTwo.add_constraint(C);
783 C = isl::constraint::alloc_equality(LS);
784 C = C.set_coefficient_si(isl::dim::in, i + 1, 1);
785 C = C.set_coefficient_si(isl::dim::out, i + 1, -1);
786 C = C.set_coefficient_si(isl::dim::param, ParamLocation, 1);
787 MapTwo = MapTwo.add_constraint(C);
788 MapTwo = MapTwo.upper_bound_si(isl::dim::in, i + 1, -1);
789
790 MapOne = MapOne.unite(MapTwo);
791 NewAccessRelation = NewAccessRelation.apply_range(MapOne);
792 }
793
794 isl::id BaseAddrId = getScopArrayInfo()->getBasePtrId();
795 isl::space Space = Statement->getDomainSpace();
796 NewAccessRelation = NewAccessRelation.set_tuple_id(
797 isl::dim::in, Space.get_tuple_id(isl::dim::set));
798 NewAccessRelation = NewAccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
799 NewAccessRelation = NewAccessRelation.gist_domain(Statement->getDomain());
800
801 // Access dimension folding might in certain cases increase the number of
802 // disjuncts in the memory access, which can possibly complicate the generated
803 // run-time checks and can lead to costly compilation.
804 if (!PollyPreciseFoldAccesses && NewAccessRelation.n_basic_map().release() >
805 AccessRelation.n_basic_map().release()) {
806 } else {
807 AccessRelation = NewAccessRelation;
808 }
809 }
810
buildAccessRelation(const ScopArrayInfo * SAI)811 void MemoryAccess::buildAccessRelation(const ScopArrayInfo *SAI) {
812 assert(AccessRelation.is_null() && "AccessRelation already built");
813
814 // Initialize the invalid domain which describes all iterations for which the
815 // access relation is not modeled correctly.
816 isl::set StmtInvalidDomain = getStatement()->getInvalidDomain();
817 InvalidDomain = isl::set::empty(StmtInvalidDomain.get_space());
818
819 isl::ctx Ctx = Id.ctx();
820 isl::id BaseAddrId = SAI->getBasePtrId();
821
822 if (getAccessInstruction() && isa<MemIntrinsic>(getAccessInstruction())) {
823 buildMemIntrinsicAccessRelation();
824 AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
825 return;
826 }
827
828 if (!isAffine()) {
829 // We overapproximate non-affine accesses with a possible access to the
830 // whole array. For read accesses it does not make a difference, if an
831 // access must or may happen. However, for write accesses it is important to
832 // differentiate between writes that must happen and writes that may happen.
833 if (AccessRelation.is_null())
834 AccessRelation = createBasicAccessMap(Statement);
835
836 AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
837 return;
838 }
839
840 isl::space Space = isl::space(Ctx, 0, Statement->getNumIterators(), 0);
841 AccessRelation = isl::map::universe(Space);
842
843 for (int i = 0, Size = Subscripts.size(); i < Size; ++i) {
844 isl::pw_aff Affine = getPwAff(Subscripts[i]);
845 isl::map SubscriptMap = isl::map::from_pw_aff(Affine);
846 AccessRelation = AccessRelation.flat_range_product(SubscriptMap);
847 }
848
849 Space = Statement->getDomainSpace();
850 AccessRelation = AccessRelation.set_tuple_id(
851 isl::dim::in, Space.get_tuple_id(isl::dim::set));
852 AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId);
853
854 AccessRelation = AccessRelation.gist_domain(Statement->getDomain());
855 }
856
MemoryAccess(ScopStmt * Stmt,Instruction * AccessInst,AccessType AccType,Value * BaseAddress,Type * ElementType,bool Affine,ArrayRef<const SCEV * > Subscripts,ArrayRef<const SCEV * > Sizes,Value * AccessValue,MemoryKind Kind)857 MemoryAccess::MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst,
858 AccessType AccType, Value *BaseAddress,
859 Type *ElementType, bool Affine,
860 ArrayRef<const SCEV *> Subscripts,
861 ArrayRef<const SCEV *> Sizes, Value *AccessValue,
862 MemoryKind Kind)
863 : Kind(Kind), AccType(AccType), Statement(Stmt), InvalidDomain(),
864 BaseAddr(BaseAddress), ElementType(ElementType),
865 Sizes(Sizes.begin(), Sizes.end()), AccessInstruction(AccessInst),
866 AccessValue(AccessValue), IsAffine(Affine),
867 Subscripts(Subscripts.begin(), Subscripts.end()), AccessRelation(),
868 NewAccessRelation() {
869 static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"};
870 const std::string Access = TypeStrings[AccType] + utostr(Stmt->size());
871
872 std::string IdName = Stmt->getBaseName() + Access;
873 Id = isl::id::alloc(Stmt->getParent()->getIslCtx(), IdName, this);
874 }
875
MemoryAccess(ScopStmt * Stmt,AccessType AccType,isl::map AccRel)876 MemoryAccess::MemoryAccess(ScopStmt *Stmt, AccessType AccType, isl::map AccRel)
877 : Kind(MemoryKind::Array), AccType(AccType), Statement(Stmt),
878 InvalidDomain(), AccessRelation(), NewAccessRelation(AccRel) {
879 isl::id ArrayInfoId = NewAccessRelation.get_tuple_id(isl::dim::out);
880 auto *SAI = ScopArrayInfo::getFromId(ArrayInfoId);
881 Sizes.push_back(nullptr);
882 for (unsigned i = 1; i < SAI->getNumberOfDimensions(); i++)
883 Sizes.push_back(SAI->getDimensionSize(i));
884 ElementType = SAI->getElementType();
885 BaseAddr = SAI->getBasePtr();
886 static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"};
887 const std::string Access = TypeStrings[AccType] + utostr(Stmt->size());
888
889 std::string IdName = Stmt->getBaseName() + Access;
890 Id = isl::id::alloc(Stmt->getParent()->getIslCtx(), IdName, this);
891 }
892
893 MemoryAccess::~MemoryAccess() = default;
894
realignParams()895 void MemoryAccess::realignParams() {
896 isl::set Ctx = Statement->getParent()->getContext();
897 InvalidDomain = InvalidDomain.gist_params(Ctx);
898 AccessRelation = AccessRelation.gist_params(Ctx);
899
900 // Predictable parameter order is required for JSON imports. Ensure alignment
901 // by explicitly calling align_params.
902 isl::space CtxSpace = Ctx.get_space();
903 InvalidDomain = InvalidDomain.align_params(CtxSpace);
904 AccessRelation = AccessRelation.align_params(CtxSpace);
905 }
906
getReductionOperatorStr() const907 const std::string MemoryAccess::getReductionOperatorStr() const {
908 return MemoryAccess::getReductionOperatorStr(getReductionType());
909 }
910
getId() const911 isl::id MemoryAccess::getId() const { return Id; }
912
operator <<(raw_ostream & OS,MemoryAccess::ReductionType RT)913 raw_ostream &polly::operator<<(raw_ostream &OS,
914 MemoryAccess::ReductionType RT) {
915 if (RT == MemoryAccess::RT_NONE)
916 OS << "NONE";
917 else
918 OS << MemoryAccess::getReductionOperatorStr(RT);
919 return OS;
920 }
921
print(raw_ostream & OS) const922 void MemoryAccess::print(raw_ostream &OS) const {
923 switch (AccType) {
924 case READ:
925 OS.indent(12) << "ReadAccess :=\t";
926 break;
927 case MUST_WRITE:
928 OS.indent(12) << "MustWriteAccess :=\t";
929 break;
930 case MAY_WRITE:
931 OS.indent(12) << "MayWriteAccess :=\t";
932 break;
933 }
934
935 OS << "[Reduction Type: " << getReductionType() << "] ";
936
937 OS << "[Scalar: " << isScalarKind() << "]\n";
938 OS.indent(16) << getOriginalAccessRelationStr() << ";\n";
939 if (hasNewAccessRelation())
940 OS.indent(11) << "new: " << getNewAccessRelationStr() << ";\n";
941 }
942
943 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const944 LLVM_DUMP_METHOD void MemoryAccess::dump() const { print(errs()); }
945 #endif
946
getPwAff(const SCEV * E)947 isl::pw_aff MemoryAccess::getPwAff(const SCEV *E) {
948 auto *Stmt = getStatement();
949 PWACtx PWAC = Stmt->getParent()->getPwAff(E, Stmt->getEntryBlock());
950 isl::set StmtDom = getStatement()->getDomain();
951 StmtDom = StmtDom.reset_tuple_id();
952 isl::set NewInvalidDom = StmtDom.intersect(PWAC.second);
953 InvalidDomain = InvalidDomain.unite(NewInvalidDom);
954 return PWAC.first;
955 }
956
957 // Create a map in the size of the provided set domain, that maps from the
958 // one element of the provided set domain to another element of the provided
959 // set domain.
960 // The mapping is limited to all points that are equal in all but the last
961 // dimension and for which the last dimension of the input is strict smaller
962 // than the last dimension of the output.
963 //
964 // getEqualAndLarger(set[i0, i1, ..., iX]):
965 //
966 // set[i0, i1, ..., iX] -> set[o0, o1, ..., oX]
967 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX
968 //
getEqualAndLarger(isl::space SetDomain)969 static isl::map getEqualAndLarger(isl::space SetDomain) {
970 isl::space Space = SetDomain.map_from_set();
971 isl::map Map = isl::map::universe(Space);
972 unsigned lastDimension = Map.domain_tuple_dim().release() - 1;
973
974 // Set all but the last dimension to be equal for the input and output
975 //
976 // input[i0, i1, ..., iX] -> output[o0, o1, ..., oX]
977 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1)
978 for (unsigned i = 0; i < lastDimension; ++i)
979 Map = Map.equate(isl::dim::in, i, isl::dim::out, i);
980
981 // Set the last dimension of the input to be strict smaller than the
982 // last dimension of the output.
983 //
984 // input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX
985 Map = Map.order_lt(isl::dim::in, lastDimension, isl::dim::out, lastDimension);
986 return Map;
987 }
988
getStride(isl::map Schedule) const989 isl::set MemoryAccess::getStride(isl::map Schedule) const {
990 isl::map AccessRelation = getAccessRelation();
991 isl::space Space = Schedule.get_space().range();
992 isl::map NextScatt = getEqualAndLarger(Space);
993
994 Schedule = Schedule.reverse();
995 NextScatt = NextScatt.lexmin();
996
997 NextScatt = NextScatt.apply_range(Schedule);
998 NextScatt = NextScatt.apply_range(AccessRelation);
999 NextScatt = NextScatt.apply_domain(Schedule);
1000 NextScatt = NextScatt.apply_domain(AccessRelation);
1001
1002 isl::set Deltas = NextScatt.deltas();
1003 return Deltas;
1004 }
1005
isStrideX(isl::map Schedule,int StrideWidth) const1006 bool MemoryAccess::isStrideX(isl::map Schedule, int StrideWidth) const {
1007 isl::set Stride, StrideX;
1008 bool IsStrideX;
1009
1010 Stride = getStride(Schedule);
1011 StrideX = isl::set::universe(Stride.get_space());
1012 int Size = unsignedFromIslSize(StrideX.tuple_dim());
1013 for (auto i : seq<int>(0, Size - 1))
1014 StrideX = StrideX.fix_si(isl::dim::set, i, 0);
1015 StrideX = StrideX.fix_si(isl::dim::set, Size - 1, StrideWidth);
1016 IsStrideX = Stride.is_subset(StrideX);
1017
1018 return IsStrideX;
1019 }
1020
isStrideZero(isl::map Schedule) const1021 bool MemoryAccess::isStrideZero(isl::map Schedule) const {
1022 return isStrideX(Schedule, 0);
1023 }
1024
isStrideOne(isl::map Schedule) const1025 bool MemoryAccess::isStrideOne(isl::map Schedule) const {
1026 return isStrideX(Schedule, 1);
1027 }
1028
setAccessRelation(isl::map NewAccess)1029 void MemoryAccess::setAccessRelation(isl::map NewAccess) {
1030 AccessRelation = NewAccess;
1031 }
1032
setNewAccessRelation(isl::map NewAccess)1033 void MemoryAccess::setNewAccessRelation(isl::map NewAccess) {
1034 assert(!NewAccess.is_null());
1035
1036 #ifndef NDEBUG
1037 // Check domain space compatibility.
1038 isl::space NewSpace = NewAccess.get_space();
1039 isl::space NewDomainSpace = NewSpace.domain();
1040 isl::space OriginalDomainSpace = getStatement()->getDomainSpace();
1041 assert(OriginalDomainSpace.has_equal_tuples(NewDomainSpace));
1042
1043 // Reads must be executed unconditionally. Writes might be executed in a
1044 // subdomain only.
1045 if (isRead()) {
1046 // Check whether there is an access for every statement instance.
1047 isl::set StmtDomain = getStatement()->getDomain();
1048 isl::set DefinedContext =
1049 getStatement()->getParent()->getBestKnownDefinedBehaviorContext();
1050 StmtDomain = StmtDomain.intersect_params(DefinedContext);
1051 isl::set NewDomain = NewAccess.domain();
1052 assert(!StmtDomain.is_subset(NewDomain).is_false() &&
1053 "Partial READ accesses not supported");
1054 }
1055
1056 isl::space NewAccessSpace = NewAccess.get_space();
1057 assert(NewAccessSpace.has_tuple_id(isl::dim::set) &&
1058 "Must specify the array that is accessed");
1059 isl::id NewArrayId = NewAccessSpace.get_tuple_id(isl::dim::set);
1060 auto *SAI = static_cast<ScopArrayInfo *>(NewArrayId.get_user());
1061 assert(SAI && "Must set a ScopArrayInfo");
1062
1063 if (SAI->isArrayKind() && SAI->getBasePtrOriginSAI()) {
1064 InvariantEquivClassTy *EqClass =
1065 getStatement()->getParent()->lookupInvariantEquivClass(
1066 SAI->getBasePtr());
1067 assert(EqClass &&
1068 "Access functions to indirect arrays must have an invariant and "
1069 "hoisted base pointer");
1070 }
1071
1072 // Check whether access dimensions correspond to number of dimensions of the
1073 // accesses array.
1074 unsigned Dims = SAI->getNumberOfDimensions();
1075 unsigned SpaceSize = unsignedFromIslSize(NewAccessSpace.dim(isl::dim::set));
1076 assert(SpaceSize == Dims && "Access dims must match array dims");
1077 #endif
1078
1079 NewAccess = NewAccess.gist_params(getStatement()->getParent()->getContext());
1080 NewAccess = NewAccess.gist_domain(getStatement()->getDomain());
1081 NewAccessRelation = NewAccess;
1082 }
1083
isLatestPartialAccess() const1084 bool MemoryAccess::isLatestPartialAccess() const {
1085 isl::set StmtDom = getStatement()->getDomain();
1086 isl::set AccDom = getLatestAccessRelation().domain();
1087
1088 return !StmtDom.is_subset(AccDom);
1089 }
1090
1091 //===----------------------------------------------------------------------===//
1092
getSchedule() const1093 isl::map ScopStmt::getSchedule() const {
1094 isl::set Domain = getDomain();
1095 if (Domain.is_empty())
1096 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
1097 auto Schedule = getParent()->getSchedule();
1098 if (Schedule.is_null())
1099 return {};
1100 Schedule = Schedule.intersect_domain(isl::union_set(Domain));
1101 if (Schedule.is_empty())
1102 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
1103 isl::map M = M.from_union_map(Schedule);
1104 M = M.coalesce();
1105 M = M.gist_domain(Domain);
1106 M = M.coalesce();
1107 return M;
1108 }
1109
restrictDomain(isl::set NewDomain)1110 void ScopStmt::restrictDomain(isl::set NewDomain) {
1111 assert(NewDomain.is_subset(Domain) &&
1112 "New domain is not a subset of old domain!");
1113 Domain = NewDomain;
1114 }
1115
addAccess(MemoryAccess * Access,bool Prepend)1116 void ScopStmt::addAccess(MemoryAccess *Access, bool Prepend) {
1117 Instruction *AccessInst = Access->getAccessInstruction();
1118
1119 if (Access->isArrayKind()) {
1120 MemoryAccessList &MAL = InstructionToAccess[AccessInst];
1121 MAL.emplace_front(Access);
1122 } else if (Access->isValueKind() && Access->isWrite()) {
1123 Instruction *AccessVal = cast<Instruction>(Access->getAccessValue());
1124 assert(!ValueWrites.lookup(AccessVal));
1125
1126 ValueWrites[AccessVal] = Access;
1127 } else if (Access->isValueKind() && Access->isRead()) {
1128 Value *AccessVal = Access->getAccessValue();
1129 assert(!ValueReads.lookup(AccessVal));
1130
1131 ValueReads[AccessVal] = Access;
1132 } else if (Access->isAnyPHIKind() && Access->isWrite()) {
1133 PHINode *PHI = cast<PHINode>(Access->getAccessValue());
1134 assert(!PHIWrites.lookup(PHI));
1135
1136 PHIWrites[PHI] = Access;
1137 } else if (Access->isAnyPHIKind() && Access->isRead()) {
1138 PHINode *PHI = cast<PHINode>(Access->getAccessValue());
1139 assert(!PHIReads.lookup(PHI));
1140
1141 PHIReads[PHI] = Access;
1142 }
1143
1144 if (Prepend) {
1145 MemAccs.insert(MemAccs.begin(), Access);
1146 return;
1147 }
1148 MemAccs.push_back(Access);
1149 }
1150
realignParams()1151 void ScopStmt::realignParams() {
1152 for (MemoryAccess *MA : *this)
1153 MA->realignParams();
1154
1155 simplify(InvalidDomain);
1156 simplify(Domain);
1157
1158 isl::set Ctx = Parent.getContext();
1159 InvalidDomain = InvalidDomain.gist_params(Ctx);
1160 Domain = Domain.gist_params(Ctx);
1161
1162 // Predictable parameter order is required for JSON imports. Ensure alignment
1163 // by explicitly calling align_params.
1164 isl::space CtxSpace = Ctx.get_space();
1165 InvalidDomain = InvalidDomain.align_params(CtxSpace);
1166 Domain = Domain.align_params(CtxSpace);
1167 }
1168
ScopStmt(Scop & parent,Region & R,StringRef Name,Loop * SurroundingLoop,std::vector<Instruction * > EntryBlockInstructions)1169 ScopStmt::ScopStmt(Scop &parent, Region &R, StringRef Name,
1170 Loop *SurroundingLoop,
1171 std::vector<Instruction *> EntryBlockInstructions)
1172 : Parent(parent), InvalidDomain(), Domain(), R(&R), Build(), BaseName(Name),
1173 SurroundingLoop(SurroundingLoop), Instructions(EntryBlockInstructions) {}
1174
ScopStmt(Scop & parent,BasicBlock & bb,StringRef Name,Loop * SurroundingLoop,std::vector<Instruction * > Instructions)1175 ScopStmt::ScopStmt(Scop &parent, BasicBlock &bb, StringRef Name,
1176 Loop *SurroundingLoop,
1177 std::vector<Instruction *> Instructions)
1178 : Parent(parent), InvalidDomain(), Domain(), BB(&bb), Build(),
1179 BaseName(Name), SurroundingLoop(SurroundingLoop),
1180 Instructions(Instructions) {}
1181
ScopStmt(Scop & parent,isl::map SourceRel,isl::map TargetRel,isl::set NewDomain)1182 ScopStmt::ScopStmt(Scop &parent, isl::map SourceRel, isl::map TargetRel,
1183 isl::set NewDomain)
1184 : Parent(parent), InvalidDomain(), Domain(NewDomain), Build() {
1185 BaseName = getIslCompatibleName("CopyStmt_", "",
1186 std::to_string(parent.getCopyStmtsNum()));
1187 isl::id Id = isl::id::alloc(getIslCtx(), getBaseName(), this);
1188 Domain = Domain.set_tuple_id(Id);
1189 TargetRel = TargetRel.set_tuple_id(isl::dim::in, Id);
1190 auto *Access =
1191 new MemoryAccess(this, MemoryAccess::AccessType::MUST_WRITE, TargetRel);
1192 parent.addAccessFunction(Access);
1193 addAccess(Access);
1194 SourceRel = SourceRel.set_tuple_id(isl::dim::in, Id);
1195 Access = new MemoryAccess(this, MemoryAccess::AccessType::READ, SourceRel);
1196 parent.addAccessFunction(Access);
1197 addAccess(Access);
1198 }
1199
1200 ScopStmt::~ScopStmt() = default;
1201
getDomainStr() const1202 std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); }
1203
getScheduleStr() const1204 std::string ScopStmt::getScheduleStr() const {
1205 return stringFromIslObj(getSchedule());
1206 }
1207
setInvalidDomain(isl::set ID)1208 void ScopStmt::setInvalidDomain(isl::set ID) { InvalidDomain = ID; }
1209
getEntryBlock() const1210 BasicBlock *ScopStmt::getEntryBlock() const {
1211 if (isBlockStmt())
1212 return getBasicBlock();
1213 return getRegion()->getEntry();
1214 }
1215
getNumIterators() const1216 unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); }
1217
getBaseName() const1218 const char *ScopStmt::getBaseName() const { return BaseName.c_str(); }
1219
getLoopForDimension(unsigned Dimension) const1220 Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const {
1221 return NestLoops[Dimension];
1222 }
1223
getIslCtx() const1224 isl::ctx ScopStmt::getIslCtx() const { return Parent.getIslCtx(); }
1225
getDomain() const1226 isl::set ScopStmt::getDomain() const { return Domain; }
1227
getDomainSpace() const1228 isl::space ScopStmt::getDomainSpace() const { return Domain.get_space(); }
1229
getDomainId() const1230 isl::id ScopStmt::getDomainId() const { return Domain.get_tuple_id(); }
1231
printInstructions(raw_ostream & OS) const1232 void ScopStmt::printInstructions(raw_ostream &OS) const {
1233 OS << "Instructions {\n";
1234
1235 for (Instruction *Inst : Instructions)
1236 OS.indent(16) << *Inst << "\n";
1237
1238 OS.indent(12) << "}\n";
1239 }
1240
print(raw_ostream & OS,bool PrintInstructions) const1241 void ScopStmt::print(raw_ostream &OS, bool PrintInstructions) const {
1242 OS << "\t" << getBaseName() << "\n";
1243 OS.indent(12) << "Domain :=\n";
1244
1245 if (!Domain.is_null()) {
1246 OS.indent(16) << getDomainStr() << ";\n";
1247 } else
1248 OS.indent(16) << "n/a\n";
1249
1250 OS.indent(12) << "Schedule :=\n";
1251
1252 if (!Domain.is_null()) {
1253 OS.indent(16) << getScheduleStr() << ";\n";
1254 } else
1255 OS.indent(16) << "n/a\n";
1256
1257 for (MemoryAccess *Access : MemAccs)
1258 Access->print(OS);
1259
1260 if (PrintInstructions)
1261 printInstructions(OS.indent(12));
1262 }
1263
1264 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const1265 LLVM_DUMP_METHOD void ScopStmt::dump() const { print(dbgs(), true); }
1266 #endif
1267
removeAccessData(MemoryAccess * MA)1268 void ScopStmt::removeAccessData(MemoryAccess *MA) {
1269 if (MA->isRead() && MA->isOriginalValueKind()) {
1270 bool Found = ValueReads.erase(MA->getAccessValue());
1271 (void)Found;
1272 assert(Found && "Expected access data not found");
1273 }
1274 if (MA->isWrite() && MA->isOriginalValueKind()) {
1275 bool Found = ValueWrites.erase(cast<Instruction>(MA->getAccessValue()));
1276 (void)Found;
1277 assert(Found && "Expected access data not found");
1278 }
1279 if (MA->isWrite() && MA->isOriginalAnyPHIKind()) {
1280 bool Found = PHIWrites.erase(cast<PHINode>(MA->getAccessInstruction()));
1281 (void)Found;
1282 assert(Found && "Expected access data not found");
1283 }
1284 if (MA->isRead() && MA->isOriginalAnyPHIKind()) {
1285 bool Found = PHIReads.erase(cast<PHINode>(MA->getAccessInstruction()));
1286 (void)Found;
1287 assert(Found && "Expected access data not found");
1288 }
1289 }
1290
removeMemoryAccess(MemoryAccess * MA)1291 void ScopStmt::removeMemoryAccess(MemoryAccess *MA) {
1292 // Remove the memory accesses from this statement together with all scalar
1293 // accesses that were caused by it. MemoryKind::Value READs have no access
1294 // instruction, hence would not be removed by this function. However, it is
1295 // only used for invariant LoadInst accesses, its arguments are always affine,
1296 // hence synthesizable, and therefore there are no MemoryKind::Value READ
1297 // accesses to be removed.
1298 auto Predicate = [&](MemoryAccess *Acc) {
1299 return Acc->getAccessInstruction() == MA->getAccessInstruction();
1300 };
1301 for (auto *MA : MemAccs) {
1302 if (Predicate(MA)) {
1303 removeAccessData(MA);
1304 Parent.removeAccessData(MA);
1305 }
1306 }
1307 llvm::erase_if(MemAccs, Predicate);
1308 InstructionToAccess.erase(MA->getAccessInstruction());
1309 }
1310
removeSingleMemoryAccess(MemoryAccess * MA,bool AfterHoisting)1311 void ScopStmt::removeSingleMemoryAccess(MemoryAccess *MA, bool AfterHoisting) {
1312 if (AfterHoisting) {
1313 auto MAIt = std::find(MemAccs.begin(), MemAccs.end(), MA);
1314 assert(MAIt != MemAccs.end());
1315 MemAccs.erase(MAIt);
1316
1317 removeAccessData(MA);
1318 Parent.removeAccessData(MA);
1319 }
1320
1321 auto It = InstructionToAccess.find(MA->getAccessInstruction());
1322 if (It != InstructionToAccess.end()) {
1323 It->second.remove(MA);
1324 if (It->second.empty())
1325 InstructionToAccess.erase(MA->getAccessInstruction());
1326 }
1327 }
1328
ensureValueRead(Value * V)1329 MemoryAccess *ScopStmt::ensureValueRead(Value *V) {
1330 MemoryAccess *Access = lookupInputAccessOf(V);
1331 if (Access)
1332 return Access;
1333
1334 ScopArrayInfo *SAI =
1335 Parent.getOrCreateScopArrayInfo(V, V->getType(), {}, MemoryKind::Value);
1336 Access = new MemoryAccess(this, nullptr, MemoryAccess::READ, V, V->getType(),
1337 true, {}, {}, V, MemoryKind::Value);
1338 Parent.addAccessFunction(Access);
1339 Access->buildAccessRelation(SAI);
1340 addAccess(Access);
1341 Parent.addAccessData(Access);
1342 return Access;
1343 }
1344
operator <<(raw_ostream & OS,const ScopStmt & S)1345 raw_ostream &polly::operator<<(raw_ostream &OS, const ScopStmt &S) {
1346 S.print(OS, PollyPrintInstructions);
1347 return OS;
1348 }
1349
1350 //===----------------------------------------------------------------------===//
1351 /// Scop class implement
1352
setContext(isl::set NewContext)1353 void Scop::setContext(isl::set NewContext) {
1354 Context = NewContext.align_params(Context.get_space());
1355 }
1356
1357 namespace {
1358
1359 /// Remap parameter values but keep AddRecs valid wrt. invariant loads.
1360 class SCEVSensitiveParameterRewriter final
1361 : public SCEVRewriteVisitor<SCEVSensitiveParameterRewriter> {
1362 const ValueToValueMap &VMap;
1363
1364 public:
SCEVSensitiveParameterRewriter(const ValueToValueMap & VMap,ScalarEvolution & SE)1365 SCEVSensitiveParameterRewriter(const ValueToValueMap &VMap,
1366 ScalarEvolution &SE)
1367 : SCEVRewriteVisitor(SE), VMap(VMap) {}
1368
rewrite(const SCEV * E,ScalarEvolution & SE,const ValueToValueMap & VMap)1369 static const SCEV *rewrite(const SCEV *E, ScalarEvolution &SE,
1370 const ValueToValueMap &VMap) {
1371 SCEVSensitiveParameterRewriter SSPR(VMap, SE);
1372 return SSPR.visit(E);
1373 }
1374
visitAddRecExpr(const SCEVAddRecExpr * E)1375 const SCEV *visitAddRecExpr(const SCEVAddRecExpr *E) {
1376 auto *Start = visit(E->getStart());
1377 auto *AddRec = SE.getAddRecExpr(SE.getConstant(E->getType(), 0),
1378 visit(E->getStepRecurrence(SE)),
1379 E->getLoop(), SCEV::FlagAnyWrap);
1380 return SE.getAddExpr(Start, AddRec);
1381 }
1382
visitUnknown(const SCEVUnknown * E)1383 const SCEV *visitUnknown(const SCEVUnknown *E) {
1384 if (auto *NewValue = VMap.lookup(E->getValue()))
1385 return SE.getUnknown(NewValue);
1386 return E;
1387 }
1388 };
1389
1390 /// Check whether we should remap a SCEV expression.
1391 class SCEVFindInsideScop : public SCEVTraversal<SCEVFindInsideScop> {
1392 const ValueToValueMap &VMap;
1393 bool FoundInside = false;
1394 const Scop *S;
1395
1396 public:
SCEVFindInsideScop(const ValueToValueMap & VMap,ScalarEvolution & SE,const Scop * S)1397 SCEVFindInsideScop(const ValueToValueMap &VMap, ScalarEvolution &SE,
1398 const Scop *S)
1399 : SCEVTraversal(*this), VMap(VMap), S(S) {}
1400
hasVariant(const SCEV * E,ScalarEvolution & SE,const ValueToValueMap & VMap,const Scop * S)1401 static bool hasVariant(const SCEV *E, ScalarEvolution &SE,
1402 const ValueToValueMap &VMap, const Scop *S) {
1403 SCEVFindInsideScop SFIS(VMap, SE, S);
1404 SFIS.visitAll(E);
1405 return SFIS.FoundInside;
1406 }
1407
follow(const SCEV * E)1408 bool follow(const SCEV *E) {
1409 if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(E)) {
1410 FoundInside |= S->getRegion().contains(AddRec->getLoop());
1411 } else if (auto *Unknown = dyn_cast<SCEVUnknown>(E)) {
1412 if (Instruction *I = dyn_cast<Instruction>(Unknown->getValue()))
1413 FoundInside |= S->getRegion().contains(I) && !VMap.count(I);
1414 }
1415 return !FoundInside;
1416 }
1417
isDone()1418 bool isDone() { return FoundInside; }
1419 };
1420 } // end anonymous namespace
1421
getRepresentingInvariantLoadSCEV(const SCEV * E) const1422 const SCEV *Scop::getRepresentingInvariantLoadSCEV(const SCEV *E) const {
1423 // Check whether it makes sense to rewrite the SCEV. (ScalarEvolution
1424 // doesn't like addition between an AddRec and an expression that
1425 // doesn't have a dominance relationship with it.)
1426 if (SCEVFindInsideScop::hasVariant(E, *SE, InvEquivClassVMap, this))
1427 return E;
1428
1429 // Rewrite SCEV.
1430 return SCEVSensitiveParameterRewriter::rewrite(E, *SE, InvEquivClassVMap);
1431 }
1432
createParameterId(const SCEV * Parameter)1433 void Scop::createParameterId(const SCEV *Parameter) {
1434 assert(Parameters.count(Parameter));
1435 assert(!ParameterIds.count(Parameter));
1436
1437 std::string ParameterName = "p_" + std::to_string(getNumParams() - 1);
1438
1439 if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) {
1440 Value *Val = ValueParameter->getValue();
1441
1442 if (UseInstructionNames) {
1443 // If this parameter references a specific Value and this value has a name
1444 // we use this name as it is likely to be unique and more useful than just
1445 // a number.
1446 if (Val->hasName())
1447 ParameterName = Val->getName().str();
1448 else if (LoadInst *LI = dyn_cast<LoadInst>(Val)) {
1449 auto *LoadOrigin = LI->getPointerOperand()->stripInBoundsOffsets();
1450 if (LoadOrigin->hasName()) {
1451 ParameterName += "_loaded_from_";
1452 ParameterName +=
1453 LI->getPointerOperand()->stripInBoundsOffsets()->getName();
1454 }
1455 }
1456 }
1457
1458 ParameterName = getIslCompatibleName("", ParameterName, "");
1459 }
1460
1461 isl::id Id = isl::id::alloc(getIslCtx(), ParameterName,
1462 const_cast<void *>((const void *)Parameter));
1463 ParameterIds[Parameter] = Id;
1464 }
1465
addParams(const ParameterSetTy & NewParameters)1466 void Scop::addParams(const ParameterSetTy &NewParameters) {
1467 for (const SCEV *Parameter : NewParameters) {
1468 // Normalize the SCEV to get the representing element for an invariant load.
1469 Parameter = extractConstantFactor(Parameter, *SE).second;
1470 Parameter = getRepresentingInvariantLoadSCEV(Parameter);
1471
1472 if (Parameters.insert(Parameter))
1473 createParameterId(Parameter);
1474 }
1475 }
1476
getIdForParam(const SCEV * Parameter) const1477 isl::id Scop::getIdForParam(const SCEV *Parameter) const {
1478 // Normalize the SCEV to get the representing element for an invariant load.
1479 Parameter = getRepresentingInvariantLoadSCEV(Parameter);
1480 return ParameterIds.lookup(Parameter);
1481 }
1482
isDominatedBy(const DominatorTree & DT,BasicBlock * BB) const1483 bool Scop::isDominatedBy(const DominatorTree &DT, BasicBlock *BB) const {
1484 return DT.dominates(BB, getEntry());
1485 }
1486
buildContext()1487 void Scop::buildContext() {
1488 isl::space Space = isl::space::params_alloc(getIslCtx(), 0);
1489 Context = isl::set::universe(Space);
1490 InvalidContext = isl::set::empty(Space);
1491 AssumedContext = isl::set::universe(Space);
1492 DefinedBehaviorContext = isl::set::universe(Space);
1493 }
1494
addParameterBounds()1495 void Scop::addParameterBounds() {
1496 unsigned PDim = 0;
1497 for (auto *Parameter : Parameters) {
1498 ConstantRange SRange = SE->getSignedRange(Parameter);
1499 Context = addRangeBoundsToSet(Context, SRange, PDim++, isl::dim::param);
1500 }
1501 intersectDefinedBehavior(Context, AS_ASSUMPTION);
1502 }
1503
realignParams()1504 void Scop::realignParams() {
1505 if (PollyIgnoreParamBounds)
1506 return;
1507
1508 // Add all parameters into a common model.
1509 isl::space Space = getFullParamSpace();
1510
1511 // Align the parameters of all data structures to the model.
1512 Context = Context.align_params(Space);
1513 AssumedContext = AssumedContext.align_params(Space);
1514 InvalidContext = InvalidContext.align_params(Space);
1515
1516 // As all parameters are known add bounds to them.
1517 addParameterBounds();
1518
1519 for (ScopStmt &Stmt : *this)
1520 Stmt.realignParams();
1521 // Simplify the schedule according to the context too.
1522 Schedule = Schedule.gist_domain_params(getContext());
1523
1524 // Predictable parameter order is required for JSON imports. Ensure alignment
1525 // by explicitly calling align_params.
1526 Schedule = Schedule.align_params(Space);
1527 }
1528
simplifyAssumptionContext(isl::set AssumptionContext,const Scop & S)1529 static isl::set simplifyAssumptionContext(isl::set AssumptionContext,
1530 const Scop &S) {
1531 // If we have modeled all blocks in the SCoP that have side effects we can
1532 // simplify the context with the constraints that are needed for anything to
1533 // be executed at all. However, if we have error blocks in the SCoP we already
1534 // assumed some parameter combinations cannot occur and removed them from the
1535 // domains, thus we cannot use the remaining domain to simplify the
1536 // assumptions.
1537 if (!S.hasErrorBlock()) {
1538 auto DomainParameters = S.getDomains().params();
1539 AssumptionContext = AssumptionContext.gist_params(DomainParameters);
1540 }
1541
1542 AssumptionContext = AssumptionContext.gist_params(S.getContext());
1543 return AssumptionContext;
1544 }
1545
simplifyContexts()1546 void Scop::simplifyContexts() {
1547 // The parameter constraints of the iteration domains give us a set of
1548 // constraints that need to hold for all cases where at least a single
1549 // statement iteration is executed in the whole scop. We now simplify the
1550 // assumed context under the assumption that such constraints hold and at
1551 // least a single statement iteration is executed. For cases where no
1552 // statement instances are executed, the assumptions we have taken about
1553 // the executed code do not matter and can be changed.
1554 //
1555 // WARNING: This only holds if the assumptions we have taken do not reduce
1556 // the set of statement instances that are executed. Otherwise we
1557 // may run into a case where the iteration domains suggest that
1558 // for a certain set of parameter constraints no code is executed,
1559 // but in the original program some computation would have been
1560 // performed. In such a case, modifying the run-time conditions and
1561 // possibly influencing the run-time check may cause certain scops
1562 // to not be executed.
1563 //
1564 // Example:
1565 //
1566 // When delinearizing the following code:
1567 //
1568 // for (long i = 0; i < 100; i++)
1569 // for (long j = 0; j < m; j++)
1570 // A[i+p][j] = 1.0;
1571 //
1572 // we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as
1573 // otherwise we would access out of bound data. Now, knowing that code is
1574 // only executed for the case m >= 0, it is sufficient to assume p >= 0.
1575 AssumedContext = simplifyAssumptionContext(AssumedContext, *this);
1576 InvalidContext = InvalidContext.align_params(getParamSpace());
1577 simplify(DefinedBehaviorContext);
1578 DefinedBehaviorContext = DefinedBehaviorContext.align_params(getParamSpace());
1579 }
1580
getDomainConditions(const ScopStmt * Stmt) const1581 isl::set Scop::getDomainConditions(const ScopStmt *Stmt) const {
1582 return getDomainConditions(Stmt->getEntryBlock());
1583 }
1584
getDomainConditions(BasicBlock * BB) const1585 isl::set Scop::getDomainConditions(BasicBlock *BB) const {
1586 auto DIt = DomainMap.find(BB);
1587 if (DIt != DomainMap.end())
1588 return DIt->getSecond();
1589
1590 auto &RI = *R.getRegionInfo();
1591 auto *BBR = RI.getRegionFor(BB);
1592 while (BBR->getEntry() == BB)
1593 BBR = BBR->getParent();
1594 return getDomainConditions(BBR->getEntry());
1595 }
1596
Scop(Region & R,ScalarEvolution & ScalarEvolution,LoopInfo & LI,DominatorTree & DT,ScopDetection::DetectionContext & DC,OptimizationRemarkEmitter & ORE,int ID)1597 Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, LoopInfo &LI,
1598 DominatorTree &DT, ScopDetection::DetectionContext &DC,
1599 OptimizationRemarkEmitter &ORE, int ID)
1600 : IslCtx(isl_ctx_alloc(), isl_ctx_free), SE(&ScalarEvolution), DT(&DT),
1601 R(R), name(None), HasSingleExitEdge(R.getExitingBlock()), DC(DC),
1602 ORE(ORE), Affinator(this, LI), ID(ID) {
1603
1604 // Options defaults that are different from ISL's.
1605 isl_options_set_schedule_serialize_sccs(IslCtx.get(), true);
1606
1607 SmallVector<char *, 8> IslArgv;
1608 IslArgv.reserve(1 + IslArgs.size());
1609
1610 // Substitute for program name.
1611 IslArgv.push_back(const_cast<char *>("-polly-isl-arg"));
1612
1613 for (std::string &Arg : IslArgs)
1614 IslArgv.push_back(const_cast<char *>(Arg.c_str()));
1615
1616 // Abort if unknown argument is passed.
1617 // Note that "-V" (print isl version) will always call exit(0), so we cannot
1618 // avoid ISL aborting the program at this point.
1619 unsigned IslParseFlags = ISL_ARG_ALL;
1620
1621 isl_ctx_parse_options(IslCtx.get(), IslArgv.size(), IslArgv.data(),
1622 IslParseFlags);
1623
1624 if (IslOnErrorAbort)
1625 isl_options_set_on_error(getIslCtx().get(), ISL_ON_ERROR_ABORT);
1626 buildContext();
1627 }
1628
1629 Scop::~Scop() = default;
1630
removeFromStmtMap(ScopStmt & Stmt)1631 void Scop::removeFromStmtMap(ScopStmt &Stmt) {
1632 for (Instruction *Inst : Stmt.getInstructions())
1633 InstStmtMap.erase(Inst);
1634
1635 if (Stmt.isRegionStmt()) {
1636 for (BasicBlock *BB : Stmt.getRegion()->blocks()) {
1637 StmtMap.erase(BB);
1638 // Skip entry basic block, as its instructions are already deleted as
1639 // part of the statement's instruction list.
1640 if (BB == Stmt.getEntryBlock())
1641 continue;
1642 for (Instruction &Inst : *BB)
1643 InstStmtMap.erase(&Inst);
1644 }
1645 } else {
1646 auto StmtMapIt = StmtMap.find(Stmt.getBasicBlock());
1647 if (StmtMapIt != StmtMap.end())
1648 StmtMapIt->second.erase(std::remove(StmtMapIt->second.begin(),
1649 StmtMapIt->second.end(), &Stmt),
1650 StmtMapIt->second.end());
1651 for (Instruction *Inst : Stmt.getInstructions())
1652 InstStmtMap.erase(Inst);
1653 }
1654 }
1655
removeStmts(function_ref<bool (ScopStmt &)> ShouldDelete,bool AfterHoisting)1656 void Scop::removeStmts(function_ref<bool(ScopStmt &)> ShouldDelete,
1657 bool AfterHoisting) {
1658 for (auto StmtIt = Stmts.begin(), StmtEnd = Stmts.end(); StmtIt != StmtEnd;) {
1659 if (!ShouldDelete(*StmtIt)) {
1660 StmtIt++;
1661 continue;
1662 }
1663
1664 // Start with removing all of the statement's accesses including erasing it
1665 // from all maps that are pointing to them.
1666 // Make a temporary copy because removing MAs invalidates the iterator.
1667 SmallVector<MemoryAccess *, 16> MAList(StmtIt->begin(), StmtIt->end());
1668 for (MemoryAccess *MA : MAList)
1669 StmtIt->removeSingleMemoryAccess(MA, AfterHoisting);
1670
1671 removeFromStmtMap(*StmtIt);
1672 StmtIt = Stmts.erase(StmtIt);
1673 }
1674 }
1675
removeStmtNotInDomainMap()1676 void Scop::removeStmtNotInDomainMap() {
1677 removeStmts([this](ScopStmt &Stmt) -> bool {
1678 isl::set Domain = DomainMap.lookup(Stmt.getEntryBlock());
1679 if (Domain.is_null())
1680 return true;
1681 return Domain.is_empty();
1682 });
1683 }
1684
simplifySCoP(bool AfterHoisting)1685 void Scop::simplifySCoP(bool AfterHoisting) {
1686 removeStmts(
1687 [AfterHoisting](ScopStmt &Stmt) -> bool {
1688 // Never delete statements that contain calls to debug functions.
1689 if (hasDebugCall(&Stmt))
1690 return false;
1691
1692 bool RemoveStmt = Stmt.isEmpty();
1693
1694 // Remove read only statements only after invariant load hoisting.
1695 if (!RemoveStmt && AfterHoisting) {
1696 bool OnlyRead = true;
1697 for (MemoryAccess *MA : Stmt) {
1698 if (MA->isRead())
1699 continue;
1700
1701 OnlyRead = false;
1702 break;
1703 }
1704
1705 RemoveStmt = OnlyRead;
1706 }
1707 return RemoveStmt;
1708 },
1709 AfterHoisting);
1710 }
1711
lookupInvariantEquivClass(Value * Val)1712 InvariantEquivClassTy *Scop::lookupInvariantEquivClass(Value *Val) {
1713 LoadInst *LInst = dyn_cast<LoadInst>(Val);
1714 if (!LInst)
1715 return nullptr;
1716
1717 if (Value *Rep = InvEquivClassVMap.lookup(LInst))
1718 LInst = cast<LoadInst>(Rep);
1719
1720 Type *Ty = LInst->getType();
1721 const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand());
1722 for (auto &IAClass : InvariantEquivClasses) {
1723 if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.AccessType)
1724 continue;
1725
1726 auto &MAs = IAClass.InvariantAccesses;
1727 for (auto *MA : MAs)
1728 if (MA->getAccessInstruction() == Val)
1729 return &IAClass;
1730 }
1731
1732 return nullptr;
1733 }
1734
getOrCreateScopArrayInfo(Value * BasePtr,Type * ElementType,ArrayRef<const SCEV * > Sizes,MemoryKind Kind,const char * BaseName)1735 ScopArrayInfo *Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType,
1736 ArrayRef<const SCEV *> Sizes,
1737 MemoryKind Kind,
1738 const char *BaseName) {
1739 assert((BasePtr || BaseName) &&
1740 "BasePtr and BaseName can not be nullptr at the same time.");
1741 assert(!(BasePtr && BaseName) && "BaseName is redundant.");
1742 auto &SAI = BasePtr ? ScopArrayInfoMap[std::make_pair(BasePtr, Kind)]
1743 : ScopArrayNameMap[BaseName];
1744 if (!SAI) {
1745 auto &DL = getFunction().getParent()->getDataLayout();
1746 SAI.reset(new ScopArrayInfo(BasePtr, ElementType, getIslCtx(), Sizes, Kind,
1747 DL, this, BaseName));
1748 ScopArrayInfoSet.insert(SAI.get());
1749 } else {
1750 SAI->updateElementType(ElementType);
1751 // In case of mismatching array sizes, we bail out by setting the run-time
1752 // context to false.
1753 if (!SAI->updateSizes(Sizes))
1754 invalidate(DELINEARIZATION, DebugLoc());
1755 }
1756 return SAI.get();
1757 }
1758
createScopArrayInfo(Type * ElementType,const std::string & BaseName,const std::vector<unsigned> & Sizes)1759 ScopArrayInfo *Scop::createScopArrayInfo(Type *ElementType,
1760 const std::string &BaseName,
1761 const std::vector<unsigned> &Sizes) {
1762 auto *DimSizeType = Type::getInt64Ty(getSE()->getContext());
1763 std::vector<const SCEV *> SCEVSizes;
1764
1765 for (auto size : Sizes)
1766 if (size)
1767 SCEVSizes.push_back(getSE()->getConstant(DimSizeType, size, false));
1768 else
1769 SCEVSizes.push_back(nullptr);
1770
1771 auto *SAI = getOrCreateScopArrayInfo(nullptr, ElementType, SCEVSizes,
1772 MemoryKind::Array, BaseName.c_str());
1773 return SAI;
1774 }
1775
getScopArrayInfoOrNull(Value * BasePtr,MemoryKind Kind)1776 ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind) {
1777 auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get();
1778 return SAI;
1779 }
1780
getScopArrayInfo(Value * BasePtr,MemoryKind Kind)1781 ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) {
1782 auto *SAI = getScopArrayInfoOrNull(BasePtr, Kind);
1783 assert(SAI && "No ScopArrayInfo available for this base pointer");
1784 return SAI;
1785 }
1786
getContextStr() const1787 std::string Scop::getContextStr() const {
1788 return stringFromIslObj(getContext());
1789 }
1790
getAssumedContextStr() const1791 std::string Scop::getAssumedContextStr() const {
1792 assert(!AssumedContext.is_null() && "Assumed context not yet built");
1793 return stringFromIslObj(AssumedContext);
1794 }
1795
getInvalidContextStr() const1796 std::string Scop::getInvalidContextStr() const {
1797 return stringFromIslObj(InvalidContext);
1798 }
1799
getNameStr() const1800 std::string Scop::getNameStr() const {
1801 std::string ExitName, EntryName;
1802 std::tie(EntryName, ExitName) = getEntryExitStr();
1803 return EntryName + "---" + ExitName;
1804 }
1805
getEntryExitStr() const1806 std::pair<std::string, std::string> Scop::getEntryExitStr() const {
1807 std::string ExitName, EntryName;
1808 raw_string_ostream ExitStr(ExitName);
1809 raw_string_ostream EntryStr(EntryName);
1810
1811 R.getEntry()->printAsOperand(EntryStr, false);
1812 EntryStr.str();
1813
1814 if (R.getExit()) {
1815 R.getExit()->printAsOperand(ExitStr, false);
1816 ExitStr.str();
1817 } else
1818 ExitName = "FunctionExit";
1819
1820 return std::make_pair(EntryName, ExitName);
1821 }
1822
getContext() const1823 isl::set Scop::getContext() const { return Context; }
1824
getParamSpace() const1825 isl::space Scop::getParamSpace() const { return getContext().get_space(); }
1826
getFullParamSpace() const1827 isl::space Scop::getFullParamSpace() const {
1828
1829 isl::space Space = isl::space::params_alloc(getIslCtx(), ParameterIds.size());
1830
1831 unsigned PDim = 0;
1832 for (const SCEV *Parameter : Parameters) {
1833 isl::id Id = getIdForParam(Parameter);
1834 Space = Space.set_dim_id(isl::dim::param, PDim++, Id);
1835 }
1836
1837 return Space;
1838 }
1839
getAssumedContext() const1840 isl::set Scop::getAssumedContext() const {
1841 assert(!AssumedContext.is_null() && "Assumed context not yet built");
1842 return AssumedContext;
1843 }
1844
isProfitable(bool ScalarsAreUnprofitable) const1845 bool Scop::isProfitable(bool ScalarsAreUnprofitable) const {
1846 if (PollyProcessUnprofitable)
1847 return true;
1848
1849 if (isEmpty())
1850 return false;
1851
1852 unsigned OptimizableStmtsOrLoops = 0;
1853 for (auto &Stmt : *this) {
1854 if (Stmt.getNumIterators() == 0)
1855 continue;
1856
1857 bool ContainsArrayAccs = false;
1858 bool ContainsScalarAccs = false;
1859 for (auto *MA : Stmt) {
1860 if (MA->isRead())
1861 continue;
1862 ContainsArrayAccs |= MA->isLatestArrayKind();
1863 ContainsScalarAccs |= MA->isLatestScalarKind();
1864 }
1865
1866 if (!ScalarsAreUnprofitable || (ContainsArrayAccs && !ContainsScalarAccs))
1867 OptimizableStmtsOrLoops += Stmt.getNumIterators();
1868 }
1869
1870 return OptimizableStmtsOrLoops > 1;
1871 }
1872
hasFeasibleRuntimeContext() const1873 bool Scop::hasFeasibleRuntimeContext() const {
1874 if (Stmts.empty())
1875 return false;
1876
1877 isl::set PositiveContext = getAssumedContext();
1878 isl::set NegativeContext = getInvalidContext();
1879 PositiveContext = PositiveContext.intersect_params(Context);
1880 PositiveContext = PositiveContext.intersect_params(getDomains().params());
1881 return PositiveContext.is_empty().is_false() &&
1882 PositiveContext.is_subset(NegativeContext).is_false();
1883 }
1884
lookupBasePtrAccess(MemoryAccess * MA)1885 MemoryAccess *Scop::lookupBasePtrAccess(MemoryAccess *MA) {
1886 Value *PointerBase = MA->getOriginalBaseAddr();
1887
1888 auto *PointerBaseInst = dyn_cast<Instruction>(PointerBase);
1889 if (!PointerBaseInst)
1890 return nullptr;
1891
1892 auto *BasePtrStmt = getStmtFor(PointerBaseInst);
1893 if (!BasePtrStmt)
1894 return nullptr;
1895
1896 return BasePtrStmt->getArrayAccessOrNULLFor(PointerBaseInst);
1897 }
1898
toString(AssumptionKind Kind)1899 static std::string toString(AssumptionKind Kind) {
1900 switch (Kind) {
1901 case ALIASING:
1902 return "No-aliasing";
1903 case INBOUNDS:
1904 return "Inbounds";
1905 case WRAPPING:
1906 return "No-overflows";
1907 case UNSIGNED:
1908 return "Signed-unsigned";
1909 case COMPLEXITY:
1910 return "Low complexity";
1911 case PROFITABLE:
1912 return "Profitable";
1913 case ERRORBLOCK:
1914 return "No-error";
1915 case INFINITELOOP:
1916 return "Finite loop";
1917 case INVARIANTLOAD:
1918 return "Invariant load";
1919 case DELINEARIZATION:
1920 return "Delinearization";
1921 }
1922 llvm_unreachable("Unknown AssumptionKind!");
1923 }
1924
isEffectiveAssumption(isl::set Set,AssumptionSign Sign)1925 bool Scop::isEffectiveAssumption(isl::set Set, AssumptionSign Sign) {
1926 if (Sign == AS_ASSUMPTION) {
1927 if (Context.is_subset(Set))
1928 return false;
1929
1930 if (AssumedContext.is_subset(Set))
1931 return false;
1932 } else {
1933 if (Set.is_disjoint(Context))
1934 return false;
1935
1936 if (Set.is_subset(InvalidContext))
1937 return false;
1938 }
1939 return true;
1940 }
1941
trackAssumption(AssumptionKind Kind,isl::set Set,DebugLoc Loc,AssumptionSign Sign,BasicBlock * BB)1942 bool Scop::trackAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
1943 AssumptionSign Sign, BasicBlock *BB) {
1944 if (PollyRemarksMinimal && !isEffectiveAssumption(Set, Sign))
1945 return false;
1946
1947 // Do never emit trivial assumptions as they only clutter the output.
1948 if (!PollyRemarksMinimal) {
1949 isl::set Univ;
1950 if (Sign == AS_ASSUMPTION)
1951 Univ = isl::set::universe(Set.get_space());
1952
1953 bool IsTrivial = (Sign == AS_RESTRICTION && Set.is_empty()) ||
1954 (Sign == AS_ASSUMPTION && Univ.is_equal(Set));
1955
1956 if (IsTrivial)
1957 return false;
1958 }
1959
1960 switch (Kind) {
1961 case ALIASING:
1962 AssumptionsAliasing++;
1963 break;
1964 case INBOUNDS:
1965 AssumptionsInbounds++;
1966 break;
1967 case WRAPPING:
1968 AssumptionsWrapping++;
1969 break;
1970 case UNSIGNED:
1971 AssumptionsUnsigned++;
1972 break;
1973 case COMPLEXITY:
1974 AssumptionsComplexity++;
1975 break;
1976 case PROFITABLE:
1977 AssumptionsUnprofitable++;
1978 break;
1979 case ERRORBLOCK:
1980 AssumptionsErrorBlock++;
1981 break;
1982 case INFINITELOOP:
1983 AssumptionsInfiniteLoop++;
1984 break;
1985 case INVARIANTLOAD:
1986 AssumptionsInvariantLoad++;
1987 break;
1988 case DELINEARIZATION:
1989 AssumptionsDelinearization++;
1990 break;
1991 }
1992
1993 auto Suffix = Sign == AS_ASSUMPTION ? " assumption:\t" : " restriction:\t";
1994 std::string Msg = toString(Kind) + Suffix + stringFromIslObj(Set);
1995 if (BB)
1996 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc, BB)
1997 << Msg);
1998 else
1999 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc,
2000 R.getEntry())
2001 << Msg);
2002 return true;
2003 }
2004
addAssumption(AssumptionKind Kind,isl::set Set,DebugLoc Loc,AssumptionSign Sign,BasicBlock * BB,bool RequiresRTC)2005 void Scop::addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
2006 AssumptionSign Sign, BasicBlock *BB,
2007 bool RequiresRTC) {
2008 // Simplify the assumptions/restrictions first.
2009 Set = Set.gist_params(getContext());
2010 intersectDefinedBehavior(Set, Sign);
2011
2012 if (!RequiresRTC)
2013 return;
2014
2015 if (!trackAssumption(Kind, Set, Loc, Sign, BB))
2016 return;
2017
2018 if (Sign == AS_ASSUMPTION)
2019 AssumedContext = AssumedContext.intersect(Set).coalesce();
2020 else
2021 InvalidContext = InvalidContext.unite(Set).coalesce();
2022 }
2023
intersectDefinedBehavior(isl::set Set,AssumptionSign Sign)2024 void Scop::intersectDefinedBehavior(isl::set Set, AssumptionSign Sign) {
2025 if (DefinedBehaviorContext.is_null())
2026 return;
2027
2028 if (Sign == AS_ASSUMPTION)
2029 DefinedBehaviorContext = DefinedBehaviorContext.intersect(Set);
2030 else
2031 DefinedBehaviorContext = DefinedBehaviorContext.subtract(Set);
2032
2033 // Limit the complexity of the context. If complexity is exceeded, simplify
2034 // the set and check again.
2035 if (DefinedBehaviorContext.n_basic_set().release() >
2036 MaxDisjunktsInDefinedBehaviourContext) {
2037 simplify(DefinedBehaviorContext);
2038 if (DefinedBehaviorContext.n_basic_set().release() >
2039 MaxDisjunktsInDefinedBehaviourContext)
2040 DefinedBehaviorContext = {};
2041 }
2042 }
2043
invalidate(AssumptionKind Kind,DebugLoc Loc,BasicBlock * BB)2044 void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB) {
2045 LLVM_DEBUG(dbgs() << "Invalidate SCoP because of reason " << Kind << "\n");
2046 addAssumption(Kind, isl::set::empty(getParamSpace()), Loc, AS_ASSUMPTION, BB);
2047 }
2048
getInvalidContext() const2049 isl::set Scop::getInvalidContext() const { return InvalidContext; }
2050
printContext(raw_ostream & OS) const2051 void Scop::printContext(raw_ostream &OS) const {
2052 OS << "Context:\n";
2053 OS.indent(4) << Context << "\n";
2054
2055 OS.indent(4) << "Assumed Context:\n";
2056 OS.indent(4) << AssumedContext << "\n";
2057
2058 OS.indent(4) << "Invalid Context:\n";
2059 OS.indent(4) << InvalidContext << "\n";
2060
2061 OS.indent(4) << "Defined Behavior Context:\n";
2062 if (!DefinedBehaviorContext.is_null())
2063 OS.indent(4) << DefinedBehaviorContext << "\n";
2064 else
2065 OS.indent(4) << "<unavailable>\n";
2066
2067 unsigned Dim = 0;
2068 for (const SCEV *Parameter : Parameters)
2069 OS.indent(4) << "p" << Dim++ << ": " << *Parameter << "\n";
2070 }
2071
printAliasAssumptions(raw_ostream & OS) const2072 void Scop::printAliasAssumptions(raw_ostream &OS) const {
2073 int noOfGroups = 0;
2074 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) {
2075 if (Pair.second.size() == 0)
2076 noOfGroups += 1;
2077 else
2078 noOfGroups += Pair.second.size();
2079 }
2080
2081 OS.indent(4) << "Alias Groups (" << noOfGroups << "):\n";
2082 if (MinMaxAliasGroups.empty()) {
2083 OS.indent(8) << "n/a\n";
2084 return;
2085 }
2086
2087 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) {
2088
2089 // If the group has no read only accesses print the write accesses.
2090 if (Pair.second.empty()) {
2091 OS.indent(8) << "[[";
2092 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) {
2093 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second
2094 << ">";
2095 }
2096 OS << " ]]\n";
2097 }
2098
2099 for (const MinMaxAccessTy &MMAReadOnly : Pair.second) {
2100 OS.indent(8) << "[[";
2101 OS << " <" << MMAReadOnly.first << ", " << MMAReadOnly.second << ">";
2102 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) {
2103 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second
2104 << ">";
2105 }
2106 OS << " ]]\n";
2107 }
2108 }
2109 }
2110
printStatements(raw_ostream & OS,bool PrintInstructions) const2111 void Scop::printStatements(raw_ostream &OS, bool PrintInstructions) const {
2112 OS << "Statements {\n";
2113
2114 for (const ScopStmt &Stmt : *this) {
2115 OS.indent(4);
2116 Stmt.print(OS, PrintInstructions);
2117 }
2118
2119 OS.indent(4) << "}\n";
2120 }
2121
printArrayInfo(raw_ostream & OS) const2122 void Scop::printArrayInfo(raw_ostream &OS) const {
2123 OS << "Arrays {\n";
2124
2125 for (auto &Array : arrays())
2126 Array->print(OS);
2127
2128 OS.indent(4) << "}\n";
2129
2130 OS.indent(4) << "Arrays (Bounds as pw_affs) {\n";
2131
2132 for (auto &Array : arrays())
2133 Array->print(OS, /* SizeAsPwAff */ true);
2134
2135 OS.indent(4) << "}\n";
2136 }
2137
print(raw_ostream & OS,bool PrintInstructions) const2138 void Scop::print(raw_ostream &OS, bool PrintInstructions) const {
2139 OS.indent(4) << "Function: " << getFunction().getName() << "\n";
2140 OS.indent(4) << "Region: " << getNameStr() << "\n";
2141 OS.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n";
2142 OS.indent(4) << "Invariant Accesses: {\n";
2143 for (const auto &IAClass : InvariantEquivClasses) {
2144 const auto &MAs = IAClass.InvariantAccesses;
2145 if (MAs.empty()) {
2146 OS.indent(12) << "Class Pointer: " << *IAClass.IdentifyingPointer << "\n";
2147 } else {
2148 MAs.front()->print(OS);
2149 OS.indent(12) << "Execution Context: " << IAClass.ExecutionContext
2150 << "\n";
2151 }
2152 }
2153 OS.indent(4) << "}\n";
2154 printContext(OS.indent(4));
2155 printArrayInfo(OS.indent(4));
2156 printAliasAssumptions(OS);
2157 printStatements(OS.indent(4), PrintInstructions);
2158 }
2159
2160 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const2161 LLVM_DUMP_METHOD void Scop::dump() const { print(dbgs(), true); }
2162 #endif
2163
getIslCtx() const2164 isl::ctx Scop::getIslCtx() const { return IslCtx.get(); }
2165
getPwAff(const SCEV * E,BasicBlock * BB,bool NonNegative,RecordedAssumptionsTy * RecordedAssumptions)2166 __isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB,
2167 bool NonNegative,
2168 RecordedAssumptionsTy *RecordedAssumptions) {
2169 // First try to use the SCEVAffinator to generate a piecewise defined
2170 // affine function from @p E in the context of @p BB. If that tasks becomes to
2171 // complex the affinator might return a nullptr. In such a case we invalidate
2172 // the SCoP and return a dummy value. This way we do not need to add error
2173 // handling code to all users of this function.
2174 auto PWAC = Affinator.getPwAff(E, BB, RecordedAssumptions);
2175 if (!PWAC.first.is_null()) {
2176 // TODO: We could use a heuristic and either use:
2177 // SCEVAffinator::takeNonNegativeAssumption
2178 // or
2179 // SCEVAffinator::interpretAsUnsigned
2180 // to deal with unsigned or "NonNegative" SCEVs.
2181 if (NonNegative)
2182 Affinator.takeNonNegativeAssumption(PWAC, RecordedAssumptions);
2183 return PWAC;
2184 }
2185
2186 auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc();
2187 invalidate(COMPLEXITY, DL, BB);
2188 return Affinator.getPwAff(SE->getZero(E->getType()), BB, RecordedAssumptions);
2189 }
2190
getDomains() const2191 isl::union_set Scop::getDomains() const {
2192 isl_space *EmptySpace = isl_space_params_alloc(getIslCtx().get(), 0);
2193 isl_union_set *Domain = isl_union_set_empty(EmptySpace);
2194
2195 for (const ScopStmt &Stmt : *this)
2196 Domain = isl_union_set_add_set(Domain, Stmt.getDomain().release());
2197
2198 return isl::manage(Domain);
2199 }
2200
getPwAffOnly(const SCEV * E,BasicBlock * BB,RecordedAssumptionsTy * RecordedAssumptions)2201 isl::pw_aff Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB,
2202 RecordedAssumptionsTy *RecordedAssumptions) {
2203 PWACtx PWAC = getPwAff(E, BB, RecordedAssumptions);
2204 return PWAC.first;
2205 }
2206
2207 isl::union_map
getAccessesOfType(std::function<bool (MemoryAccess &)> Predicate)2208 Scop::getAccessesOfType(std::function<bool(MemoryAccess &)> Predicate) {
2209 isl::union_map Accesses = isl::union_map::empty(getIslCtx());
2210
2211 for (ScopStmt &Stmt : *this) {
2212 for (MemoryAccess *MA : Stmt) {
2213 if (!Predicate(*MA))
2214 continue;
2215
2216 isl::set Domain = Stmt.getDomain();
2217 isl::map AccessDomain = MA->getAccessRelation();
2218 AccessDomain = AccessDomain.intersect_domain(Domain);
2219 Accesses = Accesses.unite(AccessDomain);
2220 }
2221 }
2222
2223 return Accesses.coalesce();
2224 }
2225
getMustWrites()2226 isl::union_map Scop::getMustWrites() {
2227 return getAccessesOfType([](MemoryAccess &MA) { return MA.isMustWrite(); });
2228 }
2229
getMayWrites()2230 isl::union_map Scop::getMayWrites() {
2231 return getAccessesOfType([](MemoryAccess &MA) { return MA.isMayWrite(); });
2232 }
2233
getWrites()2234 isl::union_map Scop::getWrites() {
2235 return getAccessesOfType([](MemoryAccess &MA) { return MA.isWrite(); });
2236 }
2237
getReads()2238 isl::union_map Scop::getReads() {
2239 return getAccessesOfType([](MemoryAccess &MA) { return MA.isRead(); });
2240 }
2241
getAccesses()2242 isl::union_map Scop::getAccesses() {
2243 return getAccessesOfType([](MemoryAccess &MA) { return true; });
2244 }
2245
getAccesses(ScopArrayInfo * Array)2246 isl::union_map Scop::getAccesses(ScopArrayInfo *Array) {
2247 return getAccessesOfType(
2248 [Array](MemoryAccess &MA) { return MA.getScopArrayInfo() == Array; });
2249 }
2250
getSchedule() const2251 isl::union_map Scop::getSchedule() const {
2252 auto Tree = getScheduleTree();
2253 return Tree.get_map();
2254 }
2255
getScheduleTree() const2256 isl::schedule Scop::getScheduleTree() const {
2257 return Schedule.intersect_domain(getDomains());
2258 }
2259
setSchedule(isl::union_map NewSchedule)2260 void Scop::setSchedule(isl::union_map NewSchedule) {
2261 auto S = isl::schedule::from_domain(getDomains());
2262 Schedule = S.insert_partial_schedule(
2263 isl::multi_union_pw_aff::from_union_map(NewSchedule));
2264 ScheduleModified = true;
2265 }
2266
setScheduleTree(isl::schedule NewSchedule)2267 void Scop::setScheduleTree(isl::schedule NewSchedule) {
2268 Schedule = NewSchedule;
2269 ScheduleModified = true;
2270 }
2271
restrictDomains(isl::union_set Domain)2272 bool Scop::restrictDomains(isl::union_set Domain) {
2273 bool Changed = false;
2274 for (ScopStmt &Stmt : *this) {
2275 isl::union_set StmtDomain = isl::union_set(Stmt.getDomain());
2276 isl::union_set NewStmtDomain = StmtDomain.intersect(Domain);
2277
2278 if (StmtDomain.is_subset(NewStmtDomain))
2279 continue;
2280
2281 Changed = true;
2282
2283 NewStmtDomain = NewStmtDomain.coalesce();
2284
2285 if (NewStmtDomain.is_empty())
2286 Stmt.restrictDomain(isl::set::empty(Stmt.getDomainSpace()));
2287 else
2288 Stmt.restrictDomain(isl::set(NewStmtDomain));
2289 }
2290 return Changed;
2291 }
2292
getSE() const2293 ScalarEvolution *Scop::getSE() const { return SE; }
2294
addScopStmt(BasicBlock * BB,StringRef Name,Loop * SurroundingLoop,std::vector<Instruction * > Instructions)2295 void Scop::addScopStmt(BasicBlock *BB, StringRef Name, Loop *SurroundingLoop,
2296 std::vector<Instruction *> Instructions) {
2297 assert(BB && "Unexpected nullptr!");
2298 Stmts.emplace_back(*this, *BB, Name, SurroundingLoop, Instructions);
2299 auto *Stmt = &Stmts.back();
2300 StmtMap[BB].push_back(Stmt);
2301 for (Instruction *Inst : Instructions) {
2302 assert(!InstStmtMap.count(Inst) &&
2303 "Unexpected statement corresponding to the instruction.");
2304 InstStmtMap[Inst] = Stmt;
2305 }
2306 }
2307
addScopStmt(Region * R,StringRef Name,Loop * SurroundingLoop,std::vector<Instruction * > Instructions)2308 void Scop::addScopStmt(Region *R, StringRef Name, Loop *SurroundingLoop,
2309 std::vector<Instruction *> Instructions) {
2310 assert(R && "Unexpected nullptr!");
2311 Stmts.emplace_back(*this, *R, Name, SurroundingLoop, Instructions);
2312 auto *Stmt = &Stmts.back();
2313
2314 for (Instruction *Inst : Instructions) {
2315 assert(!InstStmtMap.count(Inst) &&
2316 "Unexpected statement corresponding to the instruction.");
2317 InstStmtMap[Inst] = Stmt;
2318 }
2319
2320 for (BasicBlock *BB : R->blocks()) {
2321 StmtMap[BB].push_back(Stmt);
2322 if (BB == R->getEntry())
2323 continue;
2324 for (Instruction &Inst : *BB) {
2325 assert(!InstStmtMap.count(&Inst) &&
2326 "Unexpected statement corresponding to the instruction.");
2327 InstStmtMap[&Inst] = Stmt;
2328 }
2329 }
2330 }
2331
addScopStmt(isl::map SourceRel,isl::map TargetRel,isl::set Domain)2332 ScopStmt *Scop::addScopStmt(isl::map SourceRel, isl::map TargetRel,
2333 isl::set Domain) {
2334 #ifndef NDEBUG
2335 isl::set SourceDomain = SourceRel.domain();
2336 isl::set TargetDomain = TargetRel.domain();
2337 assert(Domain.is_subset(TargetDomain) &&
2338 "Target access not defined for complete statement domain");
2339 assert(Domain.is_subset(SourceDomain) &&
2340 "Source access not defined for complete statement domain");
2341 #endif
2342 Stmts.emplace_back(*this, SourceRel, TargetRel, Domain);
2343 CopyStmtsNum++;
2344 return &(Stmts.back());
2345 }
2346
getStmtListFor(BasicBlock * BB) const2347 ArrayRef<ScopStmt *> Scop::getStmtListFor(BasicBlock *BB) const {
2348 auto StmtMapIt = StmtMap.find(BB);
2349 if (StmtMapIt == StmtMap.end())
2350 return {};
2351 return StmtMapIt->second;
2352 }
2353
getIncomingStmtFor(const Use & U) const2354 ScopStmt *Scop::getIncomingStmtFor(const Use &U) const {
2355 auto *PHI = cast<PHINode>(U.getUser());
2356 BasicBlock *IncomingBB = PHI->getIncomingBlock(U);
2357
2358 // If the value is a non-synthesizable from the incoming block, use the
2359 // statement that contains it as user statement.
2360 if (auto *IncomingInst = dyn_cast<Instruction>(U.get())) {
2361 if (IncomingInst->getParent() == IncomingBB) {
2362 if (ScopStmt *IncomingStmt = getStmtFor(IncomingInst))
2363 return IncomingStmt;
2364 }
2365 }
2366
2367 // Otherwise, use the epilogue/last statement.
2368 return getLastStmtFor(IncomingBB);
2369 }
2370
getLastStmtFor(BasicBlock * BB) const2371 ScopStmt *Scop::getLastStmtFor(BasicBlock *BB) const {
2372 ArrayRef<ScopStmt *> StmtList = getStmtListFor(BB);
2373 if (!StmtList.empty())
2374 return StmtList.back();
2375 return nullptr;
2376 }
2377
getStmtListFor(RegionNode * RN) const2378 ArrayRef<ScopStmt *> Scop::getStmtListFor(RegionNode *RN) const {
2379 if (RN->isSubRegion())
2380 return getStmtListFor(RN->getNodeAs<Region>());
2381 return getStmtListFor(RN->getNodeAs<BasicBlock>());
2382 }
2383
getStmtListFor(Region * R) const2384 ArrayRef<ScopStmt *> Scop::getStmtListFor(Region *R) const {
2385 return getStmtListFor(R->getEntry());
2386 }
2387
getRelativeLoopDepth(const Loop * L) const2388 int Scop::getRelativeLoopDepth(const Loop *L) const {
2389 if (!L || !R.contains(L))
2390 return -1;
2391 // outermostLoopInRegion always returns nullptr for top level regions
2392 if (R.isTopLevelRegion()) {
2393 // LoopInfo's depths start at 1, we start at 0
2394 return L->getLoopDepth() - 1;
2395 } else {
2396 Loop *OuterLoop = R.outermostLoopInRegion(const_cast<Loop *>(L));
2397 assert(OuterLoop);
2398 return L->getLoopDepth() - OuterLoop->getLoopDepth();
2399 }
2400 }
2401
getArrayInfoByName(const std::string BaseName)2402 ScopArrayInfo *Scop::getArrayInfoByName(const std::string BaseName) {
2403 for (auto &SAI : arrays()) {
2404 if (SAI->getName() == BaseName)
2405 return SAI;
2406 }
2407 return nullptr;
2408 }
2409
addAccessData(MemoryAccess * Access)2410 void Scop::addAccessData(MemoryAccess *Access) {
2411 const ScopArrayInfo *SAI = Access->getOriginalScopArrayInfo();
2412 assert(SAI && "can only use after access relations have been constructed");
2413
2414 if (Access->isOriginalValueKind() && Access->isRead())
2415 ValueUseAccs[SAI].push_back(Access);
2416 else if (Access->isOriginalAnyPHIKind() && Access->isWrite())
2417 PHIIncomingAccs[SAI].push_back(Access);
2418 }
2419
removeAccessData(MemoryAccess * Access)2420 void Scop::removeAccessData(MemoryAccess *Access) {
2421 if (Access->isOriginalValueKind() && Access->isWrite()) {
2422 ValueDefAccs.erase(Access->getAccessValue());
2423 } else if (Access->isOriginalValueKind() && Access->isRead()) {
2424 auto &Uses = ValueUseAccs[Access->getScopArrayInfo()];
2425 auto NewEnd = std::remove(Uses.begin(), Uses.end(), Access);
2426 Uses.erase(NewEnd, Uses.end());
2427 } else if (Access->isOriginalPHIKind() && Access->isRead()) {
2428 PHINode *PHI = cast<PHINode>(Access->getAccessInstruction());
2429 PHIReadAccs.erase(PHI);
2430 } else if (Access->isOriginalAnyPHIKind() && Access->isWrite()) {
2431 auto &Incomings = PHIIncomingAccs[Access->getScopArrayInfo()];
2432 auto NewEnd = std::remove(Incomings.begin(), Incomings.end(), Access);
2433 Incomings.erase(NewEnd, Incomings.end());
2434 }
2435 }
2436
getValueDef(const ScopArrayInfo * SAI) const2437 MemoryAccess *Scop::getValueDef(const ScopArrayInfo *SAI) const {
2438 assert(SAI->isValueKind());
2439
2440 Instruction *Val = dyn_cast<Instruction>(SAI->getBasePtr());
2441 if (!Val)
2442 return nullptr;
2443
2444 return ValueDefAccs.lookup(Val);
2445 }
2446
getValueUses(const ScopArrayInfo * SAI) const2447 ArrayRef<MemoryAccess *> Scop::getValueUses(const ScopArrayInfo *SAI) const {
2448 assert(SAI->isValueKind());
2449 auto It = ValueUseAccs.find(SAI);
2450 if (It == ValueUseAccs.end())
2451 return {};
2452 return It->second;
2453 }
2454
getPHIRead(const ScopArrayInfo * SAI) const2455 MemoryAccess *Scop::getPHIRead(const ScopArrayInfo *SAI) const {
2456 assert(SAI->isPHIKind() || SAI->isExitPHIKind());
2457
2458 if (SAI->isExitPHIKind())
2459 return nullptr;
2460
2461 PHINode *PHI = cast<PHINode>(SAI->getBasePtr());
2462 return PHIReadAccs.lookup(PHI);
2463 }
2464
getPHIIncomings(const ScopArrayInfo * SAI) const2465 ArrayRef<MemoryAccess *> Scop::getPHIIncomings(const ScopArrayInfo *SAI) const {
2466 assert(SAI->isPHIKind() || SAI->isExitPHIKind());
2467 auto It = PHIIncomingAccs.find(SAI);
2468 if (It == PHIIncomingAccs.end())
2469 return {};
2470 return It->second;
2471 }
2472
isEscaping(Instruction * Inst)2473 bool Scop::isEscaping(Instruction *Inst) {
2474 assert(contains(Inst) && "The concept of escaping makes only sense for "
2475 "values defined inside the SCoP");
2476
2477 for (Use &Use : Inst->uses()) {
2478 BasicBlock *UserBB = getUseBlock(Use);
2479 if (!contains(UserBB))
2480 return true;
2481
2482 // When the SCoP region exit needs to be simplified, PHIs in the region exit
2483 // move to a new basic block such that its incoming blocks are not in the
2484 // SCoP anymore.
2485 if (hasSingleExitEdge() && isa<PHINode>(Use.getUser()) &&
2486 isExit(cast<PHINode>(Use.getUser())->getParent()))
2487 return true;
2488 }
2489 return false;
2490 }
2491
incrementNumberOfAliasingAssumptions(unsigned step)2492 void Scop::incrementNumberOfAliasingAssumptions(unsigned step) {
2493 AssumptionsAliasing += step;
2494 }
2495
getStatistics() const2496 Scop::ScopStatistics Scop::getStatistics() const {
2497 ScopStatistics Result;
2498 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2499 auto LoopStat = ScopDetection::countBeneficialLoops(&R, *SE, *getLI(), 0);
2500
2501 int NumTotalLoops = LoopStat.NumLoops;
2502 Result.NumBoxedLoops = getBoxedLoops().size();
2503 Result.NumAffineLoops = NumTotalLoops - Result.NumBoxedLoops;
2504
2505 for (const ScopStmt &Stmt : *this) {
2506 isl::set Domain = Stmt.getDomain().intersect_params(getContext());
2507 bool IsInLoop = Stmt.getNumIterators() >= 1;
2508 for (MemoryAccess *MA : Stmt) {
2509 if (!MA->isWrite())
2510 continue;
2511
2512 if (MA->isLatestValueKind()) {
2513 Result.NumValueWrites += 1;
2514 if (IsInLoop)
2515 Result.NumValueWritesInLoops += 1;
2516 }
2517
2518 if (MA->isLatestAnyPHIKind()) {
2519 Result.NumPHIWrites += 1;
2520 if (IsInLoop)
2521 Result.NumPHIWritesInLoops += 1;
2522 }
2523
2524 isl::set AccSet =
2525 MA->getAccessRelation().intersect_domain(Domain).range();
2526 if (AccSet.is_singleton()) {
2527 Result.NumSingletonWrites += 1;
2528 if (IsInLoop)
2529 Result.NumSingletonWritesInLoops += 1;
2530 }
2531 }
2532 }
2533 #endif
2534 return Result;
2535 }
2536
operator <<(raw_ostream & OS,const Scop & scop)2537 raw_ostream &polly::operator<<(raw_ostream &OS, const Scop &scop) {
2538 scop.print(OS, PollyPrintInstructions);
2539 return OS;
2540 }
2541
2542 //===----------------------------------------------------------------------===//
getAnalysisUsage(AnalysisUsage & AU) const2543 void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage &AU) const {
2544 AU.addRequired<LoopInfoWrapperPass>();
2545 AU.addRequired<RegionInfoPass>();
2546 AU.addRequired<DominatorTreeWrapperPass>();
2547 AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
2548 AU.addRequiredTransitive<ScopDetectionWrapperPass>();
2549 AU.addRequired<AAResultsWrapperPass>();
2550 AU.addRequired<AssumptionCacheTracker>();
2551 AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
2552 AU.setPreservesAll();
2553 }
2554
updateLoopCountStatistic(ScopDetection::LoopStats Stats,Scop::ScopStatistics ScopStats)2555 void updateLoopCountStatistic(ScopDetection::LoopStats Stats,
2556 Scop::ScopStatistics ScopStats) {
2557 assert(Stats.NumLoops == ScopStats.NumAffineLoops + ScopStats.NumBoxedLoops);
2558
2559 NumScops++;
2560 NumLoopsInScop += Stats.NumLoops;
2561 MaxNumLoopsInScop =
2562 std::max(MaxNumLoopsInScop.getValue(), (uint64_t)Stats.NumLoops);
2563
2564 if (Stats.MaxDepth == 0)
2565 NumScopsDepthZero++;
2566 else if (Stats.MaxDepth == 1)
2567 NumScopsDepthOne++;
2568 else if (Stats.MaxDepth == 2)
2569 NumScopsDepthTwo++;
2570 else if (Stats.MaxDepth == 3)
2571 NumScopsDepthThree++;
2572 else if (Stats.MaxDepth == 4)
2573 NumScopsDepthFour++;
2574 else if (Stats.MaxDepth == 5)
2575 NumScopsDepthFive++;
2576 else
2577 NumScopsDepthLarger++;
2578
2579 NumAffineLoops += ScopStats.NumAffineLoops;
2580 NumBoxedLoops += ScopStats.NumBoxedLoops;
2581
2582 NumValueWrites += ScopStats.NumValueWrites;
2583 NumValueWritesInLoops += ScopStats.NumValueWritesInLoops;
2584 NumPHIWrites += ScopStats.NumPHIWrites;
2585 NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops;
2586 NumSingletonWrites += ScopStats.NumSingletonWrites;
2587 NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops;
2588 }
2589
runOnRegion(Region * R,RGPassManager & RGM)2590 bool ScopInfoRegionPass::runOnRegion(Region *R, RGPassManager &RGM) {
2591 auto &SD = getAnalysis<ScopDetectionWrapperPass>().getSD();
2592
2593 if (!SD.isMaxRegionInScop(*R))
2594 return false;
2595
2596 Function *F = R->getEntry()->getParent();
2597 auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
2598 auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
2599 auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
2600 auto const &DL = F->getParent()->getDataLayout();
2601 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
2602 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(*F);
2603 auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
2604
2605 ScopBuilder SB(R, AC, AA, DL, DT, LI, SD, SE, ORE);
2606 S = SB.getScop(); // take ownership of scop object
2607
2608 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2609 if (S) {
2610 ScopDetection::LoopStats Stats =
2611 ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0);
2612 updateLoopCountStatistic(Stats, S->getStatistics());
2613 }
2614 #endif
2615
2616 return false;
2617 }
2618
print(raw_ostream & OS,const Module *) const2619 void ScopInfoRegionPass::print(raw_ostream &OS, const Module *) const {
2620 if (S)
2621 S->print(OS, PollyPrintInstructions);
2622 else
2623 OS << "Invalid Scop!\n";
2624 }
2625
2626 char ScopInfoRegionPass::ID = 0;
2627
createScopInfoRegionPassPass()2628 Pass *polly::createScopInfoRegionPassPass() { return new ScopInfoRegionPass(); }
2629
2630 INITIALIZE_PASS_BEGIN(ScopInfoRegionPass, "polly-scops",
2631 "Polly - Create polyhedral description of Scops", false,
2632 false);
2633 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
2634 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker);
2635 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
2636 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
2637 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
2638 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass);
2639 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
2640 INITIALIZE_PASS_END(ScopInfoRegionPass, "polly-scops",
2641 "Polly - Create polyhedral description of Scops", false,
2642 false)
2643
2644 //===----------------------------------------------------------------------===//
2645
2646 namespace {
2647
2648 /// Print result from ScopInfoRegionPass.
2649 class ScopInfoPrinterLegacyRegionPass final : public RegionPass {
2650 public:
2651 static char ID;
2652
ScopInfoPrinterLegacyRegionPass()2653 ScopInfoPrinterLegacyRegionPass() : ScopInfoPrinterLegacyRegionPass(outs()) {}
2654
ScopInfoPrinterLegacyRegionPass(llvm::raw_ostream & OS)2655 explicit ScopInfoPrinterLegacyRegionPass(llvm::raw_ostream &OS)
2656 : RegionPass(ID), OS(OS) {}
2657
runOnRegion(Region * R,RGPassManager & RGM)2658 bool runOnRegion(Region *R, RGPassManager &RGM) override {
2659 ScopInfoRegionPass &P = getAnalysis<ScopInfoRegionPass>();
2660
2661 OS << "Printing analysis '" << P.getPassName() << "' for region: '"
2662 << R->getNameStr() << "' in function '"
2663 << R->getEntry()->getParent()->getName() << "':\n";
2664 P.print(OS);
2665
2666 return false;
2667 }
2668
getAnalysisUsage(AnalysisUsage & AU) const2669 void getAnalysisUsage(AnalysisUsage &AU) const override {
2670 RegionPass::getAnalysisUsage(AU);
2671 AU.addRequired<ScopInfoRegionPass>();
2672 AU.setPreservesAll();
2673 }
2674
2675 private:
2676 llvm::raw_ostream &OS;
2677 };
2678
2679 char ScopInfoPrinterLegacyRegionPass::ID = 0;
2680 } // namespace
2681
createScopInfoPrinterLegacyRegionPass(raw_ostream & OS)2682 Pass *polly::createScopInfoPrinterLegacyRegionPass(raw_ostream &OS) {
2683 return new ScopInfoPrinterLegacyRegionPass(OS);
2684 }
2685
2686 INITIALIZE_PASS_BEGIN(ScopInfoPrinterLegacyRegionPass, "polly-print-scops",
2687 "Polly - Print polyhedral description of Scops", false,
2688 false);
2689 INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass);
2690 INITIALIZE_PASS_END(ScopInfoPrinterLegacyRegionPass, "polly-print-scops",
2691 "Polly - Print polyhedral description of Scops", false,
2692 false)
2693
2694 //===----------------------------------------------------------------------===//
2695
ScopInfo(const DataLayout & DL,ScopDetection & SD,ScalarEvolution & SE,LoopInfo & LI,AliasAnalysis & AA,DominatorTree & DT,AssumptionCache & AC,OptimizationRemarkEmitter & ORE)2696 ScopInfo::ScopInfo(const DataLayout &DL, ScopDetection &SD, ScalarEvolution &SE,
2697 LoopInfo &LI, AliasAnalysis &AA, DominatorTree &DT,
2698 AssumptionCache &AC, OptimizationRemarkEmitter &ORE)
2699 : DL(DL), SD(SD), SE(SE), LI(LI), AA(AA), DT(DT), AC(AC), ORE(ORE) {
2700 recompute();
2701 }
2702
recompute()2703 void ScopInfo::recompute() {
2704 RegionToScopMap.clear();
2705 /// Create polyhedral description of scops for all the valid regions of a
2706 /// function.
2707 for (auto &It : SD) {
2708 Region *R = const_cast<Region *>(It);
2709 if (!SD.isMaxRegionInScop(*R))
2710 continue;
2711
2712 ScopBuilder SB(R, AC, AA, DL, DT, LI, SD, SE, ORE);
2713 std::unique_ptr<Scop> S = SB.getScop();
2714 if (!S)
2715 continue;
2716 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2717 ScopDetection::LoopStats Stats =
2718 ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0);
2719 updateLoopCountStatistic(Stats, S->getStatistics());
2720 #endif
2721 bool Inserted = RegionToScopMap.insert({R, std::move(S)}).second;
2722 assert(Inserted && "Building Scop for the same region twice!");
2723 (void)Inserted;
2724 }
2725 }
2726
invalidate(Function & F,const PreservedAnalyses & PA,FunctionAnalysisManager::Invalidator & Inv)2727 bool ScopInfo::invalidate(Function &F, const PreservedAnalyses &PA,
2728 FunctionAnalysisManager::Invalidator &Inv) {
2729 // Check whether the analysis, all analyses on functions have been preserved
2730 // or anything we're holding references to is being invalidated
2731 auto PAC = PA.getChecker<ScopInfoAnalysis>();
2732 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) ||
2733 Inv.invalidate<ScopAnalysis>(F, PA) ||
2734 Inv.invalidate<ScalarEvolutionAnalysis>(F, PA) ||
2735 Inv.invalidate<LoopAnalysis>(F, PA) ||
2736 Inv.invalidate<AAManager>(F, PA) ||
2737 Inv.invalidate<DominatorTreeAnalysis>(F, PA) ||
2738 Inv.invalidate<AssumptionAnalysis>(F, PA);
2739 }
2740
2741 AnalysisKey ScopInfoAnalysis::Key;
2742
run(Function & F,FunctionAnalysisManager & FAM)2743 ScopInfoAnalysis::Result ScopInfoAnalysis::run(Function &F,
2744 FunctionAnalysisManager &FAM) {
2745 auto &SD = FAM.getResult<ScopAnalysis>(F);
2746 auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(F);
2747 auto &LI = FAM.getResult<LoopAnalysis>(F);
2748 auto &AA = FAM.getResult<AAManager>(F);
2749 auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
2750 auto &AC = FAM.getResult<AssumptionAnalysis>(F);
2751 auto &DL = F.getParent()->getDataLayout();
2752 auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
2753 return {DL, SD, SE, LI, AA, DT, AC, ORE};
2754 }
2755
run(Function & F,FunctionAnalysisManager & FAM)2756 PreservedAnalyses ScopInfoPrinterPass::run(Function &F,
2757 FunctionAnalysisManager &FAM) {
2758 auto &SI = FAM.getResult<ScopInfoAnalysis>(F);
2759 // Since the legacy PM processes Scops in bottom up, we print them in reverse
2760 // order here to keep the output persistent
2761 for (auto &It : reverse(SI)) {
2762 if (It.second)
2763 It.second->print(Stream, PollyPrintInstructions);
2764 else
2765 Stream << "Invalid Scop!\n";
2766 }
2767 return PreservedAnalyses::all();
2768 }
2769
getAnalysisUsage(AnalysisUsage & AU) const2770 void ScopInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
2771 AU.addRequired<LoopInfoWrapperPass>();
2772 AU.addRequired<RegionInfoPass>();
2773 AU.addRequired<DominatorTreeWrapperPass>();
2774 AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
2775 AU.addRequiredTransitive<ScopDetectionWrapperPass>();
2776 AU.addRequired<AAResultsWrapperPass>();
2777 AU.addRequired<AssumptionCacheTracker>();
2778 AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
2779 AU.setPreservesAll();
2780 }
2781
runOnFunction(Function & F)2782 bool ScopInfoWrapperPass::runOnFunction(Function &F) {
2783 auto &SD = getAnalysis<ScopDetectionWrapperPass>().getSD();
2784 auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
2785 auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
2786 auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults();
2787 auto const &DL = F.getParent()->getDataLayout();
2788 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
2789 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
2790 auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE();
2791
2792 Result.reset(new ScopInfo{DL, SD, SE, LI, AA, DT, AC, ORE});
2793 return false;
2794 }
2795
print(raw_ostream & OS,const Module *) const2796 void ScopInfoWrapperPass::print(raw_ostream &OS, const Module *) const {
2797 for (auto &It : *Result) {
2798 if (It.second)
2799 It.second->print(OS, PollyPrintInstructions);
2800 else
2801 OS << "Invalid Scop!\n";
2802 }
2803 }
2804
2805 char ScopInfoWrapperPass::ID = 0;
2806
createScopInfoWrapperPassPass()2807 Pass *polly::createScopInfoWrapperPassPass() {
2808 return new ScopInfoWrapperPass();
2809 }
2810
2811 INITIALIZE_PASS_BEGIN(
2812 ScopInfoWrapperPass, "polly-function-scops",
2813 "Polly - Create polyhedral description of all Scops of a function", false,
2814 false);
2815 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
2816 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker);
2817 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
2818 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
2819 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
2820 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass);
2821 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass);
2822 INITIALIZE_PASS_END(
2823 ScopInfoWrapperPass, "polly-function-scops",
2824 "Polly - Create polyhedral description of all Scops of a function", false,
2825 false)
2826
2827 //===----------------------------------------------------------------------===//
2828
2829 namespace {
2830 /// Print result from ScopInfoWrapperPass.
2831 class ScopInfoPrinterLegacyFunctionPass final : public FunctionPass {
2832 public:
2833 static char ID;
2834
ScopInfoPrinterLegacyFunctionPass()2835 ScopInfoPrinterLegacyFunctionPass()
2836 : ScopInfoPrinterLegacyFunctionPass(outs()) {}
ScopInfoPrinterLegacyFunctionPass(llvm::raw_ostream & OS)2837 explicit ScopInfoPrinterLegacyFunctionPass(llvm::raw_ostream &OS)
2838 : FunctionPass(ID), OS(OS) {}
2839
runOnFunction(Function & F)2840 bool runOnFunction(Function &F) override {
2841 ScopInfoWrapperPass &P = getAnalysis<ScopInfoWrapperPass>();
2842
2843 OS << "Printing analysis '" << P.getPassName() << "' for function '"
2844 << F.getName() << "':\n";
2845 P.print(OS);
2846
2847 return false;
2848 }
2849
getAnalysisUsage(AnalysisUsage & AU) const2850 void getAnalysisUsage(AnalysisUsage &AU) const override {
2851 FunctionPass::getAnalysisUsage(AU);
2852 AU.addRequired<ScopInfoWrapperPass>();
2853 AU.setPreservesAll();
2854 }
2855
2856 private:
2857 llvm::raw_ostream &OS;
2858 };
2859
2860 char ScopInfoPrinterLegacyFunctionPass::ID = 0;
2861 } // namespace
2862
createScopInfoPrinterLegacyFunctionPass(raw_ostream & OS)2863 Pass *polly::createScopInfoPrinterLegacyFunctionPass(raw_ostream &OS) {
2864 return new ScopInfoPrinterLegacyFunctionPass(OS);
2865 }
2866
2867 INITIALIZE_PASS_BEGIN(
2868 ScopInfoPrinterLegacyFunctionPass, "polly-print-function-scops",
2869 "Polly - Print polyhedral description of all Scops of a function", false,
2870 false);
2871 INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass);
2872 INITIALIZE_PASS_END(
2873 ScopInfoPrinterLegacyFunctionPass, "polly-print-function-scops",
2874 "Polly - Print polyhedral description of all Scops of a function", false,
2875 false)
2876