43 explicit CallGraph(std::string_view name) : name(name) {}
49 [[nodiscard]]
bool empty()
const {
return nodes.empty(); }
52 [[nodiscard]]
size_t size()
const {
return nodes.size(); }
67 if (nodes.find(caller) != nodes.end())
return;
68 LOG1(name <<
": " << cgMakeString(caller));
69 out_edges[caller] =
new std::vector<T>();
70 in_edges[caller] =
new std::vector<T>();
71 nodes.emplace(caller);
73 void calls(T caller, T callee) {
74 LOG1(name <<
": " << cgMakeString(callee) <<
" is called by " << cgMakeString(caller));
77 out_edges[caller]->push_back(callee);
78 in_edges[callee]->push_back(caller);
81 auto n = nodes.find(node);
82 BUG_CHECK(n != nodes.end(),
"%1%: Node not in graph", node);
84 auto in = in_edges.find(node);
85 if (in != in_edges.end()) {
87 for (
auto n : *in->second) {
88 auto out = out_edges[n];
90 auto oe = std::find(out->begin(), out->end(), node);
95 auto it = out_edges.find(node);
96 if (it != out_edges.end()) {
98 for (
auto n : *it->second) {
99 auto in = in_edges[n];
101 auto ie = std::find(in->begin(), in->end(), node);
110 bool isCallee(T callee)
const {
111 auto callees = ::P4::get(in_edges, callee);
112 return callees !=
nullptr && !callees->empty();
114 bool isCaller(T caller)
const {
115 auto edges = ::P4::get(out_edges, caller);
116 if (edges ==
nullptr)
return false;
117 return !edges->empty();
120 const_iterator begin()
const {
return out_edges.cbegin(); }
121 const_iterator end()
const {
return out_edges.cend(); }
122 std::vector<T> *getCallees(T caller) {
return out_edges[caller]; }
123 std::vector<T> *getCallers(T callee) {
return in_edges[callee]; }
125 void getCallees(T caller, std::set<T> &toAppend) {
126 if (isCaller(caller)) toAppend.insert(out_edges[caller]->begin(), out_edges[caller]->end());
129 void reachable(T start, std::set<T> &out)
const {
132 while (!work.empty()) {
133 T node = *work.begin();
135 if (out.find(node) != out.end())
continue;
137 auto edges = out_edges.find(node);
138 if (edges == out_edges.end())
continue;
139 for (
auto c : *(edges->second)) work.emplace(c);
143 void restrict(
const std::set<T> &to) {
144 std::vector<T> toRemove;
146 if (to.find(n) == to.end()) toRemove.push_back(n);
147 for (
auto n : toRemove) remove(n);
150 using Set = std::unordered_set<T>;
156 void dominators(T start, std::map<T, Set> &dominators) {
158 for (
auto n : nodes) {
160 dominators[n].emplace(start);
162 dominators[n].insert(nodes.begin(), nodes.end());
169 for (
auto node : nodes) {
170 auto vec = in_edges[node];
171 if (vec ==
nullptr)
continue;
172 auto size = dominators[node].size();
173 for (
auto c : *vec) insersectWith(dominators[node], dominators[c]);
174 dominators[node].emplace(node);
175 if (dominators[node].
size() !=
size) changes =
true;
185 std::set<T> back_edge_heads;
187 explicit Loop(T entry) : entry(entry) {}
192 std::vector<Loop *> loops;
196 int isLoopEntryPoint(T node)
const {
197 for (
size_t i = 0; i < loops.size(); i++) {
198 auto loop = loops.at(i);
199 if (loop->entry == node)
return i;
203 bool isInLoop(
int loopIndex, T node)
const {
204 if (loopIndex == -1)
return false;
205 auto loop = loops.at(loopIndex);
206 return (loop->body.find(node) != loop->body.end());
210 Loops *compute_loops(T start) {
211 auto result =
new Loops();
212 std::map<T, Set> dom;
213 dominators(start, dom);
215 std::map<T, Loop *> entryToLoop;
217 for (
auto e : nodes) {
218 auto next = out_edges[e];
220 for (
auto n : *next) {
221 if (dome.find(n) != dome.end()) {
223 auto loop = get(entryToLoop, n);
224 if (loop ==
nullptr) {
226 entryToLoop[n] = loop;
227 result->loops.push_back(loop);
229 loop->back_edge_heads.emplace(e);
234 while (!work.empty()) {
235 auto crt = *work.begin();
237 loop->body.emplace(crt);
238 if (crt == n)
continue;
239 for (
auto i : *in_edges[crt])
240 if (loop->body.find(i) == loop->body.end()) work.emplace(i);
250 static void insersectWith(Set &set, Set &with) {
251 std::vector<T> toRemove;
253 if (with.find(e) == with.end()) toRemove.push_back(e);
254 for (
auto e : toRemove) set.erase(e);
261 std::vector<T> stack;
263 std::map<T, unsigned> index;
264 std::map<T, unsigned> lowlink;
266 sccInfo() : crtIndex(0) {}
268 stack.push_back(node);
269 onStack.emplace(node);
271 bool isOnStack(T node) {
return onStack.count(node) != 0; }
272 bool unknown(T node) {
return index.count(node) == 0; }
273 void setLowLink(T node,
unsigned value) {
274 lowlink[node] = value;
275 LOG1(node <<
".lowlink = " << value <<
" = " << get(lowlink, node));
277 void setLowLink(T node, T successor) {
278 unsigned nlink = get(lowlink, node);
279 unsigned slink = get(lowlink, successor);
280 if (slink < nlink) setLowLink(node, slink);
283 T result = stack.back();
285 onStack.erase(result);
291 bool strongConnect(T node,
sccInfo &helper, std::vector<T> &out) {
294 LOG1(
"scc " << cgMakeString(node));
295 helper.index.emplace(node, helper.crtIndex);
296 helper.setLowLink(node, helper.crtIndex);
299 auto oe = out_edges[node];
301 for (
auto next : *oe) {
302 LOG1(cgMakeString(node) <<
" => " << cgMakeString(next));
303 if (helper.unknown(next)) {
304 bool l = strongConnect(next, helper, out);
306 helper.setLowLink(node, next);
307 }
else if (helper.isOnStack(next)) {
308 helper.setLowLink(node, next);
316 if (get(helper.lowlink, node) == get(helper.index, node)) {
317 LOG1(cgMakeString(node) <<
" index=" << get(helper.index, node)
318 <<
" lowlink=" << get(helper.lowlink, node));
320 T sccMember = helper.pop();
321 LOG1(
"Scc order " << cgMakeString(sccMember) <<
"[" << cgMakeString(node) <<
"]");
322 out.push_back(sccMember);
323 if (sccMember == node)
break;
336 bool sccSort(T start, std::vector<T> &out) {
338 return strongConnect(start, helper, out);
340 bool sort(std::vector<T> &start, std::vector<T> &out) {
343 for (
auto n : start) {
344 if (std::find(out.begin(), out.end(), n) == out.end()) {
345 bool c = strongConnect(n, helper, out);
346 cycles = cycles || c;
351 bool sort(std::vector<T> &out) {
354 for (
auto n : nodes) {
355 if (std::find(out.begin(), out.end(), n) == out.end()) {
356 bool c = strongConnect(n, helper, out);
357 cycles = cycles || c;