Skip to content

Commit c0ebfbe

Browse files
committed
Add an optional list of blocks to avoid when looking for a path in isPotentiallyReachable.
The leads to some ambiguous overloads, so update three callers. Differential Revision: https://reviews.llvm.org/D60085 llvm-svn: 357447
1 parent 536383a commit c0ebfbe

File tree

6 files changed

+158
-48
lines changed

6 files changed

+158
-48
lines changed

llvm/include/llvm/Analysis/CFG.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ unsigned GetSuccessorNumber(const BasicBlock *BB, const BasicBlock *Succ);
4747
bool isCriticalEdge(const Instruction *TI, unsigned SuccNum,
4848
bool AllowIdenticalEdges = false);
4949

50-
/// Determine whether instruction 'To' is reachable from 'From',
51-
/// returning true if uncertain.
50+
/// Determine whether instruction 'To' is reachable from 'From', without passing
51+
/// through any blocks in ExclusionSet, returning true if uncertain.
5252
///
5353
/// Determine whether there is a path from From to To within a single function.
5454
/// Returns false only if we can prove that once 'From' has been executed then
@@ -62,9 +62,10 @@ bool isCriticalEdge(const Instruction *TI, unsigned SuccNum,
6262
/// we find a block that dominates the block containing 'To'. DT is most useful
6363
/// on branchy code but not loops, and LI is most useful on code with loops but
6464
/// does not help on branchy code outside loops.
65-
bool isPotentiallyReachable(const Instruction *From, const Instruction *To,
66-
const DominatorTree *DT = nullptr,
67-
const LoopInfo *LI = nullptr);
65+
bool isPotentiallyReachable(
66+
const Instruction *From, const Instruction *To,
67+
const SmallPtrSetImpl<BasicBlock *> *ExclusionSet = nullptr,
68+
const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);
6869

6970
/// Determine whether block 'To' is reachable from 'From', returning
7071
/// true if uncertain.
@@ -88,6 +89,20 @@ bool isPotentiallyReachableFromMany(SmallVectorImpl<BasicBlock *> &Worklist,
8889
const DominatorTree *DT = nullptr,
8990
const LoopInfo *LI = nullptr);
9091

92+
/// Determine whether there is at least one path from a block in
93+
/// 'Worklist' to 'StopBB' without passing through any blocks in
94+
/// 'ExclusionSet', returning true if uncertain.
95+
///
96+
/// Determine whether there is a path from at least one block in Worklist to
97+
/// StopBB within a single function without passing through any of the blocks
98+
/// in 'ExclusionSet'. Returns false only if we can prove that once any block
99+
/// in 'Worklist' has been reached then 'StopBB' can not be executed.
100+
/// Conservatively returns true.
101+
bool isPotentiallyReachableFromMany(
102+
SmallVectorImpl<BasicBlock *> &Worklist, BasicBlock *StopBB,
103+
const SmallPtrSetImpl<BasicBlock *> *ExclusionSet,
104+
const DominatorTree *DT = nullptr, const LoopInfo *LI = nullptr);
105+
91106
/// Return true if the control flow in \p RPOTraversal is irreducible.
92107
///
93108
/// This is a generic implementation to detect CFG irreducibility based on loop

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1906,7 +1906,7 @@ bool BasicAAResult::isValueEqualInPotentialCycles(const Value *V,
19061906
// the Values cannot come from different iterations of a potential cycle the
19071907
// phi nodes could be involved in.
19081908
for (auto *P : VisitedPhiBBs)
1909-
if (isPotentiallyReachable(&P->front(), Inst, DT, LI))
1909+
if (isPotentiallyReachable(&P->front(), Inst, nullptr, DT, LI))
19101910
return false;
19111911

19121912
return true;

llvm/lib/Analysis/CFG.cpp

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "llvm/Analysis/CFG.h"
15+
#include "llvm/ADT/SmallPtrSet.h"
1516
#include "llvm/ADT/SmallSet.h"
1617
#include "llvm/Analysis/LoopInfo.h"
1718
#include "llvm/IR/Dominators.h"
@@ -119,22 +120,33 @@ static const Loop *getOutermostLoop(const LoopInfo *LI, const BasicBlock *BB) {
119120
return L;
120121
}
121122

122-
// True if there is a loop which contains both BB1 and BB2.
123-
static bool loopContainsBoth(const LoopInfo *LI,
124-
const BasicBlock *BB1, const BasicBlock *BB2) {
125-
const Loop *L1 = getOutermostLoop(LI, BB1);
126-
const Loop *L2 = getOutermostLoop(LI, BB2);
127-
return L1 != nullptr && L1 == L2;
128-
}
129-
130123
bool llvm::isPotentiallyReachableFromMany(
131124
SmallVectorImpl<BasicBlock *> &Worklist, BasicBlock *StopBB,
132-
const DominatorTree *DT, const LoopInfo *LI) {
125+
const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
126+
const LoopInfo *LI) {
133127
// When the stop block is unreachable, it's dominated from everywhere,
134128
// regardless of whether there's a path between the two blocks.
135129
if (DT && !DT->isReachableFromEntry(StopBB))
136130
DT = nullptr;
137131

132+
// We can't skip directly from a block that dominates the stop block if the
133+
// exclusion block is potentially in between.
134+
if (ExclusionSet && !ExclusionSet->empty())
135+
DT = nullptr;
136+
137+
// Normally any block in a loop is reachable from any other block in a loop,
138+
// however excluded blocks might partition the body of a loop to make that
139+
// untrue.
140+
SmallPtrSet<const Loop *, 8> LoopsWithHoles;
141+
if (LI && ExclusionSet) {
142+
for (auto BB : *ExclusionSet) {
143+
if (const Loop *L = getOutermostLoop(LI, BB))
144+
LoopsWithHoles.insert(L);
145+
}
146+
}
147+
148+
const Loop *StopLoop = LI ? getOutermostLoop(LI, StopBB) : nullptr;
149+
138150
// Limit the number of blocks we visit. The goal is to avoid run-away compile
139151
// times on large CFGs without hampering sensible code. Arbitrarily chosen.
140152
unsigned Limit = 32;
@@ -145,18 +157,31 @@ bool llvm::isPotentiallyReachableFromMany(
145157
continue;
146158
if (BB == StopBB)
147159
return true;
160+
if (ExclusionSet && ExclusionSet->count(BB))
161+
continue;
148162
if (DT && DT->dominates(BB, StopBB))
149163
return true;
150-
if (LI && loopContainsBoth(LI, BB, StopBB))
151-
return true;
164+
165+
const Loop *Outer = nullptr;
166+
if (LI) {
167+
Outer = getOutermostLoop(LI, BB);
168+
// If we're in a loop with a hole, not all blocks in the loop are
169+
// reachable from all other blocks. That implies we can't simply jump to
170+
// the loop's exit blocks, as that exit might need to pass through an
171+
// excluded block. Clear Outer so we process BB's successors.
172+
if (LoopsWithHoles.count(Outer))
173+
Outer = nullptr;
174+
if (StopLoop && Outer == StopLoop)
175+
return true;
176+
}
152177

153178
if (!--Limit) {
154179
// We haven't been able to prove it one way or the other. Conservatively
155180
// answer true -- that there is potentially a path.
156181
return true;
157182
}
158183

159-
if (const Loop *Outer = LI ? getOutermostLoop(LI, BB) : nullptr) {
184+
if (Outer) {
160185
// All blocks in a single loop are reachable from all other blocks. From
161186
// any of these blocks, we can skip directly to the exits of the loop,
162187
// ignoring any other blocks inside the loop body.
@@ -180,11 +205,13 @@ bool llvm::isPotentiallyReachable(const BasicBlock *A, const BasicBlock *B,
180205
Worklist.push_back(const_cast<BasicBlock*>(A));
181206

182207
return isPotentiallyReachableFromMany(Worklist, const_cast<BasicBlock *>(B),
183-
DT, LI);
208+
nullptr, DT, LI);
184209
}
185210

186-
bool llvm::isPotentiallyReachable(const Instruction *A, const Instruction *B,
187-
const DominatorTree *DT, const LoopInfo *LI) {
211+
bool llvm::isPotentiallyReachable(
212+
const Instruction *A, const Instruction *B,
213+
const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
214+
const LoopInfo *LI) {
188215
assert(A->getParent()->getParent() == B->getParent()->getParent() &&
189216
"This analysis is function-local!");
190217

@@ -230,14 +257,16 @@ bool llvm::isPotentiallyReachable(const Instruction *A, const Instruction *B,
230257
if (DT->isReachableFromEntry(A->getParent()) !=
231258
DT->isReachableFromEntry(B->getParent()))
232259
return false;
233-
if (A->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
234-
DT->isReachableFromEntry(B->getParent()))
235-
return true;
236-
if (B->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
237-
DT->isReachableFromEntry(A->getParent()))
238-
return false;
260+
if (!ExclusionSet || ExclusionSet->empty()) {
261+
if (A->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
262+
DT->isReachableFromEntry(B->getParent()))
263+
return true;
264+
if (B->getParent() == &A->getParent()->getParent()->getEntryBlock() &&
265+
DT->isReachableFromEntry(A->getParent()))
266+
return false;
267+
}
239268
}
240269

241270
return isPotentiallyReachableFromMany(
242-
Worklist, const_cast<BasicBlock *>(B->getParent()), DT, LI);
271+
Worklist, const_cast<BasicBlock *>(B->getParent()), ExclusionSet, DT, LI);
243272
}

llvm/lib/Analysis/CaptureTracking.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,14 @@ namespace {
101101

102102
SmallVector<BasicBlock*, 32> Worklist;
103103
Worklist.append(succ_begin(BB), succ_end(BB));
104-
return !isPotentiallyReachableFromMany(Worklist, BB, DT);
104+
return !isPotentiallyReachableFromMany(Worklist, BB, nullptr, DT);
105105
}
106106

107107
// If the value is defined in the same basic block as use and BeforeHere,
108108
// there is no need to explore the use if BeforeHere dominates use.
109109
// Check whether there is a path from I to BeforeHere.
110110
if (BeforeHere != I && DT->dominates(BeforeHere, I) &&
111-
!isPotentiallyReachable(I, BeforeHere, DT))
111+
!isPotentiallyReachable(I, BeforeHere, nullptr, DT))
112112
return true;
113113

114114
return false;

llvm/lib/CodeGen/DwarfEHPrepare.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ size_t DwarfEHPrepare::pruneUnreachableResumes(
145145
size_t ResumeIndex = 0;
146146
for (auto *RI : Resumes) {
147147
for (auto *LP : CleanupLPads) {
148-
if (isPotentiallyReachable(LP, RI, DT)) {
148+
if (isPotentiallyReachable(LP, RI, nullptr, DT)) {
149149
ResumeReachable.set(ResumeIndex);
150150
break;
151151
}

llvm/unittests/Analysis/CFGTest.cpp

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/Analysis/CFG.h"
10+
#include "llvm/ADT/SmallPtrSet.h"
1011
#include "llvm/Analysis/LoopInfo.h"
1112
#include "llvm/AsmParser/Parser.h"
1213
#include "llvm/IR/Dominators.h"
@@ -57,24 +58,32 @@ class IsPotentiallyReachableTest : public testing::Test {
5758
report_fatal_error("@test must have an instruction %A");
5859
if (B == nullptr)
5960
report_fatal_error("@test must have an instruction %B");
61+
62+
assert(ExclusionSet.empty());
63+
for (auto I = F->begin(), E = F->end(); I != E; ++I) {
64+
if (I->hasName() && I->getName().startswith("excluded"))
65+
ExclusionSet.insert(&*I);
66+
}
6067
}
6168

6269
void ExpectPath(bool ExpectedResult) {
6370
static char ID;
6471
class IsPotentiallyReachableTestPass : public FunctionPass {
6572
public:
66-
IsPotentiallyReachableTestPass(bool ExpectedResult,
67-
Instruction *A, Instruction *B)
68-
: FunctionPass(ID), ExpectedResult(ExpectedResult), A(A), B(B) {}
69-
70-
static int initialize() {
71-
PassInfo *PI = new PassInfo("isPotentiallyReachable testing pass",
72-
"", &ID, nullptr, true, true);
73-
PassRegistry::getPassRegistry()->registerPass(*PI, false);
74-
initializeLoopInfoWrapperPassPass(*PassRegistry::getPassRegistry());
75-
initializeDominatorTreeWrapperPassPass(
76-
*PassRegistry::getPassRegistry());
77-
return 0;
73+
IsPotentiallyReachableTestPass(bool ExpectedResult, Instruction *A,
74+
Instruction *B,
75+
SmallPtrSet<BasicBlock *, 4> ExclusionSet)
76+
: FunctionPass(ID), ExpectedResult(ExpectedResult), A(A), B(B),
77+
ExclusionSet(ExclusionSet) {}
78+
79+
static int initialize() {
80+
PassInfo *PI = new PassInfo("isPotentiallyReachable testing pass", "",
81+
&ID, nullptr, true, true);
82+
PassRegistry::getPassRegistry()->registerPass(*PI, false);
83+
initializeLoopInfoWrapperPassPass(*PassRegistry::getPassRegistry());
84+
initializeDominatorTreeWrapperPassPass(
85+
*PassRegistry::getPassRegistry());
86+
return 0;
7887
}
7988

8089
void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -90,22 +99,26 @@ class IsPotentiallyReachableTest : public testing::Test {
9099
LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
91100
DominatorTree *DT =
92101
&getAnalysis<DominatorTreeWrapperPass>().getDomTree();
93-
EXPECT_EQ(isPotentiallyReachable(A, B, nullptr, nullptr),
102+
EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, nullptr, nullptr),
103+
ExpectedResult);
104+
EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, DT, nullptr),
105+
ExpectedResult);
106+
EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, nullptr, LI),
107+
ExpectedResult);
108+
EXPECT_EQ(isPotentiallyReachable(A, B, &ExclusionSet, DT, LI),
94109
ExpectedResult);
95-
EXPECT_EQ(isPotentiallyReachable(A, B, DT, nullptr), ExpectedResult);
96-
EXPECT_EQ(isPotentiallyReachable(A, B, nullptr, LI), ExpectedResult);
97-
EXPECT_EQ(isPotentiallyReachable(A, B, DT, LI), ExpectedResult);
98110
return false;
99111
}
100112
bool ExpectedResult;
101113
Instruction *A, *B;
114+
SmallPtrSet<BasicBlock *, 4> ExclusionSet;
102115
};
103116

104117
static int initialize = IsPotentiallyReachableTestPass::initialize();
105118
(void)initialize;
106119

107120
IsPotentiallyReachableTestPass *P =
108-
new IsPotentiallyReachableTestPass(ExpectedResult, A, B);
121+
new IsPotentiallyReachableTestPass(ExpectedResult, A, B, ExclusionSet);
109122
legacy::PassManager PM;
110123
PM.add(P);
111124
PM.run(*M);
@@ -114,6 +127,7 @@ class IsPotentiallyReachableTest : public testing::Test {
114127
LLVMContext Context;
115128
std::unique_ptr<Module> M;
116129
Instruction *A, *B;
130+
SmallPtrSet<BasicBlock *, 4> ExclusionSet;
117131
};
118132

119133
}
@@ -425,3 +439,55 @@ TEST_F(IsPotentiallyReachableTest, UnreachableBlocksTest2) {
425439
"}");
426440
ExpectPath(false);
427441
}
442+
443+
TEST_F(IsPotentiallyReachableTest, SimpleExclusionTest) {
444+
ParseAssembly("define void @test() {\n"
445+
"entry:\n"
446+
" %A = bitcast i8 undef to i8\n"
447+
" br label %excluded\n"
448+
"excluded:\n"
449+
" br label %exit\n"
450+
"exit:\n"
451+
" %B = bitcast i8 undef to i8\n"
452+
" ret void\n"
453+
"}");
454+
ExpectPath(false);
455+
}
456+
457+
TEST_F(IsPotentiallyReachableTest, DiamondExcludedTest) {
458+
ParseAssembly("declare i1 @switch()\n"
459+
"\n"
460+
"define void @test() {\n"
461+
"entry:\n"
462+
" %x = call i1 @switch()\n"
463+
" %A = bitcast i8 undef to i8\n"
464+
" br i1 %x, label %excluded.1, label %excluded.2\n"
465+
"excluded.1:\n"
466+
" br label %exit\n"
467+
"excluded.2:\n"
468+
" br label %exit\n"
469+
"exit:\n"
470+
" %B = bitcast i8 undef to i8\n"
471+
" ret void\n"
472+
"}");
473+
ExpectPath(false);
474+
}
475+
476+
TEST_F(IsPotentiallyReachableTest, DiamondOneSideExcludedTest) {
477+
ParseAssembly("declare i1 @switch()\n"
478+
"\n"
479+
"define void @test() {\n"
480+
"entry:\n"
481+
" %x = call i1 @switch()\n"
482+
" %A = bitcast i8 undef to i8\n"
483+
" br i1 %x, label %excluded, label %diamond\n"
484+
"excluded:\n"
485+
" br label %exit\n"
486+
"diamond:\n"
487+
" br label %exit\n"
488+
"exit:\n"
489+
" %B = bitcast i8 undef to i8\n"
490+
" ret void\n"
491+
"}");
492+
ExpectPath(true);
493+
}

0 commit comments

Comments
 (0)