Skip to content

Commit b27a332

Browse files
committed
Add support for vectorising a limited set of early exit loops
1 parent 5b4094c commit b27a332

21 files changed

+1014
-417
lines changed

llvm/include/llvm/Support/GenericLoopInfo.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ template <class BlockT, class LoopT> class LoopBase {
294294
/// Otherwise return null.
295295
BlockT *getUniqueExitBlock() const;
296296

297+
/// Return the unique exit block for the latch, or null if there are multiple
298+
/// different exit blocks.
299+
BlockT *getUniqueLatchExitBlock() const;
300+
297301
/// Return true if this loop does not have any exit blocks.
298302
bool hasNoExitBlocks() const;
299303

llvm/include/llvm/Support/GenericLoopInfoImpl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ BlockT *LoopBase<BlockT, LoopT>::getUniqueExitBlock() const {
159159
return getExitBlockHelper(this, true).first;
160160
}
161161

162+
template <class BlockT, class LoopT>
163+
BlockT *LoopBase<BlockT, LoopT>::getUniqueLatchExitBlock() const {
164+
const BlockT *Latch = getLoopLatch();
165+
assert(Latch && "Latch block must exists");
166+
SmallVector<BlockT *, 4> ExitBlocks;
167+
getUniqueExitBlocksHelper(this, ExitBlocks,
168+
[Latch](const BlockT *BB) { return BB == Latch; });
169+
return ExitBlocks.size() == 1 ? ExitBlocks[0] : nullptr;
170+
}
171+
162172
/// getExitEdges - Return all pairs of (_inside_block_,_outside_block_).
163173
template <class BlockT, class LoopT>
164174
void LoopBase<BlockT, LoopT>::getExitEdges(

llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,6 @@ class LoopVectorizationLegality {
287287
/// we can use in-order reductions.
288288
bool canVectorizeFPMath(bool EnableStrictReductions);
289289

290-
/// Returns true if the loop has an early exit that we can vectorize.
291-
bool canVectorizeEarlyExit() const;
292-
293290
/// Return true if we can vectorize this loop while folding its tail by
294291
/// masking.
295292
bool canFoldTailByMasking() const;

llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,6 @@ AllowStridedPointerIVs("lv-strided-pointer-ivs", cl::init(false), cl::Hidden,
4343
cl::desc("Enable recognition of non-constant strided "
4444
"pointer induction variables."));
4545

46-
static cl::opt<bool>
47-
EnableEarlyExitVectorization("enable-early-exit-vectorization",
48-
cl::init(false), cl::Hidden, cl::desc(""));
49-
5046
namespace llvm {
5147
cl::opt<bool>
5248
HintsAllowReordering("hints-allow-reordering", cl::init(true), cl::Hidden,
@@ -87,6 +83,12 @@ static cl::opt<bool> EnableHistogramVectorization(
8783
"enable-histogram-loop-vectorization", cl::init(false), cl::Hidden,
8884
cl::desc("Enables autovectorization of some loops containing histograms"));
8985

86+
static cl::opt<bool> AssumeNoMemFault(
87+
"vectorizer-no-mem-fault", cl::init(false), cl::Hidden,
88+
cl::desc("Assume vectorized loops will not have memory faults, which is "
89+
"potentially unsafe but can be useful for testing vectorization "
90+
"of early exit loops."));
91+
9092
/// Maximum vectorization interleave count.
9193
static const unsigned MaxInterleaveFactor = 16;
9294

@@ -1379,10 +1381,14 @@ bool LoopVectorizationLegality::isFixedOrderRecurrence(
13791381
}
13801382

13811383
bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) const {
1382-
// When vectorizing early exits, create predicates for all blocks, except the
1383-
// header.
1384-
if (canVectorizeEarlyExit() && BB != TheLoop->getHeader())
1384+
// The only block currently permitted after the early exiting block is the
1385+
// loop latch, so only that blocks needs predication.
1386+
// FIXME: Once we support instructions in the loop that cannot be executed
1387+
// speculatively, such as stores, we will also need to predicate all blocks
1388+
// leading up to the early exit too.
1389+
if (hasUncountableEarlyExit() && BB == TheLoop->getLoopLatch())
13851390
return true;
1391+
13861392
return LoopAccessInfo::blockNeedsPredication(BB, TheLoop, DT);
13871393
}
13881394

@@ -1519,27 +1525,6 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() {
15191525
return true;
15201526
}
15211527

1522-
bool LoopVectorizationLegality::canVectorizeEarlyExit() const {
1523-
// Currently only allow vectorizing loops with early exits, if early-exit
1524-
// vectorization is explicitly enabled and the loop has metadata to force
1525-
// vectorization.
1526-
if (!EnableEarlyExitVectorization)
1527-
return false;
1528-
1529-
SmallVector<BasicBlock *> Exiting;
1530-
TheLoop->getExitingBlocks(Exiting);
1531-
if (Exiting.size() == 1)
1532-
return false;
1533-
1534-
LoopVectorizeHints Hints(TheLoop, true, *ORE);
1535-
if (Hints.getForce() == LoopVectorizeHints::FK_Undefined)
1536-
return false;
1537-
1538-
Function *Fn = TheLoop->getHeader()->getParent();
1539-
return Hints.allowVectorization(Fn, TheLoop,
1540-
true /*VectorizeOnlyWhenForced*/);
1541-
}
1542-
15431528
// Helper function to canVectorizeLoopNestCFG.
15441529
bool LoopVectorizationLegality::canVectorizeLoopCFG(Loop *Lp,
15451530
bool UseVPlanNativePath) {
@@ -1662,6 +1647,15 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
16621647
// PSE.getSymbolicMaxBackedgeTakenCount() below.
16631648
Predicates.clear();
16641649

1650+
unsigned NumUncountableExits = getUncountableExitingBlocks().size();
1651+
if (NumUncountableExits > 0) {
1652+
LoopVectorizeHints Hints(TheLoop, true, *ORE);
1653+
if (Hints.getForce() != LoopVectorizeHints::FK_Undefined &&
1654+
Hints.allowVectorization(TheLoop->getHeader()->getParent(), TheLoop,
1655+
true /*VectorizeOnlyWhenForced*/))
1656+
return true;
1657+
}
1658+
16651659
// We only support one uncountable early exit.
16661660
if (getUncountableExitingBlocks().size() != 1) {
16671661
reportVectorizationFailure(
@@ -1736,11 +1730,15 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
17361730
Predicates.clear();
17371731
if (!isDereferenceableReadOnlyLoop(TheLoop, PSE.getSE(), DT, AC,
17381732
&Predicates)) {
1739-
reportVectorizationFailure(
1740-
"Loop may fault",
1741-
"Cannot vectorize potentially faulting early exit loop",
1742-
"PotentiallyFaultingEarlyExitLoop", ORE, TheLoop);
1743-
return false;
1733+
if (!AssumeNoMemFault) {
1734+
reportVectorizationFailure(
1735+
"Loop may fault",
1736+
"Cannot vectorize potentially faulting early exit loop",
1737+
"PotentiallyFaultingEarlyExitLoop", ORE, TheLoop);
1738+
return false;
1739+
} else
1740+
LLVM_DEBUG(dbgs() << "LV: Assuming early exit vector loop will not "
1741+
<< "fault\n");
17441742
}
17451743

17461744
[[maybe_unused]] const SCEV *SymbolicMaxBTC =

0 commit comments

Comments
 (0)