Coverage Report

Created: 2023-10-30 17:15

/builds/2mk6rsew/0/parcoach/parcoach/src/include/parcoach/andersen/CycleDetector.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef ANDERSEN_CYCLEDETECTOR_H
2
#define ANDERSEN_CYCLEDETECTOR_H
3
4
#include "GraphTraits.h"
5
6
#include "llvm/ADT/DenseMap.h"
7
#include "llvm/ADT/DenseSet.h"
8
#include "llvm/ADT/GraphTraits.h"
9
10
#include <deque>
11
#include <stack>
12
13
// An abstract base class that offers the functionality of detecting SCC in a
14
// graph Any concreate class that does cycle detection should inherit from this
15
// class, specifiy the GraphType, and implement all the abstract virtual
16
// functions
17
template <class GraphType> class CycleDetector {
18
public:
19
  typedef AndersGraphTraits<GraphType> GraphTraits;
20
  typedef typename GraphTraits::NodeType NodeType;
21
  typedef typename GraphTraits::NodeIterator node_iterator;
22
  typedef typename GraphTraits::ChildIterator child_iterator;
23
24
private:
25
  // The SCC stack
26
  std::stack<NodeType const *> sccStack;
27
  // Map from NodeIndex to DFS number. Nodes that are not in the map are never
28
  // visited
29
  llvm::DenseMap<NodeType const *, unsigned> dfsNum;
30
  // The "inComponent" array in Nutilla's improved SCC algorithm
31
  llvm::DenseSet<NodeType const *> inComponent;
32
  // DFS timestamp
33
  unsigned timestamp;
34
35
  // visiting each node and perform some task
36
33.0k
  void visit(NodeType *node) {
37
33.0k
    unsigned myTimeStamp = timestamp++;
38
33.0k
    assert(!dfsNum.count(node) && "Revisit the same node again?");
39
33.0k
    dfsNum[node] = myTimeStamp;
40
41
    // Traverse succecessor edges
42
33.0k
    for (auto childItr = GraphTraits::child_begin(node),
43
33.0k
              childIte = GraphTraits::child_end(node);
44
56.3k
         childItr != childIte; ++childItr) {
45
23.3k
      NodeType *succRep = getRep(*childItr);
46
23.3k
      if (!dfsNum.count(succRep))
47
19.9k
        visit(succRep);
48
49
23.3k
      if (!inComponent.count(succRep) && dfsNum[node] > dfsNum[succRep])
50
0
        dfsNum[node] = dfsNum[succRep];
51
23.3k
    }
52
53
    // See if we have any cycle detected
54
33.0k
    if (myTimeStamp != dfsNum[node]) {
55
      // If not, push the sccStack and go on
56
0
      sccStack.push(node);
57
0
      return;
58
0
    }
59
60
    // Cycle detected
61
33.0k
    inComponent.insert(node);
62
33.0k
    while (!sccStack.empty()) {
63
0
      NodeType const *cycleNode = sccStack.top();
64
0
      if (dfsNum[cycleNode] < myTimeStamp)
65
0
        break;
66
67
0
      processNodeOnCycle(cycleNode, node);
68
0
      inComponent.insert(cycleNode);
69
0
      sccStack.pop();
70
0
    }
71
72
33.0k
    processCycleRepNode(node);
73
33.0k
  }
_ZN13CycleDetectorI20SparseBitVectorGraphE5visitEP24SparseBitVectorGraphNode
Line
Count
Source
36
25.8k
  void visit(NodeType *node) {
37
25.8k
    unsigned myTimeStamp = timestamp++;
38
25.8k
    assert(!dfsNum.count(node) && "Revisit the same node again?");
39
25.8k
    dfsNum[node] = myTimeStamp;
40
41
    // Traverse succecessor edges
42
25.8k
    for (auto childItr = GraphTraits::child_begin(node),
43
25.8k
              childIte = GraphTraits::child_end(node);
44
49.1k
         childItr != childIte; ++childItr) {
45
23.2k
      NodeType *succRep = getRep(*childItr);
46
23.2k
      if (!dfsNum.count(succRep))
47
19.8k
        visit(succRep);
48
49
23.2k
      if (!inComponent.count(succRep) && dfsNum[node] > dfsNum[succRep])
50
0
        dfsNum[node] = dfsNum[succRep];
51
23.2k
    }
52
53
    // See if we have any cycle detected
54
25.8k
    if (myTimeStamp != dfsNum[node]) {
55
      // If not, push the sccStack and go on
56
0
      sccStack.push(node);
57
0
      return;
58
0
    }
59
60
    // Cycle detected
61
25.8k
    inComponent.insert(node);
62
25.8k
    while (!sccStack.empty()) {
63
0
      NodeType const *cycleNode = sccStack.top();
64
0
      if (dfsNum[cycleNode] < myTimeStamp)
65
0
        break;
66
67
0
      processNodeOnCycle(cycleNode, node);
68
0
      inComponent.insert(cycleNode);
69
0
      sccStack.pop();
70
0
    }
71
72
25.8k
    processCycleRepNode(node);
73
25.8k
  }
ConstraintSolving.cpp:_ZN13CycleDetectorIN12_GLOBAL__N_115ConstraintGraphEE5visitEPNS0_19ConstraintGraphNodeE
Line
Count
Source
36
7.14k
  void visit(NodeType *node) {
37
7.14k
    unsigned myTimeStamp = timestamp++;
38
7.14k
    assert(!dfsNum.count(node) && "Revisit the same node again?");
39
7.14k
    dfsNum[node] = myTimeStamp;
40
41
    // Traverse succecessor edges
42
7.14k
    for (auto childItr = GraphTraits::child_begin(node),
43
7.14k
              childIte = GraphTraits::child_end(node);
44
7.25k
         childItr != childIte; ++childItr) {
45
108
      NodeType *succRep = getRep(*childItr);
46
108
      if (!dfsNum.count(succRep))
47
108
        visit(succRep);
48
49
108
      if (!inComponent.count(succRep) && dfsNum[node] > dfsNum[succRep])
50
0
        dfsNum[node] = dfsNum[succRep];
51
108
    }
52
53
    // See if we have any cycle detected
54
7.14k
    if (myTimeStamp != dfsNum[node]) {
55
      // If not, push the sccStack and go on
56
0
      sccStack.push(node);
57
0
      return;
58
0
    }
59
60
    // Cycle detected
61
7.14k
    inComponent.insert(node);
62
7.14k
    while (!sccStack.empty()) {
63
0
      NodeType const *cycleNode = sccStack.top();
64
0
      if (dfsNum[cycleNode] < myTimeStamp)
65
0
        break;
66
67
0
      processNodeOnCycle(cycleNode, node);
68
0
      inComponent.insert(cycleNode);
69
0
      sccStack.pop();
70
0
    }
71
72
7.14k
    processCycleRepNode(node);
73
7.14k
  }
74
75
protected:
76
  // Nodes may get merged during the analysis. This function returns the merge
77
  // target (if the node is merged into another node) or the node itself (if the
78
  // nodes has not been merged into another node)
79
  virtual NodeType *getRep(NodeIndex node) = 0;
80
  // Specify how to process the non-rep nodes if a cycle is found
81
  virtual void processNodeOnCycle(NodeType const *node,
82
                                  NodeType const *repNode) = 0;
83
  // Specify how to process the rep nodes if a cycle is found
84
  virtual void processCycleRepNode(NodeType const *node) = 0;
85
86
  // Running the cycle detection algorithm on a given graph G
87
1.76k
  void runOnGraph(GraphType *graph) {
88
1.76k
    assert(sccStack.empty() && "sccStack is not empty before cycle detection!");
89
1.76k
    assert(dfsNum.empty() && "dfsNum is not empty before cycle detection!");
90
1.76k
    assert(inComponent.empty() &&
91
1.76k
           "inComponent is not empty before cycle detection!");
92
93
1.76k
    for (auto itr = GraphTraits::node_begin(graph),
94
1.76k
              ite = GraphTraits::node_end(graph);
95
18.1k
         itr != ite; ++itr) {
96
16.4k
      NodeType *repNode = getRep(itr->getNodeIndex());
97
16.4k
      if (!dfsNum.count(repNode))
98
6.05k
        visit(repNode);
99
16.4k
    }
100
101
1.76k
    assert(sccStack.empty() && "sccStack not empty after cycle detection!");
102
1.76k
  }
103
104
  // Running the cycle detection algorithm on a given graph node. This function
105
  // is used when walking through the entire graph is not the desirable
106
  // behavior.
107
7.03k
  void runOnNode(NodeIndex node) {
108
7.03k
    assert(sccStack.empty() && "sccStack is not empty before cycle detection!");
109
110
7.03k
    NodeType *repNode = getRep(node);
111
7.03k
    if (!dfsNum.count(repNode))
112
7.03k
      visit(repNode);
113
114
7.03k
    assert(sccStack.empty() && "sccStack not empty after cycle detection!");
115
7.03k
  }
116
117
1.76k
  void releaseSCCMemory() {
118
1.76k
    dfsNum.clear();
119
1.76k
    inComponent.clear();
120
1.76k
  }
121
122
public:
123
3.47k
  CycleDetector() : timestamp(0) {}
_ZN13CycleDetectorI20SparseBitVectorGraphEC2Ev
Line
Count
Source
123
1.76k
  CycleDetector() : timestamp(0) {}
ConstraintSolving.cpp:_ZN13CycleDetectorIN12_GLOBAL__N_115ConstraintGraphEEC2Ev
Line
Count
Source
123
1.71k
  CycleDetector() : timestamp(0) {}
124
125
  // The public interface of running the detector
126
  virtual void run() = 0;
127
};
128
129
#endif