[llvm] f765445 - [LoopUnroll] Clean up exit folding (NFC)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri May 28 13:31:23 PDT 2021


Author: Nikita Popov
Date: 2021-05-28T22:31:13+02:00
New Revision: f765445a691187c69a8a7c14991acb4589314e93

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

LOG: [LoopUnroll] Clean up exit folding (NFC)

This does some non-functional cleanup of exit folding during
unrolling. The two main changes are:

 * First rewrite latch->header edges, which is unrelated to exit
   folding.
 * Combine folding for latch and non-latch exits. After the
   previous change, the only difference in their logic is that
   for non-latch exits we currently only fold "known non-exit"
   cases, but not "known exit" cases.

I think this helps a lot to clarify this code and prepare it for
future changes.

Differential Revision: https://reviews.llvm.org/D103333

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/LoopUnroll.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp
index 15c9fc31ba01..cb84eb642c96 100644
--- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp
@@ -528,12 +528,6 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI,
 
   if (!LatchIsExiting)
     ++NumUnrolledNotLatch;
-  Optional<bool> ContinueOnTrue = None;
-  BasicBlock *LoopExit = nullptr;
-  if (ExitingBI) {
-    ContinueOnTrue = L->contains(ExitingBI->getSuccessor(0));
-    LoopExit = ExitingBI->getSuccessor(*ContinueOnTrue);
-  }
 
   // For the first iteration of the loop, we should use the precloned values for
   // PHI nodes.  Insert associations now.
@@ -545,14 +539,11 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI,
 
   std::vector<BasicBlock *> Headers;
   std::vector<BasicBlock *> ExitingBlocks;
-  std::vector<BasicBlock *> ExitingSucc;
   std::vector<BasicBlock *> Latches;
   Headers.push_back(Header);
   Latches.push_back(LatchBlock);
-  if (ExitingBI) {
+  if (ExitingBI)
     ExitingBlocks.push_back(ExitingBI->getParent());
-    ExitingSucc.push_back(ExitingBI->getSuccessor(!(*ContinueOnTrue)));
-  }
 
   // The current on-the-fly SSA update requires blocks to be processed in
   // reverse postorder so that LastValueMap contains the correct value at each
@@ -652,12 +643,9 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI,
 
       // Keep track of the exiting block and its successor block contained in
       // the loop for the current iteration.
-      if (ExitingBI) {
+      if (ExitingBI)
         if (*BB == ExitingBlocks[0])
           ExitingBlocks.push_back(New);
-        if (*BB == ExitingSucc[0])
-          ExitingSucc.push_back(New);
-      }
 
       NewBlocks.push_back(New);
       UnrolledLoopBlocks.push_back(New);
@@ -714,111 +702,74 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI,
     }
   }
 
