aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-08-02 22:21:25 +0200
committerNikita Popov <nikita.ppv@gmail.com>2021-08-02 22:23:34 +0200
commitc7770574f9b1c7b8548bf0596ed2008aa5cc5ca4 (patch)
tree69717369b08bd9e32877be72b63bca146aff340f /llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
parentb58eda39eb1fcb7df942c8569d031a342fa1308d (diff)
downloadllvm-c7770574f9b1c7b8548bf0596ed2008aa5cc5ca4.zip
llvm-c7770574f9b1c7b8548bf0596ed2008aa5cc5ca4.tar.gz
llvm-c7770574f9b1c7b8548bf0596ed2008aa5cc5ca4.tar.bz2
Revert "[unroll] Move multiple exit costing into consumer pass [NFC]"
This reverts commit 76940577e4bf9c63a8a4ebd32b556bd7feb8cad3. This causes Transforms/LoopUnroll/ARM/multi-blocks.ll to fail.
Diffstat (limited to 'llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp')
-rw-r--r--llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp66
1 files changed, 65 insertions, 1 deletions
diff --git a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp
index 8305165..e2eb001 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())) {