Skip to content

Commit 0087f54

Browse files
committed
Address review comments
* Combined changes from canVectorizeMemory into isVectorizableEarlyExitLoop. * Documented restrictions for isVectorizableEarlyExitLoop in header file. * Added reportVectorizationFailure call in LoopVectorize when we bail out. * General code refactor, clean-up.
1 parent d0cf2c6 commit 0087f54

File tree

4 files changed

+67
-66
lines changed

4 files changed

+67
-66
lines changed

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ class LoopVectorizationLegality {
470470
/// we read and write from memory. This method checks if it is
471471
/// legal to vectorize the code, considering only memory constrains.
472472
/// Returns true if the loop is vectorizable
473-
bool canVectorizeMemory(bool IsEarlyExitLoop);
473+
bool canVectorizeMemory();
474474

475475
/// Return true if we can vectorize this loop using the IF-conversion
476476
/// transformation.
@@ -481,6 +481,21 @@ class LoopVectorizationLegality {
481481
bool canVectorizeOuterLoop();
482482

483483
/// Returns true if this is an early exit loop that can be vectorized.
484+
/// Currently, a loop with an uncountable early exit is considered
485+
/// vectorizable if:
486+
/// 1. There are no writes to memory in the loop.
487+
/// 2. The loop has only one early uncountable exit
488+
/// 3. The early exit block dominates the latch block.
489+
/// 4. The latch block has an exact exit count.
490+
/// 5. There are no loads after the early exit block.
491+
/// 6. The loop does not contain reductions or recurrences.
492+
/// 7. We can prove at compile-time that loops will not contain faulting
493+
/// loads.
494+
/// 8. It is safe to speculatively execute instructions such as divide or
495+
/// call instructions.
496+
/// The list above is not based on theoretical limitations of vectorization,
497+
/// but simply a statement that more work is needed to support these
498+
/// additional cases safely.
484499
bool isVectorizableEarlyExitLoop();
485500

486501
/// Return true if all of the instructions in the block can be speculatively

llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp

Lines changed: 45 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ bool LoopVectorizationLegality::canVectorizeInstrs() {
10511051
return true;
10521052
}
10531053

1054-
bool LoopVectorizationLegality::canVectorizeMemory(bool IsEarlyExitLoop) {
1054+
bool LoopVectorizationLegality::canVectorizeMemory() {
10551055
LAI = &LAIs.getInfo(*TheLoop);
10561056
const OptimizationRemarkAnalysis *LAR = LAI->getReport();
10571057
if (LAR) {
@@ -1073,51 +1073,6 @@ bool LoopVectorizationLegality::canVectorizeMemory(bool IsEarlyExitLoop) {
10731073
return false;
10741074
}
10751075

1076-
// For loops with uncountable early exiting blocks that are not the latch
1077-
// it's necessary to perform extra checks, since the vectoriser is currently
1078-
// only capable of handling simple search loops.
1079-
if (IsEarlyExitLoop) {
1080-
// We don't support calls or any memory accesses that write to memory.
1081-
if (LAI->getNumStores()) {
1082-
reportVectorizationFailure(
1083-
"Writes to memory unsupported in early exit loops",
1084-
"Cannot vectorize early exit loop with writes to memory",
1085-
"WritesInEarlyExitLoop", ORE, TheLoop);
1086-
return false;
1087-
}
1088-
1089-
// The vectoriser cannot handle loads that occur after the early exit block.
1090-
BasicBlock *LatchBB = TheLoop->getLoopLatch();
1091-
assert(LatchBB->getUniquePredecessor() ==
1092-
getUncountableExitingBlocks()[0] &&
1093-
"Expected latch predecessor to be the early exiting block");
1094-
1095-
for (Instruction &I : *LatchBB) {
1096-
if (I.mayReadFromMemory()) {
1097-
reportVectorizationFailure(
1098-
"Loads not permitted after early exit",
1099-
"Cannot vectorize early exit loop with loads after early exit",
1100-
"LoadsAfterEarlyExit", ORE, TheLoop);
1101-
return false;
1102-
}
1103-
// Any other problematic instructions should have been caught earlier.
1104-
assert(!I.mayWriteToMemory() && !I.mayThrow() &&
1105-
!I.mayHaveSideEffects() &&
1106-
"Unexpected instructions in latch block of early exit loop");
1107-
}
1108-
1109-
// The vectoriser does not yet handle loops that may fault, but this will
1110-
// be improved in a follow-on patch.
1111-
// TODO: Handle loops that may fault.
1112-
if (!isDereferenceableReadOnlyLoop(TheLoop, PSE.getSE(), DT, AC)) {
1113-
reportVectorizationFailure(
1114-
"Loop may fault",
1115-
"Cannot vectorize potentially faulting early exit loop",
1116-
"PotentiallyFaultingEarlyExitLoop", ORE, TheLoop);
1117-
return false;
1118-
}
1119-
}
1120-
11211076
// We can vectorize stores to invariant address when final reduction value is
11221077
// guaranteed to be stored at the end of the loop. Also, if decision to
11231078
// vectorize loop is made, runtime checks are added so as to make sure that
@@ -1491,7 +1446,6 @@ bool LoopVectorizationLegality::canVectorizeLoopNestCFG(
14911446
}
14921447

14931448
bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
1494-
// At least one of the exiting blocks must be the latch.
14951449
BasicBlock *LatchBB = TheLoop->getLoopLatch();
14961450
if (!LatchBB) {
14971451
reportVectorizationFailure("Loop does not have a latch",
@@ -1553,33 +1507,38 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
15531507
// The only supported early exit loops so far are ones where the early
15541508
// exiting block is a unique predecessor of the latch block.
15551509
BasicBlock *LatchPredBB = LatchBB->getUniquePredecessor();
1556-
if (!LatchPredBB || LatchPredBB != getUncountableExitingBlocks()[0]) {
1510+
if (LatchPredBB != getSpeculativeEarlyExitingBlock()) {
15571511
reportVectorizationFailure("Early exit is not the latch predecessor",
15581512
"Cannot vectorize early exit loop",
15591513
"EarlyExitNotLatchPredecessor", ORE, TheLoop);
15601514
return false;
15611515
}
15621516

1563-
// Check all instructions in the loop to see if they could potentially
1564-
// generate exceptions or have side-effects.
1517+
// Check to see if there are instructions that could potentially generate
1518+
// exceptions or have side-effects.
15651519
auto IsSafeOperation = [](Instruction *I) -> bool {
1566-
// Is this a divide?
15671520
switch (I->getOpcode()) {
15681521
case Instruction::Load:
15691522
case Instruction::Store:
15701523
case Instruction::PHI:
15711524
case Instruction::Br:
1572-
// These are checked separately. For example, canVectorizeMemory will
1573-
// analyze the loads and stores in the loop.
1525+
// These are checked separately.
15741526
return true;
15751527
default:
15761528
return isSafeToSpeculativelyExecute(I);
15771529
}
15781530
};
15791531

15801532
for (auto *BB : TheLoop->blocks())
1581-
for (auto &I : *BB)
1582-
if (!IsSafeOperation(&I)) {
1533+
for (auto &I : *BB) {
1534+
if (I.mayWriteToMemory()) {
1535+
// We don't support writes to memory.
1536+
reportVectorizationFailure(
1537+
"Writes to memory unsupported in early exit loops",
1538+
"Cannot vectorize early exit loop with writes to memory",
1539+
"WritesInEarlyExitLoop", ORE, TheLoop);
1540+
return false;
1541+
} else if (!IsSafeOperation(&I)) {
15831542
reportVectorizationFailure("Early exit loop contains operations that "
15841543
"cannot be speculatively executed",
15851544
"Early exit loop contains operations that "
@@ -1588,10 +1547,9 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
15881547
TheLoop);
15891548
return false;
15901549
}
1550+
}
15911551

1592-
LLVM_DEBUG(
1593-
dbgs()
1594-
<< "LV: Found an early exit. Retrying with speculative exit count.\n");
1552+
// At least one of the exiting blocks must be the latch.
15951553
if (isa<SCEVCouldNotCompute>(
15961554
PSE.getSE()->getPredicatedExitCount(TheLoop, LatchBB, &Predicates))) {
15971555
reportVectorizationFailure(
@@ -1601,6 +1559,34 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
16011559
return false;
16021560
}
16031561

1562+
// The vectoriser cannot handle loads that occur after the early exit block.
1563+
assert(LatchBB->getUniquePredecessor() == getSpeculativeEarlyExitingBlock() &&
1564+
"Expected latch predecessor to be the early exiting block");
1565+
for (Instruction &I : *LatchBB) {
1566+
if (I.mayReadFromMemory()) {
1567+
reportVectorizationFailure(
1568+
"Loads not permitted after early exit",
1569+
"Cannot vectorize early exit loop with loads after early exit",
1570+
"LoadsAfterEarlyExit", ORE, TheLoop);
1571+
return false;
1572+
}
1573+
// Any other problematic instructions should have been caught earlier.
1574+
assert(!I.mayWriteToMemory() && !I.mayThrow() && !I.mayHaveSideEffects() &&
1575+
"Unexpected instructions in latch block of early exit loop");
1576+
}
1577+
1578+
// TODO: Handle loops that may fault.
1579+
if (!isDereferenceableReadOnlyLoop(TheLoop, PSE.getSE(), DT, AC)) {
1580+
reportVectorizationFailure(
1581+
"Loop may fault",
1582+
"Cannot vectorize potentially faulting early exit loop",
1583+
"PotentiallyFaultingEarlyExitLoop", ORE, TheLoop);
1584+
return false;
1585+
}
1586+
1587+
LLVM_DEBUG(
1588+
dbgs()
1589+
<< "LV: Found an early exit. Retrying with speculative exit count.\n");
16041590
const SCEV *SpecExitCount = PSE.getSymbolicMaxBackedgeTakenCount();
16051591
assert(!isa<SCEVCouldNotCompute>(SpecExitCount) &&
16061592
"Failed to get symbolic expression for backedge taken count");
@@ -1682,7 +1668,7 @@ bool LoopVectorizationLegality::canVectorize(bool UseVPlanNativePath) {
16821668
}
16831669

16841670
// Go over each instruction and look at memory deps.
1685-
if (!canVectorizeMemory(HasSpeculativeEarlyExit)) {
1671+
if (!canVectorizeMemory()) {
16861672
LLVM_DEBUG(dbgs() << "LV: Can't vectorize due to memory conflicts\n");
16871673
if (DoExtraAnalysis)
16881674
Result = false;

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9816,8 +9816,10 @@ bool LoopVectorizePass::processLoop(Loop *L) {
98169816
}
98179817

98189818
if (LVL.hasSpeculativeEarlyExit()) {
9819-
LLVM_DEBUG(dbgs() << "LV: Not vectorizing: Auto-vectorization of early "
9820-
<< "exit loops is not yet supported.\n");
9819+
reportVectorizationFailure(
9820+
"Auto-vectorization of early exit loops is not yet supported.",
9821+
"Auto-vectorization of early exit loops is not yet supported.",
9822+
"EarlyExitLoopsUnsupported", ORE, L);
98219823
return false;
98229824
}
98239825

llvm/test/Transforms/LoopVectorize/AArch64/simple_early_exit.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,9 +1648,7 @@ loop.end:
16481648
; requesting the small constant max trip count.
16491649
define i32 @diff_exit_block_needs_scev_check(i32 %end) {
16501650
; DEBUG-LABEL: LV: Checking a loop in 'diff_exit_block_needs_scev_check'
1651-
; DEBUG: LV: Found an early exit. Retrying with speculative exit count.
1652-
; DEBUG-NEXT: LV: Found speculative backedge taken count: (-1 + (1 umax (zext i10 (trunc i32 %end to i10) to i32)))<nsw>
1653-
; DEBUG-NEXT: LV: Not vectorizing: Loop may fault.
1651+
; DEBUG: LV: Not vectorizing: Loop may fault.
16541652
; CHECK-LABEL: define i32 @diff_exit_block_needs_scev_check(
16551653
; CHECK-SAME: i32 [[END:%.*]]) #[[ATTR0]] {
16561654
; CHECK-NEXT: entry:
@@ -1962,7 +1960,7 @@ loop.end:
19621960

19631961

19641962

1965-
declare i32 @foo(i32)
1963+
declare i32 @foo(i32) readonly
19661964
declare <vscale x 4 x i32> @foo_vec(<vscale x 4 x i32>)
19671965

19681966
attributes #0 = { "vector-function-abi-variant"="_ZGVsNxv_foo(foo_vec)" }

0 commit comments

Comments
 (0)