[llvm] 7694057 - [unroll] Move multiple exit costing into consumer pass [NFC]

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 2 12:46:32 PDT 2021


Author: Philip Reames
Date: 2021-08-02T12:46:23-07:00
New Revision: 76940577e4bf9c63a8a4ebd32b556bd7feb8cad3

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

LOG: [unroll] Move multiple exit costing into consumer pass [NFC]

This aligns the multiple exit costing with all the other cost decisions.  Note that UnrollAndJam, which is the only other caller of the original home of this code, unconditionally bails out of multiple exit loops.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
    llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
index 49501f324a49..b8799622d8ab 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
@@ -175,6 +175,14 @@ static cl::opt<unsigned>
                            cl::desc("Default threshold (max size of unrolled "
                                     "loop), used in all but O3 optimizations"));
 
+static cl::opt<bool> UnrollRuntimeMultiExit(
+    "unroll-runtime-multi-exit", cl::init(false), cl::Hidden,
+    cl::desc("Allow runtime unrolling for loops with multiple exits, when "
+             "epilog is generated"));
+static cl::opt<bool> UnrollRuntimeOtherExitPredictable(
+    "unroll-runtime-other-exit-predictable", cl::init(false), cl::Hidden,
+    cl::desc("Assume the non latch exit block to be predictable"));
+
 /// A magic value for use with the Threshold parameter to indicate
 /// that the loop unroll should be performed regardless of how much
 /// code expansion would result.
@@ -734,6 +742,57 @@ static unsigned getFullUnrollBoostingFactor(const EstimatedUnrollCost &Cost,
     return MaxPercentThresholdBoost;
 }
 
+/// Returns true if we can profitably unroll the multi-exit loop L. Currently,
+/// unrolling a multiple exit loop is generally considered unprofitable outside
+/// of some very restricted cases.  (TODO: Relax this!)
+static bool canProfitablyUnrollMultiExitLoop(Loop *L) {
+
+  SmallVector<BasicBlock *> OtherExits;
+  L->getUniqueNonLatchExitBlocks(OtherExits);
+
+  // Priority goes to UnrollRuntimeMultiExit if it's supplied.
+  if (UnrollRuntimeMultiExit.getNumOccurrences())
+    return UnrollRuntimeMultiExit;
+
+  // The main pain point with multi-exit loop unrolling is that once unrolled,
+  // we will not be able to merge all blocks into a straight line code.
+  // There are branches within the unrolled loop that go to the OtherExits.
+  // The second point is the increase in code size, but this is true
+  // irrespective of multiple exits.
+
+  // Note: Both the heuristics below are coarse grained. We are essentially
+  // enabling unrolling of loops that have a single side exit other than the
+  // normal LatchExit (i.e. exiting into a deoptimize block).
+  // The heuristics considered are:
+  // 1. low number of branches in the unrolled version.
+  // 2. high predictability of these extra branches.
+  // We avoid unrolling loops that have more than two exiting blocks. This
+  // limits the total number of branches in the unrolled loop to be atmost
+  // the unroll factor (since one of the exiting blocks is the latch block).
+  SmallVector<BasicBlock*, 4> ExitingBlocks;
+  L->getExitingBlocks(ExitingBlocks);
+  if (ExitingBlocks.size() > 2)
+    return false;
+
+  // Allow unrolling of loops with no non latch exit blocks.
+  if (OtherExits.size() == 0)
+    return true;
+
+  // The second heuristic is that L has one exit other than the latchexit and
+  // that exit is a deoptimize block. We know that deoptimize blocks are rarely
+  // taken, which also implies the branch leading to the deoptimize block is
+  // highly predictable. When UnrollRuntimeOtherExitPredictable is specified, we
+  // assume the other exit branch is predictable even if it has no deoptimize
+  // call.
+  return (OtherExits.size() == 1 &&
+          (UnrollRuntimeOtherExitPredictable ||
+           OtherExits[0]->getTerminatingDeoptimizeCall()));
+  // TODO: These can be fine-tuned further to consider code size or deopt states
+  // that are captured by the deoptimize exit block.
+  // Also, we can extend this to support more cases, if we actually
+  // know of kinds of multiexit loops that would benefit from unrolling.
+}
+
 // Produce an estimate of the unrolled cost of the specified loop.  This
 // is used to a) produce a cost estimate for partial unrolling and b) to
 // cheaply estimate cost for full unrolling when we don't want to symbolically
@@ -982,6 +1041,13 @@ bool llvm::computeUnrollCount(
     }
   }
 
