• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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