-  auto setDest = [](BasicBlock *Src, BasicBlock *Dest, BasicBlock *BlockInLoop,
-                    bool NeedConditional, Optional<bool> ContinueOnTrue,
-                    bool IsDestLoopExit) {
-    auto *Term = cast<BranchInst>(Src->getTerminator());
-    if (NeedConditional) {
-      // Update the conditional branch's successor for the following
-      // iteration.
-      assert(ContinueOnTrue.hasValue() &&
-             "Expecting valid ContinueOnTrue when NeedConditional is true");
-      Term->setSuccessor(!(*ContinueOnTrue), Dest);
-    } else {
-      // Remove phi operands at this loop exit
-      if (!IsDestLoopExit) {
-        BasicBlock *BB = Src;
-        for (BasicBlock *Succ : successors(BB)) {
-          // Preserve the incoming value from BB if we are jumping to the block
-          // in the current loop.
-          if (Succ == BlockInLoop)
-            continue;
-          for (PHINode &Phi : Succ->phis())
-            Phi.removeIncomingValue(BB, false);
-        }
+  // Connect latches of the unrolled iterations to the headers of the next
+  // iteration. Currently they point to the header of the same iteration.
+  for (unsigned i = 0, e = Latches.size(); i != e; ++i) {
+    unsigned j = (i + 1) % e;
+    Latches[i]->getTerminator()->replaceSuccessorWith(Headers[i], Headers[j]);
+  }
+
+  if (ExitingBI) {
+    auto SetDest = [](BasicBlock *Src, bool WillExit, bool ExitOnTrue) {
+      auto *Term = cast<BranchInst>(Src->getTerminator());
+      BasicBlock *Dest = Term->getSuccessor(ExitOnTrue ^ WillExit);
+
+      // Remove predecessors from all non-Dest successors.
+      for (BasicBlock *Succ : successors(Src)) {
+        if (Succ == Dest)
+          continue;
+        Succ->removePredecessor(Src, /* KeepOneInputPHIs */ true);
       }
+
       // Replace the conditional branch with an unconditional one.
       BranchInst::Create(Dest, Term);
       Term->eraseFromParent();
-    }
-  };
+    };
 
-  // Connect latches of the unrolled iterations to the headers of the next
-  // iteration. If the latch is also the exiting block, the conditional branch
-  // may have to be preserved.
-  for (unsigned i = 0, e = Latches.size(); i != e; ++i) {
-    // The branch destination.
-    unsigned j = (i + 1) % e;
-    BasicBlock *Dest = Headers[j];
-    bool NeedConditional = LatchIsExiting;
+    auto WillExit = [&](unsigned i, unsigned j) -> Optional<bool> {
+      if (CompletelyUnroll) {
+        if (ULO.PreserveCondBr && j && !(ULO.PreserveOnlyFirst && i != 0))
+          return None;
+        return j == 0;
+      }
 
-    if (LatchIsExiting) {
       if (RuntimeTripCount && j != 0)
-        NeedConditional = false;
+        return false;
 
-      // For a complete unroll, make the last iteration end with a branch
-      // to the exit block.
-      if (CompletelyUnroll) {
-        if (j == 0)
-          Dest = LoopExit;
-        // If using trip count upper bound to completely unroll, we need to
-        // keep the conditional branch except the last one because the loop
-        // may exit after any iteration.
-        assert(NeedConditional &&
-               "NeedCondition cannot be modified by both complete "
-               "unrolling and runtime unrolling");
-        NeedConditional =
-            (ULO.PreserveCondBr && j && !(ULO.PreserveOnlyFirst && i != 0));
-      } else if (j != BreakoutTrip &&
-                 (ULO.TripMultiple == 0 || j % ULO.TripMultiple != 0)) {
+      if (j != BreakoutTrip &&
+          (ULO.TripMultiple == 0 || j % ULO.TripMultiple != 0)) {
         // If we know the trip count or a multiple of it, we can safely use an
         // unconditional branch for some iterations.
-        NeedConditional = false;
+        return false;
       }
-    }
-
-    setDest(Latches[i], Dest, Headers[i], NeedConditional, ContinueOnTrue,
-            Dest == LoopExit);
-  }
+      return None;
+    };
 
-  if (!LatchIsExiting) {
-    // If the latch is not exiting, we may be able to simplify the conditional
-    // branches in the unrolled exiting blocks.
+    // Fold branches for iterations where we know that they will exit or not
+    // exit.
+    bool ExitOnTrue = !L->contains(ExitingBI->getSuccessor(0));
     for (unsigned i = 0, e = ExitingBlocks.size(); i != e; ++i) {
       // The branch destination.
       unsigned j = (i + 1) % e;
-      bool NeedConditional = true;
-
-      if (RuntimeTripCount && j != 0)
-        NeedConditional = false;
-
-      if (CompletelyUnroll)
-        // We cannot drop the conditional branch for the last condition, as we
-        // may have to execute the loop body depending on the condition.
-        NeedConditional = j == 0 || ULO.PreserveCondBr;
-      else if (j != BreakoutTrip &&
-               (ULO.TripMultiple == 0 || j % ULO.TripMultiple != 0))
-        // If we know the trip count or a multiple of it, we can safely use an
-        // unconditional branch for some iterations.
-        NeedConditional = false;
+      Optional<bool> KnownWillExit = WillExit(i, j);
+      if (!KnownWillExit)
+        continue;
 
-      // Conditional branches from non-latch exiting block have successors
-      // either in the same loop iteration or outside the loop. The branches are
-      // already correct.
-      if (NeedConditional)
+      // TODO: Also fold known-exiting branches for non-latch exits.
+      if (*KnownWillExit && !LatchIsExiting)
         continue;
-      setDest(ExitingBlocks[i], ExitingSucc[i], ExitingSucc[i], NeedConditional,
-              None, false);
-    }
 
-    // When completely unrolling, the last latch becomes unreachable.
-    if (CompletelyUnroll) {
-      BranchInst *Term = cast<BranchInst>(Latches.back()->getTerminator());
-      new UnreachableInst(Term->getContext(), Term);
-      Term->eraseFromParent();
+      SetDest(ExitingBlocks[i], *KnownWillExit, ExitOnTrue);
     }
   }
 
+  // When completely unrolling, the last latch becomes unreachable.
+  if (!LatchIsExiting && CompletelyUnroll) {
+    BranchInst *Term = cast<BranchInst>(Latches.back()->getTerminator());
+    new UnreachableInst(Term->getContext(), Term);
+    Term->eraseFromParent();
+  }
+
   // Update dominators of blocks we might reach through exits.
   // Immediate dominator of such block might change, because we add more
   // routes which can lead to the exit: we can now reach it from the copied


        


More information about the llvm-commits mailing list