156#include "llvm/ADT/Statistic.h"
157#include "llvm/Support/raw_ostream.h"
160#define DEBUG_TYPE "polly-zone"
162STATISTIC(NumIncompatibleArrays,
"Number of not zone-analyzable arrays");
163STATISTIC(NumCompatibleArrays,
"Number of zone-analyzable arrays");
165STATISTIC(NumNormalizablePHIs,
"Number of normalizable PHIs");
166STATISTIC(NumPHINormialization,
"Number of PHI executed normalizations");
168using namespace polly;
173 bool InclDef,
bool InclRedef) {
201 return ReachDefs.curry().range().unwrap();
258 Result = Result.
unite(Map);
264 : PassName(PassName), IslCtx(
S->getSharedIslCtx()),
S(
S), LI(LI),
265 Schedule(
S->getSchedule()) {
266 auto Domains =
S->getDomains();
300 for (
auto *MA : *Stmt) {
301 if (!MA->isLatestArrayKind() || !MA->isMustWrite() ||
302 !MA->isOriginalArrayKind())
306 V = MA->getAccessValue();
310 if (V != MA->getAccessValue())
320 return !OuterLoop || OuterLoop->contains(InnerLoop);
331 for (
auto *MA : *Stmt) {
332 if (!MA->isOriginalArrayKind())
341 AllElts = AllElts.
unite(ArrayElts);
345 if (!
Stores.is_disjoint(AccRel)) {
347 dbgs() <<
"Load after store of same element in same statement\n");
348 OptimizationRemarkMissed R(
PassName,
"LoadAfterStore",
349 MA->getAccessInstruction());
350 R <<
"load after store of same element in same statement";
351 R <<
" (previous stores: " <<
Stores;
352 R <<
", loading: " << AccRel <<
")";
353 S->getFunction().getContext().diagnose(R);
355 IncompatibleElts = IncompatibleElts.
unite(ArrayElts);
358 Loads = Loads.
unite(AccRel);
365 if (Stmt->
isRegionStmt() && !Loads.is_disjoint(AccRel)) {
366 POLLY_DEBUG(dbgs() <<
"WRITE in non-affine subregion not supported\n");
367 OptimizationRemarkMissed R(
PassName,
"StoreInSubregion",
368 MA->getAccessInstruction());
369 R <<
"store is in a non-affine subregion";
370 S->getFunction().getContext().diagnose(R);
372 IncompatibleElts = IncompatibleElts.
unite(ArrayElts);
377 POLLY_DEBUG(dbgs() <<
"WRITE after WRITE to same element\n");
378 OptimizationRemarkMissed R(
PassName,
"StoreAfterStore",
379 MA->getAccessInstruction());
380 R <<
"store after store of same element in same statement";
381 R <<
" (previous stores: " <<
Stores;
382 R <<
", storing: " << AccRel <<
")";
383 S->getFunction().getContext().diagnose(R);
385 IncompatibleElts = IncompatibleElts.
unite(ArrayElts);
404 Load, Stmt,
LI->getLoopFor(Load->getParent()), Stmt->
isBlockStmt());
436 if (
auto *Memset = dyn_cast<MemSetInst>(AccInst)) {
437 auto *WrittenConstant = dyn_cast<Constant>(Memset->getValue());
439 if (WrittenConstant && WrittenConstant->isZeroValue()) {
440 Constant *Zero = Constant::getNullValue(Ty);
464 if (WriteValInstance.
is_null())
512 SmallVector<const PHINode *, 8> Worklist;
513 SmallPtrSet<const PHINode *, 8> Visited;
514 Worklist.push_back(
PHI);
516 while (!Worklist.empty()) {
517 const PHINode *Cur = Worklist.pop_back_val();
519 if (Visited.count(Cur))
523 for (
const Use &Incoming : Cur->incoming_values()) {
524 Value *IncomingVal = Incoming.get();
525 auto *IncomingPHI = dyn_cast<PHINode>(IncomingVal);
529 if (IncomingPHI ==
PHI)
531 Worklist.push_back(IncomingPHI);
549 isl::set DefinedContext =
S->getDefinedBehaviorContext();
561 PHIWriteScatter = PHIWriteScatter.
unite(Scatter);
608 for (
auto &Stmt : *
S)
634 auto Result =
singleton(std::move(UResult), std::move(ResultSpace));
656 if (TargetStmt == DefStmt)
685 if (Result.
is_null() &&
S->isOriginalSchedule() &&
709 if (!Result.is_null())
725 return StmtResult.intersect_range(DomainDef);
765 switch (VUse.getKind()) {
776 auto *ScevExpr = VUse.getScevExpr();
777 auto UseDomainSpace = DomainUse.get_space();
783 const_cast<SCEV *
>(ScevExpr)));
785 auto ScevSpace = UseDomainSpace.drop_dims(
isl::dim::set, 0, 0);
805 auto Result = ValInstSet.domain_map().reverse();
813 auto *Inst = cast<Instruction>(Val);
814 auto *ValStmt =
S->getStmtFor(Inst);
820 return ::makeUnknownForDomain(DomainUse);
832 auto Result = UsedInstance.range_product(ValInstSet);
838 llvm_unreachable(
"Unhandled use type");
849 const DenseSet<PHINode *> &ComputedPHIs,
859 Result = Result.
unite(Map);
863 auto *
PHI = dyn_cast<PHINode>(
static_cast<Value *
>(
867 if (!ComputedPHIs.count(
PHI)) {
868 Result = Result.
unite(Map);
874 Result = Result.
unite(Mapped);
875 NumPHINormialization++;
896 return isa<StoreInst>(AccInst) || isa<LoadInst>(AccInst);
918 auto Incomings =
S->getPHIIncomings(SAI);
920 if (Incoming->getIncoming().size() != 1)
977 for (
auto &Stmt : *
S) {
978 for (
auto *MA : Stmt) {
979 if (!MA->isLatestArrayKind())
1004 if (!MA->isPHIKind())
1011 auto *
PHI = cast<PHINode>(MA->getAccessInstruction());
1023 DenseSet<PHINode *> AllPHIs;
1026 if (!MA->isOriginalPHIKind())
1033 auto *
PHI = cast<PHINode>(MA->getAccessInstruction());
1051 ScopStmt *IncomingStmt = MA->getStatement();
1053 auto Incoming = MA->getIncoming();
1054 assert(Incoming.size() == 1 &&
"The incoming value must be "
1055 "representable by something else than "
1057 Value *IncomingVal = Incoming[0].second;
1063 IncomingValInsts = IncomingValInsts.
unite(IncomingValInst);
1076 AllPHIs.insert(
PHI);
1079 AllPHIMaps = AllPHIMaps.
unite(PHIMap);
1080 NumNormalizablePHIs++;
1093 OS.indent(Indent) <<
"After accesses {\n";
1094 for (
auto &Stmt : *
S) {
1095 OS.indent(Indent + 4) << Stmt.getBaseName() <<
"\n";
1096 for (
auto *MA : Stmt)
1099 OS.indent(Indent) <<
"}\n";
1110 return EltReachdDef.
apply_range(AllKnownWriteValInst);
1162 bool FromRead)
const {
static bool isRecursivePHI(const PHINode *PHI)
Return whether PHI refers (also transitively through other PHIs) to itself.
static bool isMapToUnknown(const isl::map &Map)
Return whether Map maps to an unknown value.
static bool isInsideLoop(Loop *OuterLoop, Loop *InnerLoop)
Is InnerLoop nested inside OuterLoop?
static bool onlySameValueWrites(ScopStmt *Stmt)
Check if all stores in Stmt store the very same value.
static isl::union_map computeScalarReachingDefinition(isl::union_map Schedule, isl::union_set Writes, bool InclDef, bool InclRedef)
Compute the reaching definition of a scalar.
static isl::map makeUnknownForDomain(isl::set Domain)
Create a domain-to-unknown value mapping.
static isl::union_map normalizeValInst(isl::union_map Input, const DenseSet< PHINode * > &ComputedPHIs, isl::union_map NormalizeMap)
Remove all computed PHIs out of Input and replace by their incoming value.
static isl::union_map computeReachingDefinition(isl::union_map Schedule, isl::union_map Writes, bool InclDef, bool InclRedef)
STATISTIC(NumIncompatibleArrays, "Number of not zone-analyzable arrays")
static isl::id alloc(isl::ctx ctx, const std::string &name, void *user)
isl::map equate(isl::dim type1, int pos1, isl::dim type2, int pos2) const
isl::map intersect_params(isl::set params) const
static isl::map from_domain_and_range(isl::set domain, isl::set range)
isl::map intersect_range(isl::set set) const
isl::map apply_range(isl::map map2) const
static isl::map from_domain(isl::set set)
isl::map apply_domain(isl::map map2) const
static isl::map identity(isl::space space)
boolean is_single_valued() const
isl::space get_space() const
isl::map domain_map() const
isl::map intersect_domain(isl::set set) const
isl::id get_tuple_id() const
static isl::set universe(isl::space space)
class size tuple_dim() const
isl::space get_space() const
isl::set remove_redundancies() const
isl::space set_tuple_id(isl::dim type, isl::id id) const
isl::space map_from_domain_and_range(isl::space range) const
boolean has_tuple_id(isl::dim type) const
class size dim(isl::dim type) const
isl::id get_tuple_id(isl::dim type) const
isl::space unwrap() const
isl::space set_from_params() const
boolean is_wrapping() const
isl::union_set range() const
isl::map extract_map(isl::space space) const
isl::union_map reverse() const
isl::union_map curry() const
isl::union_set wrap() const
isl::union_map unite(isl::union_map umap2) const
isl::union_set domain() const
isl::map_list get_map_list() const
isl::space get_space() const
isl::union_map apply_domain(isl::union_map umap2) const
static isl::union_map from_domain(isl::union_set uset)
isl::union_map apply_range(isl::union_map umap2) const
isl::union_map range_product(isl::union_map umap2) const
boolean is_injective() const
static isl::union_map empty(isl::ctx ctx)
boolean is_single_valued() const
isl::union_map domain_map() const
isl::union_map intersect_domain(isl::space space) const
static isl::union_map from_domain_and_range(isl::union_set domain, isl::union_set range)
__isl_keep isl_union_set * get() const
static isl::union_set empty(isl::ctx ctx)
isl::union_set subtract(isl::union_set uset2) const
isl::union_set unite(isl::union_set uset2) const
Represent memory accesses in statements.
const ScopArrayInfo * getLatestScopArrayInfo() const
Get the ScopArrayInfo object for the base address, or the one set by setNewAccessRelation().
bool isOriginalArrayKind() const
Whether this is an access of an explicit load or store in the IR.
isl::map getLatestAccessRelation() const
Return the newest access relation of this access.
bool isLatestArrayKind() const
Whether storage memory is either an custom .s2a/.phiops alloca (false) or an existing pointer into an...
bool isWrite() const
Is this a write memory access?
const ScopArrayInfo * getOriginalScopArrayInfo() const
Get the detection-time ScopArrayInfo object for the base address.
Instruction * getAccessInstruction() const
Return the access instruction of this memory access.
bool isRead() const
Is this a read memory access?
bool isMustWrite() const
Is this a must-write memory access?
bool isOriginalPHIKind() const
Was this MemoryAccess detected as a special PHI node access?
ScopStmt * getStatement() const
Get the statement that contains this memory access.
bool isMayWrite() const
Is this a may-write memory access?
Value * getAccessValue() const
Return the access value of this memory access.
A class to store information about arrays in the SCoP.
bool isPHIKind() const
Is this array info modeling special PHI node memory?
Value * getBasePtr() const
Return the base pointer.
Type * getElementType() const
Get the canonical element type of this array.
bool isBlockStmt() const
Return true if this statement represents a single basic block.
bool isRegionStmt() const
Return true if this statement represents a whole region.
isl::set getDomain() const
Get the iteration domain of this ScopStmt.
Loop * getSurroundingLoop() const
Return the closest innermost loop that contains this statement, but is not contained in it.
isl::space getDomainSpace() const
Get the space of the iteration domain.
static VirtualUse create(Scop *S, const Use &U, LoopInfo *LI, bool Virtual)
Get a VirtualUse for an llvm::Use.
isl::map makeUnknownForDomain(ScopStmt *Stmt) const
Create a statement-to-unknown value mapping.
isl::union_map Schedule
Cached version of the schedule and domains.
llvm::DenseMap< std::pair< ScopStmt *, ScopStmt * >, isl::map > DefToTargetCache
A cache for getDefToTarget().
isl::union_map AllReads
Combined access relations of all MemoryKind::Array READ accesses.
isl::union_set makeEmptyUnionSet() const
bool isNormalizable(MemoryAccess *MA)
Is MA a PHI READ access that can be normalized?
isl::union_map makeEmptyUnionMap() const
isl::set makeValueSet(llvm::Value *V)
Create a set with the llvm::Value V which is available everywhere.
void printAccesses(llvm::raw_ostream &OS, int Indent=0) const
Print the current state of all MemoryAccesses to .
isl::space ParamSpace
Parameter space that does not need realignment.
llvm::LoopInfo * LI
LoopInfo analysis used to determine whether values are synthesizable.
isl::set getDomainFor(ScopStmt *Stmt) const
Get the domain of Stmt.
ZoneAlgorithm(const char *PassName, Scop *S, llvm::LoopInfo *LI)
Prepare the object before computing the zones of S.
isl::map makeValInst(llvm::Value *Val, ScopStmt *UserStmt, llvm::Loop *Scope, bool IsCertain=true)
Create a mapping from a statement instance to the instance of an llvm::Value that can be used in ther...
void collectCompatibleElts()
Find the array elements that can be used for zone analysis.
isl::space makeValueSpace(llvm::Value *V)
Create the space for an llvm::Value that is available everywhere.
const char * PassName
The name of the pass this is used from. Used for optimization remarks.
isl::union_map AllReadValInst
The loaded values (llvm::LoadInst) of all reads.
isl::map getScatterFor(ScopStmt *Stmt) const
Get the schedule for Stmt.
void collectIncompatibleElts(ScopStmt *Stmt, isl::union_set &IncompatibleElts, isl::union_set &AllElts)
Find the array elements that violate the zone analysis assumptions.
isl::union_map computeKnownFromMustWrites() const
A reaching definition zone is known to have the definition's written value if the definition is a MUS...
isl::union_map makeNormalizedValInst(llvm::Value *Val, ScopStmt *UserStmt, llvm::Loop *Scope, bool IsCertain=true)
Create and normalize a ValInst.
isl::union_map AllWriteValInst
The value instances written to array elements of all write accesses.
isl::union_map NormalizeMap
For computed PHIs, contains the ValInst they stand for.
isl::union_map computePerPHI(const polly::ScopArrayInfo *SAI)
For each 'execution' of a PHINode, get the incoming block that was executed before.
isl::union_map WriteReachDefZone
All reaching definitions for MemoryKind::Array writes.
void addArrayReadAccess(MemoryAccess *MA)
llvm::DenseMap< llvm::Value *, isl::id > ValueIds
Map llvm::Values to an isl identifier.
void computeNormalizedPHIs()
Compute the normalization map that replaces PHIs by their incoming values.
isl::union_map AllMayWrites
Combined access relations of all MemoryKind::Array, MAY_WRITE accesses.
isl::map computeUseToDefFlowDependency(ScopStmt *UseStmt, ScopStmt *DefStmt)
For an llvm::Value defined in DefStmt, compute the RAW dependency for a use in every instance of UseS...
isl::id makeValueId(llvm::Value *V)
Create an isl_id that represents V.
llvm::DenseMap< ScopStmt *, isl::map > ScalarReachDefZone
Cached reaching definitions for each ScopStmt.
llvm::SmallDenseMap< llvm::PHINode *, isl::union_map > PerPHIMaps
Cache for computePerPHI(const ScopArrayInfo *)
llvm::DenseSet< llvm::PHINode * > ComputedPHIs
PHIs that have been computed.
isl::union_map computeKnownFromLoad() const
A reaching definition zone is known to be the same value as any load that reads from that array eleme...
isl::map getDefToTarget(ScopStmt *DefStmt, ScopStmt *TargetStmt)
Get a domain translation map from a (scalar) definition to the statement where the definition is bein...
isl::union_map getWrittenValue(MemoryAccess *MA, isl::map AccRel)
Return the ValInst write by a (must-)write access.
void computeCommon()
Compute the different zones.
llvm::SmallPtrSet< llvm::PHINode *, 4 > RecursivePHIs
List of PHIs that may transitively refer to themselves.
isl::space ScatterSpace
Space the schedule maps to.
isl::union_map computeKnown(bool FromWrite, bool FromRead) const
Compute which value an array element stores at every instant.
isl::map getScalarReachingDefinition(ScopStmt *Stmt)
Get the reaching definition of a scalar defined in Stmt.
isl::union_set CompatibleElts
Set of array elements that can be reliably used for zone analysis.
isl::union_map AllMustWrites
Combined access relations of all MemoryKind::Array, MUST_WRITE accesses.
std::shared_ptr< isl_ctx > IslCtx
Hold a reference to the isl_ctx to avoid it being freed before we released all of the isl objects.
isl::boolean isNormalized(isl::map Map)
isl::map getAccessRelationFor(MemoryAccess *MA) const
Get the access relation of MA.
void addArrayWriteAccess(MemoryAccess *MA)
bool isCompatibleAccess(MemoryAccess *MA)
Return whether MA can be used for transformations (e.g.
isl::union_map AllWrites
Combined access relations of all MK_Array write accesses (union of AllMayWrites and AllMustWrites).
void * isl_id_get_user(__isl_keep isl_id *id)
__isl_give isl_id * isl_id_alloc(isl_ctx *ctx, __isl_keep const char *name, void *user)
boolean manage(isl_bool val)
This file contains the declaration of the PolyhedralInfo class, which will provide an interface to ex...
std::string getIslCompatibleName(const std::string &Prefix, const llvm::Value *Val, long Number, const std::string &Suffix, bool UseInstructionNames)
Combine Prefix, Val (or Number) and Suffix to an isl-compatible name.
isl::union_map makeUnknownForDomain(isl::union_set Domain)
Create a domain-to-unknown value mapping.
isl::map beforeScatter(isl::map Map, bool Strict)
Return the range elements that are lexicographically smaller.
isl::union_map computeReachingWrite(isl::union_map Schedule, isl::union_map Writes, bool Reverse, bool InclPrevDef, bool InclNextDef)
Compute the reaching definition statement or the next overwrite for each definition of an array eleme...
@ Value
MemoryKind::Value: Models an llvm::Value.
@ PHI
MemoryKind::PHI: Models PHI nodes within the SCoP.
isl::map distributeDomain(isl::map Map)
Distribute the domain to the tuples of a wrapped range map.
llvm::iota_range< unsigned > rangeIslSize(unsigned Begin, isl::size End)
Check that End is valid and return an iterator from Begin to End.
isl::map intersectRange(isl::map Map, isl::union_set Range)
Intersect the range of Map with Range.
isl::union_set convertZoneToTimepoints(isl::union_set Zone, bool InclStart, bool InclEnd)
Convert a zone (range between timepoints) to timepoints.
isl::map singleton(isl::union_map UMap, isl::space ExpectedSpace)
If by construction a union map is known to contain only a single map, return it.
isl::union_map filterKnownValInst(const isl::union_map &UMap)
Return only the mappings that map to known values.
isl::space getScatterSpace(const isl::union_map &Schedule)
Return the scatter space of a Schedule.
static TupleKindPtr Domain("Domain")
isl_size isl_union_set_n_set(__isl_keep isl_union_set *uset)