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