14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef MPL2MPL_INCLUDE_SCC_H 174514f5e3Sopenharmony_ci#define MPL2MPL_INCLUDE_SCC_H 184514f5e3Sopenharmony_ci#include "base_graph_node.h" 194514f5e3Sopenharmony_cinamespace maple { 204514f5e3Sopenharmony_ciclass BaseGraphNode; 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_ciconstexpr uint32 kShiftSccUniqueIDNum = 16; 234514f5e3Sopenharmony_ci 244514f5e3Sopenharmony_ci// Note that T is the type of the graph node. 254514f5e3Sopenharmony_citemplate <typename T> 264514f5e3Sopenharmony_ciclass SCCNode { 274514f5e3Sopenharmony_cipublic: 284514f5e3Sopenharmony_ci SCCNode(uint32 index, MapleAllocator &alloc) 294514f5e3Sopenharmony_ci : id(index), nodes(alloc.Adapter()), inScc(alloc.Adapter()), outScc(alloc.Adapter()) 304514f5e3Sopenharmony_ci { 314514f5e3Sopenharmony_ci } 324514f5e3Sopenharmony_ci 334514f5e3Sopenharmony_ci ~SCCNode() = default; 344514f5e3Sopenharmony_ci 354514f5e3Sopenharmony_ci void AddNode(T *node) 364514f5e3Sopenharmony_ci { 374514f5e3Sopenharmony_ci nodes.push_back(node); 384514f5e3Sopenharmony_ci } 394514f5e3Sopenharmony_ci 404514f5e3Sopenharmony_ci void Dump() const 414514f5e3Sopenharmony_ci { 424514f5e3Sopenharmony_ci LogInfo::MapleLogger() << "SCC " << id << " contains " << nodes.size() << " node(s)\n"; 434514f5e3Sopenharmony_ci for (auto const kIt : nodes) { 444514f5e3Sopenharmony_ci T *node = kIt; 454514f5e3Sopenharmony_ci LogInfo::MapleLogger() << " " << node->GetIdentity() << "\n"; 464514f5e3Sopenharmony_ci } 474514f5e3Sopenharmony_ci } 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ci void DumpCycle() const 504514f5e3Sopenharmony_ci { 514514f5e3Sopenharmony_ci T *currNode = nodes[0]; 524514f5e3Sopenharmony_ci std::vector<T *> searched; 534514f5e3Sopenharmony_ci searched.push_back(currNode); 544514f5e3Sopenharmony_ci std::vector<T *> invalidNodes; 554514f5e3Sopenharmony_ci std::vector<BaseGraphNode *> outNodes; 564514f5e3Sopenharmony_ci while (true) { 574514f5e3Sopenharmony_ci bool findNewOut = false; 584514f5e3Sopenharmony_ci currNode->GetOutNodes(outNodes); 594514f5e3Sopenharmony_ci for (auto outIt : outNodes) { 604514f5e3Sopenharmony_ci auto outNode = static_cast<T *>(outIt); 614514f5e3Sopenharmony_ci if (outNode->GetSCCNode() == this) { 624514f5e3Sopenharmony_ci size_t j = 0; 634514f5e3Sopenharmony_ci for (; j < invalidNodes.size(); ++j) { 644514f5e3Sopenharmony_ci if (invalidNodes[j] == outNode) { 654514f5e3Sopenharmony_ci break; 664514f5e3Sopenharmony_ci } 674514f5e3Sopenharmony_ci } 684514f5e3Sopenharmony_ci // Find a invalid node 694514f5e3Sopenharmony_ci if (j < invalidNodes.size()) { 704514f5e3Sopenharmony_ci continue; 714514f5e3Sopenharmony_ci } 724514f5e3Sopenharmony_ci for (j = 0; j < searched.size(); ++j) { 734514f5e3Sopenharmony_ci if (searched[j] == outNode) { 744514f5e3Sopenharmony_ci break; 754514f5e3Sopenharmony_ci } 764514f5e3Sopenharmony_ci } 774514f5e3Sopenharmony_ci if (j == searched.size()) { 784514f5e3Sopenharmony_ci currNode = outNode; 794514f5e3Sopenharmony_ci searched.push_back(currNode); 804514f5e3Sopenharmony_ci findNewOut = true; 814514f5e3Sopenharmony_ci break; 824514f5e3Sopenharmony_ci } 834514f5e3Sopenharmony_ci } 844514f5e3Sopenharmony_ci } 854514f5e3Sopenharmony_ci outNodes.clear(); 864514f5e3Sopenharmony_ci if (searched.size() == nodes.size()) { 874514f5e3Sopenharmony_ci break; 884514f5e3Sopenharmony_ci } 894514f5e3Sopenharmony_ci if (!findNewOut) { 904514f5e3Sopenharmony_ci invalidNodes.push_back(searched[searched.size() - 1]); 914514f5e3Sopenharmony_ci searched.pop_back(); 924514f5e3Sopenharmony_ci currNode = searched[searched.size() - 1]; 934514f5e3Sopenharmony_ci } 944514f5e3Sopenharmony_ci } 954514f5e3Sopenharmony_ci for (auto it = searched.begin(); it != searched.end(); ++it) { 964514f5e3Sopenharmony_ci LogInfo::MapleLogger() << (*it)->GetIdentity() << '\n'; 974514f5e3Sopenharmony_ci } 984514f5e3Sopenharmony_ci } 994514f5e3Sopenharmony_ci 1004514f5e3Sopenharmony_ci void Verify() const 1014514f5e3Sopenharmony_ci { 1024514f5e3Sopenharmony_ci CHECK_FATAL(!nodes.empty(), "the size of nodes less than zero"); 1034514f5e3Sopenharmony_ci for (T *const &node : nodes) { 1044514f5e3Sopenharmony_ci if (node->GetSCCNode() != this) { 1054514f5e3Sopenharmony_ci CHECK_FATAL(false, "must equal this"); 1064514f5e3Sopenharmony_ci } 1074514f5e3Sopenharmony_ci } 1084514f5e3Sopenharmony_ci } 1094514f5e3Sopenharmony_ci 1104514f5e3Sopenharmony_ci void Setup() 1114514f5e3Sopenharmony_ci { 1124514f5e3Sopenharmony_ci std::vector<BaseGraphNode *> outNodes; 1134514f5e3Sopenharmony_ci std::vector<BaseGraphNode *> inNodes; 1144514f5e3Sopenharmony_ci for (T *const &node : nodes) { 1154514f5e3Sopenharmony_ci node->GetOutNodes(outNodes); 1164514f5e3Sopenharmony_ci for (auto outIt : outNodes) { 1174514f5e3Sopenharmony_ci auto outNode = static_cast<T *>(outIt); 1184514f5e3Sopenharmony_ci if (outNode == nullptr) { 1194514f5e3Sopenharmony_ci continue; 1204514f5e3Sopenharmony_ci } 1214514f5e3Sopenharmony_ci auto outNodeScc = outNode->GetSCCNode(); 1224514f5e3Sopenharmony_ci if (outNodeScc == this) { 1234514f5e3Sopenharmony_ci continue; 1244514f5e3Sopenharmony_ci } 1254514f5e3Sopenharmony_ci outScc.insert(outNodeScc); 1264514f5e3Sopenharmony_ci outNodeScc->inScc.insert(this); 1274514f5e3Sopenharmony_ci } 1284514f5e3Sopenharmony_ci outNodes.clear(); 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci } 1314514f5e3Sopenharmony_ci 1324514f5e3Sopenharmony_ci const MapleVector<T *> &GetNodes() const 1334514f5e3Sopenharmony_ci { 1344514f5e3Sopenharmony_ci return nodes; 1354514f5e3Sopenharmony_ci } 1364514f5e3Sopenharmony_ci 1374514f5e3Sopenharmony_ci MapleVector<T *> &GetNodes() 1384514f5e3Sopenharmony_ci { 1394514f5e3Sopenharmony_ci return nodes; 1404514f5e3Sopenharmony_ci } 1414514f5e3Sopenharmony_ci 1424514f5e3Sopenharmony_ci const MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> &GetOutScc() const 1434514f5e3Sopenharmony_ci { 1444514f5e3Sopenharmony_ci return outScc; 1454514f5e3Sopenharmony_ci } 1464514f5e3Sopenharmony_ci 1474514f5e3Sopenharmony_ci const MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> &GetInScc() const 1484514f5e3Sopenharmony_ci { 1494514f5e3Sopenharmony_ci return inScc; 1504514f5e3Sopenharmony_ci } 1514514f5e3Sopenharmony_ci 1524514f5e3Sopenharmony_ci void RemoveInScc(SCCNode<T> *const sccNode) 1534514f5e3Sopenharmony_ci { 1544514f5e3Sopenharmony_ci inScc.erase(sccNode); 1554514f5e3Sopenharmony_ci } 1564514f5e3Sopenharmony_ci 1574514f5e3Sopenharmony_ci bool HasRecursion() const 1584514f5e3Sopenharmony_ci { 1594514f5e3Sopenharmony_ci if (nodes.empty()) { 1604514f5e3Sopenharmony_ci return false; 1614514f5e3Sopenharmony_ci } 1624514f5e3Sopenharmony_ci if (nodes.size() > 1) { 1634514f5e3Sopenharmony_ci return true; 1644514f5e3Sopenharmony_ci } 1654514f5e3Sopenharmony_ci T *node = nodes[0]; 1664514f5e3Sopenharmony_ci std::vector<BaseGraphNode *> outNodes; 1674514f5e3Sopenharmony_ci node->GetOutNodes(outNodes); 1684514f5e3Sopenharmony_ci for (auto outIt : outNodes) { 1694514f5e3Sopenharmony_ci auto outNode = static_cast<T *>(outIt); 1704514f5e3Sopenharmony_ci if (outNode == nullptr) { 1714514f5e3Sopenharmony_ci continue; 1724514f5e3Sopenharmony_ci } 1734514f5e3Sopenharmony_ci if (node == outNode) { 1744514f5e3Sopenharmony_ci return true; 1754514f5e3Sopenharmony_ci } 1764514f5e3Sopenharmony_ci } 1774514f5e3Sopenharmony_ci return false; 1784514f5e3Sopenharmony_ci } 1794514f5e3Sopenharmony_ci 1804514f5e3Sopenharmony_ci bool HasSelfRecursion() const 1814514f5e3Sopenharmony_ci { 1824514f5e3Sopenharmony_ci if (nodes.size() != 1) { 1834514f5e3Sopenharmony_ci return false; 1844514f5e3Sopenharmony_ci } 1854514f5e3Sopenharmony_ci T *node = nodes[0]; 1864514f5e3Sopenharmony_ci std::vector<BaseGraphNode *> outNodes; 1874514f5e3Sopenharmony_ci node->GetOutNodes(outNodes); 1884514f5e3Sopenharmony_ci for (auto outIt : outNodes) { 1894514f5e3Sopenharmony_ci auto outNode = static_cast<T *>(outIt); 1904514f5e3Sopenharmony_ci if (outNode == nullptr) { 1914514f5e3Sopenharmony_ci continue; 1924514f5e3Sopenharmony_ci } 1934514f5e3Sopenharmony_ci if (node == outNode) { 1944514f5e3Sopenharmony_ci return true; 1954514f5e3Sopenharmony_ci } 1964514f5e3Sopenharmony_ci } 1974514f5e3Sopenharmony_ci return false; 1984514f5e3Sopenharmony_ci } 1994514f5e3Sopenharmony_ci 2004514f5e3Sopenharmony_ci bool HasInScc() const 2014514f5e3Sopenharmony_ci { 2024514f5e3Sopenharmony_ci return (!inScc.empty()); 2034514f5e3Sopenharmony_ci } 2044514f5e3Sopenharmony_ci 2054514f5e3Sopenharmony_ci uint32 GetID() const 2064514f5e3Sopenharmony_ci { 2074514f5e3Sopenharmony_ci return id; 2084514f5e3Sopenharmony_ci } 2094514f5e3Sopenharmony_ci 2104514f5e3Sopenharmony_ci uint32 GetUniqueID() const 2114514f5e3Sopenharmony_ci { 2124514f5e3Sopenharmony_ci return GetID() << maple::kShiftSccUniqueIDNum; 2134514f5e3Sopenharmony_ci } 2144514f5e3Sopenharmony_ci 2154514f5e3Sopenharmony_ciprivate: 2164514f5e3Sopenharmony_ci uint32 id; 2174514f5e3Sopenharmony_ci MapleVector<T *> nodes; 2184514f5e3Sopenharmony_ci MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> inScc; 2194514f5e3Sopenharmony_ci MapleSet<SCCNode<T> *, Comparator<SCCNode<T>>> outScc; 2204514f5e3Sopenharmony_ci}; 2214514f5e3Sopenharmony_ci 2224514f5e3Sopenharmony_citemplate <typename T> 2234514f5e3Sopenharmony_civoid BuildSCCDFS(T &rootNode, uint32 &visitIndex, MapleVector<SCCNode<T> *> &sccNodes, std::vector<T *> &nodes, 2244514f5e3Sopenharmony_ci std::vector<uint32> &visitedOrder, std::vector<uint32> &lowestOrder, std::vector<bool> &inStack, 2254514f5e3Sopenharmony_ci std::vector<uint32> &visitStack, uint32 &numOfSccs, MapleAllocator &cgAlloc) 2264514f5e3Sopenharmony_ci{ 2274514f5e3Sopenharmony_ci uint32 id = rootNode.GetID(); 2284514f5e3Sopenharmony_ci nodes.at(id) = &rootNode; 2294514f5e3Sopenharmony_ci visitedOrder.at(id) = visitIndex; 2304514f5e3Sopenharmony_ci lowestOrder.at(id) = visitIndex; 2314514f5e3Sopenharmony_ci ++visitIndex; 2324514f5e3Sopenharmony_ci inStack.at(id) = true; 2334514f5e3Sopenharmony_ci 2344514f5e3Sopenharmony_ci std::vector<BaseGraphNode *> outNodes; 2354514f5e3Sopenharmony_ci rootNode.GetOutNodes(outNodes); 2364514f5e3Sopenharmony_ci for (auto outIt : outNodes) { 2374514f5e3Sopenharmony_ci auto outNode = static_cast<T *>(outIt); 2384514f5e3Sopenharmony_ci if (outNode == nullptr) { 2394514f5e3Sopenharmony_ci continue; 2404514f5e3Sopenharmony_ci } 2414514f5e3Sopenharmony_ci uint32 outNodeId = outNode->GetID(); 2424514f5e3Sopenharmony_ci if (visitedOrder.at(outNodeId) == 0) { 2434514f5e3Sopenharmony_ci // callee has not been processed yet 2444514f5e3Sopenharmony_ci BuildSCCDFS(*outNode, visitIndex, sccNodes, nodes, visitedOrder, lowestOrder, inStack, visitStack, 2454514f5e3Sopenharmony_ci numOfSccs, cgAlloc); 2464514f5e3Sopenharmony_ci if (lowestOrder.at(outNodeId) < lowestOrder.at(id)) { 2474514f5e3Sopenharmony_ci lowestOrder.at(id) = lowestOrder.at(outNodeId); 2484514f5e3Sopenharmony_ci } 2494514f5e3Sopenharmony_ci } else if (inStack.at(outNodeId) && (visitedOrder.at(outNodeId) < lowestOrder.at(id))) { 2504514f5e3Sopenharmony_ci // back edge 2514514f5e3Sopenharmony_ci lowestOrder.at(id) = visitedOrder.at(outNodeId); 2524514f5e3Sopenharmony_ci } 2534514f5e3Sopenharmony_ci } 2544514f5e3Sopenharmony_ci 2554514f5e3Sopenharmony_ci if (visitedOrder.at(id) == lowestOrder.at(id)) { 2564514f5e3Sopenharmony_ci SCCNode<T> *sccNode = cgAlloc.GetMemPool()->New<SCCNode<T>>(numOfSccs++, cgAlloc); 2574514f5e3Sopenharmony_ci inStack.at(id) = false; 2584514f5e3Sopenharmony_ci T *rootNode = nodes.at(id); 2594514f5e3Sopenharmony_ci rootNode->SetSCCNode(sccNode); 2604514f5e3Sopenharmony_ci sccNode->AddNode(rootNode); 2614514f5e3Sopenharmony_ci while (!visitStack.empty()) { 2624514f5e3Sopenharmony_ci auto stackTopId = visitStack.back(); 2634514f5e3Sopenharmony_ci if (visitedOrder.at(stackTopId) < visitedOrder.at(id)) { 2644514f5e3Sopenharmony_ci break; 2654514f5e3Sopenharmony_ci } 2664514f5e3Sopenharmony_ci visitStack.pop_back(); 2674514f5e3Sopenharmony_ci inStack.at(stackTopId) = false; 2684514f5e3Sopenharmony_ci T *topNode = nodes.at(stackTopId); 2694514f5e3Sopenharmony_ci topNode->SetSCCNode(sccNode); 2704514f5e3Sopenharmony_ci sccNode->AddNode(topNode); 2714514f5e3Sopenharmony_ci } 2724514f5e3Sopenharmony_ci sccNodes.push_back(sccNode); 2734514f5e3Sopenharmony_ci } else { 2744514f5e3Sopenharmony_ci visitStack.push_back(id); 2754514f5e3Sopenharmony_ci } 2764514f5e3Sopenharmony_ci} 2774514f5e3Sopenharmony_ci 2784514f5e3Sopenharmony_citemplate <typename T> 2794514f5e3Sopenharmony_civoid VerifySCC(std::vector<T *> nodes) 2804514f5e3Sopenharmony_ci{ 2814514f5e3Sopenharmony_ci for (auto node : nodes) { 2824514f5e3Sopenharmony_ci if (node->GetSCCNode() == nullptr) { 2834514f5e3Sopenharmony_ci CHECK_FATAL(false, "nullptr check in VerifySCC()"); 2844514f5e3Sopenharmony_ci } 2854514f5e3Sopenharmony_ci } 2864514f5e3Sopenharmony_ci} 2874514f5e3Sopenharmony_ci 2884514f5e3Sopenharmony_citemplate <typename T> 2894514f5e3Sopenharmony_ciuint32 BuildSCC(MapleAllocator &cgAlloc, uint32 numOfNodes, std::vector<T *> &allNodes, bool debugScc, 2904514f5e3Sopenharmony_ci MapleVector<SCCNode<T> *> &topologicalVec, bool clearOld = false) 2914514f5e3Sopenharmony_ci{ 2924514f5e3Sopenharmony_ci // This is the mapping between cg_id to node. 2934514f5e3Sopenharmony_ci std::vector<T *> id2NodeMap(numOfNodes, nullptr); 2944514f5e3Sopenharmony_ci std::vector<uint32> visitedOrder(numOfNodes, 0); 2954514f5e3Sopenharmony_ci std::vector<uint32> lowestOrder(numOfNodes, 0); 2964514f5e3Sopenharmony_ci std::vector<bool> inStack(numOfNodes, false); 2974514f5e3Sopenharmony_ci std::vector<uint32> visitStack; 2984514f5e3Sopenharmony_ci uint32 visitIndex = 1; 2994514f5e3Sopenharmony_ci uint32 numOfSccs = 0; 3004514f5e3Sopenharmony_ci if (clearOld) { 3014514f5e3Sopenharmony_ci // clear old scc before computing 3024514f5e3Sopenharmony_ci for (auto node : allNodes) { 3034514f5e3Sopenharmony_ci node->SetSCCNode(nullptr); 3044514f5e3Sopenharmony_ci } 3054514f5e3Sopenharmony_ci } 3064514f5e3Sopenharmony_ci // However, not all SCC can be reached from roots. 3074514f5e3Sopenharmony_ci // E.g. foo()->foo(), foo is not considered as a root. 3084514f5e3Sopenharmony_ci for (auto node : allNodes) { 3094514f5e3Sopenharmony_ci if (node->GetSCCNode() == nullptr) { 3104514f5e3Sopenharmony_ci BuildSCCDFS(*node, visitIndex, topologicalVec, id2NodeMap, visitedOrder, lowestOrder, inStack, visitStack, 3114514f5e3Sopenharmony_ci numOfSccs, cgAlloc); 3124514f5e3Sopenharmony_ci } 3134514f5e3Sopenharmony_ci } 3144514f5e3Sopenharmony_ci for (auto scc : topologicalVec) { 3154514f5e3Sopenharmony_ci scc->Verify(); 3164514f5e3Sopenharmony_ci scc->Setup(); // fix caller and callee info. 3174514f5e3Sopenharmony_ci if (debugScc && scc->HasRecursion()) { 3184514f5e3Sopenharmony_ci scc->Dump(); 3194514f5e3Sopenharmony_ci } 3204514f5e3Sopenharmony_ci } 3214514f5e3Sopenharmony_ci std::reverse(topologicalVec.begin(), topologicalVec.end()); 3224514f5e3Sopenharmony_ci return numOfSccs; 3234514f5e3Sopenharmony_ci} 3244514f5e3Sopenharmony_ci} // namespace maple 3254514f5e3Sopenharmony_ci#endif // MPL2MPL_INCLUDE_SCC_H