52 explicit CallGraph(std::string_view name) : name(name) {}
58 [[nodiscard]]
bool empty()
const {
return nodes.empty(); }
61 [[nodiscard]]
size_t size()
const {
return nodes.size(); }
76 if (nodes.find(caller) != nodes.end())
return;
77 LOG1(name <<
": " << cgMakeString(caller));
78 out_edges[caller] =
new std::vector<T>();
79 in_edges[caller] =
new std::vector<T>();
80 nodes.emplace(caller);
82 void calls(T caller, T callee) {
83 LOG1(name <<
": " << cgMakeString(callee) <<
" is called by " << cgMakeString(caller));
86 out_edges[caller]->push_back(callee);
87 in_edges[callee]->push_back(caller);
90 auto n = nodes.find(node);
91 BUG_CHECK(n != nodes.end(),
"%1%: Node not in graph", node);
93 auto in = in_edges.find(node);
94 if (in != in_edges.end()) {
96 for (
auto n : *in->second) {
97 auto out = out_edges[n];
99 auto oe = std::find(out->begin(), out->end(), node);
104 auto it = out_edges.find(node);
105 if (it != out_edges.end()) {
107 for (
auto n : *it->second) {
108 auto in = in_edges[n];
110 auto ie = std::find(in->begin(), in->end(), node);
119 bool isCallee(T callee)
const {
120 auto callees = ::P4::get(in_edges, callee);
121 return callees !=
nullptr && !callees->empty();
123 bool isCaller(T caller)
const {
124 auto edges = ::P4::get(out_edges, caller);
125 if (edges ==
nullptr)
return false;
126 return !edges->empty();
129 const_iterator begin()
const {
return out_edges.cbegin(); }
130 const_iterator end()
const {
return out_edges.cend(); }
131 std::vector<T> *getCallees(T caller) {
return out_edges[caller]; }
132 std::vector<T> *getCallers(T callee) {
return in_edges[callee]; }
134 void getCallees(T caller, std::set<T> &toAppend) {
135 if (isCaller(caller)) toAppend.insert(out_edges[caller]->begin(), out_edges[caller]->end());
138 void reachable(T start, std::set<T> &out)
const {
141 while (!work.empty()) {
142 T node = *work.begin();
144 if (out.find(node) != out.end())
continue;
146 auto edges = out_edges.find(node);
147 if (edges == out_edges.end())
continue;
148 for (
auto c : *(edges->second)) work.emplace(c);
152 void restrict(
const std::set<T> &to) {
153 std::vector<T> toRemove;
155 if (to.find(n) == to.end()) toRemove.push_back(n);
156 for (
auto n : toRemove) remove(n);
159 using Set = std::unordered_set<T>;
165 void dominators(T start, std::map<T, Set> &dominators) {
167 for (
auto n : nodes) {
169 dominators[n].emplace(start);
171 dominators[n].insert(nodes.begin(), nodes.end());
178 for (
auto node : nodes) {
179 auto vec = in_edges[node];
180 if (vec ==
nullptr)
continue;
181 auto size = dominators[node].size();
182 for (
auto c : *vec) insersectWith(dominators[node], dominators[c]);
183 dominators[node].emplace(node);
184 if (dominators[node].
size() !=
size) changes =
true;
194 std::set<T> back_edge_heads;
196 explicit Loop(T entry) : entry(entry) {}
201 std::vector<Loop *> loops;
205 int isLoopEntryPoint(T node)
const {
206 for (
size_t i = 0; i < loops.size(); i++) {
207 auto loop = loops.at(i);
208 if (loop->entry == node)
return i;
212 bool isInLoop(
int loopIndex, T node)
const {
213 if (loopIndex == -1)
return false;
214 auto loop = loops.at(loopIndex);
215 return (loop->body.find(node) != loop->body.end());
219 Loops *compute_loops(T start) {
220 auto result =
new Loops();
221 std::map<T, Set> dom;
222 dominators(start, dom);
224 std::map<T, Loop *> entryToLoop;
226 for (
auto e : nodes) {
227 auto next = out_edges[e];
229 for (
auto n : *next) {
230 if (dome.find(n) != dome.end()) {
232 auto loop = get(entryToLoop, n);
233 if (loop ==
nullptr) {
235 entryToLoop[n] = loop;
236 result->loops.push_back(loop);
238 loop->back_edge_heads.emplace(e);
243 while (!work.empty()) {
244 auto crt = *work.begin();
246 loop->body.emplace(crt);
247 if (crt == n)
continue;
248 for (
auto i : *in_edges[crt])
249 if (loop->body.find(i) == loop->body.end()) work.emplace(i);
259 static void insersectWith(Set &set, Set &with) {
260 std::vector<T> toRemove;
262 if (with.find(e) == with.end()) toRemove.push_back(e);
263 for (
auto e : toRemove) set.erase(e);
270 std::vector<T> stack;
272 std::map<T, unsigned> index;
273 std::map<T, unsigned> lowlink;
277 stack.push_back(node);
278 onStack.emplace(node);
280 bool isOnStack(T node) {
return onStack.count(node) != 0; }
281 bool unknown(T node) {
return index.count(node) == 0; }
282 void setLowLink(T node,
unsigned value) {
283 lowlink[node] = value;
284 LOG1(node <<
".lowlink = " << value <<
" = " << get(lowlink, node));
286 void setLowLink(T node, T successor) {
287 unsigned nlink = get(lowlink, node);
288 unsigned slink = get(lowlink, successor);
289 if (slink < nlink) setLowLink(node, slink);
292 T result = stack.back();
294 onStack.erase(result);
300 bool strongConnect(T node,
sccInfo &helper, std::vector<T> &out) {
303 LOG1(
"scc " << cgMakeString(node));
304 helper.index.emplace(node, helper.crtIndex);
305 helper.setLowLink(node, helper.crtIndex);
308 auto oe = out_edges[node];
310 for (
auto next : *oe) {
311 LOG1(cgMakeString(node) <<
" => " << cgMakeString(next));
312 if (helper.unknown(next)) {
313 bool l = strongConnect(next, helper, out);
315 helper.setLowLink(node, next);
316 }
else if (helper.isOnStack(next)) {
317 helper.setLowLink(node, next);
325 if (get(helper.lowlink, node) == get(helper.index, node)) {
326 LOG1(cgMakeString(node) <<
" index=" << get(helper.index, node)
327 <<
" lowlink=" << get(helper.lowlink, node));
329 T sccMember = helper.pop();
330 LOG1(
"Scc order " << cgMakeString(sccMember) <<
"[" << cgMakeString(node) <<
"]");
331 out.push_back(sccMember);
332 if (sccMember == node)
break;
345 bool sccSort(T start, std::vector<T> &out) {
347 return strongConnect(start, helper, out);
349 bool sort(std::vector<T> &start, std::vector<T> &out) {
352 for (
auto n : start) {
353 if (std::find(out.begin(), out.end(), n) == out.end()) {
354 bool c = strongConnect(n, helper, out);
355 cycles = cycles || c;
360 bool sort(std::vector<T> &out) {
363 for (
auto n : nodes) {
364 if (std::find(out.begin(), out.end(), n) == out.end()) {
365 bool c = strongConnect(n, helper, out);
366 cycles = cycles || c;