[llvm] 9c5e656 - [LoopDeletion] Handle switch in proving that loop exits on first iteration

Max Kazantsev via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 9 04:05:38 PDT 2021


Author: Max Kazantsev
Date: 2021-07-09T18:03:34+07:00
New Revision: 9c5e65691e129a816ea4bba10be103ca67172ca5

URL: https://github.com/llvm/llvm-project/commit/9c5e65691e129a816ea4bba10be103ca67172ca5
DIFF: https://github.com/llvm/llvm-project/commit/9c5e65691e129a816ea4bba10be103ca67172ca5.diff

LOG: [LoopDeletion] Handle switch in proving that loop exits on first iteration

Added check for switch-terminated blocks in loops.
Now if a block is terminated with a switch, we try to find out which of the
cases is taken on 1st iteration and mark corresponding edge from the block
to the case successor as live.

Patch by Dmitry Makogon!

Differential Revision: https://reviews.llvm.org/D105688
Reviewed By: nikic, mkazantsev

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/LoopDeletion.cpp
    llvm/test/Transforms/LoopDeletion/eval_first_iteration.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
index 573dc5438251..f7e8442fae81 100644
--- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp
@@ -318,53 +318,63 @@ static bool canProveExitOnFirstIteration(Loop *L, DominatorTree &DT,
     Value *LHS, *RHS;
     BasicBlock *IfTrue, *IfFalse;
     auto *Term = BB->getTerminator();
-    // TODO: Handle switch.
-    if (!match(Term, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)),
-                          m_BasicBlock(IfTrue), m_BasicBlock(IfFalse)))) {
-      MarkAllSuccessorsLive(BB);
-      continue;
-    }
-
-    if (!LHS->getType()->isIntegerTy()) {
-      MarkAllSuccessorsLive(BB);
-      continue;
-    }
+    if (match(Term, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)),
+                         m_BasicBlock(IfTrue), m_BasicBlock(IfFalse)))) {
+      if (!LHS->getType()->isIntegerTy()) {
+        MarkAllSuccessorsLive(BB);
+        continue;
+      }
 
-    // Can we prove constant true or false for this condition?
-    LHS = getValueOnFirstIteration(LHS, FirstIterValue, SQ);
-    RHS = getValueOnFirstIteration(RHS, FirstIterValue, SQ);
-    auto *KnownCondition = SimplifyICmpInst(Pred, LHS, RHS, SQ);
-    if (!KnownCondition) {
-      // Failed to simplify.
-      MarkAllSuccessorsLive(BB);
-      continue;
-    }
-    if (isa<UndefValue>(KnownCondition)) {
-      // TODO: According to langref, branching by undef is undefined behavior.
-      // It means that, theoretically, we should be able to just continue
-      // without marking any successors as live. However, we are not certain
-      // how correct our compiler is at handling such cases. So we are being
-      // very conservative here.
-      //
-      // If there is a non-loop successor, always assume this branch leaves the
-      // loop. Otherwise, arbitrarily take IfTrue.
-      //
-      // Once we are certain that branching by undef is handled correctly by
-      // other transforms, we should not mark any successors live here.
-      if (L->contains(IfTrue) && L->contains(IfFalse))
+      // Can we prove constant true or false for this condition?
+      LHS = getValueOnFirstIteration(LHS, FirstIterValue, SQ);
+      RHS = getValueOnFirstIteration(RHS, FirstIterValue, SQ);
+      auto *KnownCondition = SimplifyICmpInst(Pred, LHS, RHS, SQ);
+      if (!KnownCondition) {
+        // Failed to simplify.
+        MarkAllSuccessorsLive(BB);
+        continue;
+      }
+      if (isa<UndefValue>(KnownCondition)) {
+        // TODO: According to langref, branching by undef is undefined behavior.
+        // It means that, theoretically, we should be able to just continue
+        // without marking any successors as live. However, we are not certain
+        // how correct our compiler is at handling such cases. So we are being
+        // very conservative here.
+        //
+        // If there is a non-loop successor, always assume this branch leaves the
+        // loop. Otherwise, arbitrarily take IfTrue.
+        //
+        // Once we are certain that branching by undef is handled correctly by
+        // other transforms, we should not mark any successors live here.
+        if (L->contains(IfTrue) && L->contains(IfFalse))
+          MarkLiveEdge(BB, IfTrue);
+        continue;
+      }
+      auto *ConstCondition = dyn_cast<ConstantInt>(KnownCondition);
+      if (!ConstCondition) {
+        // Non-constant condition, cannot analyze any further.
+        MarkAllSuccessorsLive(BB);
+        continue;
+      }
+      if (ConstCondition->isAllOnesValue())
         MarkLiveEdge(BB, IfTrue);
-      continue;
-    }
-    auto *ConstCondition = dyn_cast<ConstantInt>(KnownCondition);
-    if (!ConstCondition) {
-      // Non-constant condition, cannot analyze any further.
+      else
+        MarkLiveEdge(BB, IfFalse);
+    } else if (SwitchInst *SI = dyn_cast<SwitchInst>(Term)) {
+      auto *SwitchValue = SI->getCondition();
+      auto *SwitchValueOnFirstIter =
+          getValueOnFirstIteration(SwitchValue, FirstIterValue, SQ);
+      auto *ConstSwitchValue = dyn_cast<ConstantInt>(SwitchValueOnFirstIter);
+      if (!ConstSwitchValue) {
+        MarkAllSuccessorsLive(BB);
+        continue;
+      }
+      auto CaseIterator = SI->findCaseValue(ConstSwitchValue);
+      MarkLiveEdge(BB, CaseIterator->getCaseSuccessor());
+    } else {
       MarkAllSuccessorsLive(BB);
       continue;
     }
-    if (ConstCondition->isAllOnesValue())
-      MarkLiveEdge(BB, IfTrue);
-    else
-      MarkLiveEdge(BB, IfFalse);
   }
 
   // We can break the latch if it wasn't live.

