Jlm
LazyCycleDetection.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2024 HÃ¥vard Krogstie <krogstie.havard@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #ifndef JLM_LLVM_OPT_ALIAS_ANALYSES_LAZYCYCLEDETECTION_HPP
7 #define JLM_LLVM_OPT_ALIAS_ANALYSES_LAZYCYCLEDETECTION_HPP
8 
10 #include <jlm/util/HashSet.hpp>
11 
12 #include <limits>
13 #include <optional>
14 #include <stack>
15 #include <vector>
16 
17 namespace jlm::llvm::aa
18 {
19 
26 template<typename GetSuccessorsFunctor, typename UnifyPointerObjectsFunctor>
28 {
29 
30 public:
32  PointerObjectSet & set,
33  const GetSuccessorsFunctor & GetSuccessors,
34  const UnifyPointerObjectsFunctor & unifyPointerObjects)
35  : Set_(set),
36  GetSuccessors_(GetSuccessors),
37  UnifyPointerObjects_(unifyPointerObjects)
38  {}
39 
43  void
45  {
47  }
48 
49  bool
50  IsInitialized() const noexcept
51  {
52  return NodeStates_.size() == Set_.NumPointerObjects();
53  }
54 
63  std::optional<PointerObjectIndex>
65  {
69 
70  // Add this edge to the list of checked edges, or return if it was already there
71  if (!CheckedEdges_.insert({ subset, superset }))
72  return std::nullopt;
73 
75 
76  JLM_ASSERT(DfsStack_.empty());
77  DfsStack_.push(superset);
78 
79  // Reset all node states
80  std::fill(NodeStates_.begin(), NodeStates_.end(), NodeStateNotVisited);
81 
82  while (!DfsStack_.empty())
83  {
84  auto node = DfsStack_.top();
85  if (NodeStates_[node] == NodeStateNotVisited)
86  {
88  // Make sure all successors get visited
89  for (auto successor : GetSuccessors_(node))
90  {
91  auto successorRoot = Set_.GetUnificationRoot(successor);
92 
93  // Cycle found! Do not add the subset to the dfs stack
94  if (successorRoot == subset)
95  continue;
96 
97  if (NodeStates_[successorRoot] != NodeStateNotVisited)
98  continue;
99 
100  DfsStack_.push(successorRoot);
101  }
102  }
103  else if (NodeStates_[node] == NodeStateVisited)
104  {
105  DfsStack_.pop();
107 
108  // Check if any successors are unified with the subset. If so, join it!
109  for (auto successor : GetSuccessors_(node))
110  {
111  auto successorRoot = Set_.GetUnificationRoot(successor);
112  if (successorRoot == subset)
113  {
114  subset = UnifyPointerObjects_(node, subset);
116  break;
117  }
118  }
119  }
120  else
121  {
122  // The node has already been visited for a second time
123  DfsStack_.pop();
124  }
125  }
126 
128  superset = Set_.GetUnificationRoot(superset);
129  if (subset == superset)
130  {
132  return subset;
133  }
134  return std::nullopt;
135  }
136 
140  [[nodiscard]] size_t
141  NumCycleDetectionAttempts() const noexcept
142  {
144  }
145 
149  [[nodiscard]] size_t
150  NumCyclesDetected() const noexcept
151  {
152  return NumCyclesDetected_;
153  }
154 
158  [[nodiscard]] size_t
159  NumCycleUnifications() const noexcept
160  {
161  return NumCycleUnifications_;
162  }
163 
164 private:
166  const GetSuccessorsFunctor & GetSuccessors_;
167  const UnifyPointerObjectsFunctor & UnifyPointerObjects_;
168 
169  // A set of all checked simple edges first -> second, to avoid checking again
171 
172  // The dfs stack, which may contain the same node multiple times
173  std::stack<PointerObjectIndex> DfsStack_;
174  // Possible states of nodes during the DFS
175  static constexpr uint8_t NodeStateNotVisited = 0;
176  static constexpr uint8_t NodeStateVisited = 1;
177  static constexpr uint8_t NodeStatePopped = 2;
178  std::vector<uint8_t> NodeStates_;
179 
181  size_t NumCyclesDetected_ = 0;
183 };
184 
185 }
186 
187 #endif // JLM_LLVM_OPT_ALIAS_ANALYSES_LAZYCYCLEDETECTION_HPP
const UnifyPointerObjectsFunctor & UnifyPointerObjects_
size_t NumCycleUnifications() const noexcept
static constexpr uint8_t NodeStateNotVisited
size_t NumCyclesDetected() const noexcept
static constexpr uint8_t NodeStateVisited
util::HashSet< std::pair< PointerObjectIndex, PointerObjectIndex > > CheckedEdges_
size_t NumCycleDetectionAttempts() const noexcept
std::stack< PointerObjectIndex > DfsStack_
const GetSuccessorsFunctor & GetSuccessors_
LazyCycleDetector(PointerObjectSet &set, const GetSuccessorsFunctor &GetSuccessors, const UnifyPointerObjectsFunctor &unifyPointerObjects)
static constexpr uint8_t NodeStatePopped
std::optional< PointerObjectIndex > OnPropagatedNothing(PointerObjectIndex subset, PointerObjectIndex superset)
PointerObjectIndex GetUnificationRoot(PointerObjectIndex index) const noexcept
bool IsUnificationRoot(PointerObjectIndex index) const noexcept
size_t NumPointerObjects() const noexcept
bool insert(ItemType item)
Definition: HashSet.hpp:210
#define JLM_ASSERT(x)
Definition: common.hpp:16
uint32_t PointerObjectIndex