Skip to content

Commit e9e3a18

Browse files
committed
[LV] Don't cost branches and conditions to empty blocks.
Update the legacy cost model skip branches with successors blocks that are empty or only contain dead instructions, together with their conditions. Such branches and conditions won't result in any generated code and will be cleaned up by VPlan transforms. This fixes a difference between the legacy and VPlan-based cost model. When running LV in its usual pipeline position, such dead blocks should already have been cleaned up, but they might be generated manually or by fuzzers. Fixes #100591.
1 parent 7180170 commit e9e3a18

File tree

2 files changed

+890
-2
lines changed

2 files changed

+890
-2
lines changed

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6730,9 +6730,12 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
67306730
return RequiresScalarEpilogue &&
67316731
!TheLoop->contains(cast<Instruction>(U)->getParent());
67326732
};
6733+
6734+
LoopBlocksDFS DFS(TheLoop);
6735+
DFS.perform(LI);
67336736
MapVector<Value *, SmallVector<Value *>> DeadInvariantStoreOps;
6734-
for (BasicBlock *BB : TheLoop->blocks())
6735-
for (Instruction &I : *BB) {
6737+
for (BasicBlock *BB : reverse(make_range(DFS.beginRPO(), DFS.endRPO())))
6738+
for (Instruction &I : reverse(*BB)) {
67366739
// Find all stores to invariant variables. Since they are going to sink
67376740
// outside the loop we do not need calculate cost for them.
67386741
StoreInst *SI;
@@ -6765,6 +6768,13 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
67656768
Value *PointerOp = getLoadStorePointerOperand(&I);
67666769
DeadInterleavePointerOps.push_back(PointerOp);
67676770
}
6771+
6772+
// Queue branches for analysis. They are dead, if their successors only
6773+
// contain dead instructions.
6774+
if (auto *Br = dyn_cast<BranchInst>(&I)) {
6775+
if (Br->isConditional())
6776+
DeadOps.push_back(&I);
6777+
}
67686778
}
67696779

67706780
// Mark ops feeding interleave group members as free, if they are only used
@@ -6789,8 +6799,36 @@ void LoopVectorizationCostModel::collectValuesToIgnore() {
67896799
// Mark ops that would be trivially dead and are only used by ignored
67906800
// instructions as free.
67916801
BasicBlock *Header = TheLoop->getHeader();
6802+
6803+
// Returns true if the block contains only dead instructions. Such blocks will
6804+
// be removed by VPlan-to-VPlan transforms and won't be considered by the
6805+
// VPlan-based cost model, so skip them in the legacy cost-model as well.
6806+
auto IsEmptyBlock = [this](BasicBlock *BB) {
6807+
return all_of(*BB, [this](Instruction &I) {
6808+
return ValuesToIgnore.contains(&I) || VecValuesToIgnore.contains(&I) ||
6809+
(isa<BranchInst>(&I) && !cast<BranchInst>(&I)->isConditional());
6810+
});
6811+
};
67926812
for (unsigned I = 0; I != DeadOps.size(); ++I) {
67936813
auto *Op = dyn_cast<Instruction>(DeadOps[I]);
6814+
6815+
// Check if the branch should be considered dead.
6816+
if (auto *Br = dyn_cast_or_null<BranchInst>(Op)) {
6817+
BasicBlock *ThenBB = Br->getSuccessor(0);
6818+
BasicBlock *ElseBB = Br->getSuccessor(1);
6819+
bool ThenEmpty = IsEmptyBlock(ThenBB);
6820+
bool ElseEmpty = IsEmptyBlock(ElseBB);
6821+
if ((ThenEmpty && ElseEmpty) ||
6822+
(ThenEmpty && ThenBB->getSingleSuccessor() == ElseBB &&
6823+
ElseBB->phis().empty()) ||
6824+
(ElseEmpty && ElseBB->getSingleSuccessor() == ThenBB &&
6825+
ThenBB->phis().empty())) {
6826+
VecValuesToIgnore.insert(Br);
6827+
DeadOps.push_back(Br->getCondition());
6828+
}
6829+
continue;
6830+
}
6831+
67946832
// Skip any op that shouldn't be considered dead.
67956833
if (!Op || !TheLoop->contains(Op) ||
67966834
(isa<PHINode>(Op) && Op->getParent() == Header) ||

0 commit comments

Comments
 (0)