diff  --git a/llvm/test/Transforms/LoopDeletion/eval_first_iteration.ll b/llvm/test/Transforms/LoopDeletion/eval_first_iteration.ll
index 8d04f5285ece..6473696219a9 100644
--- a/llvm/test/Transforms/LoopDeletion/eval_first_iteration.ll
+++ b/llvm/test/Transforms/LoopDeletion/eval_first_iteration.ll
@@ -1057,7 +1057,7 @@ define i32 @test_switch_ne_default() {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT:    [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    [[SUB:%.*]] = sub i32 4, [[SUM]]
 ; CHECK-NEXT:    switch i32 [[SUB]], label [[DEFAULT:%.*]] [
 ; CHECK-NEXT:    i32 0, label [[ONZERO:%.*]]
@@ -1065,7 +1065,7 @@ define i32 @test_switch_ne_default() {
 ; CHECK-NEXT:    i32 2, label [[ONTWO:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
-; CHECK-NEXT:    br label [[BACKEDGE]]
+; CHECK-NEXT:    br label [[BACKEDGE:%.*]]
 ; CHECK:       onzero:
 ; CHECK-NEXT:    br label [[BACKEDGE]]
 ; CHECK:       onone:
@@ -1074,9 +1074,11 @@ define i32 @test_switch_ne_default() {
 ; CHECK-NEXT:    br label [[BACKEDGE]]
 ; CHECK:       backedge:
 ; CHECK-NEXT:    [[MERGE_PHI:%.*]] = phi i32 [ [[SUB]], [[DEFAULT]] ], [ 0, [[ONZERO]] ], [ 1, [[ONONE]] ], [ 2, [[ONTWO]] ]
-; CHECK-NEXT:    [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
+; CHECK-NEXT:    [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]]
 ; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ne i32 [[SUM_NEXT]], 4
-; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]]
+; CHECK:       backedge.loop_crit_edge:
+; CHECK-NEXT:    unreachable
 ; CHECK:       done:
 ; CHECK-NEXT:    [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
 ; CHECK-NEXT:    ret i32 [[SUM_NEXT_LCSSA]]
@@ -1122,7 +1124,7 @@ define i32 @test_switch_ne_one_case() {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT:    [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    [[SUB:%.*]] = sub i32 4, [[SUM]]
 ; CHECK-NEXT:    switch i32 [[SUB]], label [[DEFAULT:%.*]] [
 ; CHECK-NEXT:    i32 0, label [[ONZERO:%.*]]
@@ -1130,7 +1132,7 @@ define i32 @test_switch_ne_one_case() {
 ; CHECK-NEXT:    i32 4, label [[ONTWO:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
-; CHECK-NEXT:    br label [[BACKEDGE]]
+; CHECK-NEXT:    br label [[BACKEDGE:%.*]]
 ; CHECK:       onzero:
 ; CHECK-NEXT:    br label [[BACKEDGE]]
 ; CHECK:       onone:
@@ -1139,9 +1141,11 @@ define i32 @test_switch_ne_one_case() {
 ; CHECK-NEXT:    br label [[BACKEDGE]]
 ; CHECK:       backedge:
 ; CHECK-NEXT:    [[MERGE_PHI:%.*]] = phi i32 [ 2, [[DEFAULT]] ], [ 0, [[ONZERO]] ], [ 1, [[ONONE]] ], [ [[SUB]], [[ONTWO]] ]
-; CHECK-NEXT:    [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
+; CHECK-NEXT:    [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]]
 ; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ne i32 [[SUM_NEXT]], 4
-; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]]
+; CHECK:       backedge.loop_crit_edge:
+; CHECK-NEXT:    unreachable
 ; CHECK:       done:
 ; CHECK-NEXT:    [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
 ; CHECK-NEXT:    ret i32 [[SUM_NEXT_LCSSA]]
@@ -1187,11 +1191,11 @@ define i32 @test_switch_ne_one_case_identical_jumps() {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
-; CHECK-NEXT:    [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT:    [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    [[SUB:%.*]] = sub i32 2, [[SUM]]
 ; CHECK-NEXT:    switch i32 [[SUB]], label [[DEFAULT:%.*]] [
 ; CHECK-NEXT:    i32 0, label [[FIRST_BLOCK:%.*]]
-; CHECK-NEXT:    i32 1, label [[BACKEDGE]]
+; CHECK-NEXT:    i32 1, label [[BACKEDGE:%.*]]
 ; CHECK-NEXT:    i32 2, label [[BACKEDGE]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
@@ -1200,9 +1204,11 @@ define i32 @test_switch_ne_one_case_identical_jumps() {
 ; CHECK-NEXT:    br label [[BACKEDGE]]
 ; CHECK:       backedge:
 ; CHECK-NEXT:    [[MERGE_PHI:%.*]] = phi i32 [ 0, [[DEFAULT]] ], [ 1, [[FIRST_BLOCK]] ], [ [[SUB]], [[LOOP]] ], [ [[SUB]], [[LOOP]] ]
-; CHECK-NEXT:    [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
+; CHECK-NEXT:    [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]]
 ; CHECK-NEXT:    [[LOOP_COND:%.*]] = icmp ne i32 [[SUM_NEXT]], 2
-; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
+; CHECK-NEXT:    br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]]
+; CHECK:       backedge.loop_crit_edge:
+; CHECK-NEXT:    unreachable
 ; CHECK:       done:
 ; CHECK-NEXT:    [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
 ; CHECK-NEXT:    ret i32 [[SUM_NEXT_LCSSA]]


        


More information about the llvm-commits mailing list