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