[polly] r270416 - Optimistic assume required invariant loads to be invariant
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Mon May 23 03:40:58 PDT 2016
Author: jdoerfert
Date: Mon May 23 05:40:54 2016
New Revision: 270416
URL: http://llvm.org/viewvc/llvm-project?rev=270416&view=rev
Log:
Optimistic assume required invariant loads to be invariant
Before this patch we bailed if a required invariant load was potentially
overwritten. However, now we will optimistically assume it is actually
invariant and, to this end, restrict the valid parameter space as well as the
execution context with regards to potential overwrites of the location.
Added:
polly/trunk/test/ScopInfo/partially_invariant_load_1.ll
polly/trunk/test/ScopInfo/partially_invariant_load_2.ll
Modified:
polly/trunk/include/polly/ScopInfo.h
polly/trunk/lib/Analysis/ScopInfo.cpp
polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll
polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll
polly/trunk/test/ScopInfo/remarks.ll
Modified: polly/trunk/include/polly/ScopInfo.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopInfo.h?rev=270416&r1=270415&r2=270416&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopInfo.h (original)
+++ polly/trunk/include/polly/ScopInfo.h Mon May 23 05:40:54 2016
@@ -913,6 +913,18 @@ llvm::raw_ostream &operator<<(llvm::raw_
/// @brief Ordered list type to hold accesses.
using MemoryAccessList = std::forward_list<MemoryAccess *>;
+/// @brief Helper structure for invariant memory accesses.
+struct InvariantAccess {
+ /// @brief The memory access that is (partially) invariant.
+ MemoryAccess *MA;
+
+ /// @brief The context under which the access is not invariant.
+ isl_set *NonHoistableCtx;
+};
+
+/// @brief Ordered container type to hold invariant accesses.
+using InvariantAccessesTy = SmallVector<InvariantAccess, 8>;
+
/// @brief Type for equivalent invariant accesses and their domain context.
///
/// The first element is the SCEV for the pointer/location that identifies this
@@ -1223,7 +1235,7 @@ public:
///
/// Note that scalar accesses that are caused by any access in @p InvMAs will
/// be eliminated too.
- void removeMemoryAccesses(MemoryAccessList &InvMAs);
+ void removeMemoryAccesses(InvariantAccessesTy &InvMAs);
typedef MemoryAccessVec::iterator iterator;
typedef MemoryAccessVec::const_iterator const_iterator;
@@ -1627,14 +1639,15 @@ private:
/// invariant location.
void buildInvariantEquivalenceClasses();
- /// @brief Check if a memory access can be hoisted.
+ /// @brief Return the context under which the access cannot be hoisted.
///
- /// @param Access The access to verify.
+ /// @param Access The access to check.
/// @param Writes The set of all memory writes in the scop.
///
- /// @return Return true if a memory access can be hoisted.
- bool isHoistableAccess(MemoryAccess *Access,
- __isl_keep isl_union_map *Writes);
+ /// @return Return the context under which the access cannot be hoisted or a
+ /// nullptr if it cannot be hoisted at all.
+ __isl_give isl_set *getNonHoistableCtx(MemoryAccess *Access,
+ __isl_keep isl_union_map *Writes);
/// @brief Verify that all required invariant loads have been hoisted.
///
@@ -1673,7 +1686,7 @@ private:
void hoistInvariantLoads();
/// @brief Add invariant loads listed in @p InvMAs with the domain of @p Stmt.
- void addInvariantLoads(ScopStmt &Stmt, MemoryAccessList &InvMAs);
+ void addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs);
/// @brief Create an id for @p Param and store it in the ParameterIds map.
void createParameterId(const SCEV *Param);
@@ -2047,6 +2060,11 @@ public:
/// @brief Add @p LI to the set of required invariant loads.
void addRequiredInvariantLoad(LoadInst *LI) { DC.RequiredILS.insert(LI); }
+ /// @brief Return true if and only if @p LI is a required invariant load.
+ bool isRequiredInvariantLoad(LoadInst *LI) const {
+ return getRequiredInvariantLoads().count(LI);
+ }
+
const BoxedLoopsSetTy &getBoxedLoops() const { return DC.BoxedLoopsSet; }
bool isNonAffineSubRegion(const Region *R) {
Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=270416&r1=270415&r2=270416&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Mon May 23 05:40:54 2016
@@ -1711,14 +1711,15 @@ void ScopStmt::print(raw_ostream &OS) co
void ScopStmt::dump() const { print(dbgs()); }
-void ScopStmt::removeMemoryAccesses(MemoryAccessList &InvMAs) {
+void ScopStmt::removeMemoryAccesses(InvariantAccessesTy &InvMAs) {
// Remove all memory accesses in @p InvMAs from this statement
// together with all scalar accesses that were caused by them.
// MK_Value READs have no access instruction, hence would not be removed by
// this function. However, it is only used for invariant LoadInst accesses,
// its arguments are always affine, hence synthesizable, and therefore there
// are no MK_Value READ accesses to be removed.
- for (MemoryAccess *MA : InvMAs) {
+ for (const auto &InvMA : InvMAs) {
+ auto *MA = InvMA.MA;
auto Predicate = [&](MemoryAccess *Acc) {
return Acc->getAccessInstruction() == MA->getAccessInstruction();
};
@@ -2855,8 +2856,12 @@ MemoryAccess *Scop::lookupBasePtrAccess(
bool Scop::hasNonHoistableBasePtrInScop(MemoryAccess *MA,
__isl_keep isl_union_map *Writes) {
- if (auto *BasePtrMA = lookupBasePtrAccess(MA))
- return !isHoistableAccess(BasePtrMA, Writes);
+ if (auto *BasePtrMA = lookupBasePtrAccess(MA)) {
+ auto *NHCtx = getNonHoistableCtx(BasePtrMA, Writes);
+ bool Hoistable = NHCtx != nullptr;
+ isl_set_free(NHCtx);
+ return !Hoistable;
+ }
auto *BaseAddr = SE->getSCEV(MA->getBaseAddr());
auto *PointerBase = dyn_cast<SCEVUnknown>(SE->getPointerBase(BaseAddr));
@@ -3278,7 +3283,8 @@ InvariantEquivClassTy *Scop::lookupInvar
/// @brief Check if @p MA can always be hoisted without execution context.
static bool canAlwaysBeHoisted(MemoryAccess *MA, bool StmtInvalidCtxIsEmpty,
- bool MAInvalidCtxIsEmpty) {
+ bool MAInvalidCtxIsEmpty,
+ bool NonHoistableCtxIsEmpty) {
LoadInst *LInst = cast<LoadInst>(MA->getAccessInstruction());
const DataLayout &DL = LInst->getParent()->getModule()->getDataLayout();
// TODO: We can provide more information for better but more expensive
@@ -3287,6 +3293,12 @@ static bool canAlwaysBeHoisted(MemoryAcc
LInst->getAlignment(), DL))
return false;
+ // If the location might be overwritten we do not hoist it unconditionally.
+ //
+ // TODO: This is probably to conservative.
+ if (!NonHoistableCtxIsEmpty)
+ return false;
+
// If a dereferencable load is in a statement that is modeled precisely we can
// hoist it.
if (StmtInvalidCtxIsEmpty && MAInvalidCtxIsEmpty)
@@ -3301,7 +3313,7 @@ static bool canAlwaysBeHoisted(MemoryAcc
return true;
}
-void Scop::addInvariantLoads(ScopStmt &Stmt, MemoryAccessList &InvMAs) {
+void Scop::addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs) {
if (InvMAs.empty())
return;
@@ -3315,9 +3327,11 @@ void Scop::addInvariantLoads(ScopStmt &S
DomainCtx = isl_set_subtract(DomainCtx, StmtInvalidCtx);
if (isl_set_n_basic_set(DomainCtx) >= MaxDisjunctionsInDomain) {
- auto *AccInst = InvMAs.front()->getAccessInstruction();
+ auto *AccInst = InvMAs.front().MA->getAccessInstruction();
invalidate(COMPLEXITY, AccInst->getDebugLoc());
isl_set_free(DomainCtx);
+ for (auto &InvMA : InvMAs)
+ isl_set_free(InvMA.NonHoistableCtx);
return;
}
@@ -3326,7 +3340,8 @@ void Scop::addInvariantLoads(ScopStmt &S
// hoisted loads are executed and we could not determine an order in which to
// pre-load them. This happens because not only lower bounds are part of the
// domain but also upper bounds.
- for (MemoryAccess *MA : InvMAs) {
+ for (auto &InvMA : InvMAs) {
+ auto *MA = InvMA.MA;
Instruction *AccInst = MA->getAccessInstruction();
if (SE->isSCEVable(AccInst->getType())) {
SetVector<Value *> Values;
@@ -3345,7 +3360,10 @@ void Scop::addInvariantLoads(ScopStmt &S
}
}
- for (MemoryAccess *MA : InvMAs) {
+ for (auto &InvMA : InvMAs) {
+ auto *MA = InvMA.MA;
+ auto *NHCtx = InvMA.NonHoistableCtx;
+
// Check for another invariant access that accesses the same location as
// MA and if found consolidate them. Otherwise create a new equivalence
// class at the end of InvariantEquivClasses.
@@ -3354,16 +3372,19 @@ void Scop::addInvariantLoads(ScopStmt &S
const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand());
auto *MAInvalidCtx = MA->getInvalidContext();
+ bool NonHoistableCtxIsEmpty = isl_set_is_empty(NHCtx);
bool MAInvalidCtxIsEmpty = isl_set_is_empty(MAInvalidCtx);
isl_set *MACtx;
// Check if we know that this pointer can be speculatively accessed.
- if (canAlwaysBeHoisted(MA, StmtInvalidCtxIsEmpty, MAInvalidCtxIsEmpty)) {
+ if (canAlwaysBeHoisted(MA, StmtInvalidCtxIsEmpty, MAInvalidCtxIsEmpty,
+ NonHoistableCtxIsEmpty)) {
MACtx = isl_set_universe(isl_set_get_space(DomainCtx));
isl_set_free(MAInvalidCtx);
+ isl_set_free(NHCtx);
} else {
MACtx = isl_set_copy(DomainCtx);
- MACtx = isl_set_subtract(MACtx, MAInvalidCtx);
+ MACtx = isl_set_subtract(MACtx, isl_set_union(MAInvalidCtx, NHCtx));
MACtx = isl_set_gist_params(MACtx, getContext());
}
@@ -3418,8 +3439,8 @@ void Scop::addInvariantLoads(ScopStmt &S
isl_set_free(DomainCtx);
}
-bool Scop::isHoistableAccess(MemoryAccess *Access,
- __isl_keep isl_union_map *Writes) {
+__isl_give isl_set *Scop::getNonHoistableCtx(MemoryAccess *Access,
+ __isl_keep isl_union_map *Writes) {
// TODO: Loads that are not loop carried, hence are in a statement with
// zero iterators, are by construction invariant, though we
// currently "hoist" them anyway. This is necessary because we allow
@@ -3430,7 +3451,7 @@ bool Scop::isHoistableAccess(MemoryAcces
BasicBlock *BB = Stmt.getEntryBlock();
if (Access->isScalarKind() || Access->isWrite() || !Access->isAffine())
- return false;
+ return nullptr;
// Skip accesses that have an invariant base pointer which is defined but
// not loaded inside the SCoP. This can happened e.g., if a readnone call
@@ -3441,14 +3462,14 @@ bool Scop::isHoistableAccess(MemoryAcces
// that it is invariant, thus it will be hoisted too. However, if there is
// no base pointer origin we check that the base pointer is defined
// outside the region.
+ auto *LI = cast<LoadInst>(Access->getAccessInstruction());
if (hasNonHoistableBasePtrInScop(Access, Writes))
- return false;
+ return nullptr;
// Skip accesses in non-affine subregions as they might not be executed
// under the same condition as the entry of the non-affine subregion.
- auto *LI = cast<LoadInst>(Access->getAccessInstruction());
if (BB != LI->getParent())
- return false;
+ return nullptr;
isl_map *AccessRelation = Access->getAccessRelation();
assert(!isl_map_is_empty(AccessRelation));
@@ -3456,7 +3477,7 @@ bool Scop::isHoistableAccess(MemoryAcces
if (isl_map_involves_dims(AccessRelation, isl_dim_in, 0,
Stmt.getNumIterators())) {
isl_map_free(AccessRelation);
- return false;
+ return nullptr;
}
AccessRelation = isl_map_intersect_domain(AccessRelation, Stmt.getDomain());
@@ -3464,10 +3485,22 @@ bool Scop::isHoistableAccess(MemoryAcces
isl_union_map *Written = isl_union_map_intersect_range(
isl_union_map_copy(Writes), isl_union_set_from_set(AccessRange));
- bool IsWritten = !isl_union_map_is_empty(Written);
- isl_union_map_free(Written);
+ auto *WrittenCtx = isl_union_map_params(Written);
+ bool IsWritten = !isl_set_is_empty(WrittenCtx);
- return !IsWritten;
+ if (!IsWritten)
+ return WrittenCtx;
+
+ WrittenCtx = isl_set_remove_divs(WrittenCtx);
+ bool TooComplex = isl_set_n_basic_set(WrittenCtx) >= MaxDisjunctionsInDomain;
+ if (TooComplex || !isRequiredInvariantLoad(LI)) {
+ isl_set_free(WrittenCtx);
+ return nullptr;
+ }
+
+ addAssumption(INVARIANTLOAD, isl_set_copy(WrittenCtx), LI->getDebugLoc(),
+ AS_RESTRICTION);
+ return WrittenCtx;
}
void Scop::verifyInvariantLoads() {
@@ -3488,18 +3521,11 @@ void Scop::hoistInvariantLoads() {
isl_union_map *Writes = getWrites();
for (ScopStmt &Stmt : *this) {
- MemoryAccessList InvariantAccesses;
+ InvariantAccessesTy InvariantAccesses;
for (MemoryAccess *Access : Stmt)
- if (isHoistableAccess(Access, Writes))
- InvariantAccesses.push_front(Access);
-
- // We inserted invariant accesses always in the front but need them to be
- // sorted in a "natural order". The statements are already sorted in
- // reverse post order and that suffices for the accesses too. The reason
- // we require an order in the first place is the dependences between
- // invariant loads that can be caused by indirect loads.
- InvariantAccesses.reverse();
+ if (auto *NHCtx = getNonHoistableCtx(Access, Writes))
+ InvariantAccesses.push_back({Access, NHCtx});
// Transfer the memory access from the statement to the SCoP.
Stmt.removeMemoryAccesses(InvariantAccesses);
Modified: polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll?rev=270416&r1=270415&r2=270416&view=diff
==============================================================================
--- polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll (original)
+++ polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_affine_loop.ll Mon May 23 05:40:54 2016
@@ -9,8 +9,7 @@
; Negative test for INNERMOST.
; At the moment we will optimistically assume A[i] in the conditional before the inner
; loop might be invariant and expand the SCoP from the loop to include the conditional. However,
-; during SCoP generation we will realize that A[i] is in fact not invariant (in this region = the body
-; of the outer loop) and bail.
+; during SCoP generation we will realize that A[i] is in not always invariant.
;
; Possible solutions could be:
; - Do not optimistically assume it to be invariant (as before this commit), however we would loose
@@ -18,7 +17,51 @@
; - Reduce the size of the SCoP if an assumed invariant access is in fact not invariant instead of
; rejecting the whole region.
;
-; INNERMOST-NOT: Function: f
+; INNERMOST: Function: f
+; INNERMOST-NEXT: Region: %bb4---%bb3
+; INNERMOST-NEXT: Max Loop Depth: 1
+; INNERMOST-NEXT: Invariant Accesses: {
+; INNERMOST-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb4[] -> MemRef_A[p_2] };
+; INNERMOST-NEXT: Execution Context: [tmp6, N, p_2] -> { : (tmp6 > 0 and p_2 >= N) or (tmp6 < 0 and p_2 >= N) or tmp6 = 0 }
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Context:
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { : -2147483648 <= tmp6 <= 2147483647 and -2147483648 <= N <= 2147483647 and 0 <= p_2 <= 1024 }
+; INNERMOST-NEXT: Assumed Context:
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { : }
+; INNERMOST-NEXT: Invalid Context:
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { : p_2 < N and (tmp6 < 0 or tmp6 > 0) }
+; INNERMOST-NEXT: p0: %tmp6
+; INNERMOST-NEXT: p1: %N
+; INNERMOST-NEXT: p2: {0,+,1}<nuw><nsw><%bb3>
+; INNERMOST-NEXT: Arrays {
+; INNERMOST-NEXT: i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT: i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Arrays (Bounds as pw_affs) {
+; INNERMOST-NEXT: i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT: i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Alias Groups (0):
+; INNERMOST-NEXT: n/a
+; INNERMOST-NEXT: Statements {
+; INNERMOST-NEXT: Stmt_bb11
+; INNERMOST-NEXT: Domain :=
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb11[i0] : 0 <= i0 < N and (tmp6 < 0 or tmp6 > 0) };
+; INNERMOST-NEXT: Schedule :=
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb11[i0] -> [0, i0] : tmp6 < 0 or tmp6 > 0 };
+; INNERMOST-NEXT: ReadAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb11[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT: MustWriteAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb11[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT: Stmt_bb18
+; INNERMOST-NEXT: Domain :=
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb18[] };
+; INNERMOST-NEXT: Schedule :=
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb18[] -> [1, 0] };
+; INNERMOST-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT: [tmp6, N, p_2] -> { Stmt_bb18[] -> MemRef_indvars_iv_next2[] };
+; INNERMOST-NEXT: }
;
; ALL: Function: f
; ALL-NEXT: Region: %bb3---%bb19
Modified: polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll?rev=270416&r1=270415&r2=270416&view=diff
==============================================================================
--- polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll (original)
+++ polly/trunk/test/ScopInfo/NonAffine/non_affine_conditional_surrounding_non_affine_loop.ll Mon May 23 05:40:54 2016
@@ -13,8 +13,7 @@
; Negative test for INNERMOST.
; At the moment we will optimistically assume A[i] in the conditional before the inner
; loop might be invariant and expand the SCoP from the loop to include the conditional. However,
-; during SCoP generation we will realize that A[i] is in fact not invariant (in this region = the body
-; of the outer loop) and bail.
+; during SCoP generation we will realize that A[i] is only sometimes invariant.
;
; Possible solutions could be:
; - Do not optimistically assume it to be invariant (as before this commit), however we would loose
@@ -22,7 +21,51 @@
; - Reduce the size of the SCoP if an assumed invariant access is in fact not invariant instead of
; rejecting the whole region.
;
-; INNERMOST-NOT: Function: f
+; INNERMOST: Function: f
+; INNERMOST-NEXT: Region: %bb4---%bb3
+; INNERMOST-NEXT: Max Loop Depth: 1
+; INNERMOST-NEXT: Invariant Accesses: {
+; INNERMOST-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb4[] -> MemRef_A[p_2] };
+; INNERMOST-NEXT: Execution Context: [tmp6, p_1, p_2] -> { : (tmp6 > 0 and p_2 >= p_1) or (tmp6 < 0 and p_2 >= p_1) or tmp6 = 0 }
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Context:
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { : -2147483648 <= tmp6 <= 2147483647 and -2199023255552 <= p_1 <= 2199023254528 and 0 <= p_2 <= 1024 }
+; INNERMOST-NEXT: Assumed Context:
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { : }
+; INNERMOST-NEXT: Invalid Context:
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { : p_2 < p_1 and (tmp6 < 0 or tmp6 > 0) }
+; INNERMOST-NEXT: p0: %tmp6
+; INNERMOST-NEXT: p1: {0,+,(sext i32 %N to i64)}<%bb3>
+; INNERMOST-NEXT: p2: {0,+,1}<nuw><nsw><%bb3>
+; INNERMOST-NEXT: Arrays {
+; INNERMOST-NEXT: i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT: i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Arrays (Bounds as pw_affs) {
+; INNERMOST-NEXT: i32 MemRef_A[*]; // Element size 4
+; INNERMOST-NEXT: i64 MemRef_indvars_iv_next2; // Element size 8
+; INNERMOST-NEXT: }
+; INNERMOST-NEXT: Alias Groups (0):
+; INNERMOST-NEXT: n/a
+; INNERMOST-NEXT: Statements {
+; INNERMOST-NEXT: Stmt_bb12
+; INNERMOST-NEXT: Domain :=
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb12[i0] : 0 <= i0 < p_1 and (tmp6 < 0 or tmp6 > 0) };
+; INNERMOST-NEXT: Schedule :=
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb12[i0] -> [0, i0] : tmp6 < 0 or tmp6 > 0 };
+; INNERMOST-NEXT: ReadAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb12[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT: MustWriteAccess := [Reduction Type: +] [Scalar: 0]
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb12[i0] -> MemRef_A[i0] };
+; INNERMOST-NEXT: Stmt_bb19
+; INNERMOST-NEXT: Domain :=
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb19[] };
+; INNERMOST-NEXT: Schedule :=
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb19[] -> [1, 0] };
+; INNERMOST-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
+; INNERMOST-NEXT: [tmp6, p_1, p_2] -> { Stmt_bb19[] -> MemRef_indvars_iv_next2[] };
+; INNERMOST-NEXT: }
;
; ALL: Function: f
; ALL-NEXT: Region: %bb3---%bb20
Added: polly/trunk/test/ScopInfo/partially_invariant_load_1.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/partially_invariant_load_1.ll?rev=270416&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/partially_invariant_load_1.ll (added)
+++ polly/trunk/test/ScopInfo/partially_invariant_load_1.ll Mon May 23 05:40:54 2016
@@ -0,0 +1,61 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+; RUN: opt %loadPolly -polly-codegen -S < %s | FileCheck %s --check-prefix=IR
+;
+; CHECK: Invariant Accesses: {
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: [N, tmp1] -> { Stmt_for_body[i0] -> MemRef_I[0] };
+; CHECK-NEXT: Execution Context: [N, tmp1] -> { : N > 0 and (tmp1 >= 43 or tmp1 <= 41) }
+; CHECK-NEXT: }
+; CHECK: Invalid Context:
+; CHECK-NEXT: [N, tmp1] -> { : tmp1 = 42 and N > 0 }
+;
+; IR: polly.preload.begin:
+; IR-NEXT: br i1 false, label %polly.start, label %for.cond
+;
+; void f(int *A, int *I, int N) {
+; for (int i = 0; i < N; i++) {
+; if (*I == 42)
+; *I = 0;
+; else
+; A[i]++;
+; }
+; }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %I, i32 %N) {
+entry:
+ %tmp = sext i32 %N to i64
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+ %cmp = icmp slt i64 %indvars.iv, %tmp
+ br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ %tmp1 = load i32, i32* %I, align 4
+ %cmp1 = icmp eq i32 %tmp1, 42
+ br i1 %cmp1, label %if.then, label %if.else
+
+if.then: ; preds = %for.body
+ store i32 0, i32* %I, align 4
+ br label %if.end
+
+if.else: ; preds = %for.body
+ %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+ %tmp2 = load i32, i32* %arrayidx, align 4
+ %inc = add nsw i32 %tmp2, 1
+ store i32 %inc, i32* %arrayidx, align 4
+ br label %if.end
+
+if.end: ; preds = %if.else, %if.then
+ br label %for.inc
+
+for.inc: ; preds = %if.end
+ %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ ret void
+}
Added: polly/trunk/test/ScopInfo/partially_invariant_load_2.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/partially_invariant_load_2.ll?rev=270416&view=auto
==============================================================================
--- polly/trunk/test/ScopInfo/partially_invariant_load_2.ll (added)
+++ polly/trunk/test/ScopInfo/partially_invariant_load_2.ll Mon May 23 05:40:54 2016
@@ -0,0 +1,70 @@
+; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
+;
+; Check that we do not try to preload *I and assume p != 42.
+;
+; CHECK: Invariant Accesses: {
+; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
+; CHECK-NEXT: [N, p, tmp1, q] -> { Stmt_if_then[i0] -> MemRef_I[0] };
+; CHECK-NEXT: Execution Context: [N, p, tmp1, q] -> { : 1 = 0 }
+; CHECK-NEXT: }
+;
+; CHECK: Invalid Context:
+; CHECK-NEXT: [N, p, tmp1, q] -> { : p = 42 and N > 0 }
+;
+; void f(int *A, int *I, int N, int p, int q) {
+; for (int i = 0; i < N; i++) {
+; if (p == 42) {
+; *I = 0;
+; if (*I == q)
+; A[i] *= 2;
+; }
+; A[i]++;
+; }
+; }
+;
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @f(i32* %A, i32* %I, i32 %N, i32 %p, i32 %q) {
+entry:
+ %tmp = sext i32 %N to i64
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %entry ]
+ %cmp = icmp slt i64 %indvars.iv, %tmp
+ br i1 %cmp, label %for.body, label %for.end
+
+for.body: ; preds = %for.cond
+ %cmp1 = icmp eq i32 %p, 42
+ br i1 %cmp1, label %if.then, label %if.end4
+
+if.then: ; preds = %for.body
+ store i32 0, i32* %I, align 4
+ %tmp1 = load i32, i32* %I, align 4
+ %cmp2 = icmp eq i32 %tmp1, %q
+ br i1 %cmp2, label %if.then3, label %if.end
+
+if.then3: ; preds = %if.then
+ %arrayidx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+ %tmp2 = load i32, i32* %arrayidx, align 4
+ %mul = shl nsw i32 %tmp2, 1
+ store i32 %mul, i32* %arrayidx, align 4
+ br label %if.end
+
+if.end: ; preds = %if.then3, %if.then
+ br label %if.end4
+
+if.end4: ; preds = %if.end, %for.body
+ %arrayidx6 = getelementptr inbounds i32, i32* %A, i64 %indvars.iv
+ %tmp3 = load i32, i32* %arrayidx6, align 4
+ %inc = add nsw i32 %tmp3, 1
+ store i32 %inc, i32* %arrayidx6, align 4
+ br label %for.inc
+
+for.inc: ; preds = %if.end4
+ %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
+ br label %for.cond
+
+for.end: ; preds = %for.cond
+ ret void
+}
Modified: polly/trunk/test/ScopInfo/remarks.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/ScopInfo/remarks.ll?rev=270416&r1=270415&r2=270416&view=diff
==============================================================================
--- polly/trunk/test/ScopInfo/remarks.ll (original)
+++ polly/trunk/test/ScopInfo/remarks.ll Mon May 23 05:40:54 2016
@@ -10,7 +10,7 @@
; CHECK: remark: test/ScopInfo/remarks.c:9:15: Possibly aliasing pointer, use restrict keyword.
; CHECK: remark: test/ScopInfo/remarks.c:14:3: SCoP ends here.
; CHECK: remark: test/ScopInfo/remarks.c:19:3: SCoP begins here.
-; CHECK: remark: test/ScopInfo/remarks.c:21:11: Invariant load assumption: [tmp] -> { : 1 = 0 }
+; CHECK: remark: test/ScopInfo/remarks.c:21:11: Invariant load restriction: [tmp] -> { : tmp < 0 or tmp > 0 }
; CHECK: remark: test/ScopInfo/remarks.c:22:16: SCoP ends here but was dismissed.
;
; #include <stdio.h>
More information about the llvm-commits
mailing list