1 //===- ScopInfo.cpp -------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Create a polyhedral description for a static control flow region.
11 // The pass creates a polyhedral description of the Scops detected by the Scop
12 // detection derived from their LLVM-IR code.
14 // This representation is shared among several tools in the polyhedral
15 // community, which are e.g. Cloog, Pluto, Loopo, Graphite.
17 //===----------------------------------------------------------------------===//
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/ADT/StringExtras.h"
38 #include "llvm/Analysis/AliasAnalysis.h"
39 #include "llvm/Analysis/AssumptionCache.h"
40 #include "llvm/Analysis/Loads.h"
41 #include "llvm/Analysis/LoopInfo.h"
42 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
43 #include "llvm/Analysis/RegionInfo.h"
44 #include "llvm/Analysis/RegionIterator.h"
45 #include "llvm/Analysis/ScalarEvolution.h"
46 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
47 #include "llvm/IR/BasicBlock.h"
48 #include "llvm/IR/ConstantRange.h"
49 #include "llvm/IR/DataLayout.h"
50 #include "llvm/IR/DebugLoc.h"
51 #include "llvm/IR/Dominators.h"
52 #include "llvm/IR/Function.h"
53 #include "llvm/IR/InstrTypes.h"
54 #include "llvm/IR/Instruction.h"
55 #include "llvm/IR/Instructions.h"
56 #include "llvm/IR/Module.h"
57 #include "llvm/IR/PassManager.h"
58 #include "llvm/IR/Type.h"
59 #include "llvm/IR/Value.h"
60 #include "llvm/InitializePasses.h"
61 #include "llvm/Support/Compiler.h"
62 #include "llvm/Support/Debug.h"
63 #include "llvm/Support/ErrorHandling.h"
64 #include "llvm/Support/raw_ostream.h"
66 #include "isl/local_space.h"
68 #include "isl/options.h"
74 using namespace polly
;
76 #include "polly/Support/PollyDebug.h"
77 #define DEBUG_TYPE "polly-scops"
79 STATISTIC(AssumptionsAliasing
, "Number of aliasing assumptions taken.");
80 STATISTIC(AssumptionsInbounds
, "Number of inbounds assumptions taken.");
81 STATISTIC(AssumptionsWrapping
, "Number of wrapping assumptions taken.");
82 STATISTIC(AssumptionsUnsigned
, "Number of unsigned assumptions taken.");
83 STATISTIC(AssumptionsComplexity
, "Number of too complex SCoPs.");
84 STATISTIC(AssumptionsUnprofitable
, "Number of unprofitable SCoPs.");
85 STATISTIC(AssumptionsErrorBlock
, "Number of error block assumptions taken.");
86 STATISTIC(AssumptionsInfiniteLoop
, "Number of bounded loop assumptions taken.");
87 STATISTIC(AssumptionsInvariantLoad
,
88 "Number of invariant loads assumptions taken.");
89 STATISTIC(AssumptionsDelinearization
,
90 "Number of delinearization assumptions taken.");
92 STATISTIC(NumScops
, "Number of feasible SCoPs after ScopInfo");
93 STATISTIC(NumLoopsInScop
, "Number of loops in scops");
94 STATISTIC(NumBoxedLoops
, "Number of boxed loops in SCoPs after ScopInfo");
95 STATISTIC(NumAffineLoops
, "Number of affine loops in SCoPs after ScopInfo");
97 STATISTIC(NumScopsDepthZero
, "Number of scops with maximal loop depth 0");
98 STATISTIC(NumScopsDepthOne
, "Number of scops with maximal loop depth 1");
99 STATISTIC(NumScopsDepthTwo
, "Number of scops with maximal loop depth 2");
100 STATISTIC(NumScopsDepthThree
, "Number of scops with maximal loop depth 3");
101 STATISTIC(NumScopsDepthFour
, "Number of scops with maximal loop depth 4");
102 STATISTIC(NumScopsDepthFive
, "Number of scops with maximal loop depth 5");
103 STATISTIC(NumScopsDepthLarger
,
104 "Number of scops with maximal loop depth 6 and larger");
105 STATISTIC(MaxNumLoopsInScop
, "Maximal number of loops in scops");
107 STATISTIC(NumValueWrites
, "Number of scalar value writes after ScopInfo");
109 NumValueWritesInLoops
,
110 "Number of scalar value writes nested in affine loops after ScopInfo");
111 STATISTIC(NumPHIWrites
, "Number of scalar phi writes after ScopInfo");
112 STATISTIC(NumPHIWritesInLoops
,
113 "Number of scalar phi writes nested in affine loops after ScopInfo");
114 STATISTIC(NumSingletonWrites
, "Number of singleton writes after ScopInfo");
115 STATISTIC(NumSingletonWritesInLoops
,
116 "Number of singleton writes nested in affine loops after ScopInfo");
118 unsigned const polly::MaxDisjunctsInDomain
= 20;
120 // The number of disjunct in the context after which we stop to add more
121 // disjuncts. This parameter is there to avoid exponential growth in the
122 // number of disjunct when adding non-convex sets to the context.
123 static int const MaxDisjunctsInContext
= 4;
125 // Be a bit more generous for the defined behavior context which is used less
127 static int const MaxDisjunktsInDefinedBehaviourContext
= 8;
129 static cl::opt
<bool> PollyRemarksMinimal(
130 "polly-remarks-minimal",
131 cl::desc("Do not emit remarks about assumptions that are known"),
132 cl::Hidden
, cl::cat(PollyCategory
));
135 IslOnErrorAbort("polly-on-isl-error-abort",
136 cl::desc("Abort if an isl error is encountered"),
137 cl::init(true), cl::cat(PollyCategory
));
139 static cl::opt
<bool> PollyPreciseInbounds(
140 "polly-precise-inbounds",
141 cl::desc("Take more precise inbounds assumptions (do not scale well)"),
142 cl::Hidden
, cl::init(false), cl::cat(PollyCategory
));
144 static cl::opt
<bool> PollyIgnoreParamBounds(
145 "polly-ignore-parameter-bounds",
147 "Do not add parameter bounds and do no gist simplify sets accordingly"),
148 cl::Hidden
, cl::init(false), cl::cat(PollyCategory
));
150 static cl::opt
<bool> PollyPreciseFoldAccesses(
151 "polly-precise-fold-accesses",
152 cl::desc("Fold memory accesses to model more possible delinearizations "
153 "(does not scale well)"),
154 cl::Hidden
, cl::init(false), cl::cat(PollyCategory
));
156 bool polly::UseInstructionNames
;
158 static cl::opt
<bool, true> XUseInstructionNames(
159 "polly-use-llvm-names",
160 cl::desc("Use LLVM-IR names when deriving statement names"),
161 cl::location(UseInstructionNames
), cl::Hidden
, cl::cat(PollyCategory
));
163 static cl::opt
<bool> PollyPrintInstructions(
164 "polly-print-instructions", cl::desc("Output instructions per ScopStmt"),
165 cl::Hidden
, cl::Optional
, cl::init(false), cl::cat(PollyCategory
));
167 static cl::list
<std::string
> IslArgs("polly-isl-arg",
168 cl::value_desc("argument"),
169 cl::desc("Option passed to ISL"),
170 cl::cat(PollyCategory
));
172 //===----------------------------------------------------------------------===//
174 static isl::set
addRangeBoundsToSet(isl::set S
, const ConstantRange
&Range
,
175 int dim
, isl::dim type
) {
177 isl::ctx Ctx
= S
.ctx();
179 // The upper and lower bound for a parameter value is derived either from
180 // the data type of the parameter or from the - possibly more restrictive -
182 V
= valFromAPInt(Ctx
.get(), Range
.getSignedMin(), true);
183 S
= S
.lower_bound_val(type
, dim
, V
);
184 V
= valFromAPInt(Ctx
.get(), Range
.getSignedMax(), true);
185 S
= S
.upper_bound_val(type
, dim
, V
);
187 if (Range
.isFullSet())
190 if (S
.n_basic_set().release() > MaxDisjunctsInContext
)
193 // In case of signed wrapping, we can refine the set of valid values by
194 // excluding the part not covered by the wrapping range.
195 if (Range
.isSignWrappedSet()) {
196 V
= valFromAPInt(Ctx
.get(), Range
.getLower(), true);
197 isl::set SLB
= S
.lower_bound_val(type
, dim
, V
);
199 V
= valFromAPInt(Ctx
.get(), Range
.getUpper(), true);
201 isl::set SUB
= S
.upper_bound_val(type
, dim
, V
);
208 static const ScopArrayInfo
*identifyBasePtrOriginSAI(Scop
*S
, Value
*BasePtr
) {
209 LoadInst
*BasePtrLI
= dyn_cast
<LoadInst
>(BasePtr
);
213 if (!S
->contains(BasePtrLI
))
216 ScalarEvolution
&SE
= *S
->getSE();
218 const SCEV
*OriginBaseSCEV
=
219 SE
.getPointerBase(SE
.getSCEV(BasePtrLI
->getPointerOperand()));
223 auto *OriginBaseSCEVUnknown
= dyn_cast
<SCEVUnknown
>(OriginBaseSCEV
);
224 if (!OriginBaseSCEVUnknown
)
227 return S
->getScopArrayInfo(OriginBaseSCEVUnknown
->getValue(),
231 ScopArrayInfo::ScopArrayInfo(Value
*BasePtr
, Type
*ElementType
, isl::ctx Ctx
,
232 ArrayRef
<const SCEV
*> Sizes
, MemoryKind Kind
,
233 const DataLayout
&DL
, Scop
*S
,
234 const char *BaseName
)
235 : BasePtr(BasePtr
), ElementType(ElementType
), Kind(Kind
), DL(DL
), S(*S
) {
236 std::string BasePtrName
=
238 : getIslCompatibleName("MemRef", BasePtr
, S
->getNextArrayIdx(),
239 Kind
== MemoryKind::PHI
? "__phi" : "",
240 UseInstructionNames
);
241 Id
= isl::id::alloc(Ctx
, BasePtrName
, this);
245 if (!BasePtr
|| Kind
!= MemoryKind::Array
) {
246 BasePtrOriginSAI
= nullptr;
250 BasePtrOriginSAI
= identifyBasePtrOriginSAI(S
, BasePtr
);
251 if (BasePtrOriginSAI
)
252 const_cast<ScopArrayInfo
*>(BasePtrOriginSAI
)->addDerivedSAI(this);
255 ScopArrayInfo::~ScopArrayInfo() = default;
257 isl::space
ScopArrayInfo::getSpace() const {
258 auto Space
= isl::space(Id
.ctx(), 0, getNumberOfDimensions());
259 Space
= Space
.set_tuple_id(isl::dim::set
, Id
);
263 bool ScopArrayInfo::isReadOnly() {
264 isl::union_set WriteSet
= S
.getWrites().range();
265 isl::space Space
= getSpace();
266 WriteSet
= WriteSet
.extract_set(Space
);
268 return bool(WriteSet
.is_empty());
271 bool ScopArrayInfo::isCompatibleWith(const ScopArrayInfo
*Array
) const {
272 if (Array
->getElementType() != getElementType())
275 if (Array
->getNumberOfDimensions() != getNumberOfDimensions())
278 for (unsigned i
= 0; i
< getNumberOfDimensions(); i
++)
279 if (Array
->getDimensionSize(i
) != getDimensionSize(i
))
285 void ScopArrayInfo::updateElementType(Type
*NewElementType
) {
286 if (NewElementType
== ElementType
)
289 auto OldElementSize
= DL
.getTypeAllocSizeInBits(ElementType
);
290 auto NewElementSize
= DL
.getTypeAllocSizeInBits(NewElementType
);
292 if (NewElementSize
== OldElementSize
|| NewElementSize
== 0)
295 if (NewElementSize
% OldElementSize
== 0 && NewElementSize
< OldElementSize
) {
296 ElementType
= NewElementType
;
298 auto GCD
= std::gcd((uint64_t)NewElementSize
, (uint64_t)OldElementSize
);
299 ElementType
= IntegerType::get(ElementType
->getContext(), GCD
);
303 bool ScopArrayInfo::updateSizes(ArrayRef
<const SCEV
*> NewSizes
,
304 bool CheckConsistency
) {
305 int SharedDims
= std::min(NewSizes
.size(), DimensionSizes
.size());
306 int ExtraDimsNew
= NewSizes
.size() - SharedDims
;
307 int ExtraDimsOld
= DimensionSizes
.size() - SharedDims
;
309 if (CheckConsistency
) {
310 for (int i
= 0; i
< SharedDims
; i
++) {
311 auto *NewSize
= NewSizes
[i
+ ExtraDimsNew
];
312 auto *KnownSize
= DimensionSizes
[i
+ ExtraDimsOld
];
313 if (NewSize
&& KnownSize
&& NewSize
!= KnownSize
)
317 if (DimensionSizes
.size() >= NewSizes
.size())
321 DimensionSizes
.clear();
322 DimensionSizes
.insert(DimensionSizes
.begin(), NewSizes
.begin(),
324 DimensionSizesPw
.clear();
325 for (const SCEV
*Expr
: DimensionSizes
) {
327 DimensionSizesPw
.push_back(isl::pw_aff());
330 isl::pw_aff Size
= S
.getPwAffOnly(Expr
);
331 DimensionSizesPw
.push_back(Size
);
336 std::string
ScopArrayInfo::getName() const { return Id
.get_name(); }
338 int ScopArrayInfo::getElemSizeInBytes() const {
339 return DL
.getTypeAllocSize(ElementType
);
342 isl::id
ScopArrayInfo::getBasePtrId() const { return Id
; }
344 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
345 LLVM_DUMP_METHOD
void ScopArrayInfo::dump() const { print(errs()); }
348 void ScopArrayInfo::print(raw_ostream
&OS
, bool SizeAsPwAff
) const {
349 OS
.indent(8) << *getElementType() << " " << getName();
352 if (getNumberOfDimensions() > 0 && !getDimensionSize(0)) {
356 for (; u
< getNumberOfDimensions(); u
++) {
360 isl::pw_aff Size
= getDimensionSizePw(u
);
361 OS
<< " " << Size
<< " ";
363 OS
<< *getDimensionSize(u
);
371 if (BasePtrOriginSAI
)
372 OS
<< " [BasePtrOrigin: " << BasePtrOriginSAI
->getName() << "]";
374 OS
<< " // Element size " << getElemSizeInBytes() << "\n";
377 const ScopArrayInfo
*
378 ScopArrayInfo::getFromAccessFunction(isl::pw_multi_aff PMA
) {
379 isl::id Id
= PMA
.get_tuple_id(isl::dim::out
);
380 assert(!Id
.is_null() && "Output dimension didn't have an ID");
381 return getFromId(Id
);
384 const ScopArrayInfo
*ScopArrayInfo::getFromId(isl::id Id
) {
385 void *User
= Id
.get_user();
386 const ScopArrayInfo
*SAI
= static_cast<ScopArrayInfo
*>(User
);
390 void MemoryAccess::wrapConstantDimensions() {
391 auto *SAI
= getScopArrayInfo();
392 isl::space ArraySpace
= SAI
->getSpace();
393 isl::ctx Ctx
= ArraySpace
.ctx();
394 unsigned DimsArray
= SAI
->getNumberOfDimensions();
396 isl::multi_aff DivModAff
= isl::multi_aff::identity(
397 ArraySpace
.map_from_domain_and_range(ArraySpace
));
398 isl::local_space LArraySpace
= isl::local_space(ArraySpace
);
400 // Begin with last dimension, to iteratively carry into higher dimensions.
401 for (int i
= DimsArray
- 1; i
> 0; i
--) {
402 auto *DimSize
= SAI
->getDimensionSize(i
);
403 auto *DimSizeCst
= dyn_cast
<SCEVConstant
>(DimSize
);
405 // This transformation is not applicable to dimensions with dynamic size.
409 // This transformation is not applicable to dimensions of size zero.
410 if (DimSize
->isZero())
413 isl::val DimSizeVal
=
414 valFromAPInt(Ctx
.get(), DimSizeCst
->getAPInt(), false);
415 isl::aff Var
= isl::aff::var_on_domain(LArraySpace
, isl::dim::set
, i
);
417 isl::aff::var_on_domain(LArraySpace
, isl::dim::set
, i
- 1);
419 // Compute: index % size
420 // Modulo must apply in the divide of the previous iteration, if any.
421 isl::aff Modulo
= Var
.mod(DimSizeVal
);
422 Modulo
= Modulo
.pullback(DivModAff
);
424 // Compute: floor(index / size)
425 isl::aff Divide
= Var
.div(isl::aff(LArraySpace
, DimSizeVal
));
426 Divide
= Divide
.floor();
427 Divide
= Divide
.add(PrevVar
);
428 Divide
= Divide
.pullback(DivModAff
);
430 // Apply Modulo and Divide.
431 DivModAff
= DivModAff
.set_aff(i
, Modulo
);
432 DivModAff
= DivModAff
.set_aff(i
- 1, Divide
);
435 // Apply all modulo/divides on the accesses.
436 isl::map Relation
= AccessRelation
;
437 Relation
= Relation
.apply_range(isl::map::from_multi_aff(DivModAff
));
438 Relation
= Relation
.detect_equalities();
439 AccessRelation
= Relation
;
442 void MemoryAccess::updateDimensionality() {
443 auto *SAI
= getScopArrayInfo();
444 isl::space ArraySpace
= SAI
->getSpace();
445 isl::space AccessSpace
= AccessRelation
.get_space().range();
446 isl::ctx Ctx
= ArraySpace
.ctx();
448 unsigned DimsArray
= unsignedFromIslSize(ArraySpace
.dim(isl::dim::set
));
449 unsigned DimsAccess
= unsignedFromIslSize(AccessSpace
.dim(isl::dim::set
));
450 assert(DimsArray
>= DimsAccess
);
451 unsigned DimsMissing
= DimsArray
- DimsAccess
;
453 auto *BB
= getStatement()->getEntryBlock();
454 auto &DL
= BB
->getModule()->getDataLayout();
455 unsigned ArrayElemSize
= SAI
->getElemSizeInBytes();
456 unsigned ElemBytes
= DL
.getTypeAllocSize(getElementType());
458 isl::map Map
= isl::map::from_domain_and_range(
459 isl::set::universe(AccessSpace
), isl::set::universe(ArraySpace
));
461 for (auto i
: seq
<unsigned>(0, DimsMissing
))
462 Map
= Map
.fix_si(isl::dim::out
, i
, 0);
464 for (auto i
: seq
<unsigned>(DimsMissing
, DimsArray
))
465 Map
= Map
.equate(isl::dim::in
, i
- DimsMissing
, isl::dim::out
, i
);
467 AccessRelation
= AccessRelation
.apply_range(Map
);
469 // For the non delinearized arrays, divide the access function of the last
470 // subscript by the size of the elements in the array.
472 // A stride one array access in C expressed as A[i] is expressed in
473 // LLVM-IR as something like A[i * elementsize]. This hides the fact that
474 // two subsequent values of 'i' index two values that are stored next to
475 // each other in memory. By this division we make this characteristic
476 // obvious again. If the base pointer was accessed with offsets not divisible
477 // by the accesses element size, we will have chosen a smaller ArrayElemSize
478 // that divides the offsets of all accesses to this base pointer.
479 if (DimsAccess
== 1) {
480 isl::val V
= isl::val(Ctx
, ArrayElemSize
);
481 AccessRelation
= AccessRelation
.floordiv_val(V
);
484 // We currently do this only if we added at least one dimension, which means
485 // some dimension's indices have not been specified, an indicator that some
486 // index values have been added together.
487 // TODO: Investigate general usefulness; Effect on unit tests is to make index
488 // expressions more complicated.
490 wrapConstantDimensions();
493 computeBoundsOnAccessRelation(ArrayElemSize
);
495 // Introduce multi-element accesses in case the type loaded by this memory
496 // access is larger than the canonical element type of the array.
498 // An access ((float *)A)[i] to an array char *A is modeled as
499 // {[i] -> A[o] : 4 i <= o <= 4 i + 3
500 if (ElemBytes
> ArrayElemSize
) {
501 assert(ElemBytes
% ArrayElemSize
== 0 &&
502 "Loaded element size should be multiple of canonical element size");
503 assert(DimsArray
>= 1);
504 isl::map Map
= isl::map::from_domain_and_range(
505 isl::set::universe(ArraySpace
), isl::set::universe(ArraySpace
));
506 for (auto i
: seq
<unsigned>(0, DimsArray
- 1))
507 Map
= Map
.equate(isl::dim::in
, i
, isl::dim::out
, i
);
512 LS
= isl::local_space(Map
.get_space());
513 int Num
= ElemBytes
/ getScopArrayInfo()->getElemSizeInBytes();
515 C
= isl::constraint::alloc_inequality(LS
);
516 C
= C
.set_constant_val(isl::val(Ctx
, Num
- 1));
517 C
= C
.set_coefficient_si(isl::dim::in
, DimsArray
- 1, 1);
518 C
= C
.set_coefficient_si(isl::dim::out
, DimsArray
- 1, -1);
519 Map
= Map
.add_constraint(C
);
521 C
= isl::constraint::alloc_inequality(LS
);
522 C
= C
.set_coefficient_si(isl::dim::in
, DimsArray
- 1, -1);
523 C
= C
.set_coefficient_si(isl::dim::out
, DimsArray
- 1, 1);
524 C
= C
.set_constant_val(isl::val(Ctx
, 0));
525 Map
= Map
.add_constraint(C
);
526 AccessRelation
= AccessRelation
.apply_range(Map
);
531 MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT
) {
533 case MemoryAccess::RT_NONE
:
534 llvm_unreachable("Requested a reduction operator string for a memory "
535 "access which isn't a reduction");
536 case MemoryAccess::RT_BOTTOM
:
537 llvm_unreachable("Requested a reduction operator string for a internal "
539 case MemoryAccess::RT_ADD
:
541 case MemoryAccess::RT_MUL
:
543 case MemoryAccess::RT_BOR
:
545 case MemoryAccess::RT_BXOR
:
547 case MemoryAccess::RT_BAND
:
550 llvm_unreachable("Unknown reduction type");
553 const ScopArrayInfo
*MemoryAccess::getOriginalScopArrayInfo() const {
554 isl::id ArrayId
= getArrayId();
555 void *User
= ArrayId
.get_user();
556 const ScopArrayInfo
*SAI
= static_cast<ScopArrayInfo
*>(User
);
560 const ScopArrayInfo
*MemoryAccess::getLatestScopArrayInfo() const {
561 isl::id ArrayId
= getLatestArrayId();
562 void *User
= ArrayId
.get_user();
563 const ScopArrayInfo
*SAI
= static_cast<ScopArrayInfo
*>(User
);
567 isl::id
MemoryAccess::getOriginalArrayId() const {
568 return AccessRelation
.get_tuple_id(isl::dim::out
);
571 isl::id
MemoryAccess::getLatestArrayId() const {
572 if (!hasNewAccessRelation())
573 return getOriginalArrayId();
574 return NewAccessRelation
.get_tuple_id(isl::dim::out
);
577 isl::map
MemoryAccess::getAddressFunction() const {
578 return getAccessRelation().lexmin();
582 MemoryAccess::applyScheduleToAccessRelation(isl::union_map USchedule
) const {
583 isl::map Schedule
, ScheduledAccRel
;
584 isl::union_set UDomain
;
586 UDomain
= getStatement()->getDomain();
587 USchedule
= USchedule
.intersect_domain(UDomain
);
588 Schedule
= isl::map::from_union_map(USchedule
);
589 ScheduledAccRel
= getAddressFunction().apply_domain(Schedule
);
590 return isl::pw_multi_aff::from_map(ScheduledAccRel
);
593 isl::map
MemoryAccess::getOriginalAccessRelation() const {
594 return AccessRelation
;
597 std::string
MemoryAccess::getOriginalAccessRelationStr() const {
598 return stringFromIslObj(AccessRelation
);
601 isl::space
MemoryAccess::getOriginalAccessRelationSpace() const {
602 return AccessRelation
.get_space();
605 isl::map
MemoryAccess::getNewAccessRelation() const {
606 return NewAccessRelation
;
609 std::string
MemoryAccess::getNewAccessRelationStr() const {
610 return stringFromIslObj(NewAccessRelation
);
613 std::string
MemoryAccess::getAccessRelationStr() const {
614 return stringFromIslObj(getAccessRelation());
617 isl::basic_map
MemoryAccess::createBasicAccessMap(ScopStmt
*Statement
) {
618 isl::space Space
= isl::space(Statement
->getIslCtx(), 0, 1);
619 Space
= Space
.align_params(Statement
->getDomainSpace());
621 return isl::basic_map::from_domain_and_range(
622 isl::basic_set::universe(Statement
->getDomainSpace()),
623 isl::basic_set::universe(Space
));
626 // Formalize no out-of-bound access assumption
628 // When delinearizing array accesses we optimistically assume that the
629 // delinearized accesses do not access out of bound locations (the subscript
630 // expression of each array evaluates for each statement instance that is
631 // executed to a value that is larger than zero and strictly smaller than the
632 // size of the corresponding dimension). The only exception is the outermost
633 // dimension for which we do not need to assume any upper bound. At this point
634 // we formalize this assumption to ensure that at code generation time the
635 // relevant run-time checks can be generated.
637 // To find the set of constraints necessary to avoid out of bound accesses, we
638 // first build the set of data locations that are not within array bounds. We
639 // then apply the reverse access relation to obtain the set of iterations that
640 // may contain invalid accesses and reduce this set of iterations to the ones
641 // that are actually executed by intersecting them with the domain of the
642 // statement. If we now project out all loop dimensions, we obtain a set of
643 // parameters that may cause statement instances to be executed that may
644 // possibly yield out of bound memory accesses. The complement of these
645 // constraints is the set of constraints that needs to be assumed to ensure such
646 // statement instances are never executed.
647 isl::set
MemoryAccess::assumeNoOutOfBound() {
648 auto *SAI
= getScopArrayInfo();
649 isl::space Space
= getOriginalAccessRelationSpace().range();
650 isl::set Outside
= isl::set::empty(Space
);
651 for (int i
= 1, Size
= Space
.dim(isl::dim::set
).release(); i
< Size
; ++i
) {
652 isl::local_space
LS(Space
);
653 isl::pw_aff Var
= isl::pw_aff::var_on_domain(LS
, isl::dim::set
, i
);
654 isl::pw_aff Zero
= isl::pw_aff(LS
);
656 isl::set DimOutside
= Var
.lt_set(Zero
);
657 isl::pw_aff SizeE
= SAI
->getDimensionSizePw(i
);
658 SizeE
= SizeE
.add_dims(isl::dim::in
, Space
.dim(isl::dim::set
).release());
659 SizeE
= SizeE
.set_tuple_id(isl::dim::in
, Space
.get_tuple_id(isl::dim::set
));
660 DimOutside
= DimOutside
.unite(SizeE
.le_set(Var
));
662 Outside
= Outside
.unite(DimOutside
);
665 Outside
= Outside
.apply(getAccessRelation().reverse());
666 Outside
= Outside
.intersect(Statement
->getDomain());
667 Outside
= Outside
.params();
669 // Remove divs to avoid the construction of overly complicated assumptions.
670 // Doing so increases the set of parameter combinations that are assumed to
671 // not appear. This is always save, but may make the resulting run-time check
672 // bail out more often than strictly necessary.
673 Outside
= Outside
.remove_divs();
674 Outside
= Outside
.complement();
676 if (!PollyPreciseInbounds
)
677 Outside
= Outside
.gist_params(Statement
->getDomain().params());
681 void MemoryAccess::buildMemIntrinsicAccessRelation() {
682 assert(isMemoryIntrinsic());
683 assert(Subscripts
.size() == 2 && Sizes
.size() == 1);
685 isl::pw_aff SubscriptPWA
= getPwAff(Subscripts
[0]);
686 isl::map SubscriptMap
= isl::map::from_pw_aff(SubscriptPWA
);
689 if (Subscripts
[1] == nullptr) {
690 LengthMap
= isl::map::universe(SubscriptMap
.get_space());
692 isl::pw_aff LengthPWA
= getPwAff(Subscripts
[1]);
693 LengthMap
= isl::map::from_pw_aff(LengthPWA
);
694 isl::space RangeSpace
= LengthMap
.get_space().range();
695 LengthMap
= LengthMap
.apply_range(isl::map::lex_gt(RangeSpace
));
697 LengthMap
= LengthMap
.lower_bound_si(isl::dim::out
, 0, 0);
698 LengthMap
= LengthMap
.align_params(SubscriptMap
.get_space());
699 SubscriptMap
= SubscriptMap
.align_params(LengthMap
.get_space());
700 LengthMap
= LengthMap
.sum(SubscriptMap
);
702 LengthMap
.set_tuple_id(isl::dim::in
, getStatement()->getDomainId());
705 void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize
) {
706 ScalarEvolution
*SE
= Statement
->getParent()->getSE();
708 auto MAI
= MemAccInst(getAccessInstruction());
709 if (isa
<MemIntrinsic
>(MAI
))
712 Value
*Ptr
= MAI
.getPointerOperand();
713 if (!Ptr
|| !SE
->isSCEVable(Ptr
->getType()))
716 const SCEV
*PtrSCEV
= SE
->getSCEV(Ptr
);
717 if (isa
<SCEVCouldNotCompute
>(PtrSCEV
))
720 const SCEV
*BasePtrSCEV
= SE
->getPointerBase(PtrSCEV
);
721 if (BasePtrSCEV
&& !isa
<SCEVCouldNotCompute
>(BasePtrSCEV
))
722 PtrSCEV
= SE
->getMinusSCEV(PtrSCEV
, BasePtrSCEV
);
724 const ConstantRange
&Range
= SE
->getSignedRange(PtrSCEV
);
725 if (Range
.isFullSet())
728 if (Range
.isUpperWrapped() || Range
.isSignWrappedSet())
731 bool isWrapping
= Range
.isSignWrappedSet();
733 unsigned BW
= Range
.getBitWidth();
734 const auto One
= APInt(BW
, 1);
735 const auto LB
= isWrapping
? Range
.getLower() : Range
.getSignedMin();
736 const auto UB
= isWrapping
? (Range
.getUpper() - One
) : Range
.getSignedMax();
738 auto Min
= LB
.sdiv(APInt(BW
, ElementSize
));
739 auto Max
= UB
.sdiv(APInt(BW
, ElementSize
)) + One
;
741 assert(Min
.sle(Max
) && "Minimum expected to be less or equal than max");
743 isl::map Relation
= AccessRelation
;
744 isl::set AccessRange
= Relation
.range();
745 AccessRange
= addRangeBoundsToSet(AccessRange
, ConstantRange(Min
, Max
), 0,
747 AccessRelation
= Relation
.intersect_range(AccessRange
);
750 void MemoryAccess::foldAccessRelation() {
751 if (Sizes
.size() < 2 || isa
<SCEVConstant
>(Sizes
[1]))
754 int Size
= Subscripts
.size();
756 isl::map NewAccessRelation
= AccessRelation
;
758 for (int i
= Size
- 2; i
>= 0; --i
) {
760 isl::map MapOne
, MapTwo
;
761 isl::pw_aff DimSize
= getPwAff(Sizes
[i
+ 1]);
763 isl::space SpaceSize
= DimSize
.get_space();
764 isl::id ParamId
= SpaceSize
.get_dim_id(isl::dim::param
, 0);
766 Space
= AccessRelation
.get_space();
767 Space
= Space
.range().map_from_set();
768 Space
= Space
.align_params(SpaceSize
);
770 int ParamLocation
= Space
.find_dim_by_id(isl::dim::param
, ParamId
);
772 MapOne
= isl::map::universe(Space
);
773 for (int j
= 0; j
< Size
; ++j
)
774 MapOne
= MapOne
.equate(isl::dim::in
, j
, isl::dim::out
, j
);
775 MapOne
= MapOne
.lower_bound_si(isl::dim::in
, i
+ 1, 0);
777 MapTwo
= isl::map::universe(Space
);
778 for (int j
= 0; j
< Size
; ++j
)
779 if (j
< i
|| j
> i
+ 1)
780 MapTwo
= MapTwo
.equate(isl::dim::in
, j
, isl::dim::out
, j
);
782 isl::local_space
LS(Space
);
784 C
= isl::constraint::alloc_equality(LS
);
785 C
= C
.set_constant_si(-1);
786 C
= C
.set_coefficient_si(isl::dim::in
, i
, 1);
787 C
= C
.set_coefficient_si(isl::dim::out
, i
, -1);
788 MapTwo
= MapTwo
.add_constraint(C
);
789 C
= isl::constraint::alloc_equality(LS
);
790 C
= C
.set_coefficient_si(isl::dim::in
, i
+ 1, 1);
791 C
= C
.set_coefficient_si(isl::dim::out
, i
+ 1, -1);
792 C
= C
.set_coefficient_si(isl::dim::param
, ParamLocation
, 1);
793 MapTwo
= MapTwo
.add_constraint(C
);
794 MapTwo
= MapTwo
.upper_bound_si(isl::dim::in
, i
+ 1, -1);
796 MapOne
= MapOne
.unite(MapTwo
);
797 NewAccessRelation
= NewAccessRelation
.apply_range(MapOne
);
800 isl::id BaseAddrId
= getScopArrayInfo()->getBasePtrId();
801 isl::space Space
= Statement
->getDomainSpace();
802 NewAccessRelation
= NewAccessRelation
.set_tuple_id(
803 isl::dim::in
, Space
.get_tuple_id(isl::dim::set
));
804 NewAccessRelation
= NewAccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
805 NewAccessRelation
= NewAccessRelation
.gist_domain(Statement
->getDomain());
807 // Access dimension folding might in certain cases increase the number of
808 // disjuncts in the memory access, which can possibly complicate the generated
809 // run-time checks and can lead to costly compilation.
810 if (!PollyPreciseFoldAccesses
&& NewAccessRelation
.n_basic_map().release() >
811 AccessRelation
.n_basic_map().release()) {
813 AccessRelation
= NewAccessRelation
;
817 void MemoryAccess::buildAccessRelation(const ScopArrayInfo
*SAI
) {
818 assert(AccessRelation
.is_null() && "AccessRelation already built");
820 // Initialize the invalid domain which describes all iterations for which the
821 // access relation is not modeled correctly.
822 isl::set StmtInvalidDomain
= getStatement()->getInvalidDomain();
823 InvalidDomain
= isl::set::empty(StmtInvalidDomain
.get_space());
825 isl::ctx Ctx
= Id
.ctx();
826 isl::id BaseAddrId
= SAI
->getBasePtrId();
828 if (getAccessInstruction() && isa
<MemIntrinsic
>(getAccessInstruction())) {
829 buildMemIntrinsicAccessRelation();
830 AccessRelation
= AccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
835 // We overapproximate non-affine accesses with a possible access to the
836 // whole array. For read accesses it does not make a difference, if an
837 // access must or may happen. However, for write accesses it is important to
838 // differentiate between writes that must happen and writes that may happen.
839 if (AccessRelation
.is_null())
840 AccessRelation
= createBasicAccessMap(Statement
);
842 AccessRelation
= AccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
846 isl::space Space
= isl::space(Ctx
, 0, Statement
->getNumIterators(), 0);
847 AccessRelation
= isl::map::universe(Space
);
849 for (int i
= 0, Size
= Subscripts
.size(); i
< Size
; ++i
) {
850 isl::pw_aff Affine
= getPwAff(Subscripts
[i
]);
851 isl::map SubscriptMap
= isl::map::from_pw_aff(Affine
);
852 AccessRelation
= AccessRelation
.flat_range_product(SubscriptMap
);
855 Space
= Statement
->getDomainSpace();
856 AccessRelation
= AccessRelation
.set_tuple_id(
857 isl::dim::in
, Space
.get_tuple_id(isl::dim::set
));
858 AccessRelation
= AccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
860 AccessRelation
= AccessRelation
.gist_domain(Statement
->getDomain());
863 MemoryAccess::MemoryAccess(ScopStmt
*Stmt
, Instruction
*AccessInst
,
864 AccessType AccType
, Value
*BaseAddress
,
865 Type
*ElementType
, bool Affine
,
866 ArrayRef
<const SCEV
*> Subscripts
,
867 ArrayRef
<const SCEV
*> Sizes
, Value
*AccessValue
,
869 : Kind(Kind
), AccType(AccType
), Statement(Stmt
), InvalidDomain(),
870 BaseAddr(BaseAddress
), ElementType(ElementType
),
871 Sizes(Sizes
.begin(), Sizes
.end()), AccessInstruction(AccessInst
),
872 AccessValue(AccessValue
), IsAffine(Affine
),
873 Subscripts(Subscripts
.begin(), Subscripts
.end()), AccessRelation(),
874 NewAccessRelation() {
875 static const std::string TypeStrings
[] = {"", "_Read", "_Write", "_MayWrite"};
876 const std::string Access
= TypeStrings
[AccType
] + utostr(Stmt
->size());
878 std::string IdName
= Stmt
->getBaseName() + Access
;
879 Id
= isl::id::alloc(Stmt
->getParent()->getIslCtx(), IdName
, this);
882 MemoryAccess::MemoryAccess(ScopStmt
*Stmt
, AccessType AccType
, isl::map AccRel
)
883 : Kind(MemoryKind::Array
), AccType(AccType
), Statement(Stmt
),
884 InvalidDomain(), AccessRelation(), NewAccessRelation(AccRel
) {
885 isl::id ArrayInfoId
= NewAccessRelation
.get_tuple_id(isl::dim::out
);
886 auto *SAI
= ScopArrayInfo::getFromId(ArrayInfoId
);
887 Sizes
.push_back(nullptr);
888 for (unsigned i
= 1; i
< SAI
->getNumberOfDimensions(); i
++)
889 Sizes
.push_back(SAI
->getDimensionSize(i
));
890 ElementType
= SAI
->getElementType();
891 BaseAddr
= SAI
->getBasePtr();
892 static const std::string TypeStrings
[] = {"", "_Read", "_Write", "_MayWrite"};
893 const std::string Access
= TypeStrings
[AccType
] + utostr(Stmt
->size());
895 std::string IdName
= Stmt
->getBaseName() + Access
;
896 Id
= isl::id::alloc(Stmt
->getParent()->getIslCtx(), IdName
, this);
899 MemoryAccess::~MemoryAccess() = default;
901 void MemoryAccess::realignParams() {
902 isl::set Ctx
= Statement
->getParent()->getContext();
903 InvalidDomain
= InvalidDomain
.gist_params(Ctx
);
904 AccessRelation
= AccessRelation
.gist_params(Ctx
);
906 // Predictable parameter order is required for JSON imports. Ensure alignment
907 // by explicitly calling align_params.
908 isl::space CtxSpace
= Ctx
.get_space();
909 InvalidDomain
= InvalidDomain
.align_params(CtxSpace
);
910 AccessRelation
= AccessRelation
.align_params(CtxSpace
);
913 const std::string
MemoryAccess::getReductionOperatorStr() const {
914 return MemoryAccess::getReductionOperatorStr(getReductionType());
917 isl::id
MemoryAccess::getId() const { return Id
; }
919 raw_ostream
&polly::operator<<(raw_ostream
&OS
,
920 MemoryAccess::ReductionType RT
) {
922 case MemoryAccess::RT_NONE
:
923 case MemoryAccess::RT_BOTTOM
:
927 OS
<< MemoryAccess::getReductionOperatorStr(RT
);
933 void MemoryAccess::print(raw_ostream
&OS
) const {
936 OS
.indent(12) << "ReadAccess :=\t";
939 OS
.indent(12) << "MustWriteAccess :=\t";
942 OS
.indent(12) << "MayWriteAccess :=\t";
946 OS
<< "[Reduction Type: " << getReductionType() << "] ";
948 OS
<< "[Scalar: " << isScalarKind() << "]\n";
949 OS
.indent(16) << getOriginalAccessRelationStr() << ";\n";
950 if (hasNewAccessRelation())
951 OS
.indent(11) << "new: " << getNewAccessRelationStr() << ";\n";
954 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
955 LLVM_DUMP_METHOD
void MemoryAccess::dump() const { print(errs()); }
958 isl::pw_aff
MemoryAccess::getPwAff(const SCEV
*E
) {
959 auto *Stmt
= getStatement();
960 PWACtx PWAC
= Stmt
->getParent()->getPwAff(E
, Stmt
->getEntryBlock());
961 isl::set StmtDom
= getStatement()->getDomain();
962 StmtDom
= StmtDom
.reset_tuple_id();
963 isl::set NewInvalidDom
= StmtDom
.intersect(PWAC
.second
);
964 InvalidDomain
= InvalidDomain
.unite(NewInvalidDom
);
968 // Create a map in the size of the provided set domain, that maps from the
969 // one element of the provided set domain to another element of the provided
971 // The mapping is limited to all points that are equal in all but the last
972 // dimension and for which the last dimension of the input is strict smaller
973 // than the last dimension of the output.
975 // getEqualAndLarger(set[i0, i1, ..., iX]):
977 // set[i0, i1, ..., iX] -> set[o0, o1, ..., oX]
978 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX
980 static isl::map
getEqualAndLarger(isl::space SetDomain
) {
981 isl::space Space
= SetDomain
.map_from_set();
982 isl::map Map
= isl::map::universe(Space
);
983 unsigned lastDimension
= Map
.domain_tuple_dim().release() - 1;
985 // Set all but the last dimension to be equal for the input and output
987 // input[i0, i1, ..., iX] -> output[o0, o1, ..., oX]
988 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1)
989 for (unsigned i
= 0; i
< lastDimension
; ++i
)
990 Map
= Map
.equate(isl::dim::in
, i
, isl::dim::out
, i
);
992 // Set the last dimension of the input to be strict smaller than the
993 // last dimension of the output.
995 // input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX
996 Map
= Map
.order_lt(isl::dim::in
, lastDimension
, isl::dim::out
, lastDimension
);
1000 isl::set
MemoryAccess::getStride(isl::map Schedule
) const {
1001 isl::map AccessRelation
= getAccessRelation();
1002 isl::space Space
= Schedule
.get_space().range();
1003 isl::map NextScatt
= getEqualAndLarger(Space
);
1005 Schedule
= Schedule
.reverse();
1006 NextScatt
= NextScatt
.lexmin();
1008 NextScatt
= NextScatt
.apply_range(Schedule
);
1009 NextScatt
= NextScatt
.apply_range(AccessRelation
);
1010 NextScatt
= NextScatt
.apply_domain(Schedule
);
1011 NextScatt
= NextScatt
.apply_domain(AccessRelation
);
1013 isl::set Deltas
= NextScatt
.deltas();
1017 bool MemoryAccess::isStrideX(isl::map Schedule
, int StrideWidth
) const {
1018 isl::set Stride
, StrideX
;
1021 Stride
= getStride(Schedule
);
1022 StrideX
= isl::set::universe(Stride
.get_space());
1023 int Size
= unsignedFromIslSize(StrideX
.tuple_dim());
1024 for (auto i
: seq
<int>(0, Size
- 1))
1025 StrideX
= StrideX
.fix_si(isl::dim::set
, i
, 0);
1026 StrideX
= StrideX
.fix_si(isl::dim::set
, Size
- 1, StrideWidth
);
1027 IsStrideX
= Stride
.is_subset(StrideX
);
1032 bool MemoryAccess::isStrideZero(isl::map Schedule
) const {
1033 return isStrideX(Schedule
, 0);
1036 bool MemoryAccess::isStrideOne(isl::map Schedule
) const {
1037 return isStrideX(Schedule
, 1);
1040 void MemoryAccess::setAccessRelation(isl::map NewAccess
) {
1041 AccessRelation
= NewAccess
;
1044 void MemoryAccess::setNewAccessRelation(isl::map NewAccess
) {
1045 assert(!NewAccess
.is_null());
1048 // Check domain space compatibility.
1049 isl::space NewSpace
= NewAccess
.get_space();
1050 isl::space NewDomainSpace
= NewSpace
.domain();
1051 isl::space OriginalDomainSpace
= getStatement()->getDomainSpace();
1052 assert(OriginalDomainSpace
.has_equal_tuples(NewDomainSpace
));
1054 // Reads must be executed unconditionally. Writes might be executed in a
1057 // Check whether there is an access for every statement instance.
1058 isl::set StmtDomain
= getStatement()->getDomain();
1059 isl::set DefinedContext
=
1060 getStatement()->getParent()->getBestKnownDefinedBehaviorContext();
1061 StmtDomain
= StmtDomain
.intersect_params(DefinedContext
);
1062 isl::set NewDomain
= NewAccess
.domain();
1063 assert(!StmtDomain
.is_subset(NewDomain
).is_false() &&
1064 "Partial READ accesses not supported");
1067 isl::space NewAccessSpace
= NewAccess
.get_space();
1068 assert(NewAccessSpace
.has_tuple_id(isl::dim::set
) &&
1069 "Must specify the array that is accessed");
1070 isl::id NewArrayId
= NewAccessSpace
.get_tuple_id(isl::dim::set
);
1071 auto *SAI
= static_cast<ScopArrayInfo
*>(NewArrayId
.get_user());
1072 assert(SAI
&& "Must set a ScopArrayInfo");
1074 if (SAI
->isArrayKind() && SAI
->getBasePtrOriginSAI()) {
1075 InvariantEquivClassTy
*EqClass
=
1076 getStatement()->getParent()->lookupInvariantEquivClass(
1079 "Access functions to indirect arrays must have an invariant and "
1080 "hoisted base pointer");
1083 // Check whether access dimensions correspond to number of dimensions of the
1085 unsigned Dims
= SAI
->getNumberOfDimensions();
1086 unsigned SpaceSize
= unsignedFromIslSize(NewAccessSpace
.dim(isl::dim::set
));
1087 assert(SpaceSize
== Dims
&& "Access dims must match array dims");
1090 NewAccess
= NewAccess
.gist_params(getStatement()->getParent()->getContext());
1091 NewAccess
= NewAccess
.gist_domain(getStatement()->getDomain());
1092 NewAccessRelation
= NewAccess
;
1095 bool MemoryAccess::isLatestPartialAccess() const {
1096 isl::set StmtDom
= getStatement()->getDomain();
1097 isl::set AccDom
= getLatestAccessRelation().domain();
1099 return !StmtDom
.is_subset(AccDom
);
1102 //===----------------------------------------------------------------------===//
1104 isl::map
ScopStmt::getSchedule() const {
1105 isl::set Domain
= getDomain();
1106 if (Domain
.is_empty())
1107 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
1108 auto Schedule
= getParent()->getSchedule();
1109 if (Schedule
.is_null())
1111 Schedule
= Schedule
.intersect_domain(isl::union_set(Domain
));
1112 if (Schedule
.is_empty())
1113 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
1114 isl::map M
= M
.from_union_map(Schedule
);
1116 M
= M
.gist_domain(Domain
);
1121 void ScopStmt::restrictDomain(isl::set NewDomain
) {
1122 assert(NewDomain
.is_subset(Domain
) &&
1123 "New domain is not a subset of old domain!");
1127 void ScopStmt::addAccess(MemoryAccess
*Access
, bool Prepend
) {
1128 Instruction
*AccessInst
= Access
->getAccessInstruction();
1130 if (Access
->isArrayKind()) {
1131 MemoryAccessList
&MAL
= InstructionToAccess
[AccessInst
];
1132 MAL
.emplace_front(Access
);
1133 } else if (Access
->isValueKind() && Access
->isWrite()) {
1134 Instruction
*AccessVal
= cast
<Instruction
>(Access
->getAccessValue());
1135 assert(!ValueWrites
.lookup(AccessVal
));
1137 ValueWrites
[AccessVal
] = Access
;
1138 } else if (Access
->isValueKind() && Access
->isRead()) {
1139 Value
*AccessVal
= Access
->getAccessValue();
1140 assert(!ValueReads
.lookup(AccessVal
));
1142 ValueReads
[AccessVal
] = Access
;
1143 } else if (Access
->isAnyPHIKind() && Access
->isWrite()) {
1144 PHINode
*PHI
= cast
<PHINode
>(Access
->getAccessValue());
1145 assert(!PHIWrites
.lookup(PHI
));
1147 PHIWrites
[PHI
] = Access
;
1148 } else if (Access
->isAnyPHIKind() && Access
->isRead()) {
1149 PHINode
*PHI
= cast
<PHINode
>(Access
->getAccessValue());
1150 assert(!PHIReads
.lookup(PHI
));
1152 PHIReads
[PHI
] = Access
;
1156 MemAccs
.insert(MemAccs
.begin(), Access
);
1159 MemAccs
.push_back(Access
);
1162 void ScopStmt::realignParams() {
1163 for (MemoryAccess
*MA
: *this)
1164 MA
->realignParams();
1166 simplify(InvalidDomain
);
1169 isl::set Ctx
= Parent
.getContext();
1170 InvalidDomain
= InvalidDomain
.gist_params(Ctx
);
1171 Domain
= Domain
.gist_params(Ctx
);
1173 // Predictable parameter order is required for JSON imports. Ensure alignment
1174 // by explicitly calling align_params.
1175 isl::space CtxSpace
= Ctx
.get_space();
1176 InvalidDomain
= InvalidDomain
.align_params(CtxSpace
);
1177 Domain
= Domain
.align_params(CtxSpace
);
1180 ScopStmt::ScopStmt(Scop
&parent
, Region
&R
, StringRef Name
,
1181 Loop
*SurroundingLoop
,
1182 std::vector
<Instruction
*> EntryBlockInstructions
)
1183 : Parent(parent
), InvalidDomain(), Domain(), R(&R
), Build(), BaseName(Name
),
1184 SurroundingLoop(SurroundingLoop
), Instructions(EntryBlockInstructions
) {}
1186 ScopStmt::ScopStmt(Scop
&parent
, BasicBlock
&bb
, StringRef Name
,
1187 Loop
*SurroundingLoop
,
1188 std::vector
<Instruction
*> Instructions
)
1189 : Parent(parent
), InvalidDomain(), Domain(), BB(&bb
), Build(),
1190 BaseName(Name
), SurroundingLoop(SurroundingLoop
),
1191 Instructions(Instructions
) {}
1193 ScopStmt::ScopStmt(Scop
&parent
, isl::map SourceRel
, isl::map TargetRel
,
1195 : Parent(parent
), InvalidDomain(), Domain(NewDomain
), Build() {
1196 BaseName
= getIslCompatibleName("CopyStmt_", "",
1197 std::to_string(parent
.getCopyStmtsNum()));
1198 isl::id Id
= isl::id::alloc(getIslCtx(), getBaseName(), this);
1199 Domain
= Domain
.set_tuple_id(Id
);
1200 TargetRel
= TargetRel
.set_tuple_id(isl::dim::in
, Id
);
1202 new MemoryAccess(this, MemoryAccess::AccessType::MUST_WRITE
, TargetRel
);
1203 parent
.addAccessFunction(Access
);
1205 SourceRel
= SourceRel
.set_tuple_id(isl::dim::in
, Id
);
1206 Access
= new MemoryAccess(this, MemoryAccess::AccessType::READ
, SourceRel
);
1207 parent
.addAccessFunction(Access
);
1211 ScopStmt::~ScopStmt() = default;
1213 std::string
ScopStmt::getDomainStr() const { return stringFromIslObj(Domain
); }
1215 std::string
ScopStmt::getScheduleStr() const {
1216 return stringFromIslObj(getSchedule());
1219 void ScopStmt::setInvalidDomain(isl::set ID
) { InvalidDomain
= ID
; }
1221 BasicBlock
*ScopStmt::getEntryBlock() const {
1223 return getBasicBlock();
1224 return getRegion()->getEntry();
1227 unsigned ScopStmt::getNumIterators() const { return NestLoops
.size(); }
1229 const char *ScopStmt::getBaseName() const { return BaseName
.c_str(); }
1231 Loop
*ScopStmt::getLoopForDimension(unsigned Dimension
) const {
1232 return NestLoops
[Dimension
];
1235 isl::ctx
ScopStmt::getIslCtx() const { return Parent
.getIslCtx(); }
1237 isl::set
ScopStmt::getDomain() const { return Domain
; }
1239 isl::space
ScopStmt::getDomainSpace() const { return Domain
.get_space(); }
1241 isl::id
ScopStmt::getDomainId() const { return Domain
.get_tuple_id(); }
1243 void ScopStmt::printInstructions(raw_ostream
&OS
) const {
1244 OS
<< "Instructions {\n";
1246 for (Instruction
*Inst
: Instructions
)
1247 OS
.indent(16) << *Inst
<< "\n";
1249 OS
.indent(12) << "}\n";
1252 void ScopStmt::print(raw_ostream
&OS
, bool PrintInstructions
) const {
1253 OS
<< "\t" << getBaseName() << "\n";
1254 OS
.indent(12) << "Domain :=\n";
1256 if (!Domain
.is_null()) {
1257 OS
.indent(16) << getDomainStr() << ";\n";
1259 OS
.indent(16) << "n/a\n";
1261 OS
.indent(12) << "Schedule :=\n";
1263 if (!Domain
.is_null()) {
1264 OS
.indent(16) << getScheduleStr() << ";\n";
1266 OS
.indent(16) << "n/a\n";
1268 for (MemoryAccess
*Access
: MemAccs
)
1271 if (PrintInstructions
)
1272 printInstructions(OS
.indent(12));
1275 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1276 LLVM_DUMP_METHOD
void ScopStmt::dump() const { print(dbgs(), true); }
1279 void ScopStmt::removeAccessData(MemoryAccess
*MA
) {
1280 if (MA
->isRead() && MA
->isOriginalValueKind()) {
1281 bool Found
= ValueReads
.erase(MA
->getAccessValue());
1283 assert(Found
&& "Expected access data not found");
1285 if (MA
->isWrite() && MA
->isOriginalValueKind()) {
1286 bool Found
= ValueWrites
.erase(cast
<Instruction
>(MA
->getAccessValue()));
1288 assert(Found
&& "Expected access data not found");
1290 if (MA
->isWrite() && MA
->isOriginalAnyPHIKind()) {
1291 bool Found
= PHIWrites
.erase(cast
<PHINode
>(MA
->getAccessInstruction()));
1293 assert(Found
&& "Expected access data not found");
1295 if (MA
->isRead() && MA
->isOriginalAnyPHIKind()) {
1296 bool Found
= PHIReads
.erase(cast
<PHINode
>(MA
->getAccessInstruction()));
1298 assert(Found
&& "Expected access data not found");
1302 void ScopStmt::removeMemoryAccess(MemoryAccess
*MA
) {
1303 // Remove the memory accesses from this statement together with all scalar
1304 // accesses that were caused by it. MemoryKind::Value READs have no access
1305 // instruction, hence would not be removed by this function. However, it is
1306 // only used for invariant LoadInst accesses, its arguments are always affine,
1307 // hence synthesizable, and therefore there are no MemoryKind::Value READ
1308 // accesses to be removed.
1309 auto Predicate
= [&](MemoryAccess
*Acc
) {
1310 return Acc
->getAccessInstruction() == MA
->getAccessInstruction();
1312 for (auto *MA
: MemAccs
) {
1313 if (Predicate(MA
)) {
1314 removeAccessData(MA
);
1315 Parent
.removeAccessData(MA
);
1318 llvm::erase_if(MemAccs
, Predicate
);
1319 InstructionToAccess
.erase(MA
->getAccessInstruction());
1322 void ScopStmt::removeSingleMemoryAccess(MemoryAccess
*MA
, bool AfterHoisting
) {
1323 if (AfterHoisting
) {
1324 auto MAIt
= std::find(MemAccs
.begin(), MemAccs
.end(), MA
);
1325 assert(MAIt
!= MemAccs
.end());
1326 MemAccs
.erase(MAIt
);
1328 removeAccessData(MA
);
1329 Parent
.removeAccessData(MA
);
1332 auto It
= InstructionToAccess
.find(MA
->getAccessInstruction());
1333 if (It
!= InstructionToAccess
.end()) {
1334 It
->second
.remove(MA
);
1335 if (It
->second
.empty())
1336 InstructionToAccess
.erase(MA
->getAccessInstruction());
1340 MemoryAccess
*ScopStmt::ensureValueRead(Value
*V
) {
1341 MemoryAccess
*Access
= lookupInputAccessOf(V
);
1345 ScopArrayInfo
*SAI
=
1346 Parent
.getOrCreateScopArrayInfo(V
, V
->getType(), {}, MemoryKind::Value
);
1347 Access
= new MemoryAccess(this, nullptr, MemoryAccess::READ
, V
, V
->getType(),
1348 true, {}, {}, V
, MemoryKind::Value
);
1349 Parent
.addAccessFunction(Access
);
1350 Access
->buildAccessRelation(SAI
);
1352 Parent
.addAccessData(Access
);
1356 raw_ostream
&polly::operator<<(raw_ostream
&OS
, const ScopStmt
&S
) {
1357 S
.print(OS
, PollyPrintInstructions
);
1361 //===----------------------------------------------------------------------===//
1362 /// Scop class implement
1364 void Scop::setContext(isl::set NewContext
) {
1365 Context
= NewContext
.align_params(Context
.get_space());
1370 /// Remap parameter values but keep AddRecs valid wrt. invariant loads.
1371 class SCEVSensitiveParameterRewriter final
1372 : public SCEVRewriteVisitor
<SCEVSensitiveParameterRewriter
> {
1373 const ValueToValueMap
&VMap
;
1376 SCEVSensitiveParameterRewriter(const ValueToValueMap
&VMap
,
1377 ScalarEvolution
&SE
)
1378 : SCEVRewriteVisitor(SE
), VMap(VMap
) {}
1380 static const SCEV
*rewrite(const SCEV
*E
, ScalarEvolution
&SE
,
1381 const ValueToValueMap
&VMap
) {
1382 SCEVSensitiveParameterRewriter
SSPR(VMap
, SE
);
1383 return SSPR
.visit(E
);
1386 const SCEV
*visitAddRecExpr(const SCEVAddRecExpr
*E
) {
1387 const SCEV
*Start
= visit(E
->getStart());
1388 const SCEV
*AddRec
= SE
.getAddRecExpr(SE
.getConstant(E
->getType(), 0),
1389 visit(E
->getStepRecurrence(SE
)),
1390 E
->getLoop(), SCEV::FlagAnyWrap
);
1391 return SE
.getAddExpr(Start
, AddRec
);
1394 const SCEV
*visitUnknown(const SCEVUnknown
*E
) {
1395 if (auto *NewValue
= VMap
.lookup(E
->getValue()))
1396 return SE
.getUnknown(NewValue
);
1401 /// Check whether we should remap a SCEV expression.
1402 class SCEVFindInsideScop
: public SCEVTraversal
<SCEVFindInsideScop
> {
1403 const ValueToValueMap
&VMap
;
1404 bool FoundInside
= false;
1408 SCEVFindInsideScop(const ValueToValueMap
&VMap
, ScalarEvolution
&SE
,
1410 : SCEVTraversal(*this), VMap(VMap
), S(S
) {}
1412 static bool hasVariant(const SCEV
*E
, ScalarEvolution
&SE
,
1413 const ValueToValueMap
&VMap
, const Scop
*S
) {
1414 SCEVFindInsideScop
SFIS(VMap
, SE
, S
);
1416 return SFIS
.FoundInside
;
1419 bool follow(const SCEV
*E
) {
1420 if (auto *AddRec
= dyn_cast
<SCEVAddRecExpr
>(E
)) {
1421 FoundInside
|= S
->getRegion().contains(AddRec
->getLoop());
1422 } else if (auto *Unknown
= dyn_cast
<SCEVUnknown
>(E
)) {
1423 if (Instruction
*I
= dyn_cast
<Instruction
>(Unknown
->getValue()))
1424 FoundInside
|= S
->getRegion().contains(I
) && !VMap
.count(I
);
1426 return !FoundInside
;
1429 bool isDone() { return FoundInside
; }
1431 } // end anonymous namespace
1433 const SCEV
*Scop::getRepresentingInvariantLoadSCEV(const SCEV
*E
) const {
1434 // Check whether it makes sense to rewrite the SCEV. (ScalarEvolution
1435 // doesn't like addition between an AddRec and an expression that
1436 // doesn't have a dominance relationship with it.)
1437 if (SCEVFindInsideScop::hasVariant(E
, *SE
, InvEquivClassVMap
, this))
1441 return SCEVSensitiveParameterRewriter::rewrite(E
, *SE
, InvEquivClassVMap
);
1444 void Scop::createParameterId(const SCEV
*Parameter
) {
1445 assert(Parameters
.count(Parameter
));
1446 assert(!ParameterIds
.count(Parameter
));
1448 std::string ParameterName
= "p_" + std::to_string(getNumParams() - 1);
1450 if (const SCEVUnknown
*ValueParameter
= dyn_cast
<SCEVUnknown
>(Parameter
)) {
1451 Value
*Val
= ValueParameter
->getValue();
1453 if (UseInstructionNames
) {
1454 // If this parameter references a specific Value and this value has a name
1455 // we use this name as it is likely to be unique and more useful than just
1458 ParameterName
= Val
->getName().str();
1459 else if (LoadInst
*LI
= dyn_cast
<LoadInst
>(Val
)) {
1460 auto *LoadOrigin
= LI
->getPointerOperand()->stripInBoundsOffsets();
1461 if (LoadOrigin
->hasName()) {
1462 ParameterName
+= "_loaded_from_";
1464 LI
->getPointerOperand()->stripInBoundsOffsets()->getName();
1469 ParameterName
= getIslCompatibleName("", ParameterName
, "");
1472 isl::id Id
= isl::id::alloc(getIslCtx(), ParameterName
,
1473 const_cast<void *>((const void *)Parameter
));
1474 ParameterIds
[Parameter
] = Id
;
1477 void Scop::addParams(const ParameterSetTy
&NewParameters
) {
1478 for (const SCEV
*Parameter
: NewParameters
) {
1479 // Normalize the SCEV to get the representing element for an invariant load.
1480 Parameter
= extractConstantFactor(Parameter
, *SE
).second
;
1481 Parameter
= getRepresentingInvariantLoadSCEV(Parameter
);
1483 if (Parameters
.insert(Parameter
))
1484 createParameterId(Parameter
);
1488 isl::id
Scop::getIdForParam(const SCEV
*Parameter
) const {
1489 // Normalize the SCEV to get the representing element for an invariant load.
1490 Parameter
= getRepresentingInvariantLoadSCEV(Parameter
);
1491 return ParameterIds
.lookup(Parameter
);
1494 bool Scop::isDominatedBy(const DominatorTree
&DT
, BasicBlock
*BB
) const {
1495 return DT
.dominates(BB
, getEntry());
1498 void Scop::buildContext() {
1499 isl::space Space
= isl::space::params_alloc(getIslCtx(), 0);
1500 Context
= isl::set::universe(Space
);
1501 InvalidContext
= isl::set::empty(Space
);
1502 AssumedContext
= isl::set::universe(Space
);
1503 DefinedBehaviorContext
= isl::set::universe(Space
);
1506 void Scop::addParameterBounds() {
1508 for (auto *Parameter
: Parameters
) {
1509 ConstantRange SRange
= SE
->getSignedRange(Parameter
);
1510 Context
= addRangeBoundsToSet(Context
, SRange
, PDim
++, isl::dim::param
);
1512 intersectDefinedBehavior(Context
, AS_ASSUMPTION
);
1515 void Scop::realignParams() {
1516 if (PollyIgnoreParamBounds
)
1519 // Add all parameters into a common model.
1520 isl::space Space
= getFullParamSpace();
1522 // Align the parameters of all data structures to the model.
1523 Context
= Context
.align_params(Space
);
1524 AssumedContext
= AssumedContext
.align_params(Space
);
1525 InvalidContext
= InvalidContext
.align_params(Space
);
1527 // As all parameters are known add bounds to them.
1528 addParameterBounds();
1530 for (ScopStmt
&Stmt
: *this)
1531 Stmt
.realignParams();
1532 // Simplify the schedule according to the context too.
1533 Schedule
= Schedule
.gist_domain_params(getContext());
1535 // Predictable parameter order is required for JSON imports. Ensure alignment
1536 // by explicitly calling align_params.
1537 Schedule
= Schedule
.align_params(Space
);
1540 static isl::set
simplifyAssumptionContext(isl::set AssumptionContext
,
1542 // If we have modeled all blocks in the SCoP that have side effects we can
1543 // simplify the context with the constraints that are needed for anything to
1544 // be executed at all. However, if we have error blocks in the SCoP we already
1545 // assumed some parameter combinations cannot occur and removed them from the
1546 // domains, thus we cannot use the remaining domain to simplify the
1548 if (!S
.hasErrorBlock()) {
1549 auto DomainParameters
= S
.getDomains().params();
1550 AssumptionContext
= AssumptionContext
.gist_params(DomainParameters
);
1553 AssumptionContext
= AssumptionContext
.gist_params(S
.getContext());
1554 return AssumptionContext
;
1557 void Scop::simplifyContexts() {
1558 // The parameter constraints of the iteration domains give us a set of
1559 // constraints that need to hold for all cases where at least a single
1560 // statement iteration is executed in the whole scop. We now simplify the
1561 // assumed context under the assumption that such constraints hold and at
1562 // least a single statement iteration is executed. For cases where no
1563 // statement instances are executed, the assumptions we have taken about
1564 // the executed code do not matter and can be changed.
1566 // WARNING: This only holds if the assumptions we have taken do not reduce
1567 // the set of statement instances that are executed. Otherwise we
1568 // may run into a case where the iteration domains suggest that
1569 // for a certain set of parameter constraints no code is executed,
1570 // but in the original program some computation would have been
1571 // performed. In such a case, modifying the run-time conditions and
1572 // possibly influencing the run-time check may cause certain scops
1573 // to not be executed.
1577 // When delinearizing the following code:
1579 // for (long i = 0; i < 100; i++)
1580 // for (long j = 0; j < m; j++)
1583 // we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as
1584 // otherwise we would access out of bound data. Now, knowing that code is
1585 // only executed for the case m >= 0, it is sufficient to assume p >= 0.
1586 AssumedContext
= simplifyAssumptionContext(AssumedContext
, *this);
1587 InvalidContext
= InvalidContext
.align_params(getParamSpace());
1588 simplify(DefinedBehaviorContext
);
1589 DefinedBehaviorContext
= DefinedBehaviorContext
.align_params(getParamSpace());
1592 isl::set
Scop::getDomainConditions(const ScopStmt
*Stmt
) const {
1593 return getDomainConditions(Stmt
->getEntryBlock());
1596 isl::set
Scop::getDomainConditions(BasicBlock
*BB
) const {
1597 auto DIt
= DomainMap
.find(BB
);
1598 if (DIt
!= DomainMap
.end())
1599 return DIt
->getSecond();
1601 auto &RI
= *R
.getRegionInfo();
1602 auto *BBR
= RI
.getRegionFor(BB
);
1603 while (BBR
->getEntry() == BB
)
1604 BBR
= BBR
->getParent();
1605 return getDomainConditions(BBR
->getEntry());
1608 Scop::Scop(Region
&R
, ScalarEvolution
&ScalarEvolution
, LoopInfo
&LI
,
1609 DominatorTree
&DT
, ScopDetection::DetectionContext
&DC
,
1610 OptimizationRemarkEmitter
&ORE
, int ID
)
1611 : IslCtx(isl_ctx_alloc(), isl_ctx_free
), SE(&ScalarEvolution
), DT(&DT
),
1612 R(R
), name(std::nullopt
), HasSingleExitEdge(R
.getExitingBlock()), DC(DC
),
1613 ORE(ORE
), Affinator(this, LI
), ID(ID
) {
1615 // Options defaults that are different from ISL's.
1616 isl_options_set_schedule_serialize_sccs(IslCtx
.get(), true);
1618 SmallVector
<char *, 8> IslArgv
;
1619 IslArgv
.reserve(1 + IslArgs
.size());
1621 // Substitute for program name.
1622 IslArgv
.push_back(const_cast<char *>("-polly-isl-arg"));
1624 for (std::string
&Arg
: IslArgs
)
1625 IslArgv
.push_back(const_cast<char *>(Arg
.c_str()));
1627 // Abort if unknown argument is passed.
1628 // Note that "-V" (print isl version) will always call exit(0), so we cannot
1629 // avoid ISL aborting the program at this point.
1630 unsigned IslParseFlags
= ISL_ARG_ALL
;
1632 isl_ctx_parse_options(IslCtx
.get(), IslArgv
.size(), IslArgv
.data(),
1635 if (IslOnErrorAbort
)
1636 isl_options_set_on_error(getIslCtx().get(), ISL_ON_ERROR_ABORT
);
1640 Scop::~Scop() = default;
1642 void Scop::removeFromStmtMap(ScopStmt
&Stmt
) {
1643 for (Instruction
*Inst
: Stmt
.getInstructions())
1644 InstStmtMap
.erase(Inst
);
1646 if (Stmt
.isRegionStmt()) {
1647 for (BasicBlock
*BB
: Stmt
.getRegion()->blocks()) {
1649 // Skip entry basic block, as its instructions are already deleted as
1650 // part of the statement's instruction list.
1651 if (BB
== Stmt
.getEntryBlock())
1653 for (Instruction
&Inst
: *BB
)
1654 InstStmtMap
.erase(&Inst
);
1657 auto StmtMapIt
= StmtMap
.find(Stmt
.getBasicBlock());
1658 if (StmtMapIt
!= StmtMap
.end())
1659 llvm::erase(StmtMapIt
->second
, &Stmt
);
1660 for (Instruction
*Inst
: Stmt
.getInstructions())
1661 InstStmtMap
.erase(Inst
);
1665 void Scop::removeStmts(function_ref
<bool(ScopStmt
&)> ShouldDelete
,
1666 bool AfterHoisting
) {
1667 for (auto StmtIt
= Stmts
.begin(), StmtEnd
= Stmts
.end(); StmtIt
!= StmtEnd
;) {
1668 if (!ShouldDelete(*StmtIt
)) {
1673 // Start with removing all of the statement's accesses including erasing it
1674 // from all maps that are pointing to them.
1675 // Make a temporary copy because removing MAs invalidates the iterator.
1676 SmallVector
<MemoryAccess
*, 16> MAList(StmtIt
->begin(), StmtIt
->end());
1677 for (MemoryAccess
*MA
: MAList
)
1678 StmtIt
->removeSingleMemoryAccess(MA
, AfterHoisting
);
1680 removeFromStmtMap(*StmtIt
);
1681 StmtIt
= Stmts
.erase(StmtIt
);
1685 void Scop::removeStmtNotInDomainMap() {
1686 removeStmts([this](ScopStmt
&Stmt
) -> bool {
1687 isl::set Domain
= DomainMap
.lookup(Stmt
.getEntryBlock());
1688 if (Domain
.is_null())
1690 return Domain
.is_empty();
1694 void Scop::simplifySCoP(bool AfterHoisting
) {
1696 [AfterHoisting
](ScopStmt
&Stmt
) -> bool {
1697 // Never delete statements that contain calls to debug functions.
1698 if (hasDebugCall(&Stmt
))
1701 bool RemoveStmt
= Stmt
.isEmpty();
1703 // Remove read only statements only after invariant load hoisting.
1704 if (!RemoveStmt
&& AfterHoisting
) {
1705 bool OnlyRead
= true;
1706 for (MemoryAccess
*MA
: Stmt
) {
1714 RemoveStmt
= OnlyRead
;
1721 InvariantEquivClassTy
*Scop::lookupInvariantEquivClass(Value
*Val
) {
1722 LoadInst
*LInst
= dyn_cast
<LoadInst
>(Val
);
1726 if (Value
*Rep
= InvEquivClassVMap
.lookup(LInst
))
1727 LInst
= cast
<LoadInst
>(Rep
);
1729 Type
*Ty
= LInst
->getType();
1730 const SCEV
*PointerSCEV
= SE
->getSCEV(LInst
->getPointerOperand());
1731 for (auto &IAClass
: InvariantEquivClasses
) {
1732 if (PointerSCEV
!= IAClass
.IdentifyingPointer
|| Ty
!= IAClass
.AccessType
)
1735 auto &MAs
= IAClass
.InvariantAccesses
;
1736 for (auto *MA
: MAs
)
1737 if (MA
->getAccessInstruction() == Val
)
1744 ScopArrayInfo
*Scop::getOrCreateScopArrayInfo(Value
*BasePtr
, Type
*ElementType
,
1745 ArrayRef
<const SCEV
*> Sizes
,
1747 const char *BaseName
) {
1748 assert((BasePtr
|| BaseName
) &&
1749 "BasePtr and BaseName can not be nullptr at the same time.");
1750 assert(!(BasePtr
&& BaseName
) && "BaseName is redundant.");
1751 auto &SAI
= BasePtr
? ScopArrayInfoMap
[std::make_pair(BasePtr
, Kind
)]
1752 : ScopArrayNameMap
[BaseName
];
1754 auto &DL
= getFunction().getParent()->getDataLayout();
1755 SAI
.reset(new ScopArrayInfo(BasePtr
, ElementType
, getIslCtx(), Sizes
, Kind
,
1756 DL
, this, BaseName
));
1757 ScopArrayInfoSet
.insert(SAI
.get());
1759 SAI
->updateElementType(ElementType
);
1760 // In case of mismatching array sizes, we bail out by setting the run-time
1761 // context to false.
1762 if (!SAI
->updateSizes(Sizes
))
1763 invalidate(DELINEARIZATION
, DebugLoc());
1768 ScopArrayInfo
*Scop::createScopArrayInfo(Type
*ElementType
,
1769 const std::string
&BaseName
,
1770 const std::vector
<unsigned> &Sizes
) {
1771 auto *DimSizeType
= Type::getInt64Ty(getSE()->getContext());
1772 std::vector
<const SCEV
*> SCEVSizes
;
1774 for (auto size
: Sizes
)
1776 SCEVSizes
.push_back(getSE()->getConstant(DimSizeType
, size
, false));
1778 SCEVSizes
.push_back(nullptr);
1780 auto *SAI
= getOrCreateScopArrayInfo(nullptr, ElementType
, SCEVSizes
,
1781 MemoryKind::Array
, BaseName
.c_str());
1785 ScopArrayInfo
*Scop::getScopArrayInfoOrNull(Value
*BasePtr
, MemoryKind Kind
) {
1786 auto *SAI
= ScopArrayInfoMap
[std::make_pair(BasePtr
, Kind
)].get();
1790 ScopArrayInfo
*Scop::getScopArrayInfo(Value
*BasePtr
, MemoryKind Kind
) {
1791 auto *SAI
= getScopArrayInfoOrNull(BasePtr
, Kind
);
1792 assert(SAI
&& "No ScopArrayInfo available for this base pointer");
1796 std::string
Scop::getContextStr() const {
1797 return stringFromIslObj(getContext());
1800 std::string
Scop::getAssumedContextStr() const {
1801 assert(!AssumedContext
.is_null() && "Assumed context not yet built");
1802 return stringFromIslObj(AssumedContext
);
1805 std::string
Scop::getInvalidContextStr() const {
1806 return stringFromIslObj(InvalidContext
);
1809 std::string
Scop::getNameStr() const {
1810 std::string ExitName
, EntryName
;
1811 std::tie(EntryName
, ExitName
) = getEntryExitStr();
1812 return EntryName
+ "---" + ExitName
;
1815 std::pair
<std::string
, std::string
> Scop::getEntryExitStr() const {
1816 std::string ExitName
, EntryName
;
1817 raw_string_ostream
ExitStr(ExitName
);
1818 raw_string_ostream
EntryStr(EntryName
);
1820 R
.getEntry()->printAsOperand(EntryStr
, false);
1823 R
.getExit()->printAsOperand(ExitStr
, false);
1825 ExitName
= "FunctionExit";
1827 return std::make_pair(EntryName
, ExitName
);
1830 isl::set
Scop::getContext() const { return Context
; }
1832 isl::space
Scop::getParamSpace() const { return getContext().get_space(); }
1834 isl::space
Scop::getFullParamSpace() const {
1836 isl::space Space
= isl::space::params_alloc(getIslCtx(), ParameterIds
.size());
1839 for (const SCEV
*Parameter
: Parameters
) {
1840 isl::id Id
= getIdForParam(Parameter
);
1841 Space
= Space
.set_dim_id(isl::dim::param
, PDim
++, Id
);
1847 isl::set
Scop::getAssumedContext() const {
1848 assert(!AssumedContext
.is_null() && "Assumed context not yet built");
1849 return AssumedContext
;
1852 bool Scop::isProfitable(bool ScalarsAreUnprofitable
) const {
1853 if (PollyProcessUnprofitable
)
1859 unsigned OptimizableStmtsOrLoops
= 0;
1860 for (auto &Stmt
: *this) {
1861 if (Stmt
.getNumIterators() == 0)
1864 bool ContainsArrayAccs
= false;
1865 bool ContainsScalarAccs
= false;
1866 for (auto *MA
: Stmt
) {
1869 ContainsArrayAccs
|= MA
->isLatestArrayKind();
1870 ContainsScalarAccs
|= MA
->isLatestScalarKind();
1873 if (!ScalarsAreUnprofitable
|| (ContainsArrayAccs
&& !ContainsScalarAccs
))
1874 OptimizableStmtsOrLoops
+= Stmt
.getNumIterators();
1877 return OptimizableStmtsOrLoops
> 1;
1880 bool Scop::hasFeasibleRuntimeContext() const {
1884 isl::set PositiveContext
= getAssumedContext();
1885 isl::set NegativeContext
= getInvalidContext();
1886 PositiveContext
= PositiveContext
.intersect_params(Context
);
1887 PositiveContext
= PositiveContext
.intersect_params(getDomains().params());
1888 return PositiveContext
.is_empty().is_false() &&
1889 PositiveContext
.is_subset(NegativeContext
).is_false();
1892 MemoryAccess
*Scop::lookupBasePtrAccess(MemoryAccess
*MA
) {
1893 Value
*PointerBase
= MA
->getOriginalBaseAddr();
1895 auto *PointerBaseInst
= dyn_cast
<Instruction
>(PointerBase
);
1896 if (!PointerBaseInst
)
1899 auto *BasePtrStmt
= getStmtFor(PointerBaseInst
);
1903 return BasePtrStmt
->getArrayAccessOrNULLFor(PointerBaseInst
);
1906 static std::string
toString(AssumptionKind Kind
) {
1909 return "No-aliasing";
1913 return "No-overflows";
1915 return "Signed-unsigned";
1917 return "Low complexity";
1919 return "Profitable";
1923 return "Finite loop";
1925 return "Invariant load";
1926 case DELINEARIZATION
:
1927 return "Delinearization";
1929 llvm_unreachable("Unknown AssumptionKind!");
1932 bool Scop::isEffectiveAssumption(isl::set Set
, AssumptionSign Sign
) {
1933 if (Sign
== AS_ASSUMPTION
) {
1934 if (Context
.is_subset(Set
))
1937 if (AssumedContext
.is_subset(Set
))
1940 if (Set
.is_disjoint(Context
))
1943 if (Set
.is_subset(InvalidContext
))
1949 bool Scop::trackAssumption(AssumptionKind Kind
, isl::set Set
, DebugLoc Loc
,
1950 AssumptionSign Sign
, BasicBlock
*BB
) {
1951 if (PollyRemarksMinimal
&& !isEffectiveAssumption(Set
, Sign
))
1954 // Do never emit trivial assumptions as they only clutter the output.
1955 if (!PollyRemarksMinimal
) {
1957 if (Sign
== AS_ASSUMPTION
)
1958 Univ
= isl::set::universe(Set
.get_space());
1960 bool IsTrivial
= (Sign
== AS_RESTRICTION
&& Set
.is_empty()) ||
1961 (Sign
== AS_ASSUMPTION
&& Univ
.is_equal(Set
));
1969 AssumptionsAliasing
++;
1972 AssumptionsInbounds
++;
1975 AssumptionsWrapping
++;
1978 AssumptionsUnsigned
++;
1981 AssumptionsComplexity
++;
1984 AssumptionsUnprofitable
++;
1987 AssumptionsErrorBlock
++;
1990 AssumptionsInfiniteLoop
++;
1993 AssumptionsInvariantLoad
++;
1995 case DELINEARIZATION
:
1996 AssumptionsDelinearization
++;
2000 auto Suffix
= Sign
== AS_ASSUMPTION
? " assumption:\t" : " restriction:\t";
2001 std::string Msg
= toString(Kind
) + Suffix
+ stringFromIslObj(Set
);
2003 ORE
.emit(OptimizationRemarkAnalysis(DEBUG_TYPE
, "AssumpRestrict", Loc
, BB
)
2006 ORE
.emit(OptimizationRemarkAnalysis(DEBUG_TYPE
, "AssumpRestrict", Loc
,
2012 void Scop::addAssumption(AssumptionKind Kind
, isl::set Set
, DebugLoc Loc
,
2013 AssumptionSign Sign
, BasicBlock
*BB
,
2015 // Simplify the assumptions/restrictions first.
2016 Set
= Set
.gist_params(getContext());
2017 intersectDefinedBehavior(Set
, Sign
);
2022 if (!trackAssumption(Kind
, Set
, Loc
, Sign
, BB
))
2025 if (Sign
== AS_ASSUMPTION
)
2026 AssumedContext
= AssumedContext
.intersect(Set
).coalesce();
2028 InvalidContext
= InvalidContext
.unite(Set
).coalesce();
2031 void Scop::intersectDefinedBehavior(isl::set Set
, AssumptionSign Sign
) {
2032 if (DefinedBehaviorContext
.is_null())
2035 if (Sign
== AS_ASSUMPTION
)
2036 DefinedBehaviorContext
= DefinedBehaviorContext
.intersect(Set
);
2038 DefinedBehaviorContext
= DefinedBehaviorContext
.subtract(Set
);
2040 // Limit the complexity of the context. If complexity is exceeded, simplify
2041 // the set and check again.
2042 if (DefinedBehaviorContext
.n_basic_set().release() >
2043 MaxDisjunktsInDefinedBehaviourContext
) {
2044 simplify(DefinedBehaviorContext
);
2045 if (DefinedBehaviorContext
.n_basic_set().release() >
2046 MaxDisjunktsInDefinedBehaviourContext
)
2047 DefinedBehaviorContext
= {};
2051 void Scop::invalidate(AssumptionKind Kind
, DebugLoc Loc
, BasicBlock
*BB
) {
2052 POLLY_DEBUG(dbgs() << "Invalidate SCoP because of reason " << Kind
<< "\n");
2053 addAssumption(Kind
, isl::set::empty(getParamSpace()), Loc
, AS_ASSUMPTION
, BB
);
2056 isl::set
Scop::getInvalidContext() const { return InvalidContext
; }
2058 void Scop::printContext(raw_ostream
&OS
) const {
2060 OS
.indent(4) << Context
<< "\n";
2062 OS
.indent(4) << "Assumed Context:\n";
2063 OS
.indent(4) << AssumedContext
<< "\n";
2065 OS
.indent(4) << "Invalid Context:\n";
2066 OS
.indent(4) << InvalidContext
<< "\n";
2068 OS
.indent(4) << "Defined Behavior Context:\n";
2069 if (!DefinedBehaviorContext
.is_null())
2070 OS
.indent(4) << DefinedBehaviorContext
<< "\n";
2072 OS
.indent(4) << "<unavailable>\n";
2075 for (const SCEV
*Parameter
: Parameters
)
2076 OS
.indent(4) << "p" << Dim
++ << ": " << *Parameter
<< "\n";
2079 void Scop::printAliasAssumptions(raw_ostream
&OS
) const {
2081 for (const MinMaxVectorPairTy
&Pair
: MinMaxAliasGroups
) {
2082 if (Pair
.second
.size() == 0)
2085 noOfGroups
+= Pair
.second
.size();
2088 OS
.indent(4) << "Alias Groups (" << noOfGroups
<< "):\n";
2089 if (MinMaxAliasGroups
.empty()) {
2090 OS
.indent(8) << "n/a\n";
2094 for (const MinMaxVectorPairTy
&Pair
: MinMaxAliasGroups
) {
2096 // If the group has no read only accesses print the write accesses.
2097 if (Pair
.second
.empty()) {
2098 OS
.indent(8) << "[[";
2099 for (const MinMaxAccessTy
&MMANonReadOnly
: Pair
.first
) {
2100 OS
<< " <" << MMANonReadOnly
.first
<< ", " << MMANonReadOnly
.second
2106 for (const MinMaxAccessTy
&MMAReadOnly
: Pair
.second
) {
2107 OS
.indent(8) << "[[";
2108 OS
<< " <" << MMAReadOnly
.first
<< ", " << MMAReadOnly
.second
<< ">";
2109 for (const MinMaxAccessTy
&MMANonReadOnly
: Pair
.first
) {
2110 OS
<< " <" << MMANonReadOnly
.first
<< ", " << MMANonReadOnly
.second
2118 void Scop::printStatements(raw_ostream
&OS
, bool PrintInstructions
) const {
2119 OS
<< "Statements {\n";
2121 for (const ScopStmt
&Stmt
: *this) {
2123 Stmt
.print(OS
, PrintInstructions
);
2126 OS
.indent(4) << "}\n";
2129 void Scop::printArrayInfo(raw_ostream
&OS
) const {
2132 for (auto &Array
: arrays())
2135 OS
.indent(4) << "}\n";
2137 OS
.indent(4) << "Arrays (Bounds as pw_affs) {\n";
2139 for (auto &Array
: arrays())
2140 Array
->print(OS
, /* SizeAsPwAff */ true);
2142 OS
.indent(4) << "}\n";
2145 void Scop::print(raw_ostream
&OS
, bool PrintInstructions
) const {
2146 OS
.indent(4) << "Function: " << getFunction().getName() << "\n";
2147 OS
.indent(4) << "Region: " << getNameStr() << "\n";
2148 OS
.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n";
2149 OS
.indent(4) << "Invariant Accesses: {\n";
2150 for (const auto &IAClass
: InvariantEquivClasses
) {
2151 const auto &MAs
= IAClass
.InvariantAccesses
;
2153 OS
.indent(12) << "Class Pointer: " << *IAClass
.IdentifyingPointer
<< "\n";
2155 MAs
.front()->print(OS
);
2156 OS
.indent(12) << "Execution Context: " << IAClass
.ExecutionContext
2160 OS
.indent(4) << "}\n";
2161 printContext(OS
.indent(4));
2162 printArrayInfo(OS
.indent(4));
2163 printAliasAssumptions(OS
);
2164 printStatements(OS
.indent(4), PrintInstructions
);
2167 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2168 LLVM_DUMP_METHOD
void Scop::dump() const { print(dbgs(), true); }
2171 isl::ctx
Scop::getIslCtx() const { return IslCtx
.get(); }
2173 __isl_give PWACtx
Scop::getPwAff(const SCEV
*E
, BasicBlock
*BB
,
2175 RecordedAssumptionsTy
*RecordedAssumptions
) {
2176 // First try to use the SCEVAffinator to generate a piecewise defined
2177 // affine function from @p E in the context of @p BB. If that tasks becomes to
2178 // complex the affinator might return a nullptr. In such a case we invalidate
2179 // the SCoP and return a dummy value. This way we do not need to add error
2180 // handling code to all users of this function.
2181 auto PWAC
= Affinator
.getPwAff(E
, BB
, RecordedAssumptions
);
2182 if (!PWAC
.first
.is_null()) {
2183 // TODO: We could use a heuristic and either use:
2184 // SCEVAffinator::takeNonNegativeAssumption
2186 // SCEVAffinator::interpretAsUnsigned
2187 // to deal with unsigned or "NonNegative" SCEVs.
2189 Affinator
.takeNonNegativeAssumption(PWAC
, RecordedAssumptions
);
2193 auto DL
= BB
? BB
->getTerminator()->getDebugLoc() : DebugLoc();
2194 invalidate(COMPLEXITY
, DL
, BB
);
2195 return Affinator
.getPwAff(SE
->getZero(E
->getType()), BB
, RecordedAssumptions
);
2198 isl::union_set
Scop::getDomains() const {
2199 isl_space
*EmptySpace
= isl_space_params_alloc(getIslCtx().get(), 0);
2200 isl_union_set
*Domain
= isl_union_set_empty(EmptySpace
);
2202 for (const ScopStmt
&Stmt
: *this)
2203 Domain
= isl_union_set_add_set(Domain
, Stmt
.getDomain().release());
2205 return isl::manage(Domain
);
2208 isl::pw_aff
Scop::getPwAffOnly(const SCEV
*E
, BasicBlock
*BB
,
2209 RecordedAssumptionsTy
*RecordedAssumptions
) {
2210 PWACtx PWAC
= getPwAff(E
, BB
, RecordedAssumptions
);
2215 Scop::getAccessesOfType(std::function
<bool(MemoryAccess
&)> Predicate
) {
2216 isl::union_map Accesses
= isl::union_map::empty(getIslCtx());
2218 for (ScopStmt
&Stmt
: *this) {
2219 for (MemoryAccess
*MA
: Stmt
) {
2220 if (!Predicate(*MA
))
2223 isl::set Domain
= Stmt
.getDomain();
2224 isl::map AccessDomain
= MA
->getAccessRelation();
2225 AccessDomain
= AccessDomain
.intersect_domain(Domain
);
2226 Accesses
= Accesses
.unite(AccessDomain
);
2230 return Accesses
.coalesce();
2233 isl::union_map
Scop::getMustWrites() {
2234 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isMustWrite(); });
2237 isl::union_map
Scop::getMayWrites() {
2238 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isMayWrite(); });
2241 isl::union_map
Scop::getWrites() {
2242 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isWrite(); });
2245 isl::union_map
Scop::getReads() {
2246 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isRead(); });
2249 isl::union_map
Scop::getAccesses() {
2250 return getAccessesOfType([](MemoryAccess
&MA
) { return true; });
2253 isl::union_map
Scop::getAccesses(ScopArrayInfo
*Array
) {
2254 return getAccessesOfType(
2255 [Array
](MemoryAccess
&MA
) { return MA
.getScopArrayInfo() == Array
; });
2258 isl::union_map
Scop::getSchedule() const {
2259 auto Tree
= getScheduleTree();
2260 return Tree
.get_map();
2263 isl::schedule
Scop::getScheduleTree() const {
2264 return Schedule
.intersect_domain(getDomains());
2267 void Scop::setSchedule(isl::union_map NewSchedule
) {
2268 auto S
= isl::schedule::from_domain(getDomains());
2269 Schedule
= S
.insert_partial_schedule(
2270 isl::multi_union_pw_aff::from_union_map(NewSchedule
));
2271 ScheduleModified
= true;
2274 void Scop::setScheduleTree(isl::schedule NewSchedule
) {
2275 Schedule
= NewSchedule
;
2276 ScheduleModified
= true;
2279 bool Scop::restrictDomains(isl::union_set Domain
) {
2280 bool Changed
= false;
2281 for (ScopStmt
&Stmt
: *this) {
2282 isl::union_set StmtDomain
= isl::union_set(Stmt
.getDomain());
2283 isl::union_set NewStmtDomain
= StmtDomain
.intersect(Domain
);
2285 if (StmtDomain
.is_subset(NewStmtDomain
))
2290 NewStmtDomain
= NewStmtDomain
.coalesce();
2292 if (NewStmtDomain
.is_empty())
2293 Stmt
.restrictDomain(isl::set::empty(Stmt
.getDomainSpace()));
2295 Stmt
.restrictDomain(isl::set(NewStmtDomain
));
2300 ScalarEvolution
*Scop::getSE() const { return SE
; }
2302 void Scop::addScopStmt(BasicBlock
*BB
, StringRef Name
, Loop
*SurroundingLoop
,
2303 std::vector
<Instruction
*> Instructions
) {
2304 assert(BB
&& "Unexpected nullptr!");
2305 Stmts
.emplace_back(*this, *BB
, Name
, SurroundingLoop
, Instructions
);
2306 auto *Stmt
= &Stmts
.back();
2307 StmtMap
[BB
].push_back(Stmt
);
2308 for (Instruction
*Inst
: Instructions
) {
2309 assert(!InstStmtMap
.count(Inst
) &&
2310 "Unexpected statement corresponding to the instruction.");
2311 InstStmtMap
[Inst
] = Stmt
;
2315 void Scop::addScopStmt(Region
*R
, StringRef Name
, Loop
*SurroundingLoop
,
2316 std::vector
<Instruction
*> Instructions
) {
2317 assert(R
&& "Unexpected nullptr!");
2318 Stmts
.emplace_back(*this, *R
, Name
, SurroundingLoop
, Instructions
);
2319 auto *Stmt
= &Stmts
.back();
2321 for (Instruction
*Inst
: Instructions
) {
2322 assert(!InstStmtMap
.count(Inst
) &&
2323 "Unexpected statement corresponding to the instruction.");
2324 InstStmtMap
[Inst
] = Stmt
;
2327 for (BasicBlock
*BB
: R
->blocks()) {
2328 StmtMap
[BB
].push_back(Stmt
);
2329 if (BB
== R
->getEntry())
2331 for (Instruction
&Inst
: *BB
) {
2332 assert(!InstStmtMap
.count(&Inst
) &&
2333 "Unexpected statement corresponding to the instruction.");
2334 InstStmtMap
[&Inst
] = Stmt
;
2339 ScopStmt
*Scop::addScopStmt(isl::map SourceRel
, isl::map TargetRel
,
2342 isl::set SourceDomain
= SourceRel
.domain();
2343 isl::set TargetDomain
= TargetRel
.domain();
2344 assert(Domain
.is_subset(TargetDomain
) &&
2345 "Target access not defined for complete statement domain");
2346 assert(Domain
.is_subset(SourceDomain
) &&
2347 "Source access not defined for complete statement domain");
2349 Stmts
.emplace_back(*this, SourceRel
, TargetRel
, Domain
);
2351 return &(Stmts
.back());
2354 ArrayRef
<ScopStmt
*> Scop::getStmtListFor(BasicBlock
*BB
) const {
2355 auto StmtMapIt
= StmtMap
.find(BB
);
2356 if (StmtMapIt
== StmtMap
.end())
2358 return StmtMapIt
->second
;
2361 ScopStmt
*Scop::getIncomingStmtFor(const Use
&U
) const {
2362 auto *PHI
= cast
<PHINode
>(U
.getUser());
2363 BasicBlock
*IncomingBB
= PHI
->getIncomingBlock(U
);
2365 // If the value is a non-synthesizable from the incoming block, use the
2366 // statement that contains it as user statement.
2367 if (auto *IncomingInst
= dyn_cast
<Instruction
>(U
.get())) {
2368 if (IncomingInst
->getParent() == IncomingBB
) {
2369 if (ScopStmt
*IncomingStmt
= getStmtFor(IncomingInst
))
2370 return IncomingStmt
;
2374 // Otherwise, use the epilogue/last statement.
2375 return getLastStmtFor(IncomingBB
);
2378 ScopStmt
*Scop::getLastStmtFor(BasicBlock
*BB
) const {
2379 ArrayRef
<ScopStmt
*> StmtList
= getStmtListFor(BB
);
2380 if (!StmtList
.empty())
2381 return StmtList
.back();
2385 ArrayRef
<ScopStmt
*> Scop::getStmtListFor(RegionNode
*RN
) const {
2386 if (RN
->isSubRegion())
2387 return getStmtListFor(RN
->getNodeAs
<Region
>());
2388 return getStmtListFor(RN
->getNodeAs
<BasicBlock
>());
2391 ArrayRef
<ScopStmt
*> Scop::getStmtListFor(Region
*R
) const {
2392 return getStmtListFor(R
->getEntry());
2395 int Scop::getRelativeLoopDepth(const Loop
*L
) const {
2396 if (!L
|| !R
.contains(L
))
2398 // outermostLoopInRegion always returns nullptr for top level regions
2399 if (R
.isTopLevelRegion()) {
2400 // LoopInfo's depths start at 1, we start at 0
2401 return L
->getLoopDepth() - 1;
2403 Loop
*OuterLoop
= R
.outermostLoopInRegion(const_cast<Loop
*>(L
));
2405 return L
->getLoopDepth() - OuterLoop
->getLoopDepth();
2409 ScopArrayInfo
*Scop::getArrayInfoByName(const std::string BaseName
) {
2410 for (auto &SAI
: arrays()) {
2411 if (SAI
->getName() == BaseName
)
2417 void Scop::addAccessData(MemoryAccess
*Access
) {
2418 const ScopArrayInfo
*SAI
= Access
->getOriginalScopArrayInfo();
2419 assert(SAI
&& "can only use after access relations have been constructed");
2421 if (Access
->isOriginalValueKind() && Access
->isRead())
2422 ValueUseAccs
[SAI
].push_back(Access
);
2423 else if (Access
->isOriginalAnyPHIKind() && Access
->isWrite())
2424 PHIIncomingAccs
[SAI
].push_back(Access
);
2427 void Scop::removeAccessData(MemoryAccess
*Access
) {
2428 if (Access
->isOriginalValueKind() && Access
->isWrite()) {
2429 ValueDefAccs
.erase(Access
->getAccessValue());
2430 } else if (Access
->isOriginalValueKind() && Access
->isRead()) {
2431 auto &Uses
= ValueUseAccs
[Access
->getScopArrayInfo()];
2432 llvm::erase(Uses
, Access
);
2433 } else if (Access
->isOriginalPHIKind() && Access
->isRead()) {
2434 PHINode
*PHI
= cast
<PHINode
>(Access
->getAccessInstruction());
2435 PHIReadAccs
.erase(PHI
);
2436 } else if (Access
->isOriginalAnyPHIKind() && Access
->isWrite()) {
2437 auto &Incomings
= PHIIncomingAccs
[Access
->getScopArrayInfo()];
2438 llvm::erase(Incomings
, Access
);
2442 MemoryAccess
*Scop::getValueDef(const ScopArrayInfo
*SAI
) const {
2443 assert(SAI
->isValueKind());
2445 Instruction
*Val
= dyn_cast
<Instruction
>(SAI
->getBasePtr());
2449 return ValueDefAccs
.lookup(Val
);
2452 ArrayRef
<MemoryAccess
*> Scop::getValueUses(const ScopArrayInfo
*SAI
) const {
2453 assert(SAI
->isValueKind());
2454 auto It
= ValueUseAccs
.find(SAI
);
2455 if (It
== ValueUseAccs
.end())
2460 MemoryAccess
*Scop::getPHIRead(const ScopArrayInfo
*SAI
) const {
2461 assert(SAI
->isPHIKind() || SAI
->isExitPHIKind());
2463 if (SAI
->isExitPHIKind())
2466 PHINode
*PHI
= cast
<PHINode
>(SAI
->getBasePtr());
2467 return PHIReadAccs
.lookup(PHI
);
2470 ArrayRef
<MemoryAccess
*> Scop::getPHIIncomings(const ScopArrayInfo
*SAI
) const {
2471 assert(SAI
->isPHIKind() || SAI
->isExitPHIKind());
2472 auto It
= PHIIncomingAccs
.find(SAI
);
2473 if (It
== PHIIncomingAccs
.end())
2478 bool Scop::isEscaping(Instruction
*Inst
) {
2479 assert(contains(Inst
) && "The concept of escaping makes only sense for "
2480 "values defined inside the SCoP");
2482 for (Use
&Use
: Inst
->uses()) {
2483 BasicBlock
*UserBB
= getUseBlock(Use
);
2484 if (!contains(UserBB
))
2487 // When the SCoP region exit needs to be simplified, PHIs in the region exit
2488 // move to a new basic block such that its incoming blocks are not in the
2490 if (hasSingleExitEdge() && isa
<PHINode
>(Use
.getUser()) &&
2491 isExit(cast
<PHINode
>(Use
.getUser())->getParent()))
2497 void Scop::incrementNumberOfAliasingAssumptions(unsigned step
) {
2498 AssumptionsAliasing
+= step
;
2501 Scop::ScopStatistics
Scop::getStatistics() const {
2502 ScopStatistics Result
;
2503 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2504 auto LoopStat
= ScopDetection::countBeneficialLoops(&R
, *SE
, *getLI(), 0);
2506 int NumTotalLoops
= LoopStat
.NumLoops
;
2507 Result
.NumBoxedLoops
= getBoxedLoops().size();
2508 Result
.NumAffineLoops
= NumTotalLoops
- Result
.NumBoxedLoops
;
2510 for (const ScopStmt
&Stmt
: *this) {
2511 isl::set Domain
= Stmt
.getDomain().intersect_params(getContext());
2512 bool IsInLoop
= Stmt
.getNumIterators() >= 1;
2513 for (MemoryAccess
*MA
: Stmt
) {
2517 if (MA
->isLatestValueKind()) {
2518 Result
.NumValueWrites
+= 1;
2520 Result
.NumValueWritesInLoops
+= 1;
2523 if (MA
->isLatestAnyPHIKind()) {
2524 Result
.NumPHIWrites
+= 1;
2526 Result
.NumPHIWritesInLoops
+= 1;
2530 MA
->getAccessRelation().intersect_domain(Domain
).range();
2531 if (AccSet
.is_singleton()) {
2532 Result
.NumSingletonWrites
+= 1;
2534 Result
.NumSingletonWritesInLoops
+= 1;
2542 raw_ostream
&polly::operator<<(raw_ostream
&OS
, const Scop
&scop
) {
2543 scop
.print(OS
, PollyPrintInstructions
);
2547 //===----------------------------------------------------------------------===//
2548 void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage
&AU
) const {
2549 AU
.addRequired
<LoopInfoWrapperPass
>();
2550 AU
.addRequired
<RegionInfoPass
>();
2551 AU
.addRequired
<DominatorTreeWrapperPass
>();
2552 AU
.addRequiredTransitive
<ScalarEvolutionWrapperPass
>();
2553 AU
.addRequiredTransitive
<ScopDetectionWrapperPass
>();
2554 AU
.addRequired
<AAResultsWrapperPass
>();
2555 AU
.addRequired
<AssumptionCacheTracker
>();
2556 AU
.addRequired
<OptimizationRemarkEmitterWrapperPass
>();
2557 AU
.setPreservesAll();
2560 void updateLoopCountStatistic(ScopDetection::LoopStats Stats
,
2561 Scop::ScopStatistics ScopStats
) {
2562 assert(Stats
.NumLoops
== ScopStats
.NumAffineLoops
+ ScopStats
.NumBoxedLoops
);
2565 NumLoopsInScop
+= Stats
.NumLoops
;
2567 std::max(MaxNumLoopsInScop
.getValue(), (uint64_t)Stats
.NumLoops
);
2569 if (Stats
.MaxDepth
== 0)
2570 NumScopsDepthZero
++;
2571 else if (Stats
.MaxDepth
== 1)
2573 else if (Stats
.MaxDepth
== 2)
2575 else if (Stats
.MaxDepth
== 3)
2576 NumScopsDepthThree
++;
2577 else if (Stats
.MaxDepth
== 4)
2578 NumScopsDepthFour
++;
2579 else if (Stats
.MaxDepth
== 5)
2580 NumScopsDepthFive
++;
2582 NumScopsDepthLarger
++;
2584 NumAffineLoops
+= ScopStats
.NumAffineLoops
;
2585 NumBoxedLoops
+= ScopStats
.NumBoxedLoops
;
2587 NumValueWrites
+= ScopStats
.NumValueWrites
;
2588 NumValueWritesInLoops
+= ScopStats
.NumValueWritesInLoops
;
2589 NumPHIWrites
+= ScopStats
.NumPHIWrites
;
2590 NumPHIWritesInLoops
+= ScopStats
.NumPHIWritesInLoops
;
2591 NumSingletonWrites
+= ScopStats
.NumSingletonWrites
;
2592 NumSingletonWritesInLoops
+= ScopStats
.NumSingletonWritesInLoops
;
2595 bool ScopInfoRegionPass::runOnRegion(Region
*R
, RGPassManager
&RGM
) {
2596 auto &SD
= getAnalysis
<ScopDetectionWrapperPass
>().getSD();
2598 if (!SD
.isMaxRegionInScop(*R
))
2601 Function
*F
= R
->getEntry()->getParent();
2602 auto &SE
= getAnalysis
<ScalarEvolutionWrapperPass
>().getSE();
2603 auto &LI
= getAnalysis
<LoopInfoWrapperPass
>().getLoopInfo();
2604 auto &AA
= getAnalysis
<AAResultsWrapperPass
>().getAAResults();
2605 auto const &DL
= F
->getParent()->getDataLayout();
2606 auto &DT
= getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
2607 auto &AC
= getAnalysis
<AssumptionCacheTracker
>().getAssumptionCache(*F
);
2608 auto &ORE
= getAnalysis
<OptimizationRemarkEmitterWrapperPass
>().getORE();
2610 ScopBuilder
SB(R
, AC
, AA
, DL
, DT
, LI
, SD
, SE
, ORE
);
2611 S
= SB
.getScop(); // take ownership of scop object
2613 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2615 ScopDetection::LoopStats Stats
=
2616 ScopDetection::countBeneficialLoops(&S
->getRegion(), SE
, LI
, 0);
2617 updateLoopCountStatistic(Stats
, S
->getStatistics());
2624 void ScopInfoRegionPass::print(raw_ostream
&OS
, const Module
*) const {
2626 S
->print(OS
, PollyPrintInstructions
);
2628 OS
<< "Invalid Scop!\n";
2631 char ScopInfoRegionPass::ID
= 0;
2633 Pass
*polly::createScopInfoRegionPassPass() { return new ScopInfoRegionPass(); }
2635 INITIALIZE_PASS_BEGIN(ScopInfoRegionPass
, "polly-scops",
2636 "Polly - Create polyhedral description of Scops", false,
2638 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass
);
2639 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker
);
2640 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass
);
2641 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass
);
2642 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass
);
2643 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass
);
2644 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
);
2645 INITIALIZE_PASS_END(ScopInfoRegionPass
, "polly-scops",
2646 "Polly - Create polyhedral description of Scops", false,
2649 //===----------------------------------------------------------------------===//
2653 /// Print result from ScopInfoRegionPass.
2654 class ScopInfoPrinterLegacyRegionPass final
: public RegionPass
{
2658 ScopInfoPrinterLegacyRegionPass() : ScopInfoPrinterLegacyRegionPass(outs()) {}
2660 explicit ScopInfoPrinterLegacyRegionPass(llvm::raw_ostream
&OS
)
2661 : RegionPass(ID
), OS(OS
) {}
2663 bool runOnRegion(Region
*R
, RGPassManager
&RGM
) override
{
2664 ScopInfoRegionPass
&P
= getAnalysis
<ScopInfoRegionPass
>();
2666 OS
<< "Printing analysis '" << P
.getPassName() << "' for region: '"
2667 << R
->getNameStr() << "' in function '"
2668 << R
->getEntry()->getParent()->getName() << "':\n";
2674 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
2675 RegionPass::getAnalysisUsage(AU
);
2676 AU
.addRequired
<ScopInfoRegionPass
>();
2677 AU
.setPreservesAll();
2681 llvm::raw_ostream
&OS
;
2684 char ScopInfoPrinterLegacyRegionPass::ID
= 0;
2687 Pass
*polly::createScopInfoPrinterLegacyRegionPass(raw_ostream
&OS
) {
2688 return new ScopInfoPrinterLegacyRegionPass(OS
);
2691 INITIALIZE_PASS_BEGIN(ScopInfoPrinterLegacyRegionPass
, "polly-print-scops",
2692 "Polly - Print polyhedral description of Scops", false,
2694 INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass
);
2695 INITIALIZE_PASS_END(ScopInfoPrinterLegacyRegionPass
, "polly-print-scops",
2696 "Polly - Print polyhedral description of Scops", false,
2699 //===----------------------------------------------------------------------===//
2701 ScopInfo::ScopInfo(const DataLayout
&DL
, ScopDetection
&SD
, ScalarEvolution
&SE
,
2702 LoopInfo
&LI
, AliasAnalysis
&AA
, DominatorTree
&DT
,
2703 AssumptionCache
&AC
, OptimizationRemarkEmitter
&ORE
)
2704 : DL(DL
), SD(SD
), SE(SE
), LI(LI
), AA(AA
), DT(DT
), AC(AC
), ORE(ORE
) {
2708 void ScopInfo::recompute() {
2709 RegionToScopMap
.clear();
2710 /// Create polyhedral description of scops for all the valid regions of a
2712 for (auto &It
: SD
) {
2713 Region
*R
= const_cast<Region
*>(It
);
2714 if (!SD
.isMaxRegionInScop(*R
))
2717 ScopBuilder
SB(R
, AC
, AA
, DL
, DT
, LI
, SD
, SE
, ORE
);
2718 std::unique_ptr
<Scop
> S
= SB
.getScop();
2721 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2722 ScopDetection::LoopStats Stats
=
2723 ScopDetection::countBeneficialLoops(&S
->getRegion(), SE
, LI
, 0);
2724 updateLoopCountStatistic(Stats
, S
->getStatistics());
2726 bool Inserted
= RegionToScopMap
.insert({R
, std::move(S
)}).second
;
2727 assert(Inserted
&& "Building Scop for the same region twice!");
2732 bool ScopInfo::invalidate(Function
&F
, const PreservedAnalyses
&PA
,
2733 FunctionAnalysisManager::Invalidator
&Inv
) {
2734 // Check whether the analysis, all analyses on functions have been preserved
2735 // or anything we're holding references to is being invalidated
2736 auto PAC
= PA
.getChecker
<ScopInfoAnalysis
>();
2737 return !(PAC
.preserved() || PAC
.preservedSet
<AllAnalysesOn
<Function
>>()) ||
2738 Inv
.invalidate
<ScopAnalysis
>(F
, PA
) ||
2739 Inv
.invalidate
<ScalarEvolutionAnalysis
>(F
, PA
) ||
2740 Inv
.invalidate
<LoopAnalysis
>(F
, PA
) ||
2741 Inv
.invalidate
<AAManager
>(F
, PA
) ||
2742 Inv
.invalidate
<DominatorTreeAnalysis
>(F
, PA
) ||
2743 Inv
.invalidate
<AssumptionAnalysis
>(F
, PA
);
2746 AnalysisKey
ScopInfoAnalysis::Key
;
2748 ScopInfoAnalysis::Result
ScopInfoAnalysis::run(Function
&F
,
2749 FunctionAnalysisManager
&FAM
) {
2750 auto &SD
= FAM
.getResult
<ScopAnalysis
>(F
);
2751 auto &SE
= FAM
.getResult
<ScalarEvolutionAnalysis
>(F
);
2752 auto &LI
= FAM
.getResult
<LoopAnalysis
>(F
);
2753 auto &AA
= FAM
.getResult
<AAManager
>(F
);
2754 auto &DT
= FAM
.getResult
<DominatorTreeAnalysis
>(F
);
2755 auto &AC
= FAM
.getResult
<AssumptionAnalysis
>(F
);
2756 auto &DL
= F
.getParent()->getDataLayout();
2757 auto &ORE
= FAM
.getResult
<OptimizationRemarkEmitterAnalysis
>(F
);
2758 return {DL
, SD
, SE
, LI
, AA
, DT
, AC
, ORE
};
2761 PreservedAnalyses
ScopInfoPrinterPass::run(Function
&F
,
2762 FunctionAnalysisManager
&FAM
) {
2763 auto &SI
= FAM
.getResult
<ScopInfoAnalysis
>(F
);
2764 // Since the legacy PM processes Scops in bottom up, we print them in reverse
2765 // order here to keep the output persistent
2766 for (auto &It
: reverse(SI
)) {
2768 It
.second
->print(Stream
, PollyPrintInstructions
);
2770 Stream
<< "Invalid Scop!\n";
2772 return PreservedAnalyses::all();
2775 void ScopInfoWrapperPass::getAnalysisUsage(AnalysisUsage
&AU
) const {
2776 AU
.addRequired
<LoopInfoWrapperPass
>();
2777 AU
.addRequired
<RegionInfoPass
>();
2778 AU
.addRequired
<DominatorTreeWrapperPass
>();
2779 AU
.addRequiredTransitive
<ScalarEvolutionWrapperPass
>();
2780 AU
.addRequiredTransitive
<ScopDetectionWrapperPass
>();
2781 AU
.addRequired
<AAResultsWrapperPass
>();
2782 AU
.addRequired
<AssumptionCacheTracker
>();
2783 AU
.addRequired
<OptimizationRemarkEmitterWrapperPass
>();
2784 AU
.setPreservesAll();
2787 bool ScopInfoWrapperPass::runOnFunction(Function
&F
) {
2788 auto &SD
= getAnalysis
<ScopDetectionWrapperPass
>().getSD();
2789 auto &SE
= getAnalysis
<ScalarEvolutionWrapperPass
>().getSE();
2790 auto &LI
= getAnalysis
<LoopInfoWrapperPass
>().getLoopInfo();
2791 auto &AA
= getAnalysis
<AAResultsWrapperPass
>().getAAResults();
2792 auto const &DL
= F
.getParent()->getDataLayout();
2793 auto &DT
= getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
2794 auto &AC
= getAnalysis
<AssumptionCacheTracker
>().getAssumptionCache(F
);
2795 auto &ORE
= getAnalysis
<OptimizationRemarkEmitterWrapperPass
>().getORE();
2797 Result
.reset(new ScopInfo
{DL
, SD
, SE
, LI
, AA
, DT
, AC
, ORE
});
2801 void ScopInfoWrapperPass::print(raw_ostream
&OS
, const Module
*) const {
2802 for (auto &It
: *Result
) {
2804 It
.second
->print(OS
, PollyPrintInstructions
);
2806 OS
<< "Invalid Scop!\n";
2810 char ScopInfoWrapperPass::ID
= 0;
2812 Pass
*polly::createScopInfoWrapperPassPass() {
2813 return new ScopInfoWrapperPass();
2816 INITIALIZE_PASS_BEGIN(
2817 ScopInfoWrapperPass
, "polly-function-scops",
2818 "Polly - Create polyhedral description of all Scops of a function", false,
2820 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass
);
2821 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker
);
2822 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass
);
2823 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass
);
2824 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass
);
2825 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass
);
2826 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
);
2827 INITIALIZE_PASS_END(
2828 ScopInfoWrapperPass
, "polly-function-scops",
2829 "Polly - Create polyhedral description of all Scops of a function", false,
2832 //===----------------------------------------------------------------------===//
2835 /// Print result from ScopInfoWrapperPass.
2836 class ScopInfoPrinterLegacyFunctionPass final
: public FunctionPass
{
2840 ScopInfoPrinterLegacyFunctionPass()
2841 : ScopInfoPrinterLegacyFunctionPass(outs()) {}
2842 explicit ScopInfoPrinterLegacyFunctionPass(llvm::raw_ostream
&OS
)
2843 : FunctionPass(ID
), OS(OS
) {}
2845 bool runOnFunction(Function
&F
) override
{
2846 ScopInfoWrapperPass
&P
= getAnalysis
<ScopInfoWrapperPass
>();
2848 OS
<< "Printing analysis '" << P
.getPassName() << "' for function '"
2849 << F
.getName() << "':\n";
2855 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
2856 FunctionPass::getAnalysisUsage(AU
);
2857 AU
.addRequired
<ScopInfoWrapperPass
>();
2858 AU
.setPreservesAll();
2862 llvm::raw_ostream
&OS
;
2865 char ScopInfoPrinterLegacyFunctionPass::ID
= 0;
2868 Pass
*polly::createScopInfoPrinterLegacyFunctionPass(raw_ostream
&OS
) {
2869 return new ScopInfoPrinterLegacyFunctionPass(OS
);
2872 INITIALIZE_PASS_BEGIN(
2873 ScopInfoPrinterLegacyFunctionPass
, "polly-print-function-scops",
2874 "Polly - Print polyhedral description of all Scops of a function", false,
2876 INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass
);
2877 INITIALIZE_PASS_END(
2878 ScopInfoPrinterLegacyFunctionPass
, "polly-print-function-scops",
2879 "Polly - Print polyhedral description of all Scops of a function", false,