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 #define DEBUG_TYPE "polly-scops"
78 STATISTIC(AssumptionsAliasing
, "Number of aliasing assumptions taken.");
79 STATISTIC(AssumptionsInbounds
, "Number of inbounds assumptions taken.");
80 STATISTIC(AssumptionsWrapping
, "Number of wrapping assumptions taken.");
81 STATISTIC(AssumptionsUnsigned
, "Number of unsigned assumptions taken.");
82 STATISTIC(AssumptionsComplexity
, "Number of too complex SCoPs.");
83 STATISTIC(AssumptionsUnprofitable
, "Number of unprofitable SCoPs.");
84 STATISTIC(AssumptionsErrorBlock
, "Number of error block assumptions taken.");
85 STATISTIC(AssumptionsInfiniteLoop
, "Number of bounded loop assumptions taken.");
86 STATISTIC(AssumptionsInvariantLoad
,
87 "Number of invariant loads assumptions taken.");
88 STATISTIC(AssumptionsDelinearization
,
89 "Number of delinearization assumptions taken.");
91 STATISTIC(NumScops
, "Number of feasible SCoPs after ScopInfo");
92 STATISTIC(NumLoopsInScop
, "Number of loops in scops");
93 STATISTIC(NumBoxedLoops
, "Number of boxed loops in SCoPs after ScopInfo");
94 STATISTIC(NumAffineLoops
, "Number of affine loops in SCoPs after ScopInfo");
96 STATISTIC(NumScopsDepthZero
, "Number of scops with maximal loop depth 0");
97 STATISTIC(NumScopsDepthOne
, "Number of scops with maximal loop depth 1");
98 STATISTIC(NumScopsDepthTwo
, "Number of scops with maximal loop depth 2");
99 STATISTIC(NumScopsDepthThree
, "Number of scops with maximal loop depth 3");
100 STATISTIC(NumScopsDepthFour
, "Number of scops with maximal loop depth 4");
101 STATISTIC(NumScopsDepthFive
, "Number of scops with maximal loop depth 5");
102 STATISTIC(NumScopsDepthLarger
,
103 "Number of scops with maximal loop depth 6 and larger");
104 STATISTIC(MaxNumLoopsInScop
, "Maximal number of loops in scops");
106 STATISTIC(NumValueWrites
, "Number of scalar value writes after ScopInfo");
108 NumValueWritesInLoops
,
109 "Number of scalar value writes nested in affine loops after ScopInfo");
110 STATISTIC(NumPHIWrites
, "Number of scalar phi writes after ScopInfo");
111 STATISTIC(NumPHIWritesInLoops
,
112 "Number of scalar phi writes nested in affine loops after ScopInfo");
113 STATISTIC(NumSingletonWrites
, "Number of singleton writes after ScopInfo");
114 STATISTIC(NumSingletonWritesInLoops
,
115 "Number of singleton writes nested in affine loops after ScopInfo");
117 unsigned const polly::MaxDisjunctsInDomain
= 20;
119 // The number of disjunct in the context after which we stop to add more
120 // disjuncts. This parameter is there to avoid exponential growth in the
121 // number of disjunct when adding non-convex sets to the context.
122 static int const MaxDisjunctsInContext
= 4;
124 // Be a bit more generous for the defined behavior context which is used less
126 static int const MaxDisjunktsInDefinedBehaviourContext
= 8;
128 static cl::opt
<bool> PollyRemarksMinimal(
129 "polly-remarks-minimal",
130 cl::desc("Do not emit remarks about assumptions that are known"),
131 cl::Hidden
, cl::cat(PollyCategory
));
134 IslOnErrorAbort("polly-on-isl-error-abort",
135 cl::desc("Abort if an isl error is encountered"),
136 cl::init(true), cl::cat(PollyCategory
));
138 static cl::opt
<bool> PollyPreciseInbounds(
139 "polly-precise-inbounds",
140 cl::desc("Take more precise inbounds assumptions (do not scale well)"),
141 cl::Hidden
, cl::init(false), cl::cat(PollyCategory
));
143 static cl::opt
<bool> PollyIgnoreParamBounds(
144 "polly-ignore-parameter-bounds",
146 "Do not add parameter bounds and do no gist simplify sets accordingly"),
147 cl::Hidden
, cl::init(false), cl::cat(PollyCategory
));
149 static cl::opt
<bool> PollyPreciseFoldAccesses(
150 "polly-precise-fold-accesses",
151 cl::desc("Fold memory accesses to model more possible delinearizations "
152 "(does not scale well)"),
153 cl::Hidden
, cl::init(false), cl::cat(PollyCategory
));
155 bool polly::UseInstructionNames
;
157 static cl::opt
<bool, true> XUseInstructionNames(
158 "polly-use-llvm-names",
159 cl::desc("Use LLVM-IR names when deriving statement names"),
160 cl::location(UseInstructionNames
), cl::Hidden
, cl::cat(PollyCategory
));
162 static cl::opt
<bool> PollyPrintInstructions(
163 "polly-print-instructions", cl::desc("Output instructions per ScopStmt"),
164 cl::Hidden
, cl::Optional
, cl::init(false), cl::cat(PollyCategory
));
166 static cl::list
<std::string
> IslArgs("polly-isl-arg",
167 cl::value_desc("argument"),
168 cl::desc("Option passed to ISL"),
169 cl::cat(PollyCategory
));
171 //===----------------------------------------------------------------------===//
173 static isl::set
addRangeBoundsToSet(isl::set S
, const ConstantRange
&Range
,
174 int dim
, isl::dim type
) {
176 isl::ctx Ctx
= S
.ctx();
178 // The upper and lower bound for a parameter value is derived either from
179 // the data type of the parameter or from the - possibly more restrictive -
181 V
= valFromAPInt(Ctx
.get(), Range
.getSignedMin(), true);
182 S
= S
.lower_bound_val(type
, dim
, V
);
183 V
= valFromAPInt(Ctx
.get(), Range
.getSignedMax(), true);
184 S
= S
.upper_bound_val(type
, dim
, V
);
186 if (Range
.isFullSet())
189 if (S
.n_basic_set().release() > MaxDisjunctsInContext
)
192 // In case of signed wrapping, we can refine the set of valid values by
193 // excluding the part not covered by the wrapping range.
194 if (Range
.isSignWrappedSet()) {
195 V
= valFromAPInt(Ctx
.get(), Range
.getLower(), true);
196 isl::set SLB
= S
.lower_bound_val(type
, dim
, V
);
198 V
= valFromAPInt(Ctx
.get(), Range
.getUpper(), true);
200 isl::set SUB
= S
.upper_bound_val(type
, dim
, V
);
207 static const ScopArrayInfo
*identifyBasePtrOriginSAI(Scop
*S
, Value
*BasePtr
) {
208 LoadInst
*BasePtrLI
= dyn_cast
<LoadInst
>(BasePtr
);
212 if (!S
->contains(BasePtrLI
))
215 ScalarEvolution
&SE
= *S
->getSE();
217 auto *OriginBaseSCEV
=
218 SE
.getPointerBase(SE
.getSCEV(BasePtrLI
->getPointerOperand()));
222 auto *OriginBaseSCEVUnknown
= dyn_cast
<SCEVUnknown
>(OriginBaseSCEV
);
223 if (!OriginBaseSCEVUnknown
)
226 return S
->getScopArrayInfo(OriginBaseSCEVUnknown
->getValue(),
230 ScopArrayInfo::ScopArrayInfo(Value
*BasePtr
, Type
*ElementType
, isl::ctx Ctx
,
231 ArrayRef
<const SCEV
*> Sizes
, MemoryKind Kind
,
232 const DataLayout
&DL
, Scop
*S
,
233 const char *BaseName
)
234 : BasePtr(BasePtr
), ElementType(ElementType
), Kind(Kind
), DL(DL
), S(*S
) {
235 std::string BasePtrName
=
237 : getIslCompatibleName("MemRef", BasePtr
, S
->getNextArrayIdx(),
238 Kind
== MemoryKind::PHI
? "__phi" : "",
239 UseInstructionNames
);
240 Id
= isl::id::alloc(Ctx
, BasePtrName
, this);
244 if (!BasePtr
|| Kind
!= MemoryKind::Array
) {
245 BasePtrOriginSAI
= nullptr;
249 BasePtrOriginSAI
= identifyBasePtrOriginSAI(S
, BasePtr
);
250 if (BasePtrOriginSAI
)
251 const_cast<ScopArrayInfo
*>(BasePtrOriginSAI
)->addDerivedSAI(this);
254 ScopArrayInfo::~ScopArrayInfo() = default;
256 isl::space
ScopArrayInfo::getSpace() const {
257 auto Space
= isl::space(Id
.ctx(), 0, getNumberOfDimensions());
258 Space
= Space
.set_tuple_id(isl::dim::set
, Id
);
262 bool ScopArrayInfo::isReadOnly() {
263 isl::union_set WriteSet
= S
.getWrites().range();
264 isl::space Space
= getSpace();
265 WriteSet
= WriteSet
.extract_set(Space
);
267 return bool(WriteSet
.is_empty());
270 bool ScopArrayInfo::isCompatibleWith(const ScopArrayInfo
*Array
) const {
271 if (Array
->getElementType() != getElementType())
274 if (Array
->getNumberOfDimensions() != getNumberOfDimensions())
277 for (unsigned i
= 0; i
< getNumberOfDimensions(); i
++)
278 if (Array
->getDimensionSize(i
) != getDimensionSize(i
))
284 void ScopArrayInfo::updateElementType(Type
*NewElementType
) {
285 if (NewElementType
== ElementType
)
288 auto OldElementSize
= DL
.getTypeAllocSizeInBits(ElementType
);
289 auto NewElementSize
= DL
.getTypeAllocSizeInBits(NewElementType
);
291 if (NewElementSize
== OldElementSize
|| NewElementSize
== 0)
294 if (NewElementSize
% OldElementSize
== 0 && NewElementSize
< OldElementSize
) {
295 ElementType
= NewElementType
;
297 auto GCD
= std::gcd((uint64_t)NewElementSize
, (uint64_t)OldElementSize
);
298 ElementType
= IntegerType::get(ElementType
->getContext(), GCD
);
302 bool ScopArrayInfo::updateSizes(ArrayRef
<const SCEV
*> NewSizes
,
303 bool CheckConsistency
) {
304 int SharedDims
= std::min(NewSizes
.size(), DimensionSizes
.size());
305 int ExtraDimsNew
= NewSizes
.size() - SharedDims
;
306 int ExtraDimsOld
= DimensionSizes
.size() - SharedDims
;
308 if (CheckConsistency
) {
309 for (int i
= 0; i
< SharedDims
; i
++) {
310 auto *NewSize
= NewSizes
[i
+ ExtraDimsNew
];
311 auto *KnownSize
= DimensionSizes
[i
+ ExtraDimsOld
];
312 if (NewSize
&& KnownSize
&& NewSize
!= KnownSize
)
316 if (DimensionSizes
.size() >= NewSizes
.size())
320 DimensionSizes
.clear();
321 DimensionSizes
.insert(DimensionSizes
.begin(), NewSizes
.begin(),
323 DimensionSizesPw
.clear();
324 for (const SCEV
*Expr
: DimensionSizes
) {
326 DimensionSizesPw
.push_back(isl::pw_aff());
329 isl::pw_aff Size
= S
.getPwAffOnly(Expr
);
330 DimensionSizesPw
.push_back(Size
);
335 std::string
ScopArrayInfo::getName() const { return Id
.get_name(); }
337 int ScopArrayInfo::getElemSizeInBytes() const {
338 return DL
.getTypeAllocSize(ElementType
);
341 isl::id
ScopArrayInfo::getBasePtrId() const { return Id
; }
343 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
344 LLVM_DUMP_METHOD
void ScopArrayInfo::dump() const { print(errs()); }
347 void ScopArrayInfo::print(raw_ostream
&OS
, bool SizeAsPwAff
) const {
348 OS
.indent(8) << *getElementType() << " " << getName();
351 if (getNumberOfDimensions() > 0 && !getDimensionSize(0)) {
355 for (; u
< getNumberOfDimensions(); u
++) {
359 isl::pw_aff Size
= getDimensionSizePw(u
);
360 OS
<< " " << Size
<< " ";
362 OS
<< *getDimensionSize(u
);
370 if (BasePtrOriginSAI
)
371 OS
<< " [BasePtrOrigin: " << BasePtrOriginSAI
->getName() << "]";
373 OS
<< " // Element size " << getElemSizeInBytes() << "\n";
376 const ScopArrayInfo
*
377 ScopArrayInfo::getFromAccessFunction(isl::pw_multi_aff PMA
) {
378 isl::id Id
= PMA
.get_tuple_id(isl::dim::out
);
379 assert(!Id
.is_null() && "Output dimension didn't have an ID");
380 return getFromId(Id
);
383 const ScopArrayInfo
*ScopArrayInfo::getFromId(isl::id Id
) {
384 void *User
= Id
.get_user();
385 const ScopArrayInfo
*SAI
= static_cast<ScopArrayInfo
*>(User
);
389 void MemoryAccess::wrapConstantDimensions() {
390 auto *SAI
= getScopArrayInfo();
391 isl::space ArraySpace
= SAI
->getSpace();
392 isl::ctx Ctx
= ArraySpace
.ctx();
393 unsigned DimsArray
= SAI
->getNumberOfDimensions();
395 isl::multi_aff DivModAff
= isl::multi_aff::identity(
396 ArraySpace
.map_from_domain_and_range(ArraySpace
));
397 isl::local_space LArraySpace
= isl::local_space(ArraySpace
);
399 // Begin with last dimension, to iteratively carry into higher dimensions.
400 for (int i
= DimsArray
- 1; i
> 0; i
--) {
401 auto *DimSize
= SAI
->getDimensionSize(i
);
402 auto *DimSizeCst
= dyn_cast
<SCEVConstant
>(DimSize
);
404 // This transformation is not applicable to dimensions with dynamic size.
408 // This transformation is not applicable to dimensions of size zero.
409 if (DimSize
->isZero())
412 isl::val DimSizeVal
=
413 valFromAPInt(Ctx
.get(), DimSizeCst
->getAPInt(), false);
414 isl::aff Var
= isl::aff::var_on_domain(LArraySpace
, isl::dim::set
, i
);
416 isl::aff::var_on_domain(LArraySpace
, isl::dim::set
, i
- 1);
418 // Compute: index % size
419 // Modulo must apply in the divide of the previous iteration, if any.
420 isl::aff Modulo
= Var
.mod(DimSizeVal
);
421 Modulo
= Modulo
.pullback(DivModAff
);
423 // Compute: floor(index / size)
424 isl::aff Divide
= Var
.div(isl::aff(LArraySpace
, DimSizeVal
));
425 Divide
= Divide
.floor();
426 Divide
= Divide
.add(PrevVar
);
427 Divide
= Divide
.pullback(DivModAff
);
429 // Apply Modulo and Divide.
430 DivModAff
= DivModAff
.set_aff(i
, Modulo
);
431 DivModAff
= DivModAff
.set_aff(i
- 1, Divide
);
434 // Apply all modulo/divides on the accesses.
435 isl::map Relation
= AccessRelation
;
436 Relation
= Relation
.apply_range(isl::map::from_multi_aff(DivModAff
));
437 Relation
= Relation
.detect_equalities();
438 AccessRelation
= Relation
;
441 void MemoryAccess::updateDimensionality() {
442 auto *SAI
= getScopArrayInfo();
443 isl::space ArraySpace
= SAI
->getSpace();
444 isl::space AccessSpace
= AccessRelation
.get_space().range();
445 isl::ctx Ctx
= ArraySpace
.ctx();
447 unsigned DimsArray
= unsignedFromIslSize(ArraySpace
.dim(isl::dim::set
));
448 unsigned DimsAccess
= unsignedFromIslSize(AccessSpace
.dim(isl::dim::set
));
449 assert(DimsArray
>= DimsAccess
);
450 unsigned DimsMissing
= DimsArray
- DimsAccess
;
452 auto *BB
= getStatement()->getEntryBlock();
453 auto &DL
= BB
->getModule()->getDataLayout();
454 unsigned ArrayElemSize
= SAI
->getElemSizeInBytes();
455 unsigned ElemBytes
= DL
.getTypeAllocSize(getElementType());
457 isl::map Map
= isl::map::from_domain_and_range(
458 isl::set::universe(AccessSpace
), isl::set::universe(ArraySpace
));
460 for (auto i
: seq
<unsigned>(0, DimsMissing
))
461 Map
= Map
.fix_si(isl::dim::out
, i
, 0);
463 for (auto i
: seq
<unsigned>(DimsMissing
, DimsArray
))
464 Map
= Map
.equate(isl::dim::in
, i
- DimsMissing
, isl::dim::out
, i
);
466 AccessRelation
= AccessRelation
.apply_range(Map
);
468 // For the non delinearized arrays, divide the access function of the last
469 // subscript by the size of the elements in the array.
471 // A stride one array access in C expressed as A[i] is expressed in
472 // LLVM-IR as something like A[i * elementsize]. This hides the fact that
473 // two subsequent values of 'i' index two values that are stored next to
474 // each other in memory. By this division we make this characteristic
475 // obvious again. If the base pointer was accessed with offsets not divisible
476 // by the accesses element size, we will have chosen a smaller ArrayElemSize
477 // that divides the offsets of all accesses to this base pointer.
478 if (DimsAccess
== 1) {
479 isl::val V
= isl::val(Ctx
, ArrayElemSize
);
480 AccessRelation
= AccessRelation
.floordiv_val(V
);
483 // We currently do this only if we added at least one dimension, which means
484 // some dimension's indices have not been specified, an indicator that some
485 // index values have been added together.
486 // TODO: Investigate general usefulness; Effect on unit tests is to make index
487 // expressions more complicated.
489 wrapConstantDimensions();
492 computeBoundsOnAccessRelation(ArrayElemSize
);
494 // Introduce multi-element accesses in case the type loaded by this memory
495 // access is larger than the canonical element type of the array.
497 // An access ((float *)A)[i] to an array char *A is modeled as
498 // {[i] -> A[o] : 4 i <= o <= 4 i + 3
499 if (ElemBytes
> ArrayElemSize
) {
500 assert(ElemBytes
% ArrayElemSize
== 0 &&
501 "Loaded element size should be multiple of canonical element size");
502 assert(DimsArray
>= 1);
503 isl::map Map
= isl::map::from_domain_and_range(
504 isl::set::universe(ArraySpace
), isl::set::universe(ArraySpace
));
505 for (auto i
: seq
<unsigned>(0, DimsArray
- 1))
506 Map
= Map
.equate(isl::dim::in
, i
, isl::dim::out
, i
);
511 LS
= isl::local_space(Map
.get_space());
512 int Num
= ElemBytes
/ getScopArrayInfo()->getElemSizeInBytes();
514 C
= isl::constraint::alloc_inequality(LS
);
515 C
= C
.set_constant_val(isl::val(Ctx
, Num
- 1));
516 C
= C
.set_coefficient_si(isl::dim::in
, DimsArray
- 1, 1);
517 C
= C
.set_coefficient_si(isl::dim::out
, DimsArray
- 1, -1);
518 Map
= Map
.add_constraint(C
);
520 C
= isl::constraint::alloc_inequality(LS
);
521 C
= C
.set_coefficient_si(isl::dim::in
, DimsArray
- 1, -1);
522 C
= C
.set_coefficient_si(isl::dim::out
, DimsArray
- 1, 1);
523 C
= C
.set_constant_val(isl::val(Ctx
, 0));
524 Map
= Map
.add_constraint(C
);
525 AccessRelation
= AccessRelation
.apply_range(Map
);
530 MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT
) {
532 case MemoryAccess::RT_NONE
:
533 llvm_unreachable("Requested a reduction operator string for a memory "
534 "access which isn't a reduction");
535 case MemoryAccess::RT_ADD
:
537 case MemoryAccess::RT_MUL
:
539 case MemoryAccess::RT_BOR
:
541 case MemoryAccess::RT_BXOR
:
543 case MemoryAccess::RT_BAND
:
546 llvm_unreachable("Unknown reduction type");
549 const ScopArrayInfo
*MemoryAccess::getOriginalScopArrayInfo() const {
550 isl::id ArrayId
= getArrayId();
551 void *User
= ArrayId
.get_user();
552 const ScopArrayInfo
*SAI
= static_cast<ScopArrayInfo
*>(User
);
556 const ScopArrayInfo
*MemoryAccess::getLatestScopArrayInfo() const {
557 isl::id ArrayId
= getLatestArrayId();
558 void *User
= ArrayId
.get_user();
559 const ScopArrayInfo
*SAI
= static_cast<ScopArrayInfo
*>(User
);
563 isl::id
MemoryAccess::getOriginalArrayId() const {
564 return AccessRelation
.get_tuple_id(isl::dim::out
);
567 isl::id
MemoryAccess::getLatestArrayId() const {
568 if (!hasNewAccessRelation())
569 return getOriginalArrayId();
570 return NewAccessRelation
.get_tuple_id(isl::dim::out
);
573 isl::map
MemoryAccess::getAddressFunction() const {
574 return getAccessRelation().lexmin();
578 MemoryAccess::applyScheduleToAccessRelation(isl::union_map USchedule
) const {
579 isl::map Schedule
, ScheduledAccRel
;
580 isl::union_set UDomain
;
582 UDomain
= getStatement()->getDomain();
583 USchedule
= USchedule
.intersect_domain(UDomain
);
584 Schedule
= isl::map::from_union_map(USchedule
);
585 ScheduledAccRel
= getAddressFunction().apply_domain(Schedule
);
586 return isl::pw_multi_aff::from_map(ScheduledAccRel
);
589 isl::map
MemoryAccess::getOriginalAccessRelation() const {
590 return AccessRelation
;
593 std::string
MemoryAccess::getOriginalAccessRelationStr() const {
594 return stringFromIslObj(AccessRelation
);
597 isl::space
MemoryAccess::getOriginalAccessRelationSpace() const {
598 return AccessRelation
.get_space();
601 isl::map
MemoryAccess::getNewAccessRelation() const {
602 return NewAccessRelation
;
605 std::string
MemoryAccess::getNewAccessRelationStr() const {
606 return stringFromIslObj(NewAccessRelation
);
609 std::string
MemoryAccess::getAccessRelationStr() const {
610 return stringFromIslObj(getAccessRelation());
613 isl::basic_map
MemoryAccess::createBasicAccessMap(ScopStmt
*Statement
) {
614 isl::space Space
= isl::space(Statement
->getIslCtx(), 0, 1);
615 Space
= Space
.align_params(Statement
->getDomainSpace());
617 return isl::basic_map::from_domain_and_range(
618 isl::basic_set::universe(Statement
->getDomainSpace()),
619 isl::basic_set::universe(Space
));
622 // Formalize no out-of-bound access assumption
624 // When delinearizing array accesses we optimistically assume that the
625 // delinearized accesses do not access out of bound locations (the subscript
626 // expression of each array evaluates for each statement instance that is
627 // executed to a value that is larger than zero and strictly smaller than the
628 // size of the corresponding dimension). The only exception is the outermost
629 // dimension for which we do not need to assume any upper bound. At this point
630 // we formalize this assumption to ensure that at code generation time the
631 // relevant run-time checks can be generated.
633 // To find the set of constraints necessary to avoid out of bound accesses, we
634 // first build the set of data locations that are not within array bounds. We
635 // then apply the reverse access relation to obtain the set of iterations that
636 // may contain invalid accesses and reduce this set of iterations to the ones
637 // that are actually executed by intersecting them with the domain of the
638 // statement. If we now project out all loop dimensions, we obtain a set of
639 // parameters that may cause statement instances to be executed that may
640 // possibly yield out of bound memory accesses. The complement of these
641 // constraints is the set of constraints that needs to be assumed to ensure such
642 // statement instances are never executed.
643 isl::set
MemoryAccess::assumeNoOutOfBound() {
644 auto *SAI
= getScopArrayInfo();
645 isl::space Space
= getOriginalAccessRelationSpace().range();
646 isl::set Outside
= isl::set::empty(Space
);
647 for (int i
= 1, Size
= Space
.dim(isl::dim::set
).release(); i
< Size
; ++i
) {
648 isl::local_space
LS(Space
);
649 isl::pw_aff Var
= isl::pw_aff::var_on_domain(LS
, isl::dim::set
, i
);
650 isl::pw_aff Zero
= isl::pw_aff(LS
);
652 isl::set DimOutside
= Var
.lt_set(Zero
);
653 isl::pw_aff SizeE
= SAI
->getDimensionSizePw(i
);
654 SizeE
= SizeE
.add_dims(isl::dim::in
, Space
.dim(isl::dim::set
).release());
655 SizeE
= SizeE
.set_tuple_id(isl::dim::in
, Space
.get_tuple_id(isl::dim::set
));
656 DimOutside
= DimOutside
.unite(SizeE
.le_set(Var
));
658 Outside
= Outside
.unite(DimOutside
);
661 Outside
= Outside
.apply(getAccessRelation().reverse());
662 Outside
= Outside
.intersect(Statement
->getDomain());
663 Outside
= Outside
.params();
665 // Remove divs to avoid the construction of overly complicated assumptions.
666 // Doing so increases the set of parameter combinations that are assumed to
667 // not appear. This is always save, but may make the resulting run-time check
668 // bail out more often than strictly necessary.
669 Outside
= Outside
.remove_divs();
670 Outside
= Outside
.complement();
672 if (!PollyPreciseInbounds
)
673 Outside
= Outside
.gist_params(Statement
->getDomain().params());
677 void MemoryAccess::buildMemIntrinsicAccessRelation() {
678 assert(isMemoryIntrinsic());
679 assert(Subscripts
.size() == 2 && Sizes
.size() == 1);
681 isl::pw_aff SubscriptPWA
= getPwAff(Subscripts
[0]);
682 isl::map SubscriptMap
= isl::map::from_pw_aff(SubscriptPWA
);
685 if (Subscripts
[1] == nullptr) {
686 LengthMap
= isl::map::universe(SubscriptMap
.get_space());
688 isl::pw_aff LengthPWA
= getPwAff(Subscripts
[1]);
689 LengthMap
= isl::map::from_pw_aff(LengthPWA
);
690 isl::space RangeSpace
= LengthMap
.get_space().range();
691 LengthMap
= LengthMap
.apply_range(isl::map::lex_gt(RangeSpace
));
693 LengthMap
= LengthMap
.lower_bound_si(isl::dim::out
, 0, 0);
694 LengthMap
= LengthMap
.align_params(SubscriptMap
.get_space());
695 SubscriptMap
= SubscriptMap
.align_params(LengthMap
.get_space());
696 LengthMap
= LengthMap
.sum(SubscriptMap
);
698 LengthMap
.set_tuple_id(isl::dim::in
, getStatement()->getDomainId());
701 void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize
) {
702 ScalarEvolution
*SE
= Statement
->getParent()->getSE();
704 auto MAI
= MemAccInst(getAccessInstruction());
705 if (isa
<MemIntrinsic
>(MAI
))
708 Value
*Ptr
= MAI
.getPointerOperand();
709 if (!Ptr
|| !SE
->isSCEVable(Ptr
->getType()))
712 auto *PtrSCEV
= SE
->getSCEV(Ptr
);
713 if (isa
<SCEVCouldNotCompute
>(PtrSCEV
))
716 auto *BasePtrSCEV
= SE
->getPointerBase(PtrSCEV
);
717 if (BasePtrSCEV
&& !isa
<SCEVCouldNotCompute
>(BasePtrSCEV
))
718 PtrSCEV
= SE
->getMinusSCEV(PtrSCEV
, BasePtrSCEV
);
720 const ConstantRange
&Range
= SE
->getSignedRange(PtrSCEV
);
721 if (Range
.isFullSet())
724 if (Range
.isUpperWrapped() || Range
.isSignWrappedSet())
727 bool isWrapping
= Range
.isSignWrappedSet();
729 unsigned BW
= Range
.getBitWidth();
730 const auto One
= APInt(BW
, 1);
731 const auto LB
= isWrapping
? Range
.getLower() : Range
.getSignedMin();
732 const auto UB
= isWrapping
? (Range
.getUpper() - One
) : Range
.getSignedMax();
734 auto Min
= LB
.sdiv(APInt(BW
, ElementSize
));
735 auto Max
= UB
.sdiv(APInt(BW
, ElementSize
)) + One
;
737 assert(Min
.sle(Max
) && "Minimum expected to be less or equal than max");
739 isl::map Relation
= AccessRelation
;
740 isl::set AccessRange
= Relation
.range();
741 AccessRange
= addRangeBoundsToSet(AccessRange
, ConstantRange(Min
, Max
), 0,
743 AccessRelation
= Relation
.intersect_range(AccessRange
);
746 void MemoryAccess::foldAccessRelation() {
747 if (Sizes
.size() < 2 || isa
<SCEVConstant
>(Sizes
[1]))
750 int Size
= Subscripts
.size();
752 isl::map NewAccessRelation
= AccessRelation
;
754 for (int i
= Size
- 2; i
>= 0; --i
) {
756 isl::map MapOne
, MapTwo
;
757 isl::pw_aff DimSize
= getPwAff(Sizes
[i
+ 1]);
759 isl::space SpaceSize
= DimSize
.get_space();
760 isl::id ParamId
= SpaceSize
.get_dim_id(isl::dim::param
, 0);
762 Space
= AccessRelation
.get_space();
763 Space
= Space
.range().map_from_set();
764 Space
= Space
.align_params(SpaceSize
);
766 int ParamLocation
= Space
.find_dim_by_id(isl::dim::param
, ParamId
);
768 MapOne
= isl::map::universe(Space
);
769 for (int j
= 0; j
< Size
; ++j
)
770 MapOne
= MapOne
.equate(isl::dim::in
, j
, isl::dim::out
, j
);
771 MapOne
= MapOne
.lower_bound_si(isl::dim::in
, i
+ 1, 0);
773 MapTwo
= isl::map::universe(Space
);
774 for (int j
= 0; j
< Size
; ++j
)
775 if (j
< i
|| j
> i
+ 1)
776 MapTwo
= MapTwo
.equate(isl::dim::in
, j
, isl::dim::out
, j
);
778 isl::local_space
LS(Space
);
780 C
= isl::constraint::alloc_equality(LS
);
781 C
= C
.set_constant_si(-1);
782 C
= C
.set_coefficient_si(isl::dim::in
, i
, 1);
783 C
= C
.set_coefficient_si(isl::dim::out
, i
, -1);
784 MapTwo
= MapTwo
.add_constraint(C
);
785 C
= isl::constraint::alloc_equality(LS
);
786 C
= C
.set_coefficient_si(isl::dim::in
, i
+ 1, 1);
787 C
= C
.set_coefficient_si(isl::dim::out
, i
+ 1, -1);
788 C
= C
.set_coefficient_si(isl::dim::param
, ParamLocation
, 1);
789 MapTwo
= MapTwo
.add_constraint(C
);
790 MapTwo
= MapTwo
.upper_bound_si(isl::dim::in
, i
+ 1, -1);
792 MapOne
= MapOne
.unite(MapTwo
);
793 NewAccessRelation
= NewAccessRelation
.apply_range(MapOne
);
796 isl::id BaseAddrId
= getScopArrayInfo()->getBasePtrId();
797 isl::space Space
= Statement
->getDomainSpace();
798 NewAccessRelation
= NewAccessRelation
.set_tuple_id(
799 isl::dim::in
, Space
.get_tuple_id(isl::dim::set
));
800 NewAccessRelation
= NewAccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
801 NewAccessRelation
= NewAccessRelation
.gist_domain(Statement
->getDomain());
803 // Access dimension folding might in certain cases increase the number of
804 // disjuncts in the memory access, which can possibly complicate the generated
805 // run-time checks and can lead to costly compilation.
806 if (!PollyPreciseFoldAccesses
&& NewAccessRelation
.n_basic_map().release() >
807 AccessRelation
.n_basic_map().release()) {
809 AccessRelation
= NewAccessRelation
;
813 void MemoryAccess::buildAccessRelation(const ScopArrayInfo
*SAI
) {
814 assert(AccessRelation
.is_null() && "AccessRelation already built");
816 // Initialize the invalid domain which describes all iterations for which the
817 // access relation is not modeled correctly.
818 isl::set StmtInvalidDomain
= getStatement()->getInvalidDomain();
819 InvalidDomain
= isl::set::empty(StmtInvalidDomain
.get_space());
821 isl::ctx Ctx
= Id
.ctx();
822 isl::id BaseAddrId
= SAI
->getBasePtrId();
824 if (getAccessInstruction() && isa
<MemIntrinsic
>(getAccessInstruction())) {
825 buildMemIntrinsicAccessRelation();
826 AccessRelation
= AccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
831 // We overapproximate non-affine accesses with a possible access to the
832 // whole array. For read accesses it does not make a difference, if an
833 // access must or may happen. However, for write accesses it is important to
834 // differentiate between writes that must happen and writes that may happen.
835 if (AccessRelation
.is_null())
836 AccessRelation
= createBasicAccessMap(Statement
);
838 AccessRelation
= AccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
842 isl::space Space
= isl::space(Ctx
, 0, Statement
->getNumIterators(), 0);
843 AccessRelation
= isl::map::universe(Space
);
845 for (int i
= 0, Size
= Subscripts
.size(); i
< Size
; ++i
) {
846 isl::pw_aff Affine
= getPwAff(Subscripts
[i
]);
847 isl::map SubscriptMap
= isl::map::from_pw_aff(Affine
);
848 AccessRelation
= AccessRelation
.flat_range_product(SubscriptMap
);
851 Space
= Statement
->getDomainSpace();
852 AccessRelation
= AccessRelation
.set_tuple_id(
853 isl::dim::in
, Space
.get_tuple_id(isl::dim::set
));
854 AccessRelation
= AccessRelation
.set_tuple_id(isl::dim::out
, BaseAddrId
);
856 AccessRelation
= AccessRelation
.gist_domain(Statement
->getDomain());
859 MemoryAccess::MemoryAccess(ScopStmt
*Stmt
, Instruction
*AccessInst
,
860 AccessType AccType
, Value
*BaseAddress
,
861 Type
*ElementType
, bool Affine
,
862 ArrayRef
<const SCEV
*> Subscripts
,
863 ArrayRef
<const SCEV
*> Sizes
, Value
*AccessValue
,
865 : Kind(Kind
), AccType(AccType
), Statement(Stmt
), InvalidDomain(),
866 BaseAddr(BaseAddress
), ElementType(ElementType
),
867 Sizes(Sizes
.begin(), Sizes
.end()), AccessInstruction(AccessInst
),
868 AccessValue(AccessValue
), IsAffine(Affine
),
869 Subscripts(Subscripts
.begin(), Subscripts
.end()), AccessRelation(),
870 NewAccessRelation() {
871 static const std::string TypeStrings
[] = {"", "_Read", "_Write", "_MayWrite"};
872 const std::string Access
= TypeStrings
[AccType
] + utostr(Stmt
->size());
874 std::string IdName
= Stmt
->getBaseName() + Access
;
875 Id
= isl::id::alloc(Stmt
->getParent()->getIslCtx(), IdName
, this);
878 MemoryAccess::MemoryAccess(ScopStmt
*Stmt
, AccessType AccType
, isl::map AccRel
)
879 : Kind(MemoryKind::Array
), AccType(AccType
), Statement(Stmt
),
880 InvalidDomain(), AccessRelation(), NewAccessRelation(AccRel
) {
881 isl::id ArrayInfoId
= NewAccessRelation
.get_tuple_id(isl::dim::out
);
882 auto *SAI
= ScopArrayInfo::getFromId(ArrayInfoId
);
883 Sizes
.push_back(nullptr);
884 for (unsigned i
= 1; i
< SAI
->getNumberOfDimensions(); i
++)
885 Sizes
.push_back(SAI
->getDimensionSize(i
));
886 ElementType
= SAI
->getElementType();
887 BaseAddr
= SAI
->getBasePtr();
888 static const std::string TypeStrings
[] = {"", "_Read", "_Write", "_MayWrite"};
889 const std::string Access
= TypeStrings
[AccType
] + utostr(Stmt
->size());
891 std::string IdName
= Stmt
->getBaseName() + Access
;
892 Id
= isl::id::alloc(Stmt
->getParent()->getIslCtx(), IdName
, this);
895 MemoryAccess::~MemoryAccess() = default;
897 void MemoryAccess::realignParams() {
898 isl::set Ctx
= Statement
->getParent()->getContext();
899 InvalidDomain
= InvalidDomain
.gist_params(Ctx
);
900 AccessRelation
= AccessRelation
.gist_params(Ctx
);
902 // Predictable parameter order is required for JSON imports. Ensure alignment
903 // by explicitly calling align_params.
904 isl::space CtxSpace
= Ctx
.get_space();
905 InvalidDomain
= InvalidDomain
.align_params(CtxSpace
);
906 AccessRelation
= AccessRelation
.align_params(CtxSpace
);
909 const std::string
MemoryAccess::getReductionOperatorStr() const {
910 return MemoryAccess::getReductionOperatorStr(getReductionType());
913 isl::id
MemoryAccess::getId() const { return Id
; }
915 raw_ostream
&polly::operator<<(raw_ostream
&OS
,
916 MemoryAccess::ReductionType RT
) {
917 if (RT
== MemoryAccess::RT_NONE
)
920 OS
<< MemoryAccess::getReductionOperatorStr(RT
);
924 void MemoryAccess::print(raw_ostream
&OS
) const {
927 OS
.indent(12) << "ReadAccess :=\t";
930 OS
.indent(12) << "MustWriteAccess :=\t";
933 OS
.indent(12) << "MayWriteAccess :=\t";
937 OS
<< "[Reduction Type: " << getReductionType() << "] ";
939 OS
<< "[Scalar: " << isScalarKind() << "]\n";
940 OS
.indent(16) << getOriginalAccessRelationStr() << ";\n";
941 if (hasNewAccessRelation())
942 OS
.indent(11) << "new: " << getNewAccessRelationStr() << ";\n";
945 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
946 LLVM_DUMP_METHOD
void MemoryAccess::dump() const { print(errs()); }
949 isl::pw_aff
MemoryAccess::getPwAff(const SCEV
*E
) {
950 auto *Stmt
= getStatement();
951 PWACtx PWAC
= Stmt
->getParent()->getPwAff(E
, Stmt
->getEntryBlock());
952 isl::set StmtDom
= getStatement()->getDomain();
953 StmtDom
= StmtDom
.reset_tuple_id();
954 isl::set NewInvalidDom
= StmtDom
.intersect(PWAC
.second
);
955 InvalidDomain
= InvalidDomain
.unite(NewInvalidDom
);
959 // Create a map in the size of the provided set domain, that maps from the
960 // one element of the provided set domain to another element of the provided
962 // The mapping is limited to all points that are equal in all but the last
963 // dimension and for which the last dimension of the input is strict smaller
964 // than the last dimension of the output.
966 // getEqualAndLarger(set[i0, i1, ..., iX]):
968 // set[i0, i1, ..., iX] -> set[o0, o1, ..., oX]
969 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX
971 static isl::map
getEqualAndLarger(isl::space SetDomain
) {
972 isl::space Space
= SetDomain
.map_from_set();
973 isl::map Map
= isl::map::universe(Space
);
974 unsigned lastDimension
= Map
.domain_tuple_dim().release() - 1;
976 // Set all but the last dimension to be equal for the input and output
978 // input[i0, i1, ..., iX] -> output[o0, o1, ..., oX]
979 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1)
980 for (unsigned i
= 0; i
< lastDimension
; ++i
)
981 Map
= Map
.equate(isl::dim::in
, i
, isl::dim::out
, i
);
983 // Set the last dimension of the input to be strict smaller than the
984 // last dimension of the output.
986 // input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX
987 Map
= Map
.order_lt(isl::dim::in
, lastDimension
, isl::dim::out
, lastDimension
);
991 isl::set
MemoryAccess::getStride(isl::map Schedule
) const {
992 isl::map AccessRelation
= getAccessRelation();
993 isl::space Space
= Schedule
.get_space().range();
994 isl::map NextScatt
= getEqualAndLarger(Space
);
996 Schedule
= Schedule
.reverse();
997 NextScatt
= NextScatt
.lexmin();
999 NextScatt
= NextScatt
.apply_range(Schedule
);
1000 NextScatt
= NextScatt
.apply_range(AccessRelation
);
1001 NextScatt
= NextScatt
.apply_domain(Schedule
);
1002 NextScatt
= NextScatt
.apply_domain(AccessRelation
);
1004 isl::set Deltas
= NextScatt
.deltas();
1008 bool MemoryAccess::isStrideX(isl::map Schedule
, int StrideWidth
) const {
1009 isl::set Stride
, StrideX
;
1012 Stride
= getStride(Schedule
);
1013 StrideX
= isl::set::universe(Stride
.get_space());
1014 int Size
= unsignedFromIslSize(StrideX
.tuple_dim());
1015 for (auto i
: seq
<int>(0, Size
- 1))
1016 StrideX
= StrideX
.fix_si(isl::dim::set
, i
, 0);
1017 StrideX
= StrideX
.fix_si(isl::dim::set
, Size
- 1, StrideWidth
);
1018 IsStrideX
= Stride
.is_subset(StrideX
);
1023 bool MemoryAccess::isStrideZero(isl::map Schedule
) const {
1024 return isStrideX(Schedule
, 0);
1027 bool MemoryAccess::isStrideOne(isl::map Schedule
) const {
1028 return isStrideX(Schedule
, 1);
1031 void MemoryAccess::setAccessRelation(isl::map NewAccess
) {
1032 AccessRelation
= NewAccess
;
1035 void MemoryAccess::setNewAccessRelation(isl::map NewAccess
) {
1036 assert(!NewAccess
.is_null());
1039 // Check domain space compatibility.
1040 isl::space NewSpace
= NewAccess
.get_space();
1041 isl::space NewDomainSpace
= NewSpace
.domain();
1042 isl::space OriginalDomainSpace
= getStatement()->getDomainSpace();
1043 assert(OriginalDomainSpace
.has_equal_tuples(NewDomainSpace
));
1045 // Reads must be executed unconditionally. Writes might be executed in a
1048 // Check whether there is an access for every statement instance.
1049 isl::set StmtDomain
= getStatement()->getDomain();
1050 isl::set DefinedContext
=
1051 getStatement()->getParent()->getBestKnownDefinedBehaviorContext();
1052 StmtDomain
= StmtDomain
.intersect_params(DefinedContext
);
1053 isl::set NewDomain
= NewAccess
.domain();
1054 assert(!StmtDomain
.is_subset(NewDomain
).is_false() &&
1055 "Partial READ accesses not supported");
1058 isl::space NewAccessSpace
= NewAccess
.get_space();
1059 assert(NewAccessSpace
.has_tuple_id(isl::dim::set
) &&
1060 "Must specify the array that is accessed");
1061 isl::id NewArrayId
= NewAccessSpace
.get_tuple_id(isl::dim::set
);
1062 auto *SAI
= static_cast<ScopArrayInfo
*>(NewArrayId
.get_user());
1063 assert(SAI
&& "Must set a ScopArrayInfo");
1065 if (SAI
->isArrayKind() && SAI
->getBasePtrOriginSAI()) {
1066 InvariantEquivClassTy
*EqClass
=
1067 getStatement()->getParent()->lookupInvariantEquivClass(
1070 "Access functions to indirect arrays must have an invariant and "
1071 "hoisted base pointer");
1074 // Check whether access dimensions correspond to number of dimensions of the
1076 unsigned Dims
= SAI
->getNumberOfDimensions();
1077 unsigned SpaceSize
= unsignedFromIslSize(NewAccessSpace
.dim(isl::dim::set
));
1078 assert(SpaceSize
== Dims
&& "Access dims must match array dims");
1081 NewAccess
= NewAccess
.gist_params(getStatement()->getParent()->getContext());
1082 NewAccess
= NewAccess
.gist_domain(getStatement()->getDomain());
1083 NewAccessRelation
= NewAccess
;
1086 bool MemoryAccess::isLatestPartialAccess() const {
1087 isl::set StmtDom
= getStatement()->getDomain();
1088 isl::set AccDom
= getLatestAccessRelation().domain();
1090 return !StmtDom
.is_subset(AccDom
);
1093 //===----------------------------------------------------------------------===//
1095 isl::map
ScopStmt::getSchedule() const {
1096 isl::set Domain
= getDomain();
1097 if (Domain
.is_empty())
1098 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
1099 auto Schedule
= getParent()->getSchedule();
1100 if (Schedule
.is_null())
1102 Schedule
= Schedule
.intersect_domain(isl::union_set(Domain
));
1103 if (Schedule
.is_empty())
1104 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace())));
1105 isl::map M
= M
.from_union_map(Schedule
);
1107 M
= M
.gist_domain(Domain
);
1112 void ScopStmt::restrictDomain(isl::set NewDomain
) {
1113 assert(NewDomain
.is_subset(Domain
) &&
1114 "New domain is not a subset of old domain!");
1118 void ScopStmt::addAccess(MemoryAccess
*Access
, bool Prepend
) {
1119 Instruction
*AccessInst
= Access
->getAccessInstruction();
1121 if (Access
->isArrayKind()) {
1122 MemoryAccessList
&MAL
= InstructionToAccess
[AccessInst
];
1123 MAL
.emplace_front(Access
);
1124 } else if (Access
->isValueKind() && Access
->isWrite()) {
1125 Instruction
*AccessVal
= cast
<Instruction
>(Access
->getAccessValue());
1126 assert(!ValueWrites
.lookup(AccessVal
));
1128 ValueWrites
[AccessVal
] = Access
;
1129 } else if (Access
->isValueKind() && Access
->isRead()) {
1130 Value
*AccessVal
= Access
->getAccessValue();
1131 assert(!ValueReads
.lookup(AccessVal
));
1133 ValueReads
[AccessVal
] = Access
;
1134 } else if (Access
->isAnyPHIKind() && Access
->isWrite()) {
1135 PHINode
*PHI
= cast
<PHINode
>(Access
->getAccessValue());
1136 assert(!PHIWrites
.lookup(PHI
));
1138 PHIWrites
[PHI
] = Access
;
1139 } else if (Access
->isAnyPHIKind() && Access
->isRead()) {
1140 PHINode
*PHI
= cast
<PHINode
>(Access
->getAccessValue());
1141 assert(!PHIReads
.lookup(PHI
));
1143 PHIReads
[PHI
] = Access
;
1147 MemAccs
.insert(MemAccs
.begin(), Access
);
1150 MemAccs
.push_back(Access
);
1153 void ScopStmt::realignParams() {
1154 for (MemoryAccess
*MA
: *this)
1155 MA
->realignParams();
1157 simplify(InvalidDomain
);
1160 isl::set Ctx
= Parent
.getContext();
1161 InvalidDomain
= InvalidDomain
.gist_params(Ctx
);
1162 Domain
= Domain
.gist_params(Ctx
);
1164 // Predictable parameter order is required for JSON imports. Ensure alignment
1165 // by explicitly calling align_params.
1166 isl::space CtxSpace
= Ctx
.get_space();
1167 InvalidDomain
= InvalidDomain
.align_params(CtxSpace
);
1168 Domain
= Domain
.align_params(CtxSpace
);
1171 ScopStmt::ScopStmt(Scop
&parent
, Region
&R
, StringRef Name
,
1172 Loop
*SurroundingLoop
,
1173 std::vector
<Instruction
*> EntryBlockInstructions
)
1174 : Parent(parent
), InvalidDomain(), Domain(), R(&R
), Build(), BaseName(Name
),
1175 SurroundingLoop(SurroundingLoop
), Instructions(EntryBlockInstructions
) {}
1177 ScopStmt::ScopStmt(Scop
&parent
, BasicBlock
&bb
, StringRef Name
,
1178 Loop
*SurroundingLoop
,
1179 std::vector
<Instruction
*> Instructions
)
1180 : Parent(parent
), InvalidDomain(), Domain(), BB(&bb
), Build(),
1181 BaseName(Name
), SurroundingLoop(SurroundingLoop
),
1182 Instructions(Instructions
) {}
1184 ScopStmt::ScopStmt(Scop
&parent
, isl::map SourceRel
, isl::map TargetRel
,
1186 : Parent(parent
), InvalidDomain(), Domain(NewDomain
), Build() {
1187 BaseName
= getIslCompatibleName("CopyStmt_", "",
1188 std::to_string(parent
.getCopyStmtsNum()));
1189 isl::id Id
= isl::id::alloc(getIslCtx(), getBaseName(), this);
1190 Domain
= Domain
.set_tuple_id(Id
);
1191 TargetRel
= TargetRel
.set_tuple_id(isl::dim::in
, Id
);
1193 new MemoryAccess(this, MemoryAccess::AccessType::MUST_WRITE
, TargetRel
);
1194 parent
.addAccessFunction(Access
);
1196 SourceRel
= SourceRel
.set_tuple_id(isl::dim::in
, Id
);
1197 Access
= new MemoryAccess(this, MemoryAccess::AccessType::READ
, SourceRel
);
1198 parent
.addAccessFunction(Access
);
1202 ScopStmt::~ScopStmt() = default;
1204 std::string
ScopStmt::getDomainStr() const { return stringFromIslObj(Domain
); }
1206 std::string
ScopStmt::getScheduleStr() const {
1207 return stringFromIslObj(getSchedule());
1210 void ScopStmt::setInvalidDomain(isl::set ID
) { InvalidDomain
= ID
; }
1212 BasicBlock
*ScopStmt::getEntryBlock() const {
1214 return getBasicBlock();
1215 return getRegion()->getEntry();
1218 unsigned ScopStmt::getNumIterators() const { return NestLoops
.size(); }
1220 const char *ScopStmt::getBaseName() const { return BaseName
.c_str(); }
1222 Loop
*ScopStmt::getLoopForDimension(unsigned Dimension
) const {
1223 return NestLoops
[Dimension
];
1226 isl::ctx
ScopStmt::getIslCtx() const { return Parent
.getIslCtx(); }
1228 isl::set
ScopStmt::getDomain() const { return Domain
; }
1230 isl::space
ScopStmt::getDomainSpace() const { return Domain
.get_space(); }
1232 isl::id
ScopStmt::getDomainId() const { return Domain
.get_tuple_id(); }
1234 void ScopStmt::printInstructions(raw_ostream
&OS
) const {
1235 OS
<< "Instructions {\n";
1237 for (Instruction
*Inst
: Instructions
)
1238 OS
.indent(16) << *Inst
<< "\n";
1240 OS
.indent(12) << "}\n";
1243 void ScopStmt::print(raw_ostream
&OS
, bool PrintInstructions
) const {
1244 OS
<< "\t" << getBaseName() << "\n";
1245 OS
.indent(12) << "Domain :=\n";
1247 if (!Domain
.is_null()) {
1248 OS
.indent(16) << getDomainStr() << ";\n";
1250 OS
.indent(16) << "n/a\n";
1252 OS
.indent(12) << "Schedule :=\n";
1254 if (!Domain
.is_null()) {
1255 OS
.indent(16) << getScheduleStr() << ";\n";
1257 OS
.indent(16) << "n/a\n";
1259 for (MemoryAccess
*Access
: MemAccs
)
1262 if (PrintInstructions
)
1263 printInstructions(OS
.indent(12));
1266 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1267 LLVM_DUMP_METHOD
void ScopStmt::dump() const { print(dbgs(), true); }
1270 void ScopStmt::removeAccessData(MemoryAccess
*MA
) {
1271 if (MA
->isRead() && MA
->isOriginalValueKind()) {
1272 bool Found
= ValueReads
.erase(MA
->getAccessValue());
1274 assert(Found
&& "Expected access data not found");
1276 if (MA
->isWrite() && MA
->isOriginalValueKind()) {
1277 bool Found
= ValueWrites
.erase(cast
<Instruction
>(MA
->getAccessValue()));
1279 assert(Found
&& "Expected access data not found");
1281 if (MA
->isWrite() && MA
->isOriginalAnyPHIKind()) {
1282 bool Found
= PHIWrites
.erase(cast
<PHINode
>(MA
->getAccessInstruction()));
1284 assert(Found
&& "Expected access data not found");
1286 if (MA
->isRead() && MA
->isOriginalAnyPHIKind()) {
1287 bool Found
= PHIReads
.erase(cast
<PHINode
>(MA
->getAccessInstruction()));
1289 assert(Found
&& "Expected access data not found");
1293 void ScopStmt::removeMemoryAccess(MemoryAccess
*MA
) {
1294 // Remove the memory accesses from this statement together with all scalar
1295 // accesses that were caused by it. MemoryKind::Value READs have no access
1296 // instruction, hence would not be removed by this function. However, it is
1297 // only used for invariant LoadInst accesses, its arguments are always affine,
1298 // hence synthesizable, and therefore there are no MemoryKind::Value READ
1299 // accesses to be removed.
1300 auto Predicate
= [&](MemoryAccess
*Acc
) {
1301 return Acc
->getAccessInstruction() == MA
->getAccessInstruction();
1303 for (auto *MA
: MemAccs
) {
1304 if (Predicate(MA
)) {
1305 removeAccessData(MA
);
1306 Parent
.removeAccessData(MA
);
1309 llvm::erase_if(MemAccs
, Predicate
);
1310 InstructionToAccess
.erase(MA
->getAccessInstruction());
1313 void ScopStmt::removeSingleMemoryAccess(MemoryAccess
*MA
, bool AfterHoisting
) {
1314 if (AfterHoisting
) {
1315 auto MAIt
= std::find(MemAccs
.begin(), MemAccs
.end(), MA
);
1316 assert(MAIt
!= MemAccs
.end());
1317 MemAccs
.erase(MAIt
);
1319 removeAccessData(MA
);
1320 Parent
.removeAccessData(MA
);
1323 auto It
= InstructionToAccess
.find(MA
->getAccessInstruction());
1324 if (It
!= InstructionToAccess
.end()) {
1325 It
->second
.remove(MA
);
1326 if (It
->second
.empty())
1327 InstructionToAccess
.erase(MA
->getAccessInstruction());
1331 MemoryAccess
*ScopStmt::ensureValueRead(Value
*V
) {
1332 MemoryAccess
*Access
= lookupInputAccessOf(V
);
1336 ScopArrayInfo
*SAI
=
1337 Parent
.getOrCreateScopArrayInfo(V
, V
->getType(), {}, MemoryKind::Value
);
1338 Access
= new MemoryAccess(this, nullptr, MemoryAccess::READ
, V
, V
->getType(),
1339 true, {}, {}, V
, MemoryKind::Value
);
1340 Parent
.addAccessFunction(Access
);
1341 Access
->buildAccessRelation(SAI
);
1343 Parent
.addAccessData(Access
);
1347 raw_ostream
&polly::operator<<(raw_ostream
&OS
, const ScopStmt
&S
) {
1348 S
.print(OS
, PollyPrintInstructions
);
1352 //===----------------------------------------------------------------------===//
1353 /// Scop class implement
1355 void Scop::setContext(isl::set NewContext
) {
1356 Context
= NewContext
.align_params(Context
.get_space());
1361 /// Remap parameter values but keep AddRecs valid wrt. invariant loads.
1362 class SCEVSensitiveParameterRewriter final
1363 : public SCEVRewriteVisitor
<SCEVSensitiveParameterRewriter
> {
1364 const ValueToValueMap
&VMap
;
1367 SCEVSensitiveParameterRewriter(const ValueToValueMap
&VMap
,
1368 ScalarEvolution
&SE
)
1369 : SCEVRewriteVisitor(SE
), VMap(VMap
) {}
1371 static const SCEV
*rewrite(const SCEV
*E
, ScalarEvolution
&SE
,
1372 const ValueToValueMap
&VMap
) {
1373 SCEVSensitiveParameterRewriter
SSPR(VMap
, SE
);
1374 return SSPR
.visit(E
);
1377 const SCEV
*visitAddRecExpr(const SCEVAddRecExpr
*E
) {
1378 auto *Start
= visit(E
->getStart());
1379 auto *AddRec
= SE
.getAddRecExpr(SE
.getConstant(E
->getType(), 0),
1380 visit(E
->getStepRecurrence(SE
)),
1381 E
->getLoop(), SCEV::FlagAnyWrap
);
1382 return SE
.getAddExpr(Start
, AddRec
);
1385 const SCEV
*visitUnknown(const SCEVUnknown
*E
) {
1386 if (auto *NewValue
= VMap
.lookup(E
->getValue()))
1387 return SE
.getUnknown(NewValue
);
1392 /// Check whether we should remap a SCEV expression.
1393 class SCEVFindInsideScop
: public SCEVTraversal
<SCEVFindInsideScop
> {
1394 const ValueToValueMap
&VMap
;
1395 bool FoundInside
= false;
1399 SCEVFindInsideScop(const ValueToValueMap
&VMap
, ScalarEvolution
&SE
,
1401 : SCEVTraversal(*this), VMap(VMap
), S(S
) {}
1403 static bool hasVariant(const SCEV
*E
, ScalarEvolution
&SE
,
1404 const ValueToValueMap
&VMap
, const Scop
*S
) {
1405 SCEVFindInsideScop
SFIS(VMap
, SE
, S
);
1407 return SFIS
.FoundInside
;
1410 bool follow(const SCEV
*E
) {
1411 if (auto *AddRec
= dyn_cast
<SCEVAddRecExpr
>(E
)) {
1412 FoundInside
|= S
->getRegion().contains(AddRec
->getLoop());
1413 } else if (auto *Unknown
= dyn_cast
<SCEVUnknown
>(E
)) {
1414 if (Instruction
*I
= dyn_cast
<Instruction
>(Unknown
->getValue()))
1415 FoundInside
|= S
->getRegion().contains(I
) && !VMap
.count(I
);
1417 return !FoundInside
;
1420 bool isDone() { return FoundInside
; }
1422 } // end anonymous namespace
1424 const SCEV
*Scop::getRepresentingInvariantLoadSCEV(const SCEV
*E
) const {
1425 // Check whether it makes sense to rewrite the SCEV. (ScalarEvolution
1426 // doesn't like addition between an AddRec and an expression that
1427 // doesn't have a dominance relationship with it.)
1428 if (SCEVFindInsideScop::hasVariant(E
, *SE
, InvEquivClassVMap
, this))
1432 return SCEVSensitiveParameterRewriter::rewrite(E
, *SE
, InvEquivClassVMap
);
1435 void Scop::createParameterId(const SCEV
*Parameter
) {
1436 assert(Parameters
.count(Parameter
));
1437 assert(!ParameterIds
.count(Parameter
));
1439 std::string ParameterName
= "p_" + std::to_string(getNumParams() - 1);
1441 if (const SCEVUnknown
*ValueParameter
= dyn_cast
<SCEVUnknown
>(Parameter
)) {
1442 Value
*Val
= ValueParameter
->getValue();
1444 if (UseInstructionNames
) {
1445 // If this parameter references a specific Value and this value has a name
1446 // we use this name as it is likely to be unique and more useful than just
1449 ParameterName
= Val
->getName().str();
1450 else if (LoadInst
*LI
= dyn_cast
<LoadInst
>(Val
)) {
1451 auto *LoadOrigin
= LI
->getPointerOperand()->stripInBoundsOffsets();
1452 if (LoadOrigin
->hasName()) {
1453 ParameterName
+= "_loaded_from_";
1455 LI
->getPointerOperand()->stripInBoundsOffsets()->getName();
1460 ParameterName
= getIslCompatibleName("", ParameterName
, "");
1463 isl::id Id
= isl::id::alloc(getIslCtx(), ParameterName
,
1464 const_cast<void *>((const void *)Parameter
));
1465 ParameterIds
[Parameter
] = Id
;
1468 void Scop::addParams(const ParameterSetTy
&NewParameters
) {
1469 for (const SCEV
*Parameter
: NewParameters
) {
1470 // Normalize the SCEV to get the representing element for an invariant load.
1471 Parameter
= extractConstantFactor(Parameter
, *SE
).second
;
1472 Parameter
= getRepresentingInvariantLoadSCEV(Parameter
);
1474 if (Parameters
.insert(Parameter
))
1475 createParameterId(Parameter
);
1479 isl::id
Scop::getIdForParam(const SCEV
*Parameter
) const {
1480 // Normalize the SCEV to get the representing element for an invariant load.
1481 Parameter
= getRepresentingInvariantLoadSCEV(Parameter
);
1482 return ParameterIds
.lookup(Parameter
);
1485 bool Scop::isDominatedBy(const DominatorTree
&DT
, BasicBlock
*BB
) const {
1486 return DT
.dominates(BB
, getEntry());
1489 void Scop::buildContext() {
1490 isl::space Space
= isl::space::params_alloc(getIslCtx(), 0);
1491 Context
= isl::set::universe(Space
);
1492 InvalidContext
= isl::set::empty(Space
);
1493 AssumedContext
= isl::set::universe(Space
);
1494 DefinedBehaviorContext
= isl::set::universe(Space
);
1497 void Scop::addParameterBounds() {
1499 for (auto *Parameter
: Parameters
) {
1500 ConstantRange SRange
= SE
->getSignedRange(Parameter
);
1501 Context
= addRangeBoundsToSet(Context
, SRange
, PDim
++, isl::dim::param
);
1503 intersectDefinedBehavior(Context
, AS_ASSUMPTION
);
1506 void Scop::realignParams() {
1507 if (PollyIgnoreParamBounds
)
1510 // Add all parameters into a common model.
1511 isl::space Space
= getFullParamSpace();
1513 // Align the parameters of all data structures to the model.
1514 Context
= Context
.align_params(Space
);
1515 AssumedContext
= AssumedContext
.align_params(Space
);
1516 InvalidContext
= InvalidContext
.align_params(Space
);
1518 // As all parameters are known add bounds to them.
1519 addParameterBounds();
1521 for (ScopStmt
&Stmt
: *this)
1522 Stmt
.realignParams();
1523 // Simplify the schedule according to the context too.
1524 Schedule
= Schedule
.gist_domain_params(getContext());
1526 // Predictable parameter order is required for JSON imports. Ensure alignment
1527 // by explicitly calling align_params.
1528 Schedule
= Schedule
.align_params(Space
);
1531 static isl::set
simplifyAssumptionContext(isl::set AssumptionContext
,
1533 // If we have modeled all blocks in the SCoP that have side effects we can
1534 // simplify the context with the constraints that are needed for anything to
1535 // be executed at all. However, if we have error blocks in the SCoP we already
1536 // assumed some parameter combinations cannot occur and removed them from the
1537 // domains, thus we cannot use the remaining domain to simplify the
1539 if (!S
.hasErrorBlock()) {
1540 auto DomainParameters
= S
.getDomains().params();
1541 AssumptionContext
= AssumptionContext
.gist_params(DomainParameters
);
1544 AssumptionContext
= AssumptionContext
.gist_params(S
.getContext());
1545 return AssumptionContext
;
1548 void Scop::simplifyContexts() {
1549 // The parameter constraints of the iteration domains give us a set of
1550 // constraints that need to hold for all cases where at least a single
1551 // statement iteration is executed in the whole scop. We now simplify the
1552 // assumed context under the assumption that such constraints hold and at
1553 // least a single statement iteration is executed. For cases where no
1554 // statement instances are executed, the assumptions we have taken about
1555 // the executed code do not matter and can be changed.
1557 // WARNING: This only holds if the assumptions we have taken do not reduce
1558 // the set of statement instances that are executed. Otherwise we
1559 // may run into a case where the iteration domains suggest that
1560 // for a certain set of parameter constraints no code is executed,
1561 // but in the original program some computation would have been
1562 // performed. In such a case, modifying the run-time conditions and
1563 // possibly influencing the run-time check may cause certain scops
1564 // to not be executed.
1568 // When delinearizing the following code:
1570 // for (long i = 0; i < 100; i++)
1571 // for (long j = 0; j < m; j++)
1574 // we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as
1575 // otherwise we would access out of bound data. Now, knowing that code is
1576 // only executed for the case m >= 0, it is sufficient to assume p >= 0.
1577 AssumedContext
= simplifyAssumptionContext(AssumedContext
, *this);
1578 InvalidContext
= InvalidContext
.align_params(getParamSpace());
1579 simplify(DefinedBehaviorContext
);
1580 DefinedBehaviorContext
= DefinedBehaviorContext
.align_params(getParamSpace());
1583 isl::set
Scop::getDomainConditions(const ScopStmt
*Stmt
) const {
1584 return getDomainConditions(Stmt
->getEntryBlock());
1587 isl::set
Scop::getDomainConditions(BasicBlock
*BB
) const {
1588 auto DIt
= DomainMap
.find(BB
);
1589 if (DIt
!= DomainMap
.end())
1590 return DIt
->getSecond();
1592 auto &RI
= *R
.getRegionInfo();
1593 auto *BBR
= RI
.getRegionFor(BB
);
1594 while (BBR
->getEntry() == BB
)
1595 BBR
= BBR
->getParent();
1596 return getDomainConditions(BBR
->getEntry());
1599 Scop::Scop(Region
&R
, ScalarEvolution
&ScalarEvolution
, LoopInfo
&LI
,
1600 DominatorTree
&DT
, ScopDetection::DetectionContext
&DC
,
1601 OptimizationRemarkEmitter
&ORE
, int ID
)
1602 : IslCtx(isl_ctx_alloc(), isl_ctx_free
), SE(&ScalarEvolution
), DT(&DT
),
1603 R(R
), name(std::nullopt
), HasSingleExitEdge(R
.getExitingBlock()), DC(DC
),
1604 ORE(ORE
), Affinator(this, LI
), ID(ID
) {
1606 // Options defaults that are different from ISL's.
1607 isl_options_set_schedule_serialize_sccs(IslCtx
.get(), true);
1609 SmallVector
<char *, 8> IslArgv
;
1610 IslArgv
.reserve(1 + IslArgs
.size());
1612 // Substitute for program name.
1613 IslArgv
.push_back(const_cast<char *>("-polly-isl-arg"));
1615 for (std::string
&Arg
: IslArgs
)
1616 IslArgv
.push_back(const_cast<char *>(Arg
.c_str()));
1618 // Abort if unknown argument is passed.
1619 // Note that "-V" (print isl version) will always call exit(0), so we cannot
1620 // avoid ISL aborting the program at this point.
1621 unsigned IslParseFlags
= ISL_ARG_ALL
;
1623 isl_ctx_parse_options(IslCtx
.get(), IslArgv
.size(), IslArgv
.data(),
1626 if (IslOnErrorAbort
)
1627 isl_options_set_on_error(getIslCtx().get(), ISL_ON_ERROR_ABORT
);
1631 Scop::~Scop() = default;
1633 void Scop::removeFromStmtMap(ScopStmt
&Stmt
) {
1634 for (Instruction
*Inst
: Stmt
.getInstructions())
1635 InstStmtMap
.erase(Inst
);
1637 if (Stmt
.isRegionStmt()) {
1638 for (BasicBlock
*BB
: Stmt
.getRegion()->blocks()) {
1640 // Skip entry basic block, as its instructions are already deleted as
1641 // part of the statement's instruction list.
1642 if (BB
== Stmt
.getEntryBlock())
1644 for (Instruction
&Inst
: *BB
)
1645 InstStmtMap
.erase(&Inst
);
1648 auto StmtMapIt
= StmtMap
.find(Stmt
.getBasicBlock());
1649 if (StmtMapIt
!= StmtMap
.end())
1650 llvm::erase(StmtMapIt
->second
, &Stmt
);
1651 for (Instruction
*Inst
: Stmt
.getInstructions())
1652 InstStmtMap
.erase(Inst
);
1656 void Scop::removeStmts(function_ref
<bool(ScopStmt
&)> ShouldDelete
,
1657 bool AfterHoisting
) {
1658 for (auto StmtIt
= Stmts
.begin(), StmtEnd
= Stmts
.end(); StmtIt
!= StmtEnd
;) {
1659 if (!ShouldDelete(*StmtIt
)) {
1664 // Start with removing all of the statement's accesses including erasing it
1665 // from all maps that are pointing to them.
1666 // Make a temporary copy because removing MAs invalidates the iterator.
1667 SmallVector
<MemoryAccess
*, 16> MAList(StmtIt
->begin(), StmtIt
->end());
1668 for (MemoryAccess
*MA
: MAList
)
1669 StmtIt
->removeSingleMemoryAccess(MA
, AfterHoisting
);
1671 removeFromStmtMap(*StmtIt
);
1672 StmtIt
= Stmts
.erase(StmtIt
);
1676 void Scop::removeStmtNotInDomainMap() {
1677 removeStmts([this](ScopStmt
&Stmt
) -> bool {
1678 isl::set Domain
= DomainMap
.lookup(Stmt
.getEntryBlock());
1679 if (Domain
.is_null())
1681 return Domain
.is_empty();
1685 void Scop::simplifySCoP(bool AfterHoisting
) {
1687 [AfterHoisting
](ScopStmt
&Stmt
) -> bool {
1688 // Never delete statements that contain calls to debug functions.
1689 if (hasDebugCall(&Stmt
))
1692 bool RemoveStmt
= Stmt
.isEmpty();
1694 // Remove read only statements only after invariant load hoisting.
1695 if (!RemoveStmt
&& AfterHoisting
) {
1696 bool OnlyRead
= true;
1697 for (MemoryAccess
*MA
: Stmt
) {
1705 RemoveStmt
= OnlyRead
;
1712 InvariantEquivClassTy
*Scop::lookupInvariantEquivClass(Value
*Val
) {
1713 LoadInst
*LInst
= dyn_cast
<LoadInst
>(Val
);
1717 if (Value
*Rep
= InvEquivClassVMap
.lookup(LInst
))
1718 LInst
= cast
<LoadInst
>(Rep
);
1720 Type
*Ty
= LInst
->getType();
1721 const SCEV
*PointerSCEV
= SE
->getSCEV(LInst
->getPointerOperand());
1722 for (auto &IAClass
: InvariantEquivClasses
) {
1723 if (PointerSCEV
!= IAClass
.IdentifyingPointer
|| Ty
!= IAClass
.AccessType
)
1726 auto &MAs
= IAClass
.InvariantAccesses
;
1727 for (auto *MA
: MAs
)
1728 if (MA
->getAccessInstruction() == Val
)
1735 ScopArrayInfo
*Scop::getOrCreateScopArrayInfo(Value
*BasePtr
, Type
*ElementType
,
1736 ArrayRef
<const SCEV
*> Sizes
,
1738 const char *BaseName
) {
1739 assert((BasePtr
|| BaseName
) &&
1740 "BasePtr and BaseName can not be nullptr at the same time.");
1741 assert(!(BasePtr
&& BaseName
) && "BaseName is redundant.");
1742 auto &SAI
= BasePtr
? ScopArrayInfoMap
[std::make_pair(BasePtr
, Kind
)]
1743 : ScopArrayNameMap
[BaseName
];
1745 auto &DL
= getFunction().getParent()->getDataLayout();
1746 SAI
.reset(new ScopArrayInfo(BasePtr
, ElementType
, getIslCtx(), Sizes
, Kind
,
1747 DL
, this, BaseName
));
1748 ScopArrayInfoSet
.insert(SAI
.get());
1750 SAI
->updateElementType(ElementType
);
1751 // In case of mismatching array sizes, we bail out by setting the run-time
1752 // context to false.
1753 if (!SAI
->updateSizes(Sizes
))
1754 invalidate(DELINEARIZATION
, DebugLoc());
1759 ScopArrayInfo
*Scop::createScopArrayInfo(Type
*ElementType
,
1760 const std::string
&BaseName
,
1761 const std::vector
<unsigned> &Sizes
) {
1762 auto *DimSizeType
= Type::getInt64Ty(getSE()->getContext());
1763 std::vector
<const SCEV
*> SCEVSizes
;
1765 for (auto size
: Sizes
)
1767 SCEVSizes
.push_back(getSE()->getConstant(DimSizeType
, size
, false));
1769 SCEVSizes
.push_back(nullptr);
1771 auto *SAI
= getOrCreateScopArrayInfo(nullptr, ElementType
, SCEVSizes
,
1772 MemoryKind::Array
, BaseName
.c_str());
1776 ScopArrayInfo
*Scop::getScopArrayInfoOrNull(Value
*BasePtr
, MemoryKind Kind
) {
1777 auto *SAI
= ScopArrayInfoMap
[std::make_pair(BasePtr
, Kind
)].get();
1781 ScopArrayInfo
*Scop::getScopArrayInfo(Value
*BasePtr
, MemoryKind Kind
) {
1782 auto *SAI
= getScopArrayInfoOrNull(BasePtr
, Kind
);
1783 assert(SAI
&& "No ScopArrayInfo available for this base pointer");
1787 std::string
Scop::getContextStr() const {
1788 return stringFromIslObj(getContext());
1791 std::string
Scop::getAssumedContextStr() const {
1792 assert(!AssumedContext
.is_null() && "Assumed context not yet built");
1793 return stringFromIslObj(AssumedContext
);
1796 std::string
Scop::getInvalidContextStr() const {
1797 return stringFromIslObj(InvalidContext
);
1800 std::string
Scop::getNameStr() const {
1801 std::string ExitName
, EntryName
;
1802 std::tie(EntryName
, ExitName
) = getEntryExitStr();
1803 return EntryName
+ "---" + ExitName
;
1806 std::pair
<std::string
, std::string
> Scop::getEntryExitStr() const {
1807 std::string ExitName
, EntryName
;
1808 raw_string_ostream
ExitStr(ExitName
);
1809 raw_string_ostream
EntryStr(EntryName
);
1811 R
.getEntry()->printAsOperand(EntryStr
, false);
1815 R
.getExit()->printAsOperand(ExitStr
, false);
1818 ExitName
= "FunctionExit";
1820 return std::make_pair(EntryName
, ExitName
);
1823 isl::set
Scop::getContext() const { return Context
; }
1825 isl::space
Scop::getParamSpace() const { return getContext().get_space(); }
1827 isl::space
Scop::getFullParamSpace() const {
1829 isl::space Space
= isl::space::params_alloc(getIslCtx(), ParameterIds
.size());
1832 for (const SCEV
*Parameter
: Parameters
) {
1833 isl::id Id
= getIdForParam(Parameter
);
1834 Space
= Space
.set_dim_id(isl::dim::param
, PDim
++, Id
);
1840 isl::set
Scop::getAssumedContext() const {
1841 assert(!AssumedContext
.is_null() && "Assumed context not yet built");
1842 return AssumedContext
;
1845 bool Scop::isProfitable(bool ScalarsAreUnprofitable
) const {
1846 if (PollyProcessUnprofitable
)
1852 unsigned OptimizableStmtsOrLoops
= 0;
1853 for (auto &Stmt
: *this) {
1854 if (Stmt
.getNumIterators() == 0)
1857 bool ContainsArrayAccs
= false;
1858 bool ContainsScalarAccs
= false;
1859 for (auto *MA
: Stmt
) {
1862 ContainsArrayAccs
|= MA
->isLatestArrayKind();
1863 ContainsScalarAccs
|= MA
->isLatestScalarKind();
1866 if (!ScalarsAreUnprofitable
|| (ContainsArrayAccs
&& !ContainsScalarAccs
))
1867 OptimizableStmtsOrLoops
+= Stmt
.getNumIterators();
1870 return OptimizableStmtsOrLoops
> 1;
1873 bool Scop::hasFeasibleRuntimeContext() const {
1877 isl::set PositiveContext
= getAssumedContext();
1878 isl::set NegativeContext
= getInvalidContext();
1879 PositiveContext
= PositiveContext
.intersect_params(Context
);
1880 PositiveContext
= PositiveContext
.intersect_params(getDomains().params());
1881 return PositiveContext
.is_empty().is_false() &&
1882 PositiveContext
.is_subset(NegativeContext
).is_false();
1885 MemoryAccess
*Scop::lookupBasePtrAccess(MemoryAccess
*MA
) {
1886 Value
*PointerBase
= MA
->getOriginalBaseAddr();
1888 auto *PointerBaseInst
= dyn_cast
<Instruction
>(PointerBase
);
1889 if (!PointerBaseInst
)
1892 auto *BasePtrStmt
= getStmtFor(PointerBaseInst
);
1896 return BasePtrStmt
->getArrayAccessOrNULLFor(PointerBaseInst
);
1899 static std::string
toString(AssumptionKind Kind
) {
1902 return "No-aliasing";
1906 return "No-overflows";
1908 return "Signed-unsigned";
1910 return "Low complexity";
1912 return "Profitable";
1916 return "Finite loop";
1918 return "Invariant load";
1919 case DELINEARIZATION
:
1920 return "Delinearization";
1922 llvm_unreachable("Unknown AssumptionKind!");
1925 bool Scop::isEffectiveAssumption(isl::set Set
, AssumptionSign Sign
) {
1926 if (Sign
== AS_ASSUMPTION
) {
1927 if (Context
.is_subset(Set
))
1930 if (AssumedContext
.is_subset(Set
))
1933 if (Set
.is_disjoint(Context
))
1936 if (Set
.is_subset(InvalidContext
))
1942 bool Scop::trackAssumption(AssumptionKind Kind
, isl::set Set
, DebugLoc Loc
,
1943 AssumptionSign Sign
, BasicBlock
*BB
) {
1944 if (PollyRemarksMinimal
&& !isEffectiveAssumption(Set
, Sign
))
1947 // Do never emit trivial assumptions as they only clutter the output.
1948 if (!PollyRemarksMinimal
) {
1950 if (Sign
== AS_ASSUMPTION
)
1951 Univ
= isl::set::universe(Set
.get_space());
1953 bool IsTrivial
= (Sign
== AS_RESTRICTION
&& Set
.is_empty()) ||
1954 (Sign
== AS_ASSUMPTION
&& Univ
.is_equal(Set
));
1962 AssumptionsAliasing
++;
1965 AssumptionsInbounds
++;
1968 AssumptionsWrapping
++;
1971 AssumptionsUnsigned
++;
1974 AssumptionsComplexity
++;
1977 AssumptionsUnprofitable
++;
1980 AssumptionsErrorBlock
++;
1983 AssumptionsInfiniteLoop
++;
1986 AssumptionsInvariantLoad
++;
1988 case DELINEARIZATION
:
1989 AssumptionsDelinearization
++;
1993 auto Suffix
= Sign
== AS_ASSUMPTION
? " assumption:\t" : " restriction:\t";
1994 std::string Msg
= toString(Kind
) + Suffix
+ stringFromIslObj(Set
);
1996 ORE
.emit(OptimizationRemarkAnalysis(DEBUG_TYPE
, "AssumpRestrict", Loc
, BB
)
1999 ORE
.emit(OptimizationRemarkAnalysis(DEBUG_TYPE
, "AssumpRestrict", Loc
,
2005 void Scop::addAssumption(AssumptionKind Kind
, isl::set Set
, DebugLoc Loc
,
2006 AssumptionSign Sign
, BasicBlock
*BB
,
2008 // Simplify the assumptions/restrictions first.
2009 Set
= Set
.gist_params(getContext());
2010 intersectDefinedBehavior(Set
, Sign
);
2015 if (!trackAssumption(Kind
, Set
, Loc
, Sign
, BB
))
2018 if (Sign
== AS_ASSUMPTION
)
2019 AssumedContext
= AssumedContext
.intersect(Set
).coalesce();
2021 InvalidContext
= InvalidContext
.unite(Set
).coalesce();
2024 void Scop::intersectDefinedBehavior(isl::set Set
, AssumptionSign Sign
) {
2025 if (DefinedBehaviorContext
.is_null())
2028 if (Sign
== AS_ASSUMPTION
)
2029 DefinedBehaviorContext
= DefinedBehaviorContext
.intersect(Set
);
2031 DefinedBehaviorContext
= DefinedBehaviorContext
.subtract(Set
);
2033 // Limit the complexity of the context. If complexity is exceeded, simplify
2034 // the set and check again.
2035 if (DefinedBehaviorContext
.n_basic_set().release() >
2036 MaxDisjunktsInDefinedBehaviourContext
) {
2037 simplify(DefinedBehaviorContext
);
2038 if (DefinedBehaviorContext
.n_basic_set().release() >
2039 MaxDisjunktsInDefinedBehaviourContext
)
2040 DefinedBehaviorContext
= {};
2044 void Scop::invalidate(AssumptionKind Kind
, DebugLoc Loc
, BasicBlock
*BB
) {
2045 LLVM_DEBUG(dbgs() << "Invalidate SCoP because of reason " << Kind
<< "\n");
2046 addAssumption(Kind
, isl::set::empty(getParamSpace()), Loc
, AS_ASSUMPTION
, BB
);
2049 isl::set
Scop::getInvalidContext() const { return InvalidContext
; }
2051 void Scop::printContext(raw_ostream
&OS
) const {
2053 OS
.indent(4) << Context
<< "\n";
2055 OS
.indent(4) << "Assumed Context:\n";
2056 OS
.indent(4) << AssumedContext
<< "\n";
2058 OS
.indent(4) << "Invalid Context:\n";
2059 OS
.indent(4) << InvalidContext
<< "\n";
2061 OS
.indent(4) << "Defined Behavior Context:\n";
2062 if (!DefinedBehaviorContext
.is_null())
2063 OS
.indent(4) << DefinedBehaviorContext
<< "\n";
2065 OS
.indent(4) << "<unavailable>\n";
2068 for (const SCEV
*Parameter
: Parameters
)
2069 OS
.indent(4) << "p" << Dim
++ << ": " << *Parameter
<< "\n";
2072 void Scop::printAliasAssumptions(raw_ostream
&OS
) const {
2074 for (const MinMaxVectorPairTy
&Pair
: MinMaxAliasGroups
) {
2075 if (Pair
.second
.size() == 0)
2078 noOfGroups
+= Pair
.second
.size();
2081 OS
.indent(4) << "Alias Groups (" << noOfGroups
<< "):\n";
2082 if (MinMaxAliasGroups
.empty()) {
2083 OS
.indent(8) << "n/a\n";
2087 for (const MinMaxVectorPairTy
&Pair
: MinMaxAliasGroups
) {
2089 // If the group has no read only accesses print the write accesses.
2090 if (Pair
.second
.empty()) {
2091 OS
.indent(8) << "[[";
2092 for (const MinMaxAccessTy
&MMANonReadOnly
: Pair
.first
) {
2093 OS
<< " <" << MMANonReadOnly
.first
<< ", " << MMANonReadOnly
.second
2099 for (const MinMaxAccessTy
&MMAReadOnly
: Pair
.second
) {
2100 OS
.indent(8) << "[[";
2101 OS
<< " <" << MMAReadOnly
.first
<< ", " << MMAReadOnly
.second
<< ">";
2102 for (const MinMaxAccessTy
&MMANonReadOnly
: Pair
.first
) {
2103 OS
<< " <" << MMANonReadOnly
.first
<< ", " << MMANonReadOnly
.second
2111 void Scop::printStatements(raw_ostream
&OS
, bool PrintInstructions
) const {
2112 OS
<< "Statements {\n";
2114 for (const ScopStmt
&Stmt
: *this) {
2116 Stmt
.print(OS
, PrintInstructions
);
2119 OS
.indent(4) << "}\n";
2122 void Scop::printArrayInfo(raw_ostream
&OS
) const {
2125 for (auto &Array
: arrays())
2128 OS
.indent(4) << "}\n";
2130 OS
.indent(4) << "Arrays (Bounds as pw_affs) {\n";
2132 for (auto &Array
: arrays())
2133 Array
->print(OS
, /* SizeAsPwAff */ true);
2135 OS
.indent(4) << "}\n";
2138 void Scop::print(raw_ostream
&OS
, bool PrintInstructions
) const {
2139 OS
.indent(4) << "Function: " << getFunction().getName() << "\n";
2140 OS
.indent(4) << "Region: " << getNameStr() << "\n";
2141 OS
.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n";
2142 OS
.indent(4) << "Invariant Accesses: {\n";
2143 for (const auto &IAClass
: InvariantEquivClasses
) {
2144 const auto &MAs
= IAClass
.InvariantAccesses
;
2146 OS
.indent(12) << "Class Pointer: " << *IAClass
.IdentifyingPointer
<< "\n";
2148 MAs
.front()->print(OS
);
2149 OS
.indent(12) << "Execution Context: " << IAClass
.ExecutionContext
2153 OS
.indent(4) << "}\n";
2154 printContext(OS
.indent(4));
2155 printArrayInfo(OS
.indent(4));
2156 printAliasAssumptions(OS
);
2157 printStatements(OS
.indent(4), PrintInstructions
);
2160 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2161 LLVM_DUMP_METHOD
void Scop::dump() const { print(dbgs(), true); }
2164 isl::ctx
Scop::getIslCtx() const { return IslCtx
.get(); }
2166 __isl_give PWACtx
Scop::getPwAff(const SCEV
*E
, BasicBlock
*BB
,
2168 RecordedAssumptionsTy
*RecordedAssumptions
) {
2169 // First try to use the SCEVAffinator to generate a piecewise defined
2170 // affine function from @p E in the context of @p BB. If that tasks becomes to
2171 // complex the affinator might return a nullptr. In such a case we invalidate
2172 // the SCoP and return a dummy value. This way we do not need to add error
2173 // handling code to all users of this function.
2174 auto PWAC
= Affinator
.getPwAff(E
, BB
, RecordedAssumptions
);
2175 if (!PWAC
.first
.is_null()) {
2176 // TODO: We could use a heuristic and either use:
2177 // SCEVAffinator::takeNonNegativeAssumption
2179 // SCEVAffinator::interpretAsUnsigned
2180 // to deal with unsigned or "NonNegative" SCEVs.
2182 Affinator
.takeNonNegativeAssumption(PWAC
, RecordedAssumptions
);
2186 auto DL
= BB
? BB
->getTerminator()->getDebugLoc() : DebugLoc();
2187 invalidate(COMPLEXITY
, DL
, BB
);
2188 return Affinator
.getPwAff(SE
->getZero(E
->getType()), BB
, RecordedAssumptions
);
2191 isl::union_set
Scop::getDomains() const {
2192 isl_space
*EmptySpace
= isl_space_params_alloc(getIslCtx().get(), 0);
2193 isl_union_set
*Domain
= isl_union_set_empty(EmptySpace
);
2195 for (const ScopStmt
&Stmt
: *this)
2196 Domain
= isl_union_set_add_set(Domain
, Stmt
.getDomain().release());
2198 return isl::manage(Domain
);
2201 isl::pw_aff
Scop::getPwAffOnly(const SCEV
*E
, BasicBlock
*BB
,
2202 RecordedAssumptionsTy
*RecordedAssumptions
) {
2203 PWACtx PWAC
= getPwAff(E
, BB
, RecordedAssumptions
);
2208 Scop::getAccessesOfType(std::function
<bool(MemoryAccess
&)> Predicate
) {
2209 isl::union_map Accesses
= isl::union_map::empty(getIslCtx());
2211 for (ScopStmt
&Stmt
: *this) {
2212 for (MemoryAccess
*MA
: Stmt
) {
2213 if (!Predicate(*MA
))
2216 isl::set Domain
= Stmt
.getDomain();
2217 isl::map AccessDomain
= MA
->getAccessRelation();
2218 AccessDomain
= AccessDomain
.intersect_domain(Domain
);
2219 Accesses
= Accesses
.unite(AccessDomain
);
2223 return Accesses
.coalesce();
2226 isl::union_map
Scop::getMustWrites() {
2227 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isMustWrite(); });
2230 isl::union_map
Scop::getMayWrites() {
2231 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isMayWrite(); });
2234 isl::union_map
Scop::getWrites() {
2235 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isWrite(); });
2238 isl::union_map
Scop::getReads() {
2239 return getAccessesOfType([](MemoryAccess
&MA
) { return MA
.isRead(); });
2242 isl::union_map
Scop::getAccesses() {
2243 return getAccessesOfType([](MemoryAccess
&MA
) { return true; });
2246 isl::union_map
Scop::getAccesses(ScopArrayInfo
*Array
) {
2247 return getAccessesOfType(
2248 [Array
](MemoryAccess
&MA
) { return MA
.getScopArrayInfo() == Array
; });
2251 isl::union_map
Scop::getSchedule() const {
2252 auto Tree
= getScheduleTree();
2253 return Tree
.get_map();
2256 isl::schedule
Scop::getScheduleTree() const {
2257 return Schedule
.intersect_domain(getDomains());
2260 void Scop::setSchedule(isl::union_map NewSchedule
) {
2261 auto S
= isl::schedule::from_domain(getDomains());
2262 Schedule
= S
.insert_partial_schedule(
2263 isl::multi_union_pw_aff::from_union_map(NewSchedule
));
2264 ScheduleModified
= true;
2267 void Scop::setScheduleTree(isl::schedule NewSchedule
) {
2268 Schedule
= NewSchedule
;
2269 ScheduleModified
= true;
2272 bool Scop::restrictDomains(isl::union_set Domain
) {
2273 bool Changed
= false;
2274 for (ScopStmt
&Stmt
: *this) {
2275 isl::union_set StmtDomain
= isl::union_set(Stmt
.getDomain());
2276 isl::union_set NewStmtDomain
= StmtDomain
.intersect(Domain
);
2278 if (StmtDomain
.is_subset(NewStmtDomain
))
2283 NewStmtDomain
= NewStmtDomain
.coalesce();
2285 if (NewStmtDomain
.is_empty())
2286 Stmt
.restrictDomain(isl::set::empty(Stmt
.getDomainSpace()));
2288 Stmt
.restrictDomain(isl::set(NewStmtDomain
));
2293 ScalarEvolution
*Scop::getSE() const { return SE
; }
2295 void Scop::addScopStmt(BasicBlock
*BB
, StringRef Name
, Loop
*SurroundingLoop
,
2296 std::vector
<Instruction
*> Instructions
) {
2297 assert(BB
&& "Unexpected nullptr!");
2298 Stmts
.emplace_back(*this, *BB
, Name
, SurroundingLoop
, Instructions
);
2299 auto *Stmt
= &Stmts
.back();
2300 StmtMap
[BB
].push_back(Stmt
);
2301 for (Instruction
*Inst
: Instructions
) {
2302 assert(!InstStmtMap
.count(Inst
) &&
2303 "Unexpected statement corresponding to the instruction.");
2304 InstStmtMap
[Inst
] = Stmt
;
2308 void Scop::addScopStmt(Region
*R
, StringRef Name
, Loop
*SurroundingLoop
,
2309 std::vector
<Instruction
*> Instructions
) {
2310 assert(R
&& "Unexpected nullptr!");
2311 Stmts
.emplace_back(*this, *R
, Name
, SurroundingLoop
, Instructions
);
2312 auto *Stmt
= &Stmts
.back();
2314 for (Instruction
*Inst
: Instructions
) {
2315 assert(!InstStmtMap
.count(Inst
) &&
2316 "Unexpected statement corresponding to the instruction.");
2317 InstStmtMap
[Inst
] = Stmt
;
2320 for (BasicBlock
*BB
: R
->blocks()) {
2321 StmtMap
[BB
].push_back(Stmt
);
2322 if (BB
== R
->getEntry())
2324 for (Instruction
&Inst
: *BB
) {
2325 assert(!InstStmtMap
.count(&Inst
) &&
2326 "Unexpected statement corresponding to the instruction.");
2327 InstStmtMap
[&Inst
] = Stmt
;
2332 ScopStmt
*Scop::addScopStmt(isl::map SourceRel
, isl::map TargetRel
,
2335 isl::set SourceDomain
= SourceRel
.domain();
2336 isl::set TargetDomain
= TargetRel
.domain();
2337 assert(Domain
.is_subset(TargetDomain
) &&
2338 "Target access not defined for complete statement domain");
2339 assert(Domain
.is_subset(SourceDomain
) &&
2340 "Source access not defined for complete statement domain");
2342 Stmts
.emplace_back(*this, SourceRel
, TargetRel
, Domain
);
2344 return &(Stmts
.back());
2347 ArrayRef
<ScopStmt
*> Scop::getStmtListFor(BasicBlock
*BB
) const {
2348 auto StmtMapIt
= StmtMap
.find(BB
);
2349 if (StmtMapIt
== StmtMap
.end())
2351 return StmtMapIt
->second
;
2354 ScopStmt
*Scop::getIncomingStmtFor(const Use
&U
) const {
2355 auto *PHI
= cast
<PHINode
>(U
.getUser());
2356 BasicBlock
*IncomingBB
= PHI
->getIncomingBlock(U
);
2358 // If the value is a non-synthesizable from the incoming block, use the
2359 // statement that contains it as user statement.
2360 if (auto *IncomingInst
= dyn_cast
<Instruction
>(U
.get())) {
2361 if (IncomingInst
->getParent() == IncomingBB
) {
2362 if (ScopStmt
*IncomingStmt
= getStmtFor(IncomingInst
))
2363 return IncomingStmt
;
2367 // Otherwise, use the epilogue/last statement.
2368 return getLastStmtFor(IncomingBB
);
2371 ScopStmt
*Scop::getLastStmtFor(BasicBlock
*BB
) const {
2372 ArrayRef
<ScopStmt
*> StmtList
= getStmtListFor(BB
);
2373 if (!StmtList
.empty())
2374 return StmtList
.back();
2378 ArrayRef
<ScopStmt
*> Scop::getStmtListFor(RegionNode
*RN
) const {
2379 if (RN
->isSubRegion())
2380 return getStmtListFor(RN
->getNodeAs
<Region
>());
2381 return getStmtListFor(RN
->getNodeAs
<BasicBlock
>());
2384 ArrayRef
<ScopStmt
*> Scop::getStmtListFor(Region
*R
) const {
2385 return getStmtListFor(R
->getEntry());
2388 int Scop::getRelativeLoopDepth(const Loop
*L
) const {
2389 if (!L
|| !R
.contains(L
))
2391 // outermostLoopInRegion always returns nullptr for top level regions
2392 if (R
.isTopLevelRegion()) {
2393 // LoopInfo's depths start at 1, we start at 0
2394 return L
->getLoopDepth() - 1;
2396 Loop
*OuterLoop
= R
.outermostLoopInRegion(const_cast<Loop
*>(L
));
2398 return L
->getLoopDepth() - OuterLoop
->getLoopDepth();
2402 ScopArrayInfo
*Scop::getArrayInfoByName(const std::string BaseName
) {
2403 for (auto &SAI
: arrays()) {
2404 if (SAI
->getName() == BaseName
)
2410 void Scop::addAccessData(MemoryAccess
*Access
) {
2411 const ScopArrayInfo
*SAI
= Access
->getOriginalScopArrayInfo();
2412 assert(SAI
&& "can only use after access relations have been constructed");
2414 if (Access
->isOriginalValueKind() && Access
->isRead())
2415 ValueUseAccs
[SAI
].push_back(Access
);
2416 else if (Access
->isOriginalAnyPHIKind() && Access
->isWrite())
2417 PHIIncomingAccs
[SAI
].push_back(Access
);
2420 void Scop::removeAccessData(MemoryAccess
*Access
) {
2421 if (Access
->isOriginalValueKind() && Access
->isWrite()) {
2422 ValueDefAccs
.erase(Access
->getAccessValue());
2423 } else if (Access
->isOriginalValueKind() && Access
->isRead()) {
2424 auto &Uses
= ValueUseAccs
[Access
->getScopArrayInfo()];
2425 llvm::erase(Uses
, Access
);
2426 } else if (Access
->isOriginalPHIKind() && Access
->isRead()) {
2427 PHINode
*PHI
= cast
<PHINode
>(Access
->getAccessInstruction());
2428 PHIReadAccs
.erase(PHI
);
2429 } else if (Access
->isOriginalAnyPHIKind() && Access
->isWrite()) {
2430 auto &Incomings
= PHIIncomingAccs
[Access
->getScopArrayInfo()];
2431 llvm::erase(Incomings
, Access
);
2435 MemoryAccess
*Scop::getValueDef(const ScopArrayInfo
*SAI
) const {
2436 assert(SAI
->isValueKind());
2438 Instruction
*Val
= dyn_cast
<Instruction
>(SAI
->getBasePtr());
2442 return ValueDefAccs
.lookup(Val
);
2445 ArrayRef
<MemoryAccess
*> Scop::getValueUses(const ScopArrayInfo
*SAI
) const {
2446 assert(SAI
->isValueKind());
2447 auto It
= ValueUseAccs
.find(SAI
);
2448 if (It
== ValueUseAccs
.end())
2453 MemoryAccess
*Scop::getPHIRead(const ScopArrayInfo
*SAI
) const {
2454 assert(SAI
->isPHIKind() || SAI
->isExitPHIKind());
2456 if (SAI
->isExitPHIKind())
2459 PHINode
*PHI
= cast
<PHINode
>(SAI
->getBasePtr());
2460 return PHIReadAccs
.lookup(PHI
);
2463 ArrayRef
<MemoryAccess
*> Scop::getPHIIncomings(const ScopArrayInfo
*SAI
) const {
2464 assert(SAI
->isPHIKind() || SAI
->isExitPHIKind());
2465 auto It
= PHIIncomingAccs
.find(SAI
);
2466 if (It
== PHIIncomingAccs
.end())
2471 bool Scop::isEscaping(Instruction
*Inst
) {
2472 assert(contains(Inst
) && "The concept of escaping makes only sense for "
2473 "values defined inside the SCoP");
2475 for (Use
&Use
: Inst
->uses()) {
2476 BasicBlock
*UserBB
= getUseBlock(Use
);
2477 if (!contains(UserBB
))
2480 // When the SCoP region exit needs to be simplified, PHIs in the region exit
2481 // move to a new basic block such that its incoming blocks are not in the
2483 if (hasSingleExitEdge() && isa
<PHINode
>(Use
.getUser()) &&
2484 isExit(cast
<PHINode
>(Use
.getUser())->getParent()))
2490 void Scop::incrementNumberOfAliasingAssumptions(unsigned step
) {
2491 AssumptionsAliasing
+= step
;
2494 Scop::ScopStatistics
Scop::getStatistics() const {
2495 ScopStatistics Result
;
2496 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2497 auto LoopStat
= ScopDetection::countBeneficialLoops(&R
, *SE
, *getLI(), 0);
2499 int NumTotalLoops
= LoopStat
.NumLoops
;
2500 Result
.NumBoxedLoops
= getBoxedLoops().size();
2501 Result
.NumAffineLoops
= NumTotalLoops
- Result
.NumBoxedLoops
;
2503 for (const ScopStmt
&Stmt
: *this) {
2504 isl::set Domain
= Stmt
.getDomain().intersect_params(getContext());
2505 bool IsInLoop
= Stmt
.getNumIterators() >= 1;
2506 for (MemoryAccess
*MA
: Stmt
) {
2510 if (MA
->isLatestValueKind()) {
2511 Result
.NumValueWrites
+= 1;
2513 Result
.NumValueWritesInLoops
+= 1;
2516 if (MA
->isLatestAnyPHIKind()) {
2517 Result
.NumPHIWrites
+= 1;
2519 Result
.NumPHIWritesInLoops
+= 1;
2523 MA
->getAccessRelation().intersect_domain(Domain
).range();
2524 if (AccSet
.is_singleton()) {
2525 Result
.NumSingletonWrites
+= 1;
2527 Result
.NumSingletonWritesInLoops
+= 1;
2535 raw_ostream
&polly::operator<<(raw_ostream
&OS
, const Scop
&scop
) {
2536 scop
.print(OS
, PollyPrintInstructions
);
2540 //===----------------------------------------------------------------------===//
2541 void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage
&AU
) const {
2542 AU
.addRequired
<LoopInfoWrapperPass
>();
2543 AU
.addRequired
<RegionInfoPass
>();
2544 AU
.addRequired
<DominatorTreeWrapperPass
>();
2545 AU
.addRequiredTransitive
<ScalarEvolutionWrapperPass
>();
2546 AU
.addRequiredTransitive
<ScopDetectionWrapperPass
>();
2547 AU
.addRequired
<AAResultsWrapperPass
>();
2548 AU
.addRequired
<AssumptionCacheTracker
>();
2549 AU
.addRequired
<OptimizationRemarkEmitterWrapperPass
>();
2550 AU
.setPreservesAll();
2553 void updateLoopCountStatistic(ScopDetection::LoopStats Stats
,
2554 Scop::ScopStatistics ScopStats
) {
2555 assert(Stats
.NumLoops
== ScopStats
.NumAffineLoops
+ ScopStats
.NumBoxedLoops
);
2558 NumLoopsInScop
+= Stats
.NumLoops
;
2560 std::max(MaxNumLoopsInScop
.getValue(), (uint64_t)Stats
.NumLoops
);
2562 if (Stats
.MaxDepth
== 0)
2563 NumScopsDepthZero
++;
2564 else if (Stats
.MaxDepth
== 1)
2566 else if (Stats
.MaxDepth
== 2)
2568 else if (Stats
.MaxDepth
== 3)
2569 NumScopsDepthThree
++;
2570 else if (Stats
.MaxDepth
== 4)
2571 NumScopsDepthFour
++;
2572 else if (Stats
.MaxDepth
== 5)
2573 NumScopsDepthFive
++;
2575 NumScopsDepthLarger
++;
2577 NumAffineLoops
+= ScopStats
.NumAffineLoops
;
2578 NumBoxedLoops
+= ScopStats
.NumBoxedLoops
;
2580 NumValueWrites
+= ScopStats
.NumValueWrites
;
2581 NumValueWritesInLoops
+= ScopStats
.NumValueWritesInLoops
;
2582 NumPHIWrites
+= ScopStats
.NumPHIWrites
;
2583 NumPHIWritesInLoops
+= ScopStats
.NumPHIWritesInLoops
;
2584 NumSingletonWrites
+= ScopStats
.NumSingletonWrites
;
2585 NumSingletonWritesInLoops
+= ScopStats
.NumSingletonWritesInLoops
;
2588 bool ScopInfoRegionPass::runOnRegion(Region
*R
, RGPassManager
&RGM
) {
2589 auto &SD
= getAnalysis
<ScopDetectionWrapperPass
>().getSD();
2591 if (!SD
.isMaxRegionInScop(*R
))
2594 Function
*F
= R
->getEntry()->getParent();
2595 auto &SE
= getAnalysis
<ScalarEvolutionWrapperPass
>().getSE();
2596 auto &LI
= getAnalysis
<LoopInfoWrapperPass
>().getLoopInfo();
2597 auto &AA
= getAnalysis
<AAResultsWrapperPass
>().getAAResults();
2598 auto const &DL
= F
->getParent()->getDataLayout();
2599 auto &DT
= getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
2600 auto &AC
= getAnalysis
<AssumptionCacheTracker
>().getAssumptionCache(*F
);
2601 auto &ORE
= getAnalysis
<OptimizationRemarkEmitterWrapperPass
>().getORE();
2603 ScopBuilder
SB(R
, AC
, AA
, DL
, DT
, LI
, SD
, SE
, ORE
);
2604 S
= SB
.getScop(); // take ownership of scop object
2606 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2608 ScopDetection::LoopStats Stats
=
2609 ScopDetection::countBeneficialLoops(&S
->getRegion(), SE
, LI
, 0);
2610 updateLoopCountStatistic(Stats
, S
->getStatistics());
2617 void ScopInfoRegionPass::print(raw_ostream
&OS
, const Module
*) const {
2619 S
->print(OS
, PollyPrintInstructions
);
2621 OS
<< "Invalid Scop!\n";
2624 char ScopInfoRegionPass::ID
= 0;
2626 Pass
*polly::createScopInfoRegionPassPass() { return new ScopInfoRegionPass(); }
2628 INITIALIZE_PASS_BEGIN(ScopInfoRegionPass
, "polly-scops",
2629 "Polly - Create polyhedral description of Scops", false,
2631 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass
);
2632 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker
);
2633 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass
);
2634 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass
);
2635 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass
);
2636 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass
);
2637 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
);
2638 INITIALIZE_PASS_END(ScopInfoRegionPass
, "polly-scops",
2639 "Polly - Create polyhedral description of Scops", false,
2642 //===----------------------------------------------------------------------===//
2646 /// Print result from ScopInfoRegionPass.
2647 class ScopInfoPrinterLegacyRegionPass final
: public RegionPass
{
2651 ScopInfoPrinterLegacyRegionPass() : ScopInfoPrinterLegacyRegionPass(outs()) {}
2653 explicit ScopInfoPrinterLegacyRegionPass(llvm::raw_ostream
&OS
)
2654 : RegionPass(ID
), OS(OS
) {}
2656 bool runOnRegion(Region
*R
, RGPassManager
&RGM
) override
{
2657 ScopInfoRegionPass
&P
= getAnalysis
<ScopInfoRegionPass
>();
2659 OS
<< "Printing analysis '" << P
.getPassName() << "' for region: '"
2660 << R
->getNameStr() << "' in function '"
2661 << R
->getEntry()->getParent()->getName() << "':\n";
2667 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
2668 RegionPass::getAnalysisUsage(AU
);
2669 AU
.addRequired
<ScopInfoRegionPass
>();
2670 AU
.setPreservesAll();
2674 llvm::raw_ostream
&OS
;
2677 char ScopInfoPrinterLegacyRegionPass::ID
= 0;
2680 Pass
*polly::createScopInfoPrinterLegacyRegionPass(raw_ostream
&OS
) {
2681 return new ScopInfoPrinterLegacyRegionPass(OS
);
2684 INITIALIZE_PASS_BEGIN(ScopInfoPrinterLegacyRegionPass
, "polly-print-scops",
2685 "Polly - Print polyhedral description of Scops", false,
2687 INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass
);
2688 INITIALIZE_PASS_END(ScopInfoPrinterLegacyRegionPass
, "polly-print-scops",
2689 "Polly - Print polyhedral description of Scops", false,
2692 //===----------------------------------------------------------------------===//
2694 ScopInfo::ScopInfo(const DataLayout
&DL
, ScopDetection
&SD
, ScalarEvolution
&SE
,
2695 LoopInfo
&LI
, AliasAnalysis
&AA
, DominatorTree
&DT
,
2696 AssumptionCache
&AC
, OptimizationRemarkEmitter
&ORE
)
2697 : DL(DL
), SD(SD
), SE(SE
), LI(LI
), AA(AA
), DT(DT
), AC(AC
), ORE(ORE
) {
2701 void ScopInfo::recompute() {
2702 RegionToScopMap
.clear();
2703 /// Create polyhedral description of scops for all the valid regions of a
2705 for (auto &It
: SD
) {
2706 Region
*R
= const_cast<Region
*>(It
);
2707 if (!SD
.isMaxRegionInScop(*R
))
2710 ScopBuilder
SB(R
, AC
, AA
, DL
, DT
, LI
, SD
, SE
, ORE
);
2711 std::unique_ptr
<Scop
> S
= SB
.getScop();
2714 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
2715 ScopDetection::LoopStats Stats
=
2716 ScopDetection::countBeneficialLoops(&S
->getRegion(), SE
, LI
, 0);
2717 updateLoopCountStatistic(Stats
, S
->getStatistics());
2719 bool Inserted
= RegionToScopMap
.insert({R
, std::move(S
)}).second
;
2720 assert(Inserted
&& "Building Scop for the same region twice!");
2725 bool ScopInfo::invalidate(Function
&F
, const PreservedAnalyses
&PA
,
2726 FunctionAnalysisManager::Invalidator
&Inv
) {
2727 // Check whether the analysis, all analyses on functions have been preserved
2728 // or anything we're holding references to is being invalidated
2729 auto PAC
= PA
.getChecker
<ScopInfoAnalysis
>();
2730 return !(PAC
.preserved() || PAC
.preservedSet
<AllAnalysesOn
<Function
>>()) ||
2731 Inv
.invalidate
<ScopAnalysis
>(F
, PA
) ||
2732 Inv
.invalidate
<ScalarEvolutionAnalysis
>(F
, PA
) ||
2733 Inv
.invalidate
<LoopAnalysis
>(F
, PA
) ||
2734 Inv
.invalidate
<AAManager
>(F
, PA
) ||
2735 Inv
.invalidate
<DominatorTreeAnalysis
>(F
, PA
) ||
2736 Inv
.invalidate
<AssumptionAnalysis
>(F
, PA
);
2739 AnalysisKey
ScopInfoAnalysis::Key
;
2741 ScopInfoAnalysis::Result
ScopInfoAnalysis::run(Function
&F
,
2742 FunctionAnalysisManager
&FAM
) {
2743 auto &SD
= FAM
.getResult
<ScopAnalysis
>(F
);
2744 auto &SE
= FAM
.getResult
<ScalarEvolutionAnalysis
>(F
);
2745 auto &LI
= FAM
.getResult
<LoopAnalysis
>(F
);
2746 auto &AA
= FAM
.getResult
<AAManager
>(F
);
2747 auto &DT
= FAM
.getResult
<DominatorTreeAnalysis
>(F
);
2748 auto &AC
= FAM
.getResult
<AssumptionAnalysis
>(F
);
2749 auto &DL
= F
.getParent()->getDataLayout();
2750 auto &ORE
= FAM
.getResult
<OptimizationRemarkEmitterAnalysis
>(F
);
2751 return {DL
, SD
, SE
, LI
, AA
, DT
, AC
, ORE
};
2754 PreservedAnalyses
ScopInfoPrinterPass::run(Function
&F
,
2755 FunctionAnalysisManager
&FAM
) {
2756 auto &SI
= FAM
.getResult
<ScopInfoAnalysis
>(F
);
2757 // Since the legacy PM processes Scops in bottom up, we print them in reverse
2758 // order here to keep the output persistent
2759 for (auto &It
: reverse(SI
)) {
2761 It
.second
->print(Stream
, PollyPrintInstructions
);
2763 Stream
<< "Invalid Scop!\n";
2765 return PreservedAnalyses::all();
2768 void ScopInfoWrapperPass::getAnalysisUsage(AnalysisUsage
&AU
) const {
2769 AU
.addRequired
<LoopInfoWrapperPass
>();
2770 AU
.addRequired
<RegionInfoPass
>();
2771 AU
.addRequired
<DominatorTreeWrapperPass
>();
2772 AU
.addRequiredTransitive
<ScalarEvolutionWrapperPass
>();
2773 AU
.addRequiredTransitive
<ScopDetectionWrapperPass
>();
2774 AU
.addRequired
<AAResultsWrapperPass
>();
2775 AU
.addRequired
<AssumptionCacheTracker
>();
2776 AU
.addRequired
<OptimizationRemarkEmitterWrapperPass
>();
2777 AU
.setPreservesAll();
2780 bool ScopInfoWrapperPass::runOnFunction(Function
&F
) {
2781 auto &SD
= getAnalysis
<ScopDetectionWrapperPass
>().getSD();
2782 auto &SE
= getAnalysis
<ScalarEvolutionWrapperPass
>().getSE();
2783 auto &LI
= getAnalysis
<LoopInfoWrapperPass
>().getLoopInfo();
2784 auto &AA
= getAnalysis
<AAResultsWrapperPass
>().getAAResults();
2785 auto const &DL
= F
.getParent()->getDataLayout();
2786 auto &DT
= getAnalysis
<DominatorTreeWrapperPass
>().getDomTree();
2787 auto &AC
= getAnalysis
<AssumptionCacheTracker
>().getAssumptionCache(F
);
2788 auto &ORE
= getAnalysis
<OptimizationRemarkEmitterWrapperPass
>().getORE();
2790 Result
.reset(new ScopInfo
{DL
, SD
, SE
, LI
, AA
, DT
, AC
, ORE
});
2794 void ScopInfoWrapperPass::print(raw_ostream
&OS
, const Module
*) const {
2795 for (auto &It
: *Result
) {
2797 It
.second
->print(OS
, PollyPrintInstructions
);
2799 OS
<< "Invalid Scop!\n";
2803 char ScopInfoWrapperPass::ID
= 0;
2805 Pass
*polly::createScopInfoWrapperPassPass() {
2806 return new ScopInfoWrapperPass();
2809 INITIALIZE_PASS_BEGIN(
2810 ScopInfoWrapperPass
, "polly-function-scops",
2811 "Polly - Create polyhedral description of all Scops of a function", false,
2813 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass
);
2814 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker
);
2815 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass
);
2816 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass
);
2817 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass
);
2818 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass
);
2819 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass
);
2820 INITIALIZE_PASS_END(
2821 ScopInfoWrapperPass
, "polly-function-scops",
2822 "Polly - Create polyhedral description of all Scops of a function", false,
2825 //===----------------------------------------------------------------------===//
2828 /// Print result from ScopInfoWrapperPass.
2829 class ScopInfoPrinterLegacyFunctionPass final
: public FunctionPass
{
2833 ScopInfoPrinterLegacyFunctionPass()
2834 : ScopInfoPrinterLegacyFunctionPass(outs()) {}
2835 explicit ScopInfoPrinterLegacyFunctionPass(llvm::raw_ostream
&OS
)
2836 : FunctionPass(ID
), OS(OS
) {}
2838 bool runOnFunction(Function
&F
) override
{
2839 ScopInfoWrapperPass
&P
= getAnalysis
<ScopInfoWrapperPass
>();
2841 OS
<< "Printing analysis '" << P
.getPassName() << "' for function '"
2842 << F
.getName() << "':\n";
2848 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
2849 FunctionPass::getAnalysisUsage(AU
);
2850 AU
.addRequired
<ScopInfoWrapperPass
>();
2851 AU
.setPreservesAll();
2855 llvm::raw_ostream
&OS
;
2858 char ScopInfoPrinterLegacyFunctionPass::ID
= 0;
2861 Pass
*polly::createScopInfoPrinterLegacyFunctionPass(raw_ostream
&OS
) {
2862 return new ScopInfoPrinterLegacyFunctionPass(OS
);
2865 INITIALIZE_PASS_BEGIN(
2866 ScopInfoPrinterLegacyFunctionPass
, "polly-print-function-scops",
2867 "Polly - Print polyhedral description of all Scops of a function", false,
2869 INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass
);
2870 INITIALIZE_PASS_END(
2871 ScopInfoPrinterLegacyFunctionPass
, "polly-print-function-scops",
2872 "Polly - Print polyhedral description of all Scops of a function", false,