1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef MPL2MPL_INCLUDE_SCC_H
17 #define MPL2MPL_INCLUDE_SCC_H
18 #include "base_graph_node.h"
19 namespace maple {
20 class BaseGraphNode;
21
22 template <typename T>
23 struct Comparator;
24
25 constexpr uint32 kShiftSccUniqueIDNum = 16;
26
27 // Note that T is the type of the graph node.
28 template <typename T>
29 class SCCNode {
30 public:
SCCNode(uint32 index,MapleAllocator & alloc)31 SCCNode(uint32 index, MapleAllocator &alloc)
32 : id(index), nodes(alloc.Adapter()), inScc(alloc.Adapter()), outScc(alloc.Adapter())
33 {
34 }
35
36 ~SCCNode() = default;
37
AddNode(T * node)38 void AddNode(T *node)
39 {
40 nodes.push_back(node);
41 }
42
Dump()43 void Dump() const
44 {
45 LogInfo::MapleLogger() << "SCC " << id << " contains " << nodes.size() << " node(s)\n";
46 for (auto const kIt : nodes) {
47 T *node = kIt;
48 LogInfo::MapleLogger() << " " << node->GetIdentity() << "\n";
49 }
50 }
51
DumpCycle()52 void DumpCycle() const
53 {
54 T *currNode = nodes[0];
55 std::vector<T *> searched;
56 searched.push_back(currNode);
57 std::vector<T *> invalidNodes;
58 std::vector<BaseGraphNode *> outNodes;
59 while (true) {
60 bool findNewOut = false;
61 currNode->GetOutNodes(outNodes);
62 for (auto outIt : outNodes) {
63 auto outNode = static_cast<T *>(outIt);
64 if (outNode->GetSCCNode() == this) {
65 size_t j = 0;
66 for (; j < invalidNodes.size(); ++j) {
67 if (invalidNodes[j] == outNode) {
68 break;
69 }
70 }
71 // Find a invalid node
72 if (j < invalidNodes.size()) {
73 continue;
74 }
75 for (j = 0; j < searched.size(); ++j) {
76 if (searched[j] == outNode) {
77 break;
78 }
79 }
80 if (j == searched.size()) {
81 currNode = outNode;
82 searched.push_back(currNode);
83 findNewOut = true;
84 break;
85 }
86 }
87 }
88 outNodes.clear();
89 if (searched.size() == nodes.size()) {
90 break;
91 }
92 if (!findNewOut) {
93 invalidNodes.push_back(searched[searched.size() - 1]);
94 searched.pop_back();
95 currNode = searched[searched.size() - 1];
96 }
97 }
98 for (auto it = searched.begin(); it != searched.end(); ++it) {
99 LogInfo::MapleLogger() << (*it)->GetIdentity() << '\n';
100 }
101 }
102
Verify()103 void Verify() const
104 {
105 CHECK_FATAL(!nodes.empty(), "the size of nodes less than zero");
106 for (T *const &node : nodes) {
107 if (node->GetSCCNode() != this) {
108 CHECK_FATAL(false, "must equal this");
109 }
110 }
111 }
112
Setup()113 void Setup()
114 {
115 std::vector<BaseGraphNode *> outNodes;
116 std::vector<BaseGraphNode *> inNodes;
117 for (T *const &node : nodes) {
118 node->GetOutNodes(outNodes);
119 for (auto outIt : outNodes) {
120 auto outNode = static_cast<T *>(outIt);
121 if (outNode == nullptr) {
122 continue;
123 }
124 auto outNodeScc = outNode->GetSCCNode();
125 if (outNodeScc == this) {
126 continue;
127 }
128 outScc.insert(outNodeScc);
129 outNodeScc->inScc.insert(this);
130 }
131 outNodes.clear();
132 }
133 }
134
GetNodes()135 const MapleVector<T *> &GetNodes() const
136 {
137 return nodes;
138 }
139
GetNodes()140 MapleVector<T *> &GetNodes()
141 {
142 return nodes;
143 }
144
GetOutScc()145 const MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> &GetOutScc() const
146 {
147 return outScc;
148 }
149
GetInScc()150 const MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> &GetInScc() const
151 {
152 return inScc;
153 }
154
RemoveInScc(SCCNode<T> * const sccNode)155 void RemoveInScc(SCCNode<T> *const sccNode)
156 {
157 inScc.erase(sccNode);
158 }
159
HasRecursion()160 bool HasRecursion() const
161 {
162 if (nodes.empty()) {
163 return false;
164 }
165 if (nodes.size() > 1) {
166 return true;
167 }
168 T *node = nodes[0];
169 std::vector<BaseGraphNode *> outNodes;
170 node->GetOutNodes(outNodes);
171 for (auto outIt : outNodes) {
172 auto outNode = static_cast<T *>(outIt);
173 if (outNode == nullptr) {
174 continue;
175 }
176 if (node == outNode) {
177 return true;
178 }
179 }
180 return false;
181 }
182
HasSelfRecursion()183 bool HasSelfRecursion() const
184 {
185 if (nodes.size() != 1) {
186 return false;
187 }
188 T *node = nodes[0];
189 std::vector<BaseGraphNode *> outNodes;
190 node->GetOutNodes(outNodes);
191 for (auto outIt : outNodes) {
192 auto outNode = static_cast<T *>(outIt);
193 if (outNode == nullptr) {
194 continue;
195 }
196 if (node == outNode) {
197 return true;
198 }
199 }
200 return false;
201 }
202
HasInScc()203 bool HasInScc() const
204 {
205 return (!inScc.empty());
206 }
207
GetID()208 uint32 GetID() const
209 {
210 return id;
211 }
212
GetUniqueID()213 uint32 GetUniqueID() const
214 {
215 return GetID() << maple::kShiftSccUniqueIDNum;
216 }
217
218 private:
219 uint32 id;
220 MapleVector<T *> nodes;
221 MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> inScc;
222 MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> outScc;
223 };
224
225 template <typename T>
BuildSCCDFS(T & rootNode,uint32 & visitIndex,MapleVector<SCCNode<T> * > & sccNodes,std::vector<T * > & nodes,std::vector<uint32> & visitedOrder,std::vector<uint32> & lowestOrder,std::vector<bool> & inStack,std::vector<uint32> & visitStack,uint32 & numOfSccs,MapleAllocator & cgAlloc)226 void BuildSCCDFS(T &rootNode, uint32 &visitIndex, MapleVector<SCCNode<T> *> &sccNodes, std::vector<T *> &nodes,
227 std::vector<uint32> &visitedOrder, std::vector<uint32> &lowestOrder, std::vector<bool> &inStack,
228 std::vector<uint32> &visitStack, uint32 &numOfSccs, MapleAllocator &cgAlloc)
229 {
230 uint32 id = rootNode.GetID();
231 nodes.at(id) = &rootNode;
232 visitedOrder.at(id) = visitIndex;
233 lowestOrder.at(id) = visitIndex;
234 ++visitIndex;
235 inStack.at(id) = true;
236
237 std::vector<BaseGraphNode *> outNodes;
238 rootNode.GetOutNodes(outNodes);
239 for (auto outIt : outNodes) {
240 auto outNode = static_cast<T *>(outIt);
241 if (outNode == nullptr) {
242 continue;
243 }
244 uint32 outNodeId = outNode->GetID();
245 if (visitedOrder.at(outNodeId) == 0) {
246 // callee has not been processed yet
247 BuildSCCDFS(*outNode, visitIndex, sccNodes, nodes, visitedOrder, lowestOrder, inStack, visitStack,
248 numOfSccs, cgAlloc);
249 if (lowestOrder.at(outNodeId) < lowestOrder.at(id)) {
250 lowestOrder.at(id) = lowestOrder.at(outNodeId);
251 }
252 } else if (inStack.at(outNodeId) && (visitedOrder.at(outNodeId) < lowestOrder.at(id))) {
253 // back edge
254 lowestOrder.at(id) = visitedOrder.at(outNodeId);
255 }
256 }
257
258 if (visitedOrder.at(id) == lowestOrder.at(id)) {
259 SCCNode<T> *sccNode = cgAlloc.GetMemPool()->New<SCCNode<T>>(numOfSccs++, cgAlloc);
260 inStack.at(id) = false;
261 T *rootNode = nodes.at(id);
262 rootNode->SetSCCNode(sccNode);
263 sccNode->AddNode(rootNode);
264 while (!visitStack.empty()) {
265 auto stackTopId = visitStack.back();
266 if (visitedOrder.at(stackTopId) < visitedOrder.at(id)) {
267 break;
268 }
269 visitStack.pop_back();
270 inStack.at(stackTopId) = false;
271 T *topNode = nodes.at(stackTopId);
272 topNode->SetSCCNode(sccNode);
273 sccNode->AddNode(topNode);
274 }
275 sccNodes.push_back(sccNode);
276 } else {
277 visitStack.push_back(id);
278 }
279 }
280
281 template <typename T>
VerifySCC(std::vector<T * > nodes)282 void VerifySCC(std::vector<T *> nodes)
283 {
284 for (auto node : nodes) {
285 if (node->GetSCCNode() == nullptr) {
286 CHECK_FATAL(false, "nullptr check in VerifySCC()");
287 }
288 }
289 }
290
291 template <typename T>
292 uint32 BuildSCC(MapleAllocator &cgAlloc, uint32 numOfNodes, std::vector<T *> &allNodes, bool debugScc,
293 MapleVector<SCCNode<T> *> &topologicalVec, bool clearOld = false)
294 {
295 // This is the mapping between cg_id to node.
296 std::vector<T *> id2NodeMap(numOfNodes, nullptr);
297 std::vector<uint32> visitedOrder(numOfNodes, 0);
298 std::vector<uint32> lowestOrder(numOfNodes, 0);
299 std::vector<bool> inStack(numOfNodes, false);
300 std::vector<uint32> visitStack;
301 uint32 visitIndex = 1;
302 uint32 numOfSccs = 0;
303 if (clearOld) {
304 // clear old scc before computing
305 for (auto node : allNodes) {
306 node->SetSCCNode(nullptr);
307 }
308 }
309 // However, not all SCC can be reached from roots.
310 // E.g. foo()->foo(), foo is not considered as a root.
311 for (auto node : allNodes) {
312 if (node->GetSCCNode() == nullptr) {
313 BuildSCCDFS(*node, visitIndex, topologicalVec, id2NodeMap, visitedOrder, lowestOrder, inStack, visitStack,
314 numOfSccs, cgAlloc);
315 }
316 }
317 for (auto scc : topologicalVec) {
318 scc->Verify();
319 scc->Setup(); // fix caller and callee info.
320 if (debugScc && scc->HasRecursion()) {
321 scc->Dump();
322 }
323 }
324 std::reverse(topologicalVec.begin(), topologicalVec.end());
325 return numOfSccs;
326 }
327 } // namespace maple
328 #endif // MPL2MPL_INCLUDE_SCC_H