10b57cec5SDimitry Andric //===-- CFG.cpp - BasicBlock analysis --------------------------------------==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This family of functions performs analyses on basic blocks, and instructions
100b57cec5SDimitry Andric // contained within basic blocks.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/Analysis/CFG.h"
150b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
160b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
17e8d8bef9SDimitry Andric #include "llvm/Support/CommandLine.h"
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric using namespace llvm;
200b57cec5SDimitry Andric
21e8d8bef9SDimitry Andric // The max number of basic blocks explored during reachability analysis between
22e8d8bef9SDimitry Andric // two basic blocks. This is kept reasonably small to limit compile time when
23e8d8bef9SDimitry Andric // repeatedly used by clients of this analysis (such as captureTracking).
24e8d8bef9SDimitry Andric static cl::opt<unsigned> DefaultMaxBBsToExplore(
25e8d8bef9SDimitry Andric "dom-tree-reachability-max-bbs-to-explore", cl::Hidden,
26e8d8bef9SDimitry Andric cl::desc("Max number of BBs to explore for reachability analysis"),
27e8d8bef9SDimitry Andric cl::init(32));
28e8d8bef9SDimitry Andric
290b57cec5SDimitry Andric /// FindFunctionBackedges - Analyze the specified function to find all of the
300b57cec5SDimitry Andric /// loop backedges in the function and return them. This is a relatively cheap
310b57cec5SDimitry Andric /// (compared to computing dominators and loop info) analysis.
320b57cec5SDimitry Andric ///
330b57cec5SDimitry Andric /// The output is added to Result, as pairs of <from,to> edge info.
FindFunctionBackedges(const Function & F,SmallVectorImpl<std::pair<const BasicBlock *,const BasicBlock * >> & Result)340b57cec5SDimitry Andric void llvm::FindFunctionBackedges(const Function &F,
350b57cec5SDimitry Andric SmallVectorImpl<std::pair<const BasicBlock*,const BasicBlock*> > &Result) {
360b57cec5SDimitry Andric const BasicBlock *BB = &F.getEntryBlock();
370b57cec5SDimitry Andric if (succ_empty(BB))
380b57cec5SDimitry Andric return;
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric SmallPtrSet<const BasicBlock*, 8> Visited;
415ffd83dbSDimitry Andric SmallVector<std::pair<const BasicBlock *, const_succ_iterator>, 8> VisitStack;
420b57cec5SDimitry Andric SmallPtrSet<const BasicBlock*, 8> InStack;
430b57cec5SDimitry Andric
440b57cec5SDimitry Andric Visited.insert(BB);
450b57cec5SDimitry Andric VisitStack.push_back(std::make_pair(BB, succ_begin(BB)));
460b57cec5SDimitry Andric InStack.insert(BB);
470b57cec5SDimitry Andric do {
485ffd83dbSDimitry Andric std::pair<const BasicBlock *, const_succ_iterator> &Top = VisitStack.back();
490b57cec5SDimitry Andric const BasicBlock *ParentBB = Top.first;
505ffd83dbSDimitry Andric const_succ_iterator &I = Top.second;
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric bool FoundNew = false;
530b57cec5SDimitry Andric while (I != succ_end(ParentBB)) {
540b57cec5SDimitry Andric BB = *I++;
550b57cec5SDimitry Andric if (Visited.insert(BB).second) {
560b57cec5SDimitry Andric FoundNew = true;
570b57cec5SDimitry Andric break;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric // Successor is in VisitStack, it's a back edge.
600b57cec5SDimitry Andric if (InStack.count(BB))
610b57cec5SDimitry Andric Result.push_back(std::make_pair(ParentBB, BB));
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric if (FoundNew) {
650b57cec5SDimitry Andric // Go down one level if there is a unvisited successor.
660b57cec5SDimitry Andric InStack.insert(BB);
670b57cec5SDimitry Andric VisitStack.push_back(std::make_pair(BB, succ_begin(BB)));
680b57cec5SDimitry Andric } else {
690b57cec5SDimitry Andric // Go up one level.
700b57cec5SDimitry Andric InStack.erase(VisitStack.pop_back_val().first);
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric } while (!VisitStack.empty());
730b57cec5SDimitry Andric }
740b57cec5SDimitry Andric
750b57cec5SDimitry Andric /// GetSuccessorNumber - Search for the specified successor of basic block BB
760b57cec5SDimitry Andric /// and return its position in the terminator instruction's list of
770b57cec5SDimitry Andric /// successors. It is an error to call this with a block that is not a
780b57cec5SDimitry Andric /// successor.
GetSuccessorNumber(const BasicBlock * BB,const BasicBlock * Succ)790b57cec5SDimitry Andric unsigned llvm::GetSuccessorNumber(const BasicBlock *BB,
800b57cec5SDimitry Andric const BasicBlock *Succ) {
810b57cec5SDimitry Andric const Instruction *Term = BB->getTerminator();
820b57cec5SDimitry Andric #ifndef NDEBUG
830b57cec5SDimitry Andric unsigned e = Term->getNumSuccessors();
840b57cec5SDimitry Andric #endif
850b57cec5SDimitry Andric for (unsigned i = 0; ; ++i) {
860b57cec5SDimitry Andric assert(i != e && "Didn't find edge?");
870b57cec5SDimitry Andric if (Term->getSuccessor(i) == Succ)
880b57cec5SDimitry Andric return i;
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric /// isCriticalEdge - Return true if the specified edge is a critical edge.
930b57cec5SDimitry Andric /// Critical edges are edges from a block with multiple successors to a block
940b57cec5SDimitry Andric /// with multiple predecessors.
isCriticalEdge(const Instruction * TI,unsigned SuccNum,bool AllowIdenticalEdges)950b57cec5SDimitry Andric bool llvm::isCriticalEdge(const Instruction *TI, unsigned SuccNum,
960b57cec5SDimitry Andric bool AllowIdenticalEdges) {
970b57cec5SDimitry Andric assert(SuccNum < TI->getNumSuccessors() && "Illegal edge specification!");
988bcb0991SDimitry Andric return isCriticalEdge(TI, TI->getSuccessor(SuccNum), AllowIdenticalEdges);
998bcb0991SDimitry Andric }
1008bcb0991SDimitry Andric
isCriticalEdge(const Instruction * TI,const BasicBlock * Dest,bool AllowIdenticalEdges)1018bcb0991SDimitry Andric bool llvm::isCriticalEdge(const Instruction *TI, const BasicBlock *Dest,
1028bcb0991SDimitry Andric bool AllowIdenticalEdges) {
1038bcb0991SDimitry Andric assert(TI->isTerminator() && "Must be a terminator to have successors!");
1040b57cec5SDimitry Andric if (TI->getNumSuccessors() == 1) return false;
1050b57cec5SDimitry Andric
106e8d8bef9SDimitry Andric assert(is_contained(predecessors(Dest), TI->getParent()) &&
1078bcb0991SDimitry Andric "No edge between TI's block and Dest.");
1088bcb0991SDimitry Andric
1090b57cec5SDimitry Andric const_pred_iterator I = pred_begin(Dest), E = pred_end(Dest);
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric // If there is more than one predecessor, this is a critical edge...
1120b57cec5SDimitry Andric assert(I != E && "No preds, but we have an edge to the block?");
1130b57cec5SDimitry Andric const BasicBlock *FirstPred = *I;
1140b57cec5SDimitry Andric ++I; // Skip one edge due to the incoming arc from TI.
1150b57cec5SDimitry Andric if (!AllowIdenticalEdges)
1160b57cec5SDimitry Andric return I != E;
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric // If AllowIdenticalEdges is true, then we allow this edge to be considered
1190b57cec5SDimitry Andric // non-critical iff all preds come from TI's block.
1200b57cec5SDimitry Andric for (; I != E; ++I)
1210b57cec5SDimitry Andric if (*I != FirstPred)
1220b57cec5SDimitry Andric return true;
1230b57cec5SDimitry Andric return false;
1240b57cec5SDimitry Andric }
1250b57cec5SDimitry Andric
1260b57cec5SDimitry Andric // LoopInfo contains a mapping from basic block to the innermost loop. Find
1270b57cec5SDimitry Andric // the outermost loop in the loop nest that contains BB.
getOutermostLoop(const LoopInfo * LI,const BasicBlock * BB)1280b57cec5SDimitry Andric static const Loop *getOutermostLoop(const LoopInfo *LI, const BasicBlock *BB) {
1290b57cec5SDimitry Andric const Loop *L = LI->getLoopFor(BB);
13081ad6265SDimitry Andric return L ? L->getOutermostLoop() : nullptr;
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric
133*0fca6ea1SDimitry Andric template <class StopSetT>
isReachableImpl(SmallVectorImpl<BasicBlock * > & Worklist,const StopSetT & StopSet,const SmallPtrSetImpl<BasicBlock * > * ExclusionSet,const DominatorTree * DT,const LoopInfo * LI)134*0fca6ea1SDimitry Andric static bool isReachableImpl(SmallVectorImpl<BasicBlock *> &Worklist,
135*0fca6ea1SDimitry Andric const StopSetT &StopSet,
136*0fca6ea1SDimitry Andric const SmallPtrSetImpl<BasicBlock *> *ExclusionSet,
137*0fca6ea1SDimitry Andric const DominatorTree *DT, const LoopInfo *LI) {
138*0fca6ea1SDimitry Andric // When a stop block is unreachable, it's dominated from everywhere,
1390b57cec5SDimitry Andric // regardless of whether there's a path between the two blocks.
140*0fca6ea1SDimitry Andric if (DT) {
141*0fca6ea1SDimitry Andric for (auto *BB : StopSet) {
142*0fca6ea1SDimitry Andric if (!DT->isReachableFromEntry(BB)) {
1430b57cec5SDimitry Andric DT = nullptr;
144*0fca6ea1SDimitry Andric break;
145*0fca6ea1SDimitry Andric }
146*0fca6ea1SDimitry Andric }
147*0fca6ea1SDimitry Andric }
1480b57cec5SDimitry Andric
1490b57cec5SDimitry Andric // We can't skip directly from a block that dominates the stop block if the
1500b57cec5SDimitry Andric // exclusion block is potentially in between.
1510b57cec5SDimitry Andric if (ExclusionSet && !ExclusionSet->empty())
1520b57cec5SDimitry Andric DT = nullptr;
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric // Normally any block in a loop is reachable from any other block in a loop,
1550b57cec5SDimitry Andric // however excluded blocks might partition the body of a loop to make that
1560b57cec5SDimitry Andric // untrue.
1570b57cec5SDimitry Andric SmallPtrSet<const Loop *, 8> LoopsWithHoles;
1580b57cec5SDimitry Andric if (LI && ExclusionSet) {
159fcaf7f86SDimitry Andric for (auto *BB : *ExclusionSet) {
1600b57cec5SDimitry Andric if (const Loop *L = getOutermostLoop(LI, BB))
1610b57cec5SDimitry Andric LoopsWithHoles.insert(L);
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric
165*0fca6ea1SDimitry Andric SmallPtrSet<const Loop *, 2> StopLoops;
166*0fca6ea1SDimitry Andric if (LI) {
167*0fca6ea1SDimitry Andric for (auto *StopSetBB : StopSet) {
168*0fca6ea1SDimitry Andric if (const Loop *L = getOutermostLoop(LI, StopSetBB))
169*0fca6ea1SDimitry Andric StopLoops.insert(L);
170*0fca6ea1SDimitry Andric }
171*0fca6ea1SDimitry Andric }
1720b57cec5SDimitry Andric
173e8d8bef9SDimitry Andric unsigned Limit = DefaultMaxBBsToExplore;
1740b57cec5SDimitry Andric SmallPtrSet<const BasicBlock*, 32> Visited;
1750b57cec5SDimitry Andric do {
1760b57cec5SDimitry Andric BasicBlock *BB = Worklist.pop_back_val();
1770b57cec5SDimitry Andric if (!Visited.insert(BB).second)
1780b57cec5SDimitry Andric continue;
179*0fca6ea1SDimitry Andric if (StopSet.contains(BB))
1800b57cec5SDimitry Andric return true;
1810b57cec5SDimitry Andric if (ExclusionSet && ExclusionSet->count(BB))
1820b57cec5SDimitry Andric continue;
183*0fca6ea1SDimitry Andric if (DT) {
184*0fca6ea1SDimitry Andric if (llvm::any_of(StopSet, [&](const BasicBlock *StopBB) {
185*0fca6ea1SDimitry Andric return DT->dominates(BB, StopBB);
186*0fca6ea1SDimitry Andric }))
1870b57cec5SDimitry Andric return true;
188*0fca6ea1SDimitry Andric }
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric const Loop *Outer = nullptr;
1910b57cec5SDimitry Andric if (LI) {
1920b57cec5SDimitry Andric Outer = getOutermostLoop(LI, BB);
1930b57cec5SDimitry Andric // If we're in a loop with a hole, not all blocks in the loop are
1940b57cec5SDimitry Andric // reachable from all other blocks. That implies we can't simply jump to
1950b57cec5SDimitry Andric // the loop's exit blocks, as that exit might need to pass through an
1960b57cec5SDimitry Andric // excluded block. Clear Outer so we process BB's successors.
1970b57cec5SDimitry Andric if (LoopsWithHoles.count(Outer))
1980b57cec5SDimitry Andric Outer = nullptr;
199*0fca6ea1SDimitry Andric if (StopLoops.contains(Outer))
2000b57cec5SDimitry Andric return true;
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric if (!--Limit) {
2040b57cec5SDimitry Andric // We haven't been able to prove it one way or the other. Conservatively
2050b57cec5SDimitry Andric // answer true -- that there is potentially a path.
2060b57cec5SDimitry Andric return true;
2070b57cec5SDimitry Andric }
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric if (Outer) {
2100b57cec5SDimitry Andric // All blocks in a single loop are reachable from all other blocks. From
2110b57cec5SDimitry Andric // any of these blocks, we can skip directly to the exits of the loop,
2120b57cec5SDimitry Andric // ignoring any other blocks inside the loop body.
2130b57cec5SDimitry Andric Outer->getExitBlocks(Worklist);
2140b57cec5SDimitry Andric } else {
2150b57cec5SDimitry Andric Worklist.append(succ_begin(BB), succ_end(BB));
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric } while (!Worklist.empty());
2180b57cec5SDimitry Andric
2190b57cec5SDimitry Andric // We have exhausted all possible paths and are certain that 'To' can not be
2200b57cec5SDimitry Andric // reached from 'From'.
2210b57cec5SDimitry Andric return false;
2220b57cec5SDimitry Andric }
2230b57cec5SDimitry Andric
224*0fca6ea1SDimitry Andric template <class T> class SingleEntrySet {
225*0fca6ea1SDimitry Andric public:
226*0fca6ea1SDimitry Andric using const_iterator = const T *;
227*0fca6ea1SDimitry Andric
SingleEntrySet(T Elem)228*0fca6ea1SDimitry Andric SingleEntrySet(T Elem) : Elem(Elem) {}
229*0fca6ea1SDimitry Andric
contains(T Other) const230*0fca6ea1SDimitry Andric bool contains(T Other) const { return Elem == Other; }
231*0fca6ea1SDimitry Andric
begin() const232*0fca6ea1SDimitry Andric const_iterator begin() const { return &Elem; }
end() const233*0fca6ea1SDimitry Andric const_iterator end() const { return &Elem + 1; }
234*0fca6ea1SDimitry Andric
235*0fca6ea1SDimitry Andric private:
236*0fca6ea1SDimitry Andric T Elem;
237*0fca6ea1SDimitry Andric };
238*0fca6ea1SDimitry Andric
isPotentiallyReachableFromMany(SmallVectorImpl<BasicBlock * > & Worklist,const BasicBlock * StopBB,const SmallPtrSetImpl<BasicBlock * > * ExclusionSet,const DominatorTree * DT,const LoopInfo * LI)239*0fca6ea1SDimitry Andric bool llvm::isPotentiallyReachableFromMany(
240*0fca6ea1SDimitry Andric SmallVectorImpl<BasicBlock *> &Worklist, const BasicBlock *StopBB,
241*0fca6ea1SDimitry Andric const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
242*0fca6ea1SDimitry Andric const LoopInfo *LI) {
243*0fca6ea1SDimitry Andric return isReachableImpl<SingleEntrySet<const BasicBlock *>>(
244*0fca6ea1SDimitry Andric Worklist, SingleEntrySet<const BasicBlock *>(StopBB), ExclusionSet, DT,
245*0fca6ea1SDimitry Andric LI);
246*0fca6ea1SDimitry Andric }
247*0fca6ea1SDimitry Andric
isManyPotentiallyReachableFromMany(SmallVectorImpl<BasicBlock * > & Worklist,const SmallPtrSetImpl<const BasicBlock * > & StopSet,const SmallPtrSetImpl<BasicBlock * > * ExclusionSet,const DominatorTree * DT,const LoopInfo * LI)248*0fca6ea1SDimitry Andric bool llvm::isManyPotentiallyReachableFromMany(
249*0fca6ea1SDimitry Andric SmallVectorImpl<BasicBlock *> &Worklist,
250*0fca6ea1SDimitry Andric const SmallPtrSetImpl<const BasicBlock *> &StopSet,
251*0fca6ea1SDimitry Andric const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
252*0fca6ea1SDimitry Andric const LoopInfo *LI) {
253*0fca6ea1SDimitry Andric return isReachableImpl<SmallPtrSetImpl<const BasicBlock *>>(
254*0fca6ea1SDimitry Andric Worklist, StopSet, ExclusionSet, DT, LI);
255*0fca6ea1SDimitry Andric }
256*0fca6ea1SDimitry Andric
isPotentiallyReachable(const BasicBlock * A,const BasicBlock * B,const SmallPtrSetImpl<BasicBlock * > * ExclusionSet,const DominatorTree * DT,const LoopInfo * LI)257fe6060f1SDimitry Andric bool llvm::isPotentiallyReachable(
258fe6060f1SDimitry Andric const BasicBlock *A, const BasicBlock *B,
259fe6060f1SDimitry Andric const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
260fe6060f1SDimitry Andric const LoopInfo *LI) {
2610b57cec5SDimitry Andric assert(A->getParent() == B->getParent() &&
2620b57cec5SDimitry Andric "This analysis is function-local!");
2630b57cec5SDimitry Andric
264fe6060f1SDimitry Andric if (DT) {
265fe6060f1SDimitry Andric if (DT->isReachableFromEntry(A) && !DT->isReachableFromEntry(B))
266fe6060f1SDimitry Andric return false;
267fe6060f1SDimitry Andric if (!ExclusionSet || ExclusionSet->empty()) {
268fe6060f1SDimitry Andric if (A->isEntryBlock() && DT->isReachableFromEntry(B))
269fe6060f1SDimitry Andric return true;
270fe6060f1SDimitry Andric if (B->isEntryBlock() && DT->isReachableFromEntry(A))
271fe6060f1SDimitry Andric return false;
272fe6060f1SDimitry Andric }
273fe6060f1SDimitry Andric }
274fe6060f1SDimitry Andric
2750b57cec5SDimitry Andric SmallVector<BasicBlock*, 32> Worklist;
2760b57cec5SDimitry Andric Worklist.push_back(const_cast<BasicBlock*>(A));
2770b57cec5SDimitry Andric
278bdd1243dSDimitry Andric return isPotentiallyReachableFromMany(Worklist, B, ExclusionSet, DT, LI);
2790b57cec5SDimitry Andric }
2800b57cec5SDimitry Andric
isPotentiallyReachable(const Instruction * A,const Instruction * B,const SmallPtrSetImpl<BasicBlock * > * ExclusionSet,const DominatorTree * DT,const LoopInfo * LI)2810b57cec5SDimitry Andric bool llvm::isPotentiallyReachable(
2820b57cec5SDimitry Andric const Instruction *A, const Instruction *B,
2830b57cec5SDimitry Andric const SmallPtrSetImpl<BasicBlock *> *ExclusionSet, const DominatorTree *DT,
2840b57cec5SDimitry Andric const LoopInfo *LI) {
2850b57cec5SDimitry Andric assert(A->getParent()->getParent() == B->getParent()->getParent() &&
2860b57cec5SDimitry Andric "This analysis is function-local!");
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andric if (A->getParent() == B->getParent()) {
2890b57cec5SDimitry Andric // The same block case is special because it's the only time we're looking
2900b57cec5SDimitry Andric // within a single block to see which instruction comes first. Once we
2910b57cec5SDimitry Andric // start looking at multiple blocks, the first instruction of the block is
2920b57cec5SDimitry Andric // reachable, so we only need to determine reachability between whole
2930b57cec5SDimitry Andric // blocks.
2940b57cec5SDimitry Andric BasicBlock *BB = const_cast<BasicBlock *>(A->getParent());
2950b57cec5SDimitry Andric
2960b57cec5SDimitry Andric // If the block is in a loop then we can reach any instruction in the block
2970b57cec5SDimitry Andric // from any other instruction in the block by going around a backedge.
2980b57cec5SDimitry Andric if (LI && LI->getLoopFor(BB) != nullptr)
2990b57cec5SDimitry Andric return true;
3000b57cec5SDimitry Andric
301fe6060f1SDimitry Andric // If A comes before B, then B is definitively reachable from A.
302fe6060f1SDimitry Andric if (A == B || A->comesBefore(B))
3030b57cec5SDimitry Andric return true;
3040b57cec5SDimitry Andric
3050b57cec5SDimitry Andric // Can't be in a loop if it's the entry block -- the entry block may not
3060b57cec5SDimitry Andric // have predecessors.
307fe6060f1SDimitry Andric if (BB->isEntryBlock())
3080b57cec5SDimitry Andric return false;
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric // Otherwise, continue doing the normal per-BB CFG walk.
311fe6060f1SDimitry Andric SmallVector<BasicBlock*, 32> Worklist;
3120b57cec5SDimitry Andric Worklist.append(succ_begin(BB), succ_end(BB));
3130b57cec5SDimitry Andric if (Worklist.empty()) {
3140b57cec5SDimitry Andric // We've proven that there's no path!
3150b57cec5SDimitry Andric return false;
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric
318bdd1243dSDimitry Andric return isPotentiallyReachableFromMany(Worklist, B->getParent(),
319bdd1243dSDimitry Andric ExclusionSet, DT, LI);
320fe6060f1SDimitry Andric }
321fe6060f1SDimitry Andric
322fe6060f1SDimitry Andric return isPotentiallyReachable(
323fe6060f1SDimitry Andric A->getParent(), B->getParent(), ExclusionSet, DT, LI);
3240b57cec5SDimitry Andric }
325