xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/CFGReachabilityAnalysis.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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