1*7330f729Sjoerg //===- CFGReachabilityAnalysis.cpp - Basic reachability analysis ----------===//
2*7330f729Sjoerg //
3*7330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*7330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7330f729Sjoerg //
7*7330f729Sjoerg //===----------------------------------------------------------------------===//
8*7330f729Sjoerg //
9*7330f729Sjoerg // This file defines a flow-sensitive, (mostly) path-insensitive reachability
10*7330f729Sjoerg // analysis based on Clang's CFGs. Clients can query if a given basic block
11*7330f729Sjoerg // is reachable within the CFG.
12*7330f729Sjoerg //
13*7330f729Sjoerg //===----------------------------------------------------------------------===//
14*7330f729Sjoerg
15*7330f729Sjoerg #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
16*7330f729Sjoerg #include "clang/Analysis/CFG.h"
17*7330f729Sjoerg #include "llvm/ADT/BitVector.h"
18*7330f729Sjoerg #include "llvm/ADT/SmallVector.h"
19*7330f729Sjoerg
20*7330f729Sjoerg using namespace clang;
21*7330f729Sjoerg
CFGReverseBlockReachabilityAnalysis(const CFG & cfg)22*7330f729Sjoerg CFGReverseBlockReachabilityAnalysis::CFGReverseBlockReachabilityAnalysis(
23*7330f729Sjoerg const CFG &cfg)
24*7330f729Sjoerg : analyzed(cfg.getNumBlockIDs(), false) {}
25*7330f729Sjoerg
isReachable(const CFGBlock * Src,const CFGBlock * Dst)26*7330f729Sjoerg bool CFGReverseBlockReachabilityAnalysis::isReachable(const CFGBlock *Src,
27*7330f729Sjoerg const CFGBlock *Dst) {
28*7330f729Sjoerg const unsigned DstBlockID = Dst->getBlockID();
29*7330f729Sjoerg
30*7330f729Sjoerg // If we haven't analyzed the destination node, run the analysis now
31*7330f729Sjoerg if (!analyzed[DstBlockID]) {
32*7330f729Sjoerg mapReachability(Dst);
33*7330f729Sjoerg analyzed[DstBlockID] = true;
34*7330f729Sjoerg }
35*7330f729Sjoerg
36*7330f729Sjoerg // Return the cached result
37*7330f729Sjoerg return reachable[DstBlockID][Src->getBlockID()];
38*7330f729Sjoerg }
39*7330f729Sjoerg
40*7330f729Sjoerg // Maps reachability to a common node by walking the predecessors of the
41*7330f729Sjoerg // destination node.
mapReachability(const CFGBlock * Dst)42*7330f729Sjoerg void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
43*7330f729Sjoerg SmallVector<const CFGBlock *, 11> worklist;
44*7330f729Sjoerg llvm::BitVector visited(analyzed.size());
45*7330f729Sjoerg
46*7330f729Sjoerg ReachableSet &DstReachability = reachable[Dst->getBlockID()];
47*7330f729Sjoerg DstReachability.resize(analyzed.size(), false);
48*7330f729Sjoerg
49*7330f729Sjoerg // Start searching from the destination node, since we commonly will perform
50*7330f729Sjoerg // multiple queries relating to a destination node.
51*7330f729Sjoerg worklist.push_back(Dst);
52*7330f729Sjoerg bool firstRun = true;
53*7330f729Sjoerg
54*7330f729Sjoerg while (!worklist.empty()) {
55*7330f729Sjoerg const CFGBlock *block = worklist.pop_back_val();
56*7330f729Sjoerg
57*7330f729Sjoerg if (visited[block->getBlockID()])
58*7330f729Sjoerg continue;
59*7330f729Sjoerg visited[block->getBlockID()] = true;
60*7330f729Sjoerg
61*7330f729Sjoerg // Update reachability information for this node -> Dst
62*7330f729Sjoerg if (!firstRun) {
63*7330f729Sjoerg // Don't insert Dst -> Dst unless it was a predecessor of itself
64*7330f729Sjoerg DstReachability[block->getBlockID()] = true;
65*7330f729Sjoerg }
66*7330f729Sjoerg else
67*7330f729Sjoerg firstRun = false;
68*7330f729Sjoerg
69*7330f729Sjoerg // Add the predecessors to the worklist.
70*7330f729Sjoerg for (CFGBlock::const_pred_iterator i = block->pred_begin(),
71*7330f729Sjoerg e = block->pred_end(); i != e; ++i) {
72*7330f729Sjoerg if (*i)
73*7330f729Sjoerg worklist.push_back(*i);
74*7330f729Sjoerg }
75*7330f729Sjoerg }
76*7330f729Sjoerg }
77