[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