[PATCH] D141361: [IndVars] Improve handling of multi-exit loops with known symbolic counts
Max Kazantsev via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Tue Jan 10 21:19:36 PST 2023
mkazantsev updated this revision to Diff 488074.
mkazantsev added a comment.
Typo fix
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D141361/new/
https://reviews.llvm.org/D141361
Files:
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
@@ -842,13 +842,14 @@
ret i32 -3
}
-; TODO: Same as test_litter_conditions, but an extra check with known exact exit count is preventing the opt.
+; Same as test_litter_conditions, but an extra check with known exact exit count is preventing the opt.
define i32 @test_litter_conditions_constant(i32 %start, i32 %len) {
; CHECK-LABEL: @test_litter_conditions_constant(
; 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: [[CANONICAL_IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[CANONICAL_IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[CONSTANT_CHECK:%.*]] = icmp ult i32 [[CANONICAL_IV]], 65635
; CHECK-NEXT: br i1 [[CONSTANT_CHECK]], label [[CONSTANT_CHECK_PASSED:%.*]], label [[CONSTANT_CHECK_FAILED:%.*]]
@@ -858,10 +859,9 @@
; CHECK-NEXT: [[AND_1:%.*]] = and i1 [[ZERO_CHECK]], [[FAKE_1]]
; CHECK-NEXT: br i1 [[AND_1]], label [[RANGE_CHECK_BLOCK:%.*]], label [[FAILED_1:%.*]]
; CHECK: range_check_block:
-; CHECK-NEXT: [[IV_MINUS_1:%.*]] = add i32 [[IV]], -1
-; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[IV_MINUS_1]], [[LEN:%.*]]
+; CHECK-NEXT: [[RANGE_CHECK_FIRST_ITER:%.*]] = icmp ult i32 [[TMP0]], [[LEN:%.*]]
; CHECK-NEXT: [[FAKE_2:%.*]] = call i1 @cond()
-; CHECK-NEXT: [[AND_2:%.*]] = and i1 [[RANGE_CHECK]], [[FAKE_2]]
+; CHECK-NEXT: [[AND_2:%.*]] = and i1 [[RANGE_CHECK_FIRST_ITER]], [[FAKE_2]]
; CHECK-NEXT: br i1 [[AND_2]], label [[BACKEDGE]], label [[FAILED_2:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], -1
Index: llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
+++ llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
@@ -1408,8 +1408,17 @@
}
if (SkipLastIter) {
- const SCEV *One = SE->getOne(MaxIter->getType());
- MaxIter = SE->getMinusSCEV(MaxIter, One);
+ // Semantically skip last iter is "subtract 1, do not bother about unsigned
+ // wrap". getLoopInvariantExitCondDuringFirstIterations knows how to deal
+ // with umin in a smart way, but umin(a, b) - 1 will likely not simplify.
+ // So we manually construct umin(a - 1, b - 1).
+ SmallVector<const SCEV *, 4> Elements;
+ if (auto *UMin = dyn_cast<SCEVUMinExpr>(MaxIter)) {
+ for (auto *Op : UMin->operands())
+ Elements.push_back(SE->getMinusSCEV(Op, SE->getOne(Op->getType())));
+ MaxIter = SE->getUMinFromMismatchedTypes(Elements);
+ } else
+ MaxIter = SE->getMinusSCEV(MaxIter, SE->getOne(MaxIter->getType()));
}
// Check if there is a loop-invariant predicate equivalent to our check.
@@ -1726,6 +1735,19 @@
bool Changed = false;
bool SkipLastIter = false;
+ const SCEV *CurrMaxExit = SE->getCouldNotCompute();
+ auto UpdateSkipLastIter = [&](const SCEV *MaxExitCount) {
+ if (SkipLastIter || isa<SCEVCouldNotCompute>(MaxExitCount))
+ return;
+ if (isa<SCEVCouldNotCompute>(CurrMaxExit))
+ CurrMaxExit = MaxExitCount;
+ else
+ CurrMaxExit = SE->getUMinFromMismatchedTypes(CurrMaxExit, MaxExitCount);
+ // If the loop has more than 1 iteration, all further checks will be
+ // executed 1 iteration less.
+ if (CurrMaxExit == MaxBECount)
+ SkipLastIter = true;
+ };
SmallSet<const SCEV *, 8> DominatingExactExitCounts;
for (BasicBlock *ExitingBB : ExitingBlocks) {
const SCEV *ExactExitCount = SE->getExitCount(L, ExitingBB);
@@ -1761,17 +1783,11 @@
Changed = true;
else if (SkipLastIter && OptimizeCond(true))
Changed = true;
- if (MaxBECount == MaxExitCount)
- // If the loop has more than 1 iteration, all further checks will be
- // executed 1 iteration less.
- SkipLastIter = true;
+ UpdateSkipLastIter(MaxExitCount);
continue;
}
- if (MaxBECount == MaxExitCount)
- // If the loop has more than 1 iteration, all further checks will be
- // executed 1 iteration less.
- SkipLastIter = true;
+ UpdateSkipLastIter(ExactExitCount);
// If we know we'd exit on the first iteration, rewrite the exit to
// reflect this. This does not imply the loop must exit through this
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D141361.488074.patch
Type: text/x-patch
Size: 4760 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20230111/913afcf0/attachment.bin>
More information about the llvm-commits
mailing list