14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021 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#include "ecmascript/compiler/scheduler.h"
174514f5e3Sopenharmony_ci#include <cmath>
184514f5e3Sopenharmony_ci#include <stack>
194514f5e3Sopenharmony_ci#include "ecmascript/compiler/gate_accessor.h"
204514f5e3Sopenharmony_ci#include "ecmascript/compiler/verifier.h"
214514f5e3Sopenharmony_ci
224514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
234514f5e3Sopenharmony_cisize_t UnionFind(std::vector<size_t> &semiDom, std::vector<size_t> &parent, std::vector<size_t> &minIdx, size_t idx)
244514f5e3Sopenharmony_ci{
254514f5e3Sopenharmony_ci    std::stack<size_t> allIdxs;
264514f5e3Sopenharmony_ci    allIdxs.emplace(idx);
274514f5e3Sopenharmony_ci    size_t pIdx = parent[idx];
284514f5e3Sopenharmony_ci    while (pIdx != allIdxs.top()) {
294514f5e3Sopenharmony_ci        allIdxs.emplace(pIdx);
304514f5e3Sopenharmony_ci        pIdx = parent[pIdx];
314514f5e3Sopenharmony_ci    }
324514f5e3Sopenharmony_ci    size_t unionFindSetRoot = pIdx;
334514f5e3Sopenharmony_ci    while (!allIdxs.empty()) {
344514f5e3Sopenharmony_ci        if (semiDom[minIdx[allIdxs.top()]] > semiDom[minIdx[pIdx]]) {
354514f5e3Sopenharmony_ci            minIdx[allIdxs.top()] = minIdx[pIdx];
364514f5e3Sopenharmony_ci        }
374514f5e3Sopenharmony_ci        parent[allIdxs.top()] = unionFindSetRoot;
384514f5e3Sopenharmony_ci        pIdx = allIdxs.top();
394514f5e3Sopenharmony_ci        allIdxs.pop();
404514f5e3Sopenharmony_ci    }
414514f5e3Sopenharmony_ci    return unionFindSetRoot;
424514f5e3Sopenharmony_ci}
434514f5e3Sopenharmony_ci
444514f5e3Sopenharmony_civoid Scheduler::CalculateDominatorTree(const Circuit *circuit,
454514f5e3Sopenharmony_ci                                       std::vector<GateRef>& bbGatesList,
464514f5e3Sopenharmony_ci                                       std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
474514f5e3Sopenharmony_ci                                       std::vector<size_t> &immDom)
484514f5e3Sopenharmony_ci{
494514f5e3Sopenharmony_ci    GateAccessor acc(const_cast<Circuit*>(circuit));
504514f5e3Sopenharmony_ci    std::unordered_map<GateRef, size_t> dfsTimestamp;
514514f5e3Sopenharmony_ci    std::unordered_map<GateRef, size_t> dfsFatherIdx;
524514f5e3Sopenharmony_ci    circuit->AdvanceTime();
534514f5e3Sopenharmony_ci    {
544514f5e3Sopenharmony_ci        size_t timestamp = 0;
554514f5e3Sopenharmony_ci        std::deque<GateRef> pendingList;
564514f5e3Sopenharmony_ci        auto startGate = acc.GetStateRoot();
574514f5e3Sopenharmony_ci        acc.SetMark(startGate, MarkCode::VISITED);
584514f5e3Sopenharmony_ci        pendingList.push_back(startGate);
594514f5e3Sopenharmony_ci        while (!pendingList.empty()) {
604514f5e3Sopenharmony_ci            auto curGate = pendingList.back();
614514f5e3Sopenharmony_ci            dfsTimestamp[curGate] = timestamp++;
624514f5e3Sopenharmony_ci            pendingList.pop_back();
634514f5e3Sopenharmony_ci            bbGatesList.push_back(curGate);
644514f5e3Sopenharmony_ci            if (acc.GetOpCode(curGate) != OpCode::LOOP_BACK) {
654514f5e3Sopenharmony_ci                auto uses = acc.Uses(curGate);
664514f5e3Sopenharmony_ci                for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) {
674514f5e3Sopenharmony_ci                    if (useIt.GetIndex() < acc.GetStateCount(*useIt) &&
684514f5e3Sopenharmony_ci                        acc.IsState(*useIt) && acc.GetMark(*useIt) == MarkCode::NO_MARK) {
694514f5e3Sopenharmony_ci                        acc.SetMark(*useIt, MarkCode::VISITED);
704514f5e3Sopenharmony_ci                        pendingList.push_back(*useIt);
714514f5e3Sopenharmony_ci                        dfsFatherIdx[*useIt] = dfsTimestamp[curGate];
724514f5e3Sopenharmony_ci                    }
734514f5e3Sopenharmony_ci                }
744514f5e3Sopenharmony_ci            }
754514f5e3Sopenharmony_ci        }
764514f5e3Sopenharmony_ci        for (size_t idx = 0; idx < bbGatesList.size(); idx++) {
774514f5e3Sopenharmony_ci            bbGatesAddrToIdx[bbGatesList[idx]] = idx;
784514f5e3Sopenharmony_ci        }
794514f5e3Sopenharmony_ci    }
804514f5e3Sopenharmony_ci    immDom.resize(bbGatesList.size());
814514f5e3Sopenharmony_ci    std::vector<size_t> semiDom(bbGatesList.size());
824514f5e3Sopenharmony_ci    std::vector<std::vector<size_t> > semiDomTree(bbGatesList.size());
834514f5e3Sopenharmony_ci    {
844514f5e3Sopenharmony_ci        std::vector<size_t> parent(bbGatesList.size());
854514f5e3Sopenharmony_ci        std::iota(parent.begin(), parent.end(), 0);
864514f5e3Sopenharmony_ci        std::vector<size_t> minIdx(bbGatesList.size());
874514f5e3Sopenharmony_ci        auto merge = [&] (size_t fatherIdx, size_t sonIdx) -> void {
884514f5e3Sopenharmony_ci            size_t parentFatherIdx = UnionFind(semiDom, parent, minIdx, fatherIdx);
894514f5e3Sopenharmony_ci            size_t parentSonIdx = UnionFind(semiDom, parent, minIdx, sonIdx);
904514f5e3Sopenharmony_ci            parent[parentSonIdx] = parentFatherIdx;
914514f5e3Sopenharmony_ci        };
924514f5e3Sopenharmony_ci        std::iota(semiDom.begin(), semiDom.end(), 0);
934514f5e3Sopenharmony_ci        semiDom[0] = semiDom.size();
944514f5e3Sopenharmony_ci        ASSERT(bbGatesList.size() > 0);
954514f5e3Sopenharmony_ci        for (size_t idx = bbGatesList.size() - 1; idx >= 1; idx--) {
964514f5e3Sopenharmony_ci            std::vector<GateRef> preGates;
974514f5e3Sopenharmony_ci            acc.GetInStates(bbGatesList[idx], preGates);
984514f5e3Sopenharmony_ci            for (const auto &predGate : preGates) {
994514f5e3Sopenharmony_ci                if (bbGatesAddrToIdx.count(predGate) > 0) {
1004514f5e3Sopenharmony_ci                    size_t preGateIdx = bbGatesAddrToIdx[predGate];
1014514f5e3Sopenharmony_ci                    if (preGateIdx < idx) {
1024514f5e3Sopenharmony_ci                        semiDom[idx] = std::min(semiDom[idx], preGateIdx);
1034514f5e3Sopenharmony_ci                    } else {
1044514f5e3Sopenharmony_ci                        UnionFind(semiDom, parent, minIdx, preGateIdx);
1054514f5e3Sopenharmony_ci                        semiDom[idx] = std::min(semiDom[idx], semiDom[minIdx[preGateIdx]]);
1064514f5e3Sopenharmony_ci                    }
1074514f5e3Sopenharmony_ci                }
1084514f5e3Sopenharmony_ci            }
1094514f5e3Sopenharmony_ci            for (const auto &succDomIdx : semiDomTree[idx]) {
1104514f5e3Sopenharmony_ci                UnionFind(semiDom, parent, minIdx, succDomIdx);
1114514f5e3Sopenharmony_ci                if (idx == semiDom[minIdx[succDomIdx]]) {
1124514f5e3Sopenharmony_ci                    immDom[succDomIdx] = idx;
1134514f5e3Sopenharmony_ci                } else {
1144514f5e3Sopenharmony_ci                    immDom[succDomIdx] = minIdx[succDomIdx];
1154514f5e3Sopenharmony_ci                }
1164514f5e3Sopenharmony_ci            }
1174514f5e3Sopenharmony_ci            minIdx[idx] = idx;
1184514f5e3Sopenharmony_ci            merge(dfsFatherIdx[bbGatesList[idx]], idx);
1194514f5e3Sopenharmony_ci            semiDomTree[semiDom[idx]].push_back(idx);
1204514f5e3Sopenharmony_ci        }
1214514f5e3Sopenharmony_ci        for (size_t idx = 1; idx < bbGatesList.size(); idx++) {
1224514f5e3Sopenharmony_ci            if (immDom[idx] != semiDom[idx]) {
1234514f5e3Sopenharmony_ci                immDom[idx] = immDom[immDom[idx]];
1244514f5e3Sopenharmony_ci            }
1254514f5e3Sopenharmony_ci        }
1264514f5e3Sopenharmony_ci        semiDom[0] = 0;
1274514f5e3Sopenharmony_ci    }
1284514f5e3Sopenharmony_ci}
1294514f5e3Sopenharmony_ci
1304514f5e3Sopenharmony_civoid Scheduler::Run(const Circuit *circuit, ControlFlowGraph &result,
1314514f5e3Sopenharmony_ci                    [[maybe_unused]] const std::string& methodName, [[maybe_unused]] bool enableLog)
1324514f5e3Sopenharmony_ci{
1334514f5e3Sopenharmony_ci    GateAccessor acc(const_cast<Circuit*>(circuit));
1344514f5e3Sopenharmony_ci    std::vector<GateRef> bbGatesList;
1354514f5e3Sopenharmony_ci    std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
1364514f5e3Sopenharmony_ci    std::vector<size_t> immDom;
1374514f5e3Sopenharmony_ci    Scheduler::CalculateDominatorTree(circuit, bbGatesList, bbGatesAddrToIdx, immDom);
1384514f5e3Sopenharmony_ci    ASSERT(result.size() == 0);
1394514f5e3Sopenharmony_ci    result.resize(bbGatesList.size());
1404514f5e3Sopenharmony_ci    for (size_t idx = 0; idx < bbGatesList.size(); idx++) {
1414514f5e3Sopenharmony_ci        result[idx].push_back(bbGatesList[idx]);
1424514f5e3Sopenharmony_ci    }
1434514f5e3Sopenharmony_ci    // assuming CFG is always reducible
1444514f5e3Sopenharmony_ci    std::vector<std::vector<size_t>> sonList(result.size());
1454514f5e3Sopenharmony_ci    for (size_t idx = 1; idx < immDom.size(); idx++) {
1464514f5e3Sopenharmony_ci        sonList[immDom[idx]].push_back(idx);
1474514f5e3Sopenharmony_ci    }
1484514f5e3Sopenharmony_ci    const size_t sizeLog = std::ceil(std::log2(static_cast<double>(result.size())) + 1);
1494514f5e3Sopenharmony_ci    std::vector<size_t> timeIn(result.size());
1504514f5e3Sopenharmony_ci    std::vector<size_t> timeOut(result.size());
1514514f5e3Sopenharmony_ci    std::vector<std::vector<size_t>> jumpUp;
1524514f5e3Sopenharmony_ci    jumpUp.assign(result.size(), std::vector<size_t>(sizeLog + 1));
1534514f5e3Sopenharmony_ci    {
1544514f5e3Sopenharmony_ci        size_t timestamp = 0;
1554514f5e3Sopenharmony_ci        struct DFSState {
1564514f5e3Sopenharmony_ci            size_t cur;
1574514f5e3Sopenharmony_ci            std::vector<size_t> &succList;
1584514f5e3Sopenharmony_ci            size_t idx;
1594514f5e3Sopenharmony_ci        };
1604514f5e3Sopenharmony_ci        std::stack<DFSState> dfsStack;
1614514f5e3Sopenharmony_ci        size_t root = 0;
1624514f5e3Sopenharmony_ci        dfsStack.push({root, sonList[root], 0});
1634514f5e3Sopenharmony_ci        timeIn[root] = timestamp++;
1644514f5e3Sopenharmony_ci        jumpUp[root][0] = root;
1654514f5e3Sopenharmony_ci        for (size_t stepSize = 1; stepSize <= sizeLog; stepSize++) {
1664514f5e3Sopenharmony_ci            auto jumpUpHalf = jumpUp[root][stepSize - 1];
1674514f5e3Sopenharmony_ci            jumpUp[root][stepSize] = jumpUp[jumpUpHalf][stepSize - 1];
1684514f5e3Sopenharmony_ci        }
1694514f5e3Sopenharmony_ci        while (!dfsStack.empty()) {
1704514f5e3Sopenharmony_ci            auto &curState = dfsStack.top();
1714514f5e3Sopenharmony_ci            auto &cur = curState.cur;
1724514f5e3Sopenharmony_ci            auto &succList = curState.succList;
1734514f5e3Sopenharmony_ci            auto &idx = curState.idx;
1744514f5e3Sopenharmony_ci            if (idx == succList.size()) {
1754514f5e3Sopenharmony_ci                timeOut[cur] = timestamp++;
1764514f5e3Sopenharmony_ci                dfsStack.pop();
1774514f5e3Sopenharmony_ci                continue;
1784514f5e3Sopenharmony_ci            }
1794514f5e3Sopenharmony_ci            const auto &succ = succList[idx];
1804514f5e3Sopenharmony_ci            dfsStack.push({succ, sonList[succ], 0});
1814514f5e3Sopenharmony_ci            timeIn[succ] = timestamp++;
1824514f5e3Sopenharmony_ci            jumpUp[succ][0] = cur;
1834514f5e3Sopenharmony_ci            for (size_t stepSize = 1; stepSize <= sizeLog; stepSize++) {
1844514f5e3Sopenharmony_ci                auto jumpUpHalf = jumpUp[succ][stepSize - 1];
1854514f5e3Sopenharmony_ci                jumpUp[succ][stepSize] = jumpUp[jumpUpHalf][stepSize - 1];
1864514f5e3Sopenharmony_ci            }
1874514f5e3Sopenharmony_ci            idx++;
1884514f5e3Sopenharmony_ci        }
1894514f5e3Sopenharmony_ci    }
1904514f5e3Sopenharmony_ci    auto isAncestor = [&](size_t nodeA, size_t nodeB) -> bool {
1914514f5e3Sopenharmony_ci        return (timeIn[nodeA] <= timeIn[nodeB]) && (timeOut[nodeA] >= timeOut[nodeB]);
1924514f5e3Sopenharmony_ci    };
1934514f5e3Sopenharmony_ci    auto lowestCommonAncestor = [&](size_t nodeA, size_t nodeB) -> size_t {
1944514f5e3Sopenharmony_ci        if (isAncestor(nodeA, nodeB)) {
1954514f5e3Sopenharmony_ci            return nodeA;
1964514f5e3Sopenharmony_ci        }
1974514f5e3Sopenharmony_ci        if (isAncestor(nodeB, nodeA)) {
1984514f5e3Sopenharmony_ci            return nodeB;
1994514f5e3Sopenharmony_ci        }
2004514f5e3Sopenharmony_ci        for (size_t stepSize = sizeLog + 1; stepSize > 0; stepSize--) {
2014514f5e3Sopenharmony_ci            if (!isAncestor(jumpUp[nodeA][stepSize - 1], nodeB)) {
2024514f5e3Sopenharmony_ci                nodeA = jumpUp[nodeA][stepSize - 1];
2034514f5e3Sopenharmony_ci            }
2044514f5e3Sopenharmony_ci        }
2054514f5e3Sopenharmony_ci        return jumpUp[nodeA][0];
2064514f5e3Sopenharmony_ci    };
2074514f5e3Sopenharmony_ci    {
2084514f5e3Sopenharmony_ci        std::vector<GateRef> order;
2094514f5e3Sopenharmony_ci        std::unordered_map<GateRef, size_t> lowerBound;
2104514f5e3Sopenharmony_ci        Scheduler::CalculateSchedulingLowerBound(circuit, bbGatesAddrToIdx, lowestCommonAncestor, lowerBound, &order);
2114514f5e3Sopenharmony_ci        for (const auto &schedulableGate : order) {
2124514f5e3Sopenharmony_ci            result[lowerBound.at(schedulableGate)].push_back(schedulableGate);
2134514f5e3Sopenharmony_ci        }
2144514f5e3Sopenharmony_ci        std::vector<GateRef> argList;
2154514f5e3Sopenharmony_ci        acc.GetOuts(acc.GetArgRoot(), argList);
2164514f5e3Sopenharmony_ci        std::sort(argList.begin(), argList.end(), [&](const GateRef &lhs, const GateRef &rhs) -> bool {
2174514f5e3Sopenharmony_ci            return acc.TryGetValue(lhs) > acc.TryGetValue(rhs);
2184514f5e3Sopenharmony_ci        });
2194514f5e3Sopenharmony_ci        for (const auto &arg : argList) {
2204514f5e3Sopenharmony_ci            result.front().push_back(arg);
2214514f5e3Sopenharmony_ci        }
2224514f5e3Sopenharmony_ci        for (const auto &bbGate : bbGatesList) {
2234514f5e3Sopenharmony_ci            auto uses = acc.Uses(bbGate);
2244514f5e3Sopenharmony_ci            for (auto i = uses.begin(); i != uses.end(); i++) {
2254514f5e3Sopenharmony_ci                GateRef succGate = *i;
2264514f5e3Sopenharmony_ci                if (acc.IsFixed(succGate)) {
2274514f5e3Sopenharmony_ci                    result[bbGatesAddrToIdx.at(acc.GetIn(succGate, 0))].push_back(succGate);
2284514f5e3Sopenharmony_ci                }
2294514f5e3Sopenharmony_ci            }
2304514f5e3Sopenharmony_ci        }
2314514f5e3Sopenharmony_ci    }
2324514f5e3Sopenharmony_ci    if (enableLog) {
2334514f5e3Sopenharmony_ci        Print(&result, circuit);
2344514f5e3Sopenharmony_ci    }
2354514f5e3Sopenharmony_ci}
2364514f5e3Sopenharmony_ci
2374514f5e3Sopenharmony_cibool Scheduler::CalculateSchedulingUpperBound(const Circuit *circuit,
2384514f5e3Sopenharmony_ci                                              const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
2394514f5e3Sopenharmony_ci                                              const std::function<bool(size_t, size_t)> &isAncestor,
2404514f5e3Sopenharmony_ci                                              const std::vector<GateRef> &schedulableGatesList,
2414514f5e3Sopenharmony_ci                                              std::unordered_map<GateRef, size_t> &upperBound)
2424514f5e3Sopenharmony_ci{
2434514f5e3Sopenharmony_ci    GateAccessor acc(const_cast<Circuit*>(circuit));
2444514f5e3Sopenharmony_ci    struct DFSState {
2454514f5e3Sopenharmony_ci        GateRef curGate = Circuit::NullGate();
2464514f5e3Sopenharmony_ci        std::vector<GateRef> predGates;
2474514f5e3Sopenharmony_ci        size_t idx = 0;
2484514f5e3Sopenharmony_ci        size_t curUpperBound = 0;
2494514f5e3Sopenharmony_ci    };
2504514f5e3Sopenharmony_ci    DFSState emptyState = {Circuit::NullGate(), std::vector<GateRef>(0), 0, 0};
2514514f5e3Sopenharmony_ci    bool getReturn = false;
2524514f5e3Sopenharmony_ci    std::optional<size_t> returnValue = 0;
2534514f5e3Sopenharmony_ci    std::stack<DFSState> dfsStack;
2544514f5e3Sopenharmony_ci    auto CheckUnschedulable = [&](GateRef gate) -> void {
2554514f5e3Sopenharmony_ci        if (upperBound.count(gate) > 0) {
2564514f5e3Sopenharmony_ci            returnValue = upperBound[gate];
2574514f5e3Sopenharmony_ci            getReturn = true;
2584514f5e3Sopenharmony_ci        } else if (acc.IsProlog(gate) || acc.IsRoot(gate) || acc.IsVirtualState(gate)) {
2594514f5e3Sopenharmony_ci            returnValue = 0;
2604514f5e3Sopenharmony_ci            getReturn = true;
2614514f5e3Sopenharmony_ci        } else if (acc.IsFixed(gate)) {
2624514f5e3Sopenharmony_ci            returnValue = bbGatesAddrToIdx.at(acc.GetIn(gate, 0));
2634514f5e3Sopenharmony_ci            getReturn = true;
2644514f5e3Sopenharmony_ci        } else if (acc.IsState(gate)) {
2654514f5e3Sopenharmony_ci            returnValue = bbGatesAddrToIdx.at(gate);
2664514f5e3Sopenharmony_ci            getReturn = true;
2674514f5e3Sopenharmony_ci        }
2684514f5e3Sopenharmony_ci        // then gate is schedulable
2694514f5e3Sopenharmony_ci    };
2704514f5e3Sopenharmony_ci    for (const auto &schedulableGate : schedulableGatesList) {
2714514f5e3Sopenharmony_ci        if (upperBound.count(schedulableGate) != 0) {
2724514f5e3Sopenharmony_ci            continue;
2734514f5e3Sopenharmony_ci        }
2744514f5e3Sopenharmony_ci        getReturn = false;
2754514f5e3Sopenharmony_ci        CheckUnschedulable(schedulableGate);
2764514f5e3Sopenharmony_ci        if (getReturn) {
2774514f5e3Sopenharmony_ci            continue;
2784514f5e3Sopenharmony_ci        }
2794514f5e3Sopenharmony_ci        dfsStack.push(emptyState);
2804514f5e3Sopenharmony_ci        auto &rootState = dfsStack.top();
2814514f5e3Sopenharmony_ci        auto &rootPredGates = rootState.predGates;
2824514f5e3Sopenharmony_ci        rootState.curGate = schedulableGate;
2834514f5e3Sopenharmony_ci        acc.GetIns(schedulableGate, rootPredGates);
2844514f5e3Sopenharmony_ci        while (!dfsStack.empty()) {
2854514f5e3Sopenharmony_ci            auto &curState = dfsStack.top();
2864514f5e3Sopenharmony_ci            auto &curGate = curState.curGate;
2874514f5e3Sopenharmony_ci            const auto &predGates = curState.predGates;
2884514f5e3Sopenharmony_ci            auto &idx = curState.idx;
2894514f5e3Sopenharmony_ci            auto &curUpperBound = curState.curUpperBound;
2904514f5e3Sopenharmony_ci            if (idx == predGates.size()) {
2914514f5e3Sopenharmony_ci                upperBound[curGate] = curUpperBound;
2924514f5e3Sopenharmony_ci                returnValue = curUpperBound;
2934514f5e3Sopenharmony_ci                dfsStack.pop();
2944514f5e3Sopenharmony_ci                getReturn = true;
2954514f5e3Sopenharmony_ci                continue;
2964514f5e3Sopenharmony_ci            }
2974514f5e3Sopenharmony_ci            if (getReturn) {
2984514f5e3Sopenharmony_ci                if (!returnValue.has_value()) {
2994514f5e3Sopenharmony_ci                    break;
3004514f5e3Sopenharmony_ci                }
3014514f5e3Sopenharmony_ci                auto predUpperBound = returnValue.value();
3024514f5e3Sopenharmony_ci                if (!isAncestor(curUpperBound, predUpperBound) && !isAncestor(predUpperBound, curUpperBound)) {
3034514f5e3Sopenharmony_ci                    PrintUpperBoundError(circuit, curGate, predUpperBound, curUpperBound);
3044514f5e3Sopenharmony_ci                    returnValue = std::nullopt;
3054514f5e3Sopenharmony_ci                    break;
3064514f5e3Sopenharmony_ci                }
3074514f5e3Sopenharmony_ci                if (isAncestor(curUpperBound, predUpperBound)) {
3084514f5e3Sopenharmony_ci                    curUpperBound = predUpperBound;
3094514f5e3Sopenharmony_ci                }
3104514f5e3Sopenharmony_ci                getReturn = false;
3114514f5e3Sopenharmony_ci                idx++;
3124514f5e3Sopenharmony_ci            } else {
3134514f5e3Sopenharmony_ci                const auto &predGate = predGates[idx];
3144514f5e3Sopenharmony_ci                CheckUnschedulable(predGate);
3154514f5e3Sopenharmony_ci                if (getReturn) {
3164514f5e3Sopenharmony_ci                    continue;
3174514f5e3Sopenharmony_ci                }
3184514f5e3Sopenharmony_ci                dfsStack.push(emptyState);
3194514f5e3Sopenharmony_ci                auto &newState = dfsStack.top();
3204514f5e3Sopenharmony_ci                auto &newPredGates = newState.predGates;
3214514f5e3Sopenharmony_ci                newState.curGate = predGate;
3224514f5e3Sopenharmony_ci                acc.GetIns(predGate, newPredGates);
3234514f5e3Sopenharmony_ci            }
3244514f5e3Sopenharmony_ci        }
3254514f5e3Sopenharmony_ci        if (!returnValue.has_value()) {
3264514f5e3Sopenharmony_ci            return false;
3274514f5e3Sopenharmony_ci        }
3284514f5e3Sopenharmony_ci    }
3294514f5e3Sopenharmony_ci    return true;
3304514f5e3Sopenharmony_ci}
3314514f5e3Sopenharmony_ci
3324514f5e3Sopenharmony_civoid Scheduler::PrintUpperBoundError(const Circuit *circuit, GateRef curGate,
3334514f5e3Sopenharmony_ci                                     GateRef predUpperBound, GateRef curUpperBound)
3344514f5e3Sopenharmony_ci{
3354514f5e3Sopenharmony_ci    GateAccessor ac(const_cast<Circuit*>(circuit));
3364514f5e3Sopenharmony_ci    LOG_COMPILER(ERROR) << "[Verifier][Error] Scheduling upper bound of gate (id="
3374514f5e3Sopenharmony_ci                        << ac.GetId(curGate)
3384514f5e3Sopenharmony_ci                        << ") does not exist, current-upper-bound = "
3394514f5e3Sopenharmony_ci                        << curUpperBound << ", pred-upper-bound = "
3404514f5e3Sopenharmony_ci                        << predUpperBound << ", there is no dominator relationship between them.";
3414514f5e3Sopenharmony_ci}
3424514f5e3Sopenharmony_ci
3434514f5e3Sopenharmony_civoid Scheduler::CalculateFixedGatesList(const Circuit *circuit,
3444514f5e3Sopenharmony_ci                                        const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
3454514f5e3Sopenharmony_ci                                        std::vector<GateRef> &bbAndFixedGatesList)
3464514f5e3Sopenharmony_ci{
3474514f5e3Sopenharmony_ci    GateAccessor acc(const_cast<Circuit*>(circuit));
3484514f5e3Sopenharmony_ci    for (const auto &item : bbGatesAddrToIdx) {
3494514f5e3Sopenharmony_ci        bbAndFixedGatesList.push_back(item.first);
3504514f5e3Sopenharmony_ci        auto uses = acc.Uses(item.first);
3514514f5e3Sopenharmony_ci        for (auto i = uses.begin(); i != uses.end(); i++) {
3524514f5e3Sopenharmony_ci            GateRef succGate = *i;
3534514f5e3Sopenharmony_ci            if (acc.IsFixed(succGate)) {
3544514f5e3Sopenharmony_ci                bbAndFixedGatesList.push_back(succGate);
3554514f5e3Sopenharmony_ci            }
3564514f5e3Sopenharmony_ci        }
3574514f5e3Sopenharmony_ci    }
3584514f5e3Sopenharmony_ci}
3594514f5e3Sopenharmony_ci
3604514f5e3Sopenharmony_civoid Scheduler::CalculateSchedulingLowerBound(const Circuit *circuit,
3614514f5e3Sopenharmony_ci                                              const std::unordered_map<GateRef, size_t> &bbGatesAddrToIdx,
3624514f5e3Sopenharmony_ci                                              const std::function<size_t(size_t, size_t)> &lowestCommonAncestor,
3634514f5e3Sopenharmony_ci                                              std::unordered_map<GateRef, size_t> &lowerBound,
3644514f5e3Sopenharmony_ci                                              std::vector<GateRef> *order)
3654514f5e3Sopenharmony_ci{
3664514f5e3Sopenharmony_ci    GateAccessor acc(const_cast<Circuit*>(circuit));
3674514f5e3Sopenharmony_ci    std::vector<GateRef> bbAndFixedGatesList;
3684514f5e3Sopenharmony_ci    CalculateFixedGatesList(circuit, bbGatesAddrToIdx, bbAndFixedGatesList);
3694514f5e3Sopenharmony_ci    std::unordered_map<GateRef, size_t> useCount;
3704514f5e3Sopenharmony_ci    struct DFSVisitState {
3714514f5e3Sopenharmony_ci        std::vector<GateRef> prevGates;
3724514f5e3Sopenharmony_ci        size_t idx = 0;
3734514f5e3Sopenharmony_ci    };
3744514f5e3Sopenharmony_ci    DFSVisitState emptyVisitState = {std::vector<GateRef>(0), 0};
3754514f5e3Sopenharmony_ci    std::stack<DFSVisitState> dfsVisitStack;
3764514f5e3Sopenharmony_ci    for (const auto &gate : bbAndFixedGatesList) {
3774514f5e3Sopenharmony_ci        dfsVisitStack.push(emptyVisitState);
3784514f5e3Sopenharmony_ci        auto &rootState = dfsVisitStack.top();
3794514f5e3Sopenharmony_ci        auto &rootPrevGates = rootState.prevGates;
3804514f5e3Sopenharmony_ci        acc.GetIns(gate, rootPrevGates);
3814514f5e3Sopenharmony_ci        while (!dfsVisitStack.empty()) {
3824514f5e3Sopenharmony_ci            auto &curState = dfsVisitStack.top();
3834514f5e3Sopenharmony_ci            auto &prevGates = curState.prevGates;
3844514f5e3Sopenharmony_ci            auto &idx = curState.idx;
3854514f5e3Sopenharmony_ci            if (idx == prevGates.size()) {
3864514f5e3Sopenharmony_ci                dfsVisitStack.pop();
3874514f5e3Sopenharmony_ci                continue;
3884514f5e3Sopenharmony_ci            }
3894514f5e3Sopenharmony_ci            const auto &prevGate = prevGates[idx];
3904514f5e3Sopenharmony_ci            if (!acc.IsSchedulable(prevGate)) {
3914514f5e3Sopenharmony_ci                ++idx;
3924514f5e3Sopenharmony_ci                continue;
3934514f5e3Sopenharmony_ci            }
3944514f5e3Sopenharmony_ci            useCount[prevGate]++;
3954514f5e3Sopenharmony_ci            if (useCount[prevGate] == 1) {
3964514f5e3Sopenharmony_ci                dfsVisitStack.push(emptyVisitState);
3974514f5e3Sopenharmony_ci                auto &newState = dfsVisitStack.top();
3984514f5e3Sopenharmony_ci                auto &newPrevGates = newState.prevGates;
3994514f5e3Sopenharmony_ci                acc.GetIns(prevGate, newPrevGates);
4004514f5e3Sopenharmony_ci            }
4014514f5e3Sopenharmony_ci            ++idx;
4024514f5e3Sopenharmony_ci        }
4034514f5e3Sopenharmony_ci    }
4044514f5e3Sopenharmony_ci    struct DFSFinishState {
4054514f5e3Sopenharmony_ci        GateRef curGate = Circuit::NullGate();
4064514f5e3Sopenharmony_ci        std::vector<GateRef> prevGates;
4074514f5e3Sopenharmony_ci        size_t idx = 0;
4084514f5e3Sopenharmony_ci    };
4094514f5e3Sopenharmony_ci    DFSFinishState emptyFinishState = {Circuit::NullGate(), std::vector<GateRef>(0), 0};
4104514f5e3Sopenharmony_ci    std::stack<DFSFinishState> dfsFinishStack;
4114514f5e3Sopenharmony_ci    for (const auto &gate : bbAndFixedGatesList) {
4124514f5e3Sopenharmony_ci        dfsFinishStack.push(emptyFinishState);
4134514f5e3Sopenharmony_ci        auto &rootState = dfsFinishStack.top();
4144514f5e3Sopenharmony_ci        auto &rootPrevGates = rootState.prevGates;
4154514f5e3Sopenharmony_ci        rootState.curGate = gate;
4164514f5e3Sopenharmony_ci        acc.GetIns(gate, rootPrevGates);
4174514f5e3Sopenharmony_ci        while (!dfsFinishStack.empty()) {
4184514f5e3Sopenharmony_ci            auto &curState = dfsFinishStack.top();
4194514f5e3Sopenharmony_ci            auto &curGate = curState.curGate;
4204514f5e3Sopenharmony_ci            auto &prevGates = curState.prevGates;
4214514f5e3Sopenharmony_ci            auto &idx = curState.idx;
4224514f5e3Sopenharmony_ci            if (idx == prevGates.size()) {
4234514f5e3Sopenharmony_ci                dfsFinishStack.pop();
4244514f5e3Sopenharmony_ci                continue;
4254514f5e3Sopenharmony_ci            }
4264514f5e3Sopenharmony_ci            const auto &prevGate = prevGates[idx];
4274514f5e3Sopenharmony_ci            if (!acc.IsSchedulable(prevGate)) {
4284514f5e3Sopenharmony_ci                ++idx;
4294514f5e3Sopenharmony_ci                continue;
4304514f5e3Sopenharmony_ci            }
4314514f5e3Sopenharmony_ci            useCount[prevGate]--;
4324514f5e3Sopenharmony_ci            size_t curLowerBound;
4334514f5e3Sopenharmony_ci            if (acc.IsState(curGate)) {  // cur_opcode would not be STATE_ENTRY
4344514f5e3Sopenharmony_ci                curLowerBound = bbGatesAddrToIdx.at(curGate);
4354514f5e3Sopenharmony_ci            } else if (acc.IsSelector(curGate)) {
4364514f5e3Sopenharmony_ci                ASSERT(idx > 0);
4374514f5e3Sopenharmony_ci                curLowerBound = bbGatesAddrToIdx.at(acc.GetIn(acc.GetIn(curGate, 0), idx - 1));
4384514f5e3Sopenharmony_ci            } else if (acc.IsFixed(curGate)) {
4394514f5e3Sopenharmony_ci                ASSERT(idx > 0);
4404514f5e3Sopenharmony_ci                curLowerBound = bbGatesAddrToIdx.at(acc.GetIn(curGate, 0));
4414514f5e3Sopenharmony_ci            } else {
4424514f5e3Sopenharmony_ci                curLowerBound = lowerBound.at(curGate);
4434514f5e3Sopenharmony_ci            }
4444514f5e3Sopenharmony_ci            if (lowerBound.count(prevGate) == 0) {
4454514f5e3Sopenharmony_ci                lowerBound[prevGate] = curLowerBound;
4464514f5e3Sopenharmony_ci            } else {
4474514f5e3Sopenharmony_ci                lowerBound[prevGate] = lowestCommonAncestor(lowerBound[prevGate], curLowerBound);
4484514f5e3Sopenharmony_ci            }
4494514f5e3Sopenharmony_ci            if (useCount[prevGate] == 0) {
4504514f5e3Sopenharmony_ci                if (order != nullptr) {
4514514f5e3Sopenharmony_ci                    order->push_back(prevGate);
4524514f5e3Sopenharmony_ci                }
4534514f5e3Sopenharmony_ci                dfsFinishStack.push(emptyFinishState);
4544514f5e3Sopenharmony_ci                auto &newState = dfsFinishStack.top();
4554514f5e3Sopenharmony_ci                auto &newPrevGates = newState.prevGates;
4564514f5e3Sopenharmony_ci                newState.curGate = prevGate;
4574514f5e3Sopenharmony_ci                acc.GetIns(prevGate, newPrevGates);
4584514f5e3Sopenharmony_ci            }
4594514f5e3Sopenharmony_ci            ++idx;
4604514f5e3Sopenharmony_ci        }
4614514f5e3Sopenharmony_ci    }
4624514f5e3Sopenharmony_ci}
4634514f5e3Sopenharmony_ci
4644514f5e3Sopenharmony_civoid Scheduler::Print(const std::vector<std::vector<GateRef>> *cfg, const Circuit *circuit)
4654514f5e3Sopenharmony_ci{
4664514f5e3Sopenharmony_ci    GateAccessor acc(const_cast<Circuit*>(circuit));
4674514f5e3Sopenharmony_ci    std::vector<GateRef> bbGatesList;
4684514f5e3Sopenharmony_ci    std::unordered_map<GateRef, size_t> bbGatesAddrToIdx;
4694514f5e3Sopenharmony_ci    std::vector<size_t> immDom;
4704514f5e3Sopenharmony_ci    Scheduler::CalculateDominatorTree(circuit, bbGatesList, bbGatesAddrToIdx, immDom);
4714514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "==================================== Scheduling ==================================";
4724514f5e3Sopenharmony_ci    for (size_t bbIdx = 0; bbIdx < cfg->size(); bbIdx++) {
4734514f5e3Sopenharmony_ci        auto opcode = acc.GetOpCode((*cfg)[bbIdx].front());
4744514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "B" << bbIdx << "_" << opcode << ":"
4754514f5e3Sopenharmony_ci                           << "  immDom=" << immDom[bbIdx];
4764514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "  pred=[";
4774514f5e3Sopenharmony_ci        bool isFirst = true;
4784514f5e3Sopenharmony_ci        GateRef head = cfg->at(bbIdx).front();
4794514f5e3Sopenharmony_ci        auto ins = acc.Ins(head);
4804514f5e3Sopenharmony_ci        for (auto i = ins.begin(); i != ins.end(); i++) {
4814514f5e3Sopenharmony_ci            GateRef predState = *i;
4824514f5e3Sopenharmony_ci            if (acc.IsState(predState) ||
4834514f5e3Sopenharmony_ci                acc.GetOpCode(predState) == OpCode::STATE_ENTRY) {
4844514f5e3Sopenharmony_ci                LOG_COMPILER(INFO) << (isFirst ? "" : " ") << bbGatesAddrToIdx.at(predState);
4854514f5e3Sopenharmony_ci                isFirst = false;
4864514f5e3Sopenharmony_ci            }
4874514f5e3Sopenharmony_ci        }
4884514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "]  succ=[";
4894514f5e3Sopenharmony_ci        isFirst = true;
4904514f5e3Sopenharmony_ci        GateRef h = cfg->at(bbIdx).front();
4914514f5e3Sopenharmony_ci        auto uses = acc.Uses(h);
4924514f5e3Sopenharmony_ci        for (auto i = uses.begin(); i != uses.end(); i++) {
4934514f5e3Sopenharmony_ci            GateRef succState = *i;
4944514f5e3Sopenharmony_ci            if (acc.IsState(succState) ||
4954514f5e3Sopenharmony_ci                acc.GetOpCode(succState) == OpCode::STATE_ENTRY) {
4964514f5e3Sopenharmony_ci                LOG_COMPILER(INFO) << (isFirst ? "" : " ") << bbGatesAddrToIdx.at(succState);
4974514f5e3Sopenharmony_ci                isFirst = false;
4984514f5e3Sopenharmony_ci            }
4994514f5e3Sopenharmony_ci        }
5004514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "]";
5014514f5e3Sopenharmony_ci        for (size_t instIdx = (*cfg)[bbIdx].size(); instIdx > 0; instIdx--) {
5024514f5e3Sopenharmony_ci            acc.Print((*cfg)[bbIdx][instIdx - 1]);
5034514f5e3Sopenharmony_ci        }
5044514f5e3Sopenharmony_ci    }
5054514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "==================================== Scheduling ==================================";
5064514f5e3Sopenharmony_ci}
5074514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::kungfu
508