[PATCH] D139934: [IndVars] Apply more optimistic SkipLastIter for AND conditions
Max Kazantsev via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 13 07:14:26 PST 2022
mkazantsev created this revision.
mkazantsev added reviewers: nikic, lebedev.ri, fhahn, reames.
Herald added a subscriber: hiraditya.
Herald added a project: All.
mkazantsev requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.
When exit by condition `C1` dominates exit by condition `C2`, and
max symbolic exit count for `C1` matches those for loop, we will
apply more optimistic logic to `C2` by setting `SkipLastIter` for it,
meaning that it will do 1 iteration less because the dominating branch
must exit on the last loop iteration.
But when we have a single exit by condition `C1 & C2`, we cannot
apply the same logic, because there is no dominating condition.
However, if we can prove that the symbolic max exit count of `C1 & C2`
matches those of `C1`, it means that for `C2` we can assume that it
doesn't matter on the last iteration (because the whole thing is `false`
because `C1` must be `false`). Therefore, in this situation, we can handle
`C2` as if it had `SkipLastIter`.
This is potentiallty CT-consuming operation, so I've limited it with reasonably
small amount of conditions to deal with.
https://reviews.llvm.org/D139934
Files:
llvm/include/llvm/Analysis/ScalarEvolution.h
llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
Index: llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
===================================================================
--- llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
+++ llvm/test/Transforms/IndVarSimplify/turn-to-invariant.ll
@@ -526,21 +526,18 @@
ret i32 -2
}
-; TODO: This test is equivalent to @test_simple_case, with only difference
-; that both checks are merged together into one 'and' check. This
-; should not prevent turning the range check into invariant.
-; https://alive2.llvm.org/ce/z/G-2ERB
+; https://alive2.llvm.org/ce/z/G-2ERB
define i32 @test_and_conditions(i32 %start, i32 %len) {
; CHECK-LABEL: define {{[^@]+}}@test_and_conditions(
; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[START:%.*]], -1
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
-; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[START]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[ZERO_CHECK:%.*]] = icmp ne i32 [[IV]], 0
-; CHECK-NEXT: [[IV_MINUS_1:%.*]] = add i32 [[IV]], -1
-; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[IV_MINUS_1]], [[LEN:%.*]]
-; CHECK-NEXT: [[BOTH_CHECKS:%.*]] = and i1 [[ZERO_CHECK]], [[RANGE_CHECK]]
-; CHECK-NEXT: br i1 [[BOTH_CHECKS]], label [[BACKEDGE]], label [[FAILED:%.*]]
+; CHECK-NEXT: [[BOTH_CHECKS2:%.*]] = icmp ult i32 [[TMP0]], [[LEN:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = and i1 [[BOTH_CHECKS2]], [[ZERO_CHECK]]
+; CHECK-NEXT: br i1 [[TMP1]], label [[BACKEDGE]], label [[FAILED:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], -1
; CHECK-NEXT: [[LOOP_COND:%.*]] = call i1 @cond()
Index: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1453,13 +1453,39 @@
// For AND aggregations, only consider true branch staying in loop.
return false;
+ // If the number of conditions is reasonably small, and this block is the last
+ // block without SkipLastIter, we can try to apply SkipLastIter to some of its
+ // conditions if there is another condition that gives the very same exit
+ // count.
+ bool TryMoreOptimisticLastIter = false;
+ if (!SkipLastIter && Conditions.size() < 8 &&
+ SE->getExitCount(L, ExitingBB,
+ ScalarEvolution::ExitCountKind::SymbolicMaximum) ==
+ MaxIter)
+ TryMoreOptimisticLastIter = true;
+
bool Changed = false;
- for (size_t i = 0; i < Conditions.size(); ++i)
- if (auto NewCond = createReplacement(Conditions[i], L, ExitingBB, MaxIter,
- SkipLastIter, SE, Rewriter)) {
+ for (size_t i = 0; i < Conditions.size(); ++i) {
+ bool OptimisticSkipLastIter = SkipLastIter;
+ if (TryMoreOptimisticLastIter) {
+ for (size_t j = 0; j < Conditions.size(); j++)
+ if (i != j) {
+ auto EL = SE->computeExitLimitFromCond(L, Conditions[j], ExitIfTrue,
+ /*ControlsExit*/ false);
+ if (EL.SymbolicMaxNotTaken == MaxIter) {
+ OptimisticSkipLastIter = true;
+ break;
+ }
+ }
+ }
+
+ if (auto NewCond =
+ createReplacement(Conditions[i], L, ExitingBB, MaxIter,
+ OptimisticSkipLastIter, SE, Rewriter)) {
Changed = true;
Conditions[i] = *NewCond;
}
+ }
if (!Changed)
return false;
Index: llvm/include/llvm/Analysis/ScalarEvolution.h
===================================================================
--- llvm/include/llvm/Analysis/ScalarEvolution.h
+++ llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -1727,6 +1727,7 @@
ExitLimit computeExitLimit(const Loop *L, BasicBlock *ExitingBlock,
bool AllowPredicates = false);
+public:
/// Compute the number of times the backedge of the specified loop will
/// execute if its exit condition were a conditional branch of ExitCond.
///
@@ -1741,6 +1742,7 @@
bool ExitIfTrue, bool ControlsExit,
bool AllowPredicates = false);
+private:
/// Return a symbolic upper bound for the backedge taken count of the loop.
/// This is more general than getConstantMaxBackedgeTakenCount as it returns
/// an arbitrary expression as opposed to only constants.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D139934.482462.patch
Type: text/x-patch
Size: 4602 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20221213/76fc5181/attachment.bin>
More information about the llvm-commits
mailing list