-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[SCEV] Add predicated version of getSymbolicMaxBackedgeTakenCount. #93498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-llvm-analysis Author: Florian Hahn (fhahn) ChangesThis patch introduces getBackedgeTakenCountForCountableExits and a predicated version to compute the minimum of the countable exits. The intended use for this is loop access analysis for loops with uncountable exits. When analyzing dependences and computing runtime checks, we need the smallest upper bound on the number of iterations. In terms of memory safety, it shouldn't matter if any uncomputable exits leave the loop, as long as we prove that there are no dependences given the minimum of the countable exits. The same should apply also for generating runtime checks. Patch is 24.16 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93498.diff 15 Files Affected:
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index 5828cc156cc78..4d75b9f61607a 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -912,6 +912,16 @@ class ScalarEvolution {
return getBackedgeTakenCount(L, SymbolicMaximum);
}
+ /// When successful, return the minimum of the exit counts for all countable exits, ignoring uncountable exits. This is an upper bound on the number of iterations of the loop.
+ const SCEV *getBackedgeTakenCountForCountableExits(const Loop *L);
+
+ /// Similar to getBackedgeTakenCountForCountableExits, except it will add a set of
+ /// SCEV predicates to Predicates that are required to be true in order for
+ /// the answer to be correct. Predicates can be checked with run-time
+ /// checks and can be used to perform loop versioning.
+ const SCEV *getPredicatedBackedgeTakenCountForCountableExits(
+ const Loop *L, SmallVector<const SCEVPredicate *, 4> &Predicates);
+
/// Return true if the backedge taken count is either the value returned by
/// getConstantMaxBackedgeTakenCount or zero.
bool isBackedgeTakenCountMaxOrZero(const Loop *L);
@@ -1531,8 +1541,9 @@ class ScalarEvolution {
/// If we allowed SCEV predicates to be generated when populating this
/// vector, this information can contain them and therefore a
/// SCEVPredicate argument should be added to getExact.
- const SCEV *getExact(const Loop *L, ScalarEvolution *SE,
- SmallVector<const SCEVPredicate *, 4> *Predicates = nullptr) const;
+ const SCEV *
+ getExact(const Loop *L, ScalarEvolution *SE, bool SkipUncountable = false,
+ SmallVector<const SCEVPredicate *, 4> *Predicates = nullptr) const;
/// Return the number of times this loop exit may fall through to the back
/// edge, or SCEVCouldNotCompute. The loop is guaranteed not to exit via
@@ -2316,6 +2327,9 @@ class PredicatedScalarEvolution {
/// Get the (predicated) backedge count for the analyzed loop.
const SCEV *getBackedgeTakenCount();
+ // Get the (predicated) minimum of the exit counts for all countable exits, ignoring uncountable exits.
+ const SCEV *getBackedgeTakenCountForCountableExits();
+
/// Adds a new predicate.
void addPredicate(const SCEVPredicate &Pred);
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 8d971e6a78e42..16b20392afce4 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -8279,7 +8279,17 @@ const SCEV *ScalarEvolution::getExitCount(const Loop *L,
const SCEV *
ScalarEvolution::getPredicatedBackedgeTakenCount(const Loop *L,
SmallVector<const SCEVPredicate *, 4> &Preds) {
- return getPredicatedBackedgeTakenInfo(L).getExact(L, this, &Preds);
+ return getPredicatedBackedgeTakenInfo(L).getExact(L, this, false, &Preds);
+}
+
+const SCEV *
+ScalarEvolution::getBackedgeTakenCountForCountableExits(const Loop *L) {
+ return getBackedgeTakenInfo(L).getExact(L, this, true);
+}
+
+const SCEV *ScalarEvolution::getPredicatedBackedgeTakenCountForCountableExits(
+ const Loop *L, SmallVector<const SCEVPredicate *, 4> &Preds) {
+ return getPredicatedBackedgeTakenInfo(L).getExact(L, this, true, &Preds);
}
const SCEV *ScalarEvolution::getBackedgeTakenCount(const Loop *L,
@@ -8561,11 +8571,11 @@ void ScalarEvolution::forgetBlockAndLoopDispositions(Value *V) {
/// is never skipped. This is a valid assumption as long as the loop exits via
/// that test. For precise results, it is the caller's responsibility to specify
/// the relevant loop exiting block using getExact(ExitingBlock, SE).
-const SCEV *
-ScalarEvolution::BackedgeTakenInfo::getExact(const Loop *L, ScalarEvolution *SE,
- SmallVector<const SCEVPredicate *, 4> *Preds) const {
+const SCEV *ScalarEvolution::BackedgeTakenInfo::getExact(
+ const Loop *L, ScalarEvolution *SE, bool SkipUncountable,
+ SmallVector<const SCEVPredicate *, 4> *Preds) const {
// If any exits were not computable, the loop is not computable.
- if (!isComplete() || ExitNotTaken.empty())
+ if ((!SkipUncountable && !isComplete()) || ExitNotTaken.empty())
return SE->getCouldNotCompute();
const BasicBlock *Latch = L->getLoopLatch();
@@ -8573,11 +8583,22 @@ ScalarEvolution::BackedgeTakenInfo::getExact(const Loop *L, ScalarEvolution *SE,
if (!Latch)
return SE->getCouldNotCompute();
+ if (SkipUncountable) {
+ SmallVector<BasicBlock *, 8> ExitingBlocks;
+ L->getExitingBlocks(ExitingBlocks);
+ if (any_of(ExitingBlocks, [SE, Latch](BasicBlock *Exiting) {
+ return !SE->DT.dominates(Exiting, Latch);
+ }))
+ return SE->getCouldNotCompute();
+ }
+
// All exiting blocks we have gathered dominate loop's latch, so exact trip
// count is simply a minimum out of all these calculated exit counts.
SmallVector<const SCEV *, 2> Ops;
for (const auto &ENT : ExitNotTaken) {
const SCEV *BECount = ENT.ExactNotTaken;
+ if (SkipUncountable && BECount == SE->getCouldNotCompute())
+ return SE->getCouldNotCompute();
assert(BECount != SE->getCouldNotCompute() && "Bad exit SCEV!");
assert(SE->DT.dominates(ENT.ExitingBlock, Latch) &&
"We should only have known counts for exiting blocks that dominate "
@@ -13522,8 +13543,15 @@ static void PrintLoopInfo(raw_ostream &OS, ScalarEvolution *SE,
if (!isa<SCEVCouldNotCompute>(BTC)) {
OS << "backedge-taken count is ";
PrintSCEVWithTypeHint(OS, BTC);
- } else
+ } else {
OS << "Unpredictable backedge-taken count.";
+ SmallVector<const SCEVPredicate *, 4> Predicates;
+ auto *BTC = SE->getBackedgeTakenCountForCountableExits(L);
+ if (!isa<SCEVCouldNotCompute>(BTC)) {
+ OS << "\nbackedge-taken count for computable exits is ";
+ PrintSCEVWithTypeHint(OS, BTC);
+ }
+ }
OS << "\n";
if (ExitingBlocks.size() > 1)
@@ -14802,6 +14830,16 @@ const SCEV *PredicatedScalarEvolution::getBackedgeTakenCount() {
return BackedgeCount;
}
+const SCEV *
+PredicatedScalarEvolution::getBackedgeTakenCountForCountableExits() {
+ SmallVector<const SCEVPredicate *, 4> Preds;
+ auto *BackedgeCount =
+ SE.getPredicatedBackedgeTakenCountForCountableExits(&L, Preds);
+ for (const auto *P : Preds)
+ addPredicate(*P);
+ return BackedgeCount;
+}
+
void PredicatedScalarEvolution::addPredicate(const SCEVPredicate &Pred) {
if (Preds->implies(&Pred))
return;
diff --git a/llvm/test/Analysis/ScalarEvolution/becount-invalidation.ll b/llvm/test/Analysis/ScalarEvolution/becount-invalidation.ll
index 0e37cf5efe3e4..4fd3cea9d0083 100644
--- a/llvm/test/Analysis/ScalarEvolution/becount-invalidation.ll
+++ b/llvm/test/Analysis/ScalarEvolution/becount-invalidation.ll
@@ -28,6 +28,7 @@ define void @test(ptr %arg) {
; CHECK-NEXT: --> %ptr2.next U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop.header: Variant, %loop2.header: Invariant }
; CHECK-NEXT: Determining loop execution counts for: @test
; CHECK-NEXT: Loop %loop2.header: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i1 false
; CHECK-NEXT: exit count for loop2.header: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for loop2.latch: i1 false
; CHECK-NEXT: Loop %loop2.header: constant max backedge-taken count is i1 false
diff --git a/llvm/test/Analysis/ScalarEvolution/exit-count-non-strict.ll b/llvm/test/Analysis/ScalarEvolution/exit-count-non-strict.ll
index e9faf98eee449..1a2b57a918266 100644
--- a/llvm/test/Analysis/ScalarEvolution/exit-count-non-strict.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exit-count-non-strict.ll
@@ -92,6 +92,7 @@ define void @ule_from_zero_no_nuw(i32 %M, i32 %N) {
; CHECK-LABEL: 'ule_from_zero_no_nuw'
; CHECK-NEXT: Determining loop execution counts for: @ule_from_zero_no_nuw
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is %N
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for latch: %N
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 -1
@@ -210,6 +211,7 @@ define void @sle_from_int_min_no_nsw(i32 %M, i32 %N) {
; CHECK-LABEL: 'sle_from_int_min_no_nsw'
; CHECK-NEXT: Determining loop execution counts for: @sle_from_int_min_no_nsw
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is (-2147483648 + %N)
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for latch: (-2147483648 + %N)
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 -1
diff --git a/llvm/test/Analysis/ScalarEvolution/exponential-behavior.ll b/llvm/test/Analysis/ScalarEvolution/exponential-behavior.ll
index 397e1d5efcc73..5d044a205de1a 100644
--- a/llvm/test/Analysis/ScalarEvolution/exponential-behavior.ll
+++ b/llvm/test/Analysis/ScalarEvolution/exponential-behavior.ll
@@ -6,6 +6,7 @@ define void @f(i32 %n, ptr %ptr) {
; CHECK-LABEL: 'f'
; CHECK-NEXT: Determining loop execution counts for: @f
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 0
; CHECK-NEXT: exit count for loop: i32 0
; CHECK-NEXT: exit count for be: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 0
diff --git a/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll b/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll
index a8531a8f57799..039004bd9e7c1 100644
--- a/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll
+++ b/llvm/test/Analysis/ScalarEvolution/flags-from-poison.ll
@@ -529,6 +529,7 @@ define void @test-add-not-header3(ptr %input, i32 %offset, i32 %numIterations,
; CHECK-NEXT: --> %cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
; CHECK-NEXT: Determining loop execution counts for: @test-add-not-header3
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is (-1 + %numIterations)
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for loop2: (-1 + %numIterations)
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 -1
@@ -1546,6 +1547,7 @@ define void @test-sext-sub(ptr %input, i32 %sub, i32 %numIterations) {
; CHECK-NEXT: --> {1,+,1}<nuw><%loop> U: [1,0) S: [1,0) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test-sext-sub
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is (-1 + %numIterations)
; CHECK-NEXT: exit count for loop: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for cont: (-1 + %numIterations)
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 -1
diff --git a/llvm/test/Analysis/ScalarEvolution/incorrect-exit-count.ll b/llvm/test/Analysis/ScalarEvolution/incorrect-exit-count.ll
index b456f11bade6b..fecf49353c347 100644
--- a/llvm/test/Analysis/ScalarEvolution/incorrect-exit-count.ll
+++ b/llvm/test/Analysis/ScalarEvolution/incorrect-exit-count.ll
@@ -58,6 +58,7 @@ define dso_local i32 @f() {
; CHECK-NEXT: --> {2,+,-1}<nsw><%outer.loop> U: [0,3) S: [0,3) Exits: <<Unknown>> LoopDispositions: { %outer.loop: Computable, %for.cond6: Invariant, %inner.loop: Invariant }
; CHECK-NEXT: Determining loop execution counts for: @f
; CHECK-NEXT: Loop %for.cond6: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 0
; CHECK-NEXT: exit count for for.cond6: i32 0
; CHECK-NEXT: exit count for for.end: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %for.cond6: constant max backedge-taken count is i32 0
@@ -65,6 +66,7 @@ define dso_local i32 @f() {
; CHECK-NEXT: symbolic max exit count for for.cond6: i32 0
; CHECK-NEXT: symbolic max exit count for for.end: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %inner.loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 0
; CHECK-NEXT: exit count for inner.loop: i32 0
; CHECK-NEXT: exit count for for.end.3: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %inner.loop: constant max backedge-taken count is i32 0
@@ -72,6 +74,7 @@ define dso_local i32 @f() {
; CHECK-NEXT: symbolic max exit count for inner.loop: i32 0
; CHECK-NEXT: symbolic max exit count for for.end.3: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %outer.loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 2
; CHECK-NEXT: exit count for for.cond6: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for inner.loop: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for for.inc13.3: i32 2
diff --git a/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll b/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll
index 501aa963f9294..90328c4ca8221 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-trip-count.ll
@@ -53,6 +53,7 @@ define i32 @main() nounwind {
; CHECK-LABEL: 'main'
; CHECK-NEXT: Determining loop execution counts for: @main
; CHECK-NEXT: Loop %for.cond: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 5
; CHECK-NEXT: exit count for for.cond: i32 5
; CHECK-NEXT: exit count for for.body: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %for.cond: constant max backedge-taken count is i32 5
@@ -125,6 +126,7 @@ define i32 @pr19799() {
; CHECK-LABEL: 'pr19799'
; CHECK-NEXT: Determining loop execution counts for: @pr19799
; CHECK-NEXT: Loop %for.body.i: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 1
; CHECK-NEXT: exit count for for.body.i: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for for.cond.i: i32 1
; CHECK-NEXT: Loop %for.body.i: constant max backedge-taken count is i32 1
@@ -158,6 +160,7 @@ define i32 @pr18886() {
; CHECK-LABEL: 'pr18886'
; CHECK-NEXT: Determining loop execution counts for: @pr18886
; CHECK-NEXT: Loop %for.body: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i64 3
; CHECK-NEXT: exit count for for.body: ***COULDNOTCOMPUTE***
; CHECK-NEXT: exit count for for.cond: i64 3
; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is i64 3
@@ -571,6 +574,7 @@ define void @max_overflow_me(i8 %n) mustprogress {
; CHECK-LABEL: 'max_overflow_me'
; CHECK-NEXT: Determining loop execution counts for: @max_overflow_me
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i8 1
; CHECK-NEXT: exit count for loop: i8 1
; CHECK-NEXT: exit count for latch: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i8 1
diff --git a/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll b/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll
index 82b4d0e4fb483..c77b8d0fd5f5a 100644
--- a/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll
+++ b/llvm/test/Analysis/ScalarEvolution/ne-overflow.ll
@@ -207,6 +207,7 @@ define void @test_other_exit(i32 %N) mustprogress {
; CHECK-LABEL: 'test_other_exit'
; CHECK-NEXT: Determining loop execution counts for: @test_other_exit
; CHECK-NEXT: Loop %for.body: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 9
; CHECK-NEXT: exit count for for.body: i32 9
; CHECK-NEXT: exit count for for.latch: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is i32 9
diff --git a/llvm/test/Analysis/ScalarEvolution/no-wrap-symbolic-becount.ll b/llvm/test/Analysis/ScalarEvolution/no-wrap-symbolic-becount.ll
index e13a8976bf5ac..808ce50f0e5b4 100644
--- a/llvm/test/Analysis/ScalarEvolution/no-wrap-symbolic-becount.ll
+++ b/llvm/test/Analysis/ScalarEvolution/no-wrap-symbolic-becount.ll
@@ -24,6 +24,7 @@ define i32 @test_01(i32 %start, ptr %p, ptr %q) {
; CHECK-NEXT: --> {(-1 + (zext i32 %start to i64))<nsw>,+,-1}<nsw><%loop> U: [-4294967296,4294967295) S: [-1,4294967295) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_01
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is (zext i32 %start to i64)
; CHECK-NEXT: exit count for loop: (zext i32 %start to i64)
; CHECK-NEXT: exit count for backedge: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 4294967295
diff --git a/llvm/test/Analysis/ScalarEvolution/outer_phi.ll b/llvm/test/Analysis/ScalarEvolution/outer_phi.ll
index e4a9753b24054..a14d2e88f689f 100644
--- a/llvm/test/Analysis/ScalarEvolution/outer_phi.ll
+++ b/llvm/test/Analysis/ScalarEvolution/outer_phi.ll
@@ -18,6 +18,7 @@ define i32 @test_01(i32 %a, i32 %b) {
; CHECK-NEXT: --> %outer.loop.cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %outer: Variant, %inner: Invariant }
; CHECK-NEXT: Determining loop execution counts for: @test_01
; CHECK-NEXT: Loop %inner: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is %b
; CHECK-NEXT: exit count for inner: %b
; CHECK-NEXT: exit count for inner.backedge: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %inner: constant max backedge-taken count is i32 2147483647
@@ -80,6 +81,7 @@ define i32 @test_02(i32 %a, i32 %b) {
; CHECK-NEXT: --> %outer.loop.cond U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %outer: Variant, %inner: Invariant }
; CHECK-NEXT: Determining loop execution counts for: @test_02
; CHECK-NEXT: Loop %inner: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is ((-1 * %outer.iv) + (%b smax %outer.iv))
; CHECK-NEXT: exit count for inner: ((-1 * %outer.iv) + (%b smax %outer.iv))
; CHECK-NEXT: exit count for inner.backedge: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %inner: constant max backedge-taken count is i32 -1
diff --git a/llvm/test/Analysis/ScalarEvolution/pr48225.ll b/llvm/test/Analysis/ScalarEvolution/pr48225.ll
index 157e98f99aa9f..7c2849f5c989f 100644
--- a/llvm/test/Analysis/ScalarEvolution/pr48225.ll
+++ b/llvm/test/Analysis/ScalarEvolution/pr48225.ll
@@ -22,6 +22,7 @@ define void @test_and(i1 %boolcond) {
; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,4) S: [1,4) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_and
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 2
; CHECK-NEXT: exit count for loop: i32 2
; CHECK-NEXT: exit count for backedge: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 2
@@ -71,6 +72,7 @@ define void @test_or(i1 %boolcond) {
; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,4) S: [1,4) Exits: <<Unknown>> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @test_or
; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: backedge-taken count for computable exits is i32 2
; CHECK-NEXT: exit count for loop: i32 2
; CHECK-NEXT: exit count for backedge: ***COULDNOTCOMPUTE***
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i32 2
diff --git a/llvm/test/Analysis/ScalarEvolution/ptrtoint.ll b/llvm/test/Analysis/ScalarEvolution/ptrtoint.ll
index e784d25385980..9509dc2d2f5c8 100644
--- a/llvm/test/Analysis/ScalarEvolution/ptrtoint.ll
+++ b/llvm/test/Analysis/ScalarEvolution/ptrtoint.ll
@@ -550,6 +550,7 @@ define voi...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
marking as a draft as this isn't ready yet |
c354c6b
to
afe475d
Compare
The PR contains 3 commits, 2 of which can be split off independently 1) refactoring getSymbolicMax to work on BackedgeTakenInfo directly and 2) adding tests for predicated symbolic max. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@@ -912,6 +912,9 @@ class ScalarEvolution { | |||
return getBackedgeTakenCount(L, SymbolicMaximum); | |||
} | |||
|
|||
const SCEV *getPredicatedSymbolicMaxBackedgeTakenCount( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doc comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added, thanks!
@@ -0,0 +1,119 @@ | |||
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5 | |||
; RUN: opt -passes='print<scalar-evolution>' %s -disable-output 2>&1 | FileCheck %s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use -scalar-evolution-classify-expressions=0
to only print the exit counts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah thanks, added in the commit that landed the tests ( ed4227a )
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 5 | ||
; RUN: opt -passes='print<scalar-evolution>' %s -disable-output 2>&1 | FileCheck %s | ||
|
||
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, removed, thanks! Landed the adjusted tests separately in ed4227a
Move symbolic max backedge taken count computation to BackedgeTakenInfo, use existing ExitNotTaken info. In preparation for #93498.
afe475d
to
68c2420
Compare
Move symbolic max backedge taken count computation to BackedgeTakenInfo, use existing ExitNotTaken info. In preparation for llvm#93498.
Add extra tests for llvm#93498.
…lvm#93498) This patch adds a predicated version of getSymbolicMaxBackedgeTakenCount. The intended use for this is loop access analysis for loops with uncountable exits. When analyzing dependences and computing runtime checks, we need the smallest upper bound on the number of iterations. In terms of memory safety, it shouldn't matter if any uncomputable exits leave the loop, as long as we prove that there are no dependences given the minimum of the countable exits. The same should apply also for generating runtime checks. PR: llvm#93498
Update LAA to use PSE::getSymbolicMaxBackedgeTakenCount which returns the minimum of the countable exits. When analyzing dependences and computing runtime checks, we need the smallest upper bound on the number of iterations. In terms of memory safety, it shouldn't matter if any uncomputable exits leave the loop, as long as we prove that there are no dependences given the minimum of the countable exits. The same should apply also for generating runtime checks. Note that this shifts the responsiblity of checking whether all exit counts are computable or handling early-exits to the users of LAA. Depends on #93498 PR: #93499
const SCEV * | ||
ScalarEvolution::BackedgeTakenInfo::getSymbolicMax(const Loop *L, | ||
ScalarEvolution *SE) { | ||
const SCEV *ScalarEvolution::BackedgeTakenInfo::getSymbolicMax( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps I'm wrong but this change looks to have taken inspiration (and a little code) from #88385. I'm happy for the collaboration but LLVM rules suggest it would have been polite to reference my PR or indicate co-authorship?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, this should have been referenced, apologies for that! To rectify that, how about reverting the patch and then recommitting with an adjusted message to include an attribution like
The extension of getSymbolicMax to support predication is inspired by David Sherwood's (@david-arm) version in https://github.com/llvm/llvm-project/pull/88385
Happy to adjust as needed, if you think a different wording would be better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's ok, there's no need to revert the patch and no harm done! Perhaps just something to remember in future that's all. Thanks!
This patch adds a predicated version of getSymbolicMaxBackedgeTakenCount.
The intended use for this is loop access analysis for loops with uncountable exits. When analyzing dependences and computing runtime checks, we need the smallest upper bound on the number of iterations. In terms of memory safety, it shouldn't matter if any uncomputable exits leave the loop, as long as we prove that there are no dependences given the minimum of the countable exits. The same should apply also for generating runtime checks.