52 explicit CallGraph(std::string_view name) : name(name) {}
54 const cstring &getName()
const {
return name; }
60 if (nodes.find(caller) != nodes.end())
return;
61 LOG1(name <<
": " << cgMakeString(caller));
62 out_edges[caller] =
new std::vector<T>();
63 in_edges[caller] =
new std::vector<T>();
64 nodes.emplace(caller);
66 void calls(T caller, T callee) {
67 LOG1(name <<
": " << cgMakeString(callee) <<
" is called by " << cgMakeString(caller));
70 out_edges[caller]->push_back(callee);
71 in_edges[callee]->push_back(caller);
74 auto n = nodes.find(node);
75 BUG_CHECK(n != nodes.end(),
"%1%: Node not in graph", node);
77 auto in = in_edges.find(node);
78 if (in != in_edges.end()) {
80 for (
auto n : *in->second) {
81 auto out = out_edges[n];
83 auto oe = std::find(out->begin(), out->end(), node);
88 auto it = out_edges.find(node);
89 if (it != out_edges.end()) {
91 for (
auto n : *it->second) {
92 auto in = in_edges[n];
94 auto ie = std::find(in->begin(), in->end(), node);
103 bool isCallee(T callee)
const {
104 auto callees = ::get(in_edges, callee);
105 return callees !=
nullptr && !callees->empty();
107 bool isCaller(T caller)
const {
108 auto edges = ::get(out_edges, caller);
109 if (edges ==
nullptr)
return false;
110 return !edges->empty();
113 const_iterator begin()
const {
return out_edges.cbegin(); }
114 const_iterator end()
const {
return out_edges.cend(); }
115 std::vector<T> *getCallees(T caller) {
return out_edges[caller]; }
116 std::vector<T> *getCallers(T callee) {
return in_edges[callee]; }
118 void getCallees(T caller, std::set<T> &toAppend) {
119 if (isCaller(caller)) toAppend.insert(out_edges[caller]->begin(), out_edges[caller]->end());
121 size_t size()
const {
return nodes.size(); }
123 void reachable(T start, std::set<T> &out)
const {
126 while (!work.empty()) {
127 T node = *work.begin();
129 if (out.find(node) != out.end())
continue;
131 auto edges = out_edges.find(node);
132 if (edges == out_edges.end())
continue;
133 for (
auto c : *(edges->second)) work.emplace(c);
137 void restrict(
const std::set<T> &to) {
138 std::vector<T> toRemove;
140 if (to.find(n) == to.end()) toRemove.push_back(n);
141 for (
auto n : toRemove) remove(n);
144 typedef std::unordered_set<T> Set;
150 void dominators(T start, std::map<T, Set> &dominators) {
152 for (
auto n : nodes) {
154 dominators[n].emplace(start);
156 dominators[n].insert(nodes.begin(), nodes.end());
163 for (
auto node : nodes) {
164 auto vec = in_edges[node];
165 if (vec ==
nullptr)
continue;
166 auto size = dominators[node].size();
167 for (
auto c : *vec) insersectWith(dominators[node], dominators[c]);
168 dominators[node].emplace(node);
169 if (dominators[node].size() != size) changes =
true;
179 std::set<T> back_edge_heads;
181 explicit Loop(T entry) : entry(entry) {}
186 std::vector<Loop *> loops;
190 int isLoopEntryPoint(T node)
const {
191 for (
size_t i = 0; i < loops.size(); i++) {
192 auto loop = loops.at(i);
193 if (loop->entry == node)
return i;
197 bool isInLoop(
int loopIndex, T node)
const {
198 if (loopIndex == -1)
return false;
199 auto loop = loops.at(loopIndex);
200 return (loop->body.find(node) != loop->body.end());
204 Loops *compute_loops(T start) {
205 auto result =
new Loops();
206 std::map<T, Set> dom;
207 dominators(start, dom);
209 std::map<T, Loop *> entryToLoop;
211 for (
auto e : nodes) {
212 auto next = out_edges[e];
214 for (
auto n : *next) {
215 if (dome.find(n) != dome.end()) {
217 auto loop = get(entryToLoop, n);
218 if (loop ==
nullptr) {
220 entryToLoop[n] = loop;
221 result->loops.push_back(loop);
223 loop->back_edge_heads.emplace(e);
228 while (!work.empty()) {
229 auto crt = *work.begin();
231 loop->body.emplace(crt);
232 if (crt == n)
continue;
233 for (
auto i : *in_edges[crt])
234 if (loop->body.find(i) == loop->body.end()) work.emplace(i);
244 static void insersectWith(Set &set, Set &with) {
245 std::vector<T> toRemove;
247 if (with.find(e) == with.end()) toRemove.push_back(e);
248 for (
auto e : toRemove) set.erase(e);
255 std::vector<T> stack;
257 std::map<T, unsigned> index;
258 std::map<T, unsigned> lowlink;
262 stack.push_back(node);
263 onStack.emplace(node);
265 bool isOnStack(T node) {
return onStack.count(node) != 0; }
266 bool unknown(T node) {
return index.count(node) == 0; }
267 void setLowLink(T node,
unsigned value) {
268 lowlink[node] = value;
269 LOG1(node <<
".lowlink = " << value <<
" = " << get(lowlink, node));
271 void setLowLink(T node, T successor) {
272 unsigned nlink = get(lowlink, node);
273 unsigned slink = get(lowlink, successor);
274 if (slink < nlink) setLowLink(node, slink);
277 T result = stack.back();
279 onStack.erase(result);
285 bool strongConnect(T node,
sccInfo &helper, std::vector<T> &out) {
288 LOG1(
"scc " << cgMakeString(node));
289 helper.index.emplace(node, helper.crtIndex);
290 helper.setLowLink(node, helper.crtIndex);
293 auto oe = out_edges[node];
295 for (
auto next : *oe) {
296 LOG1(cgMakeString(node) <<
" => " << cgMakeString(next));
297 if (helper.unknown(next)) {
298 bool l = strongConnect(next, helper, out);
300 helper.setLowLink(node, next);
301 }
else if (helper.isOnStack(next)) {
302 helper.setLowLink(node, next);
310 if (get(helper.lowlink, node) == get(helper.index, node)) {
311 LOG1(cgMakeString(node) <<
" index=" << get(helper.index, node)
312 <<
" lowlink=" << get(helper.lowlink, node));
314 T sccMember = helper.pop();
315 LOG1(
"Scc order " << cgMakeString(sccMember) <<
"[" << cgMakeString(node) <<
"]");
316 out.push_back(sccMember);
317 if (sccMember == node)
break;
330 bool sccSort(T start, std::vector<T> &out) {
332 return strongConnect(start, helper, out);
334 bool sort(std::vector<T> &start, std::vector<T> &out) {
337 for (
auto n : start) {
338 if (std::find(out.begin(), out.end(), n) == out.end()) {
339 bool c = strongConnect(n, helper, out);
340 cycles = cycles || c;
345 bool sort(std::vector<T> &out) {
348 for (
auto n : nodes) {
349 if (std::find(out.begin(), out.end(), n) == out.end()) {
350 bool c = strongConnect(n, helper, out);
351 cycles = cycles || c;