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