CFGReachabilityAnalysis.cpp 2.6 KB

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