Skip to content

Commit d0cf2c6

Browse files
committed
Address review comments
* Reverted LoopAccessAnalysis changes in favour of new code in LoopVectorizationLegality.cpp that checks if instructions are safe to speculatively execute. * Updated some comments and done minor code refactoring. * Added new tests for demonstrating under which circumstances we can speculatively execute calls and divides. * Added new test where the early exit is in a conditional block. * Added new test containing store instructions. * Added new test containing loads after early exit.
1 parent ec58810 commit d0cf2c6

File tree

5 files changed

+450
-39
lines changed

5 files changed

+450
-39
lines changed

llvm/include/llvm/Analysis/LoopAccessAnalysis.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -661,8 +661,7 @@ class LoopAccessInfo {
661661
bool isInvariant(Value *V) const;
662662

663663
unsigned getNumStores() const { return NumStores; }
664-
unsigned getNumLoads() const { return NumLoads; }
665-
unsigned getNumCalls() const { return NumCalls; }
664+
unsigned getNumLoads() const { return NumLoads;}
666665

667666
/// The diagnostics report generated for the analysis. E.g. why we
668667
/// couldn't analyze the loop.
@@ -755,7 +754,6 @@ class LoopAccessInfo {
755754

756755
unsigned NumLoads = 0;
757756
unsigned NumStores = 0;
758-
unsigned NumCalls = 0;
759757

760758
/// Cache the result of analyzeLoop.
761759
bool CanVecMem = false;

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,7 @@ class LoopVectorizationLegality {
480480
/// specific checks for outer loop vectorization.
481481
bool canVectorizeOuterLoop();
482482

483-
/// Returns true if this is a supported early exit loop that we can
484-
/// vectorize.
483+
/// Returns true if this is an early exit loop that can be vectorized.
485484
bool isVectorizableEarlyExitLoop();
486485

487486
/// Return true if all of the instructions in the block can be speculatively
@@ -594,10 +593,11 @@ class LoopVectorizationLegality {
594593
/// uncountable exiting block that is not the latch.
595594
bool HasSpeculativeEarlyExit = false;
596595

597-
/// Keeps track of all the exits with known or countable exit-not-taken
598-
/// counts.
596+
/// Keep track of all the loop exiting blocks.
599597
SmallVector<BasicBlock *, 4> CountableExitingBlocks;
600598
SmallVector<BasicBlock *, 4> UncountableExitingBlocks;
599+
600+
/// Keep track of the destinations of all uncountable exits.
601601
SmallVector<BasicBlock *, 4> UncountableExitBlocks;
602602
};
603603

llvm/lib/Analysis/LoopAccessAnalysis.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2445,11 +2445,8 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, const LoopInfo *LI,
24452445
// vectorize a loop if it contains known function calls that don't set
24462446
// the flag. Therefore, it is safe to ignore this read from memory.
24472447
auto *Call = dyn_cast<CallInst>(&I);
2448-
if (Call) {
2449-
NumCalls++;
2450-
if (getVectorIntrinsicIDForCall(Call, TLI))
2451-
continue;
2452-
}
2448+
if (Call && getVectorIntrinsicIDForCall(Call, TLI))
2449+
continue;
24532450

24542451
// If this is a load, save it. If this instruction can read from memory
24552452
// but is not a load, then we quit. Notice that we don't handle function

llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,16 +1086,12 @@ bool LoopVectorizationLegality::canVectorizeMemory(bool IsEarlyExitLoop) {
10861086
return false;
10871087
}
10881088

1089-
if (LAI->getNumCalls()) {
1090-
reportVectorizationFailure(
1091-
"Calls unsupported in early exit loops",
1092-
"Cannot vectorize early exit loop with function calls",
1093-
"CallsInEarlyExitLoop", ORE, TheLoop);
1094-
return false;
1095-
}
1096-
10971089
// The vectoriser cannot handle loads that occur after the early exit block.
10981090
BasicBlock *LatchBB = TheLoop->getLoopLatch();
1091+
assert(LatchBB->getUniquePredecessor() ==
1092+
getUncountableExitingBlocks()[0] &&
1093+
"Expected latch predecessor to be the early exiting block");
1094+
10991095
for (Instruction &I : *LatchBB) {
11001096
if (I.mayReadFromMemory()) {
11011097
reportVectorizationFailure(
@@ -1104,10 +1100,15 @@ bool LoopVectorizationLegality::canVectorizeMemory(bool IsEarlyExitLoop) {
11041100
"LoadsAfterEarlyExit", ORE, TheLoop);
11051101
return false;
11061102
}
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");
11071107
}
11081108

11091109
// The vectoriser does not yet handle loops that may fault, but this will
11101110
// be improved in a follow-on patch.
1111+
// TODO: Handle loops that may fault.
11111112
if (!isDereferenceableReadOnlyLoop(TheLoop, PSE.getSE(), DT, AC)) {
11121113
reportVectorizationFailure(
11131114
"Loop may fault",
@@ -1499,32 +1500,42 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
14991500
return false;
15001501
}
15011502

1503+
if (Reductions.size() || FixedOrderRecurrences.size()) {
1504+
reportVectorizationFailure(
1505+
"Found reductions or recurrences in early-exit loop",
1506+
"Cannot vectorize early exit loop with reductions or recurrences",
1507+
"RecurrencesInEarlyExitLoop", ORE, TheLoop);
1508+
return false;
1509+
}
1510+
15021511
SmallVector<BasicBlock *, 8> ExitingBlocks;
15031512
TheLoop->getExitingBlocks(ExitingBlocks);
15041513

1505-
// Keep a record of all the exiting blocks with exact exit counts, as well as
1506-
// those with inexact counts.
1514+
// Keep a record of all the exiting blocks.
15071515
SmallVector<const SCEVPredicate *, 4> Predicates;
15081516
for (BasicBlock *BB1 : ExitingBlocks) {
15091517
const SCEV *EC =
15101518
PSE.getSE()->getPredicatedExitCount(TheLoop, BB1, &Predicates);
15111519
if (isa<SCEVCouldNotCompute>(EC)) {
15121520
UncountableExitingBlocks.push_back(BB1);
15131521

1514-
unsigned NumExitBlocks = 0;
1515-
for (BasicBlock *BB2 : successors(BB1)) {
1516-
if (!TheLoop->contains(BB2)) {
1517-
UncountableExitBlocks.push_back(BB2);
1518-
NumExitBlocks++;
1519-
}
1520-
}
1521-
if (NumExitBlocks > 1) {
1522+
SmallVector<BasicBlock *, 2> Succs(successors(BB1));
1523+
if (Succs.size() != 2) {
15221524
reportVectorizationFailure(
1523-
"Early exiting block has more than one successor outside of loop",
1524-
"Too many successors from early exiting block",
1525+
"Early exiting block does not have exactly two successors",
1526+
"Incorrect number of successors from early exiting block",
15251527
"EarlyExitTooManySuccessors", ORE, TheLoop);
15261528
return false;
15271529
}
1530+
1531+
BasicBlock *BB2;
1532+
if (!TheLoop->contains(Succs[0]))
1533+
BB2 = Succs[0];
1534+
else {
1535+
assert(!TheLoop->contains(Succs[1]));
1536+
BB2 = Succs[1];
1537+
}
1538+
UncountableExitBlocks.push_back(BB2);
15281539
} else
15291540
CountableExitingBlocks.push_back(BB1);
15301541
}
@@ -1549,13 +1560,34 @@ bool LoopVectorizationLegality::isVectorizableEarlyExitLoop() {
15491560
return false;
15501561
}
15511562

1552-
if (Reductions.size() || FixedOrderRecurrences.size()) {
1553-
reportVectorizationFailure(
1554-
"Found reductions or recurrences in early-exit loop",
1555-
"Cannot vectorize early exit loop with reductions or recurrences",
1556-
"RecurrencesInEarlyExitLoop", ORE, TheLoop);
1557-
return false;
1558-
}
1563+
// Check all instructions in the loop to see if they could potentially
1564+
// generate exceptions or have side-effects.
1565+
auto IsSafeOperation = [](Instruction *I) -> bool {
1566+
// Is this a divide?
1567+
switch (I->getOpcode()) {
1568+
case Instruction::Load:
1569+
case Instruction::Store:
1570+
case Instruction::PHI:
1571+
case Instruction::Br:
1572+
// These are checked separately. For example, canVectorizeMemory will
1573+
// analyze the loads and stores in the loop.
1574+
return true;
1575+
default:
1576+
return isSafeToSpeculativelyExecute(I);
1577+
}
1578+
};
1579+
1580+
for (auto *BB : TheLoop->blocks())
1581+
for (auto &I : *BB)
1582+
if (!IsSafeOperation(&I)) {
1583+
reportVectorizationFailure("Early exit loop contains operations that "
1584+
"cannot be speculatively executed",
1585+
"Early exit loop contains operations that "
1586+
"cannot be speculatively executed",
1587+
"UnsafeOperationsEarlyExitLoop", ORE,
1588+
TheLoop);
1589+
return false;
1590+
}
15591591

15601592
LLVM_DEBUG(
15611593
dbgs()

0 commit comments

Comments
 (0)