+  // Is this is a multiple exit loop which we consider unprofitable to
+  // unroll?
+  if (!L->getExitingBlock() && !canProfitablyUnrollMultiExitLoop(L)) {
+    UP.Count = 0;
+    return false;
+  }
+
   // Reduce count based on the type of unrolling and the threshold values.
   UP.Runtime |= PragmaEnableUnroll || PragmaCount > 0 || UserUnrollCount;
   if (!UP.Runtime) {

diff  --git a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
index e2eb0015af10..8305165d401d 100644
--- a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
@@ -46,13 +46,6 @@ using namespace llvm;
 
 STATISTIC(NumRuntimeUnrolled,
           "Number of loops unrolled with run-time trip counts");
-static cl::opt<bool> UnrollRuntimeMultiExit(
-    "unroll-runtime-multi-exit", cl::init(false), cl::Hidden,
-    cl::desc("Allow runtime unrolling for loops with multiple exits, when "
-             "epilog is generated"));
-static cl::opt<bool> UnrollRuntimeOtherExitPredictable(
-    "unroll-runtime-other-exit-predictable", cl::init(false), cl::Hidden,
-    cl::desc("Assume the non latch exit block to be predictable"));
 
 /// Connect the unrolling prolog code to the original loop.
 /// The unrolling prolog code contains code to execute the
@@ -461,61 +454,6 @@ static bool canSafelyUnrollMultiExitLoop(Loop *L, BasicBlock *LatchExit,
   return true;
 }
 
-/// Returns true if we can profitably unroll the multi-exit loop L. Currently,
-/// we return true only if UnrollRuntimeMultiExit is set to true.
-static bool canProfitablyUnrollMultiExitLoop(
-    Loop *L, SmallVectorImpl<BasicBlock *> &OtherExits, BasicBlock *LatchExit,
-    bool PreserveLCSSA, bool UseEpilogRemainder) {
-
-#if !defined(NDEBUG)
-  assert(canSafelyUnrollMultiExitLoop(L, LatchExit, PreserveLCSSA,
-                                      UseEpilogRemainder) &&
-         "Should be safe to unroll before checking profitability!");
-#endif
-
-  // Priority goes to UnrollRuntimeMultiExit if it's supplied.
-  if (UnrollRuntimeMultiExit.getNumOccurrences())
-    return UnrollRuntimeMultiExit;
-
-  // The main pain point with multi-exit loop unrolling is that once unrolled,
-  // we will not be able to merge all blocks into a straight line code.
-  // There are branches within the unrolled loop that go to the OtherExits.
-  // The second point is the increase in code size, but this is true
-  // irrespective of multiple exits.
-
-  // Note: Both the heuristics below are coarse grained. We are essentially
-  // enabling unrolling of loops that have a single side exit other than the
-  // normal LatchExit (i.e. exiting into a deoptimize block).
-  // The heuristics considered are:
-  // 1. low number of branches in the unrolled version.
-  // 2. high predictability of these extra branches.
-  // We avoid unrolling loops that have more than two exiting blocks. This
-  // limits the total number of branches in the unrolled loop to be atmost
-  // the unroll factor (since one of the exiting blocks is the latch block).
-  SmallVector<BasicBlock*, 4> ExitingBlocks;
-  L->getExitingBlocks(ExitingBlocks);
-  if (ExitingBlocks.size() > 2)
-    return false;
-
-  // Allow unrolling of loops with no non latch exit blocks.
-  if (OtherExits.size() == 0)
-    return true;
-
-  // The second heuristic is that L has one exit other than the latchexit and
-  // that exit is a deoptimize block. We know that deoptimize blocks are rarely
-  // taken, which also implies the branch leading to the deoptimize block is
-  // highly predictable. When UnrollRuntimeOtherExitPredictable is specified, we
-  // assume the other exit branch is predictable even if it has no deoptimize
-  // call.
-  return (OtherExits.size() == 1 &&
-          (UnrollRuntimeOtherExitPredictable ||
-           OtherExits[0]->getTerminatingDeoptimizeCall()));
-  // TODO: These can be fine-tuned further to consider code size or deopt states
-  // that are captured by the deoptimize exit block.
-  // Also, we can extend this to support more cases, if we actually
-  // know of kinds of multiexit loops that would benefit from unrolling.
-}
-
 // Assign the maximum possible trip count as the back edge weight for the
 // remainder loop if the original loop comes with a branch weight.
 static void updateLatchBranchWeightsForRemainderLoop(Loop *OrigLoop,
@@ -659,9 +597,7 @@ bool llvm::UnrollRuntimeLoopRemainder(
   L->getUniqueNonLatchExitBlocks(OtherExits);
   bool isMultiExitUnrollingEnabled =
       canSafelyUnrollMultiExitLoop(L, LatchExit, PreserveLCSSA,
-                                   UseEpilogRemainder) &&
-      canProfitablyUnrollMultiExitLoop(L, OtherExits, LatchExit, PreserveLCSSA,
-                                       UseEpilogRemainder);
+                                   UseEpilogRemainder);
   // Support only single exit and exiting block unless multi-exit loop unrolling is enabled.
   if (!isMultiExitUnrollingEnabled &&
       (!L->getExitingBlock() || OtherExits.size())) {


        


More information about the llvm-commits mailing list