[llvm] c777057 - Revert "[unroll] Move multiple exit costing into consumer pass [NFC]"

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 2 13:23:57 PDT 2021


Author: Nikita Popov
Date: 2021-08-02T22:23:34+02:00
New Revision: c7770574f9b1c7b8548bf0596ed2008aa5cc5ca4

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

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

This reverts commit 76940577e4bf9c63a8a4ebd32b556bd7feb8cad3.

This causes Transforms/LoopUnroll/ARM/multi-blocks.ll to fail.

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 b8799622d8ab..49501f324a49 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
@@ -175,14 +175,6 @@ 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.
@@ -742,57 +734,6 @@ 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
@@ -1041,13 +982,6 @@ 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 8305165d401d..e2eb0015af10 100644
--- a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
@@ -46,6 +46,13 @@ 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
@@ -454,6 +461,61 @@ 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,
@@ -597,7 +659,9 @@ bool llvm::UnrollRuntimeLoopRemainder(
   L->getUniqueNonLatchExitBlocks(OtherExits);
   bool isMultiExitUnrollingEnabled =
       canSafelyUnrollMultiExitLoop(L, LatchExit, PreserveLCSSA,
-                                   UseEpilogRemainder);
+                                   UseEpilogRemainder) &&
+      canProfitablyUnrollMultiExitLoop(L, OtherExits, LatchExit, PreserveLCSSA,
+                                       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