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#include "ecmascript/compiler/loop_analysis.h"
174514f5e3Sopenharmony_ci#include "ecmascript/compiler/loop_peeling.h"
184514f5e3Sopenharmony_ci#include "ecmascript/compiler/bytecodes.h"
194514f5e3Sopenharmony_ci#include "ecmascript/compiler/share_gate_meta_data.h"
204514f5e3Sopenharmony_ci#include "ecmascript/log_wrapper.h"
214514f5e3Sopenharmony_ci
224514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
234514f5e3Sopenharmony_civoid LoopAnalysis::PrintLoop(LoopInfo* loopInfo)
244514f5e3Sopenharmony_ci{
254514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "--------------------------------- LoopInfo Start ---------------------------------";
264514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "Head: " << acc_.GetId(loopInfo->loopHead);
274514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "Size: " << loopInfo->size;
284514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "MaxDepth: " << loopInfo->maxDepth;
294514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "Body: [";
304514f5e3Sopenharmony_ci    for (auto gate : loopInfo->loopBodys) {
314514f5e3Sopenharmony_ci        acc_.ShortPrint(gate);
324514f5e3Sopenharmony_ci    }
334514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "]";
344514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "Exit: [";
354514f5e3Sopenharmony_ci    for (auto gate : loopInfo->loopExits) {
364514f5e3Sopenharmony_ci        acc_.ShortPrint(gate);
374514f5e3Sopenharmony_ci    }
384514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "]";
394514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "--------------------------------- LoopInfo End ---------------------------------";
404514f5e3Sopenharmony_ci}
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_civoid LoopAnalysis::Run()
434514f5e3Sopenharmony_ci{
444514f5e3Sopenharmony_ci    ChunkVector<GateRef>& headerGates = bcBuilder_->GetLoopHeaderGates();
454514f5e3Sopenharmony_ci    for (auto it = headerGates.rbegin(); it != headerGates.rend(); ++it) {
464514f5e3Sopenharmony_ci        auto gate = *it;
474514f5e3Sopenharmony_ci        if (gate == Circuit::NullGate()) {
484514f5e3Sopenharmony_ci            continue;
494514f5e3Sopenharmony_ci        }
504514f5e3Sopenharmony_ci        auto loopInfo = chunk_->New<LoopInfo>(chunk_, gate);
514514f5e3Sopenharmony_ci        loopInfos_.emplace_back(loopInfo);
524514f5e3Sopenharmony_ci    }
534514f5e3Sopenharmony_ci}
544514f5e3Sopenharmony_ci
554514f5e3Sopenharmony_civoid LoopAnalysis::CollectUseGate(ChunkUnorderedMap<GateRef, size_t>& gateToDepth,
564514f5e3Sopenharmony_ci    ChunkQueue<GateRef>& firstList, ChunkQueue<GateRef>& secondList,
574514f5e3Sopenharmony_ci    LoopInfo* loopInfo, GateRef cur)
584514f5e3Sopenharmony_ci{
594514f5e3Sopenharmony_ci    auto use = acc_.Uses(cur);
604514f5e3Sopenharmony_ci    ASSERT(use.begin() != use.end());
614514f5e3Sopenharmony_ci    bool isCurLoop = gateToDepth[cur] == 1; // 1: loopDepth
624514f5e3Sopenharmony_ci    for (auto it = use.begin(); it != use.end(); ++it) {
634514f5e3Sopenharmony_ci        auto nex = *it;
644514f5e3Sopenharmony_ci        if (isCurLoop && acc_.IsLoopExit(cur) && (!acc_.IsFixed(*it))) {
654514f5e3Sopenharmony_ci            continue;
664514f5e3Sopenharmony_ci        } else if (isCurLoop && acc_.IsLoopExitRelated(cur) && acc_.IsFixed(cur)) {
674514f5e3Sopenharmony_ci            continue;
684514f5e3Sopenharmony_ci        } else if (acc_.GetDependCount(nex) == 0 && acc_.GetStateCount(nex) == 0) {
694514f5e3Sopenharmony_ci            continue;
704514f5e3Sopenharmony_ci        }
714514f5e3Sopenharmony_ci        if (gateToDepth.count(nex)) {
724514f5e3Sopenharmony_ci            // loop back
734514f5e3Sopenharmony_ci            if (acc_.IsStateIn(it) || acc_.IsDependIn(it)) {
744514f5e3Sopenharmony_ci                ASSERT(gateToDepth[nex] == ComputeLoopDepth(cur, nex, gateToDepth[cur]));
754514f5e3Sopenharmony_ci            }
764514f5e3Sopenharmony_ci            continue;
774514f5e3Sopenharmony_ci        }
784514f5e3Sopenharmony_ci        if (acc_.IsStateIn(it) || acc_.IsDependIn(it)) {
794514f5e3Sopenharmony_ci            // only calculate loop depth for state & depend edges,
804514f5e3Sopenharmony_ci            // since there is no phi of each value and each loop head.
814514f5e3Sopenharmony_ci            gateToDepth[nex] = ComputeLoopDepth(cur, nex, gateToDepth[cur]);
824514f5e3Sopenharmony_ci            if (acc_.HasFrameState(nex)) {
834514f5e3Sopenharmony_ci                auto frameState = acc_.GetFrameState(nex);
844514f5e3Sopenharmony_ci                if (acc_.GetOpCode(frameState) == OpCode::FRAME_STATE) {
854514f5e3Sopenharmony_ci                    gateToDepth[frameState] = gateToDepth[nex];
864514f5e3Sopenharmony_ci                    gateToDepth[acc_.GetValueIn(frameState, 1)] = gateToDepth[nex];
874514f5e3Sopenharmony_ci                }
884514f5e3Sopenharmony_ci            }
894514f5e3Sopenharmony_ci            // state and depend edge should be visited first.
904514f5e3Sopenharmony_ci            firstList.push(nex);
914514f5e3Sopenharmony_ci            UpdateLoopInfo(loopInfo, nex, gateToDepth.at(nex));
924514f5e3Sopenharmony_ci        } else {
934514f5e3Sopenharmony_ci            secondList.push(nex);
944514f5e3Sopenharmony_ci        }
954514f5e3Sopenharmony_ci    }
964514f5e3Sopenharmony_ci}
974514f5e3Sopenharmony_ci
984514f5e3Sopenharmony_civoid LoopAnalysis::CollectLoopBody(LoopInfo* loopInfo)
994514f5e3Sopenharmony_ci{
1004514f5e3Sopenharmony_ci    ASSERT(acc_.IsLoopHead(loopInfo->loopHead));
1014514f5e3Sopenharmony_ci    ChunkUnorderedMap<GateRef, size_t> gateToDepth(chunk_);
1024514f5e3Sopenharmony_ci    ChunkQueue<GateRef> firstList(chunk_);  // for state and depend edges
1034514f5e3Sopenharmony_ci    ChunkQueue<GateRef> secondList(chunk_); // for other edges
1044514f5e3Sopenharmony_ci    gateToDepth[loopInfo->loopHead] = 1;
1054514f5e3Sopenharmony_ci    firstList.push(loopInfo->loopHead);
1064514f5e3Sopenharmony_ci    while ((!firstList.empty()) || (!secondList.empty())) {
1074514f5e3Sopenharmony_ci        GateRef cur = Circuit::NullGate();
1084514f5e3Sopenharmony_ci        if (!firstList.empty()) {
1094514f5e3Sopenharmony_ci            cur = firstList.front();
1104514f5e3Sopenharmony_ci            firstList.pop();
1114514f5e3Sopenharmony_ci        } else {
1124514f5e3Sopenharmony_ci            cur = secondList.front();
1134514f5e3Sopenharmony_ci            secondList.pop();
1144514f5e3Sopenharmony_ci        }
1154514f5e3Sopenharmony_ci        ASSERT(gateToDepth.count(cur) > 0);
1164514f5e3Sopenharmony_ci        CollectUseGate(gateToDepth, firstList, secondList, loopInfo, cur);
1174514f5e3Sopenharmony_ci    }
1184514f5e3Sopenharmony_ci}
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_civoid LoopAnalysis::UpdateLoopInfo(LoopInfo* loopInfo, GateRef gate, size_t dep)
1214514f5e3Sopenharmony_ci{
1224514f5e3Sopenharmony_ci    auto op = acc_.GetOpCode(gate);
1234514f5e3Sopenharmony_ci    loopInfo->maxDepth = std::max(loopInfo->maxDepth, dep);
1244514f5e3Sopenharmony_ci    loopInfo->size++;
1254514f5e3Sopenharmony_ci    switch (op) {
1264514f5e3Sopenharmony_ci        case OpCode::LOOP_BACK: {
1274514f5e3Sopenharmony_ci            if (dep == 1) { // 1: depth of loop head
1284514f5e3Sopenharmony_ci                loopInfo->loopBacks.emplace_back(gate);
1294514f5e3Sopenharmony_ci                return;
1304514f5e3Sopenharmony_ci            }
1314514f5e3Sopenharmony_ci            break;
1324514f5e3Sopenharmony_ci        }
1334514f5e3Sopenharmony_ci        case OpCode::LOOP_EXIT: {
1344514f5e3Sopenharmony_ci            if (dep == 1) { // 1: depth of loop head
1354514f5e3Sopenharmony_ci                loopInfo->loopExits.emplace_back(gate);
1364514f5e3Sopenharmony_ci                return;
1374514f5e3Sopenharmony_ci            }
1384514f5e3Sopenharmony_ci            break;
1394514f5e3Sopenharmony_ci        }
1404514f5e3Sopenharmony_ci        case OpCode::LOOP_EXIT_DEPEND:
1414514f5e3Sopenharmony_ci        case OpCode::LOOP_EXIT_VALUE: {
1424514f5e3Sopenharmony_ci            if (dep == 1) {
1434514f5e3Sopenharmony_ci                return;
1444514f5e3Sopenharmony_ci            }
1454514f5e3Sopenharmony_ci            break;
1464514f5e3Sopenharmony_ci        }
1474514f5e3Sopenharmony_ci        default:
1484514f5e3Sopenharmony_ci            break;
1494514f5e3Sopenharmony_ci    }
1504514f5e3Sopenharmony_ci    if (acc_.HasFrameState(gate)) {
1514514f5e3Sopenharmony_ci        auto frameState = acc_.GetFrameState(gate);
1524514f5e3Sopenharmony_ci        if (acc_.GetOpCode(frameState) == OpCode::FRAME_STATE) {
1534514f5e3Sopenharmony_ci            loopInfo->size += 2;    // 2: framestate and framevalues
1544514f5e3Sopenharmony_ci            loopInfo->loopBodys.emplace_back(frameState);
1554514f5e3Sopenharmony_ci            loopInfo->loopBodys.emplace_back(acc_.GetValueIn(frameState, 1));
1564514f5e3Sopenharmony_ci        }
1574514f5e3Sopenharmony_ci    }
1584514f5e3Sopenharmony_ci    loopInfo->loopBodys.emplace_back(gate);
1594514f5e3Sopenharmony_ci}
1604514f5e3Sopenharmony_ci
1614514f5e3Sopenharmony_ci// only receive state or depend edge (cur -> dep)
1624514f5e3Sopenharmony_cisize_t LoopAnalysis::ComputeLoopDepth(GateRef cur, GateRef nex, size_t curDep)
1634514f5e3Sopenharmony_ci{
1644514f5e3Sopenharmony_ci    if (acc_.IsLoopExitRelated(cur)) {
1654514f5e3Sopenharmony_ci        if ((!acc_.IsLoopExit(cur)) || (!acc_.IsFixed(nex))) {
1664514f5e3Sopenharmony_ci            // exit from some loop
1674514f5e3Sopenharmony_ci            ASSERT(curDep > 0);
1684514f5e3Sopenharmony_ci            curDep--;
1694514f5e3Sopenharmony_ci        }
1704514f5e3Sopenharmony_ci    }
1714514f5e3Sopenharmony_ci    auto nexOp = acc_.GetOpCode(nex);
1724514f5e3Sopenharmony_ci    switch (nexOp) {
1734514f5e3Sopenharmony_ci        case OpCode::LOOP_BEGIN: {
1744514f5e3Sopenharmony_ci            if (acc_.GetState(nex) == cur) {
1754514f5e3Sopenharmony_ci                // enter new loop by state edge
1764514f5e3Sopenharmony_ci                curDep++;
1774514f5e3Sopenharmony_ci            }
1784514f5e3Sopenharmony_ci            break;
1794514f5e3Sopenharmony_ci        }
1804514f5e3Sopenharmony_ci        case OpCode::DEPEND_SELECTOR: {
1814514f5e3Sopenharmony_ci            GateRef state = acc_.GetState(nex);
1824514f5e3Sopenharmony_ci            if (acc_.IsLoopHead(state) && (cur == acc_.GetDep(nex))) {
1834514f5e3Sopenharmony_ci                // enter new loop by depend edge
1844514f5e3Sopenharmony_ci                curDep++;
1854514f5e3Sopenharmony_ci            }
1864514f5e3Sopenharmony_ci            break;
1874514f5e3Sopenharmony_ci        }
1884514f5e3Sopenharmony_ci        default: {
1894514f5e3Sopenharmony_ci            break;
1904514f5e3Sopenharmony_ci        }
1914514f5e3Sopenharmony_ci    }
1924514f5e3Sopenharmony_ci    return curDep;
1934514f5e3Sopenharmony_ci}
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_civoid LoopAnalysis::LoopExitElimination()
1964514f5e3Sopenharmony_ci{
1974514f5e3Sopenharmony_ci    std::vector<GateRef> gateList;
1984514f5e3Sopenharmony_ci    acc_.GetAllGates(gateList);
1994514f5e3Sopenharmony_ci    ChunkQueue<GateRef> workList(chunk_);
2004514f5e3Sopenharmony_ci    ChunkSet<GateRef> inList(chunk_);
2014514f5e3Sopenharmony_ci    for (auto gate : gateList) {
2024514f5e3Sopenharmony_ci        auto op = acc_.GetOpCode(gate);
2034514f5e3Sopenharmony_ci        switch (op) {
2044514f5e3Sopenharmony_ci            case OpCode::LOOP_EXIT: {
2054514f5e3Sopenharmony_ci                acc_.UpdateAllUses(gate, acc_.GetIn(gate, 0));
2064514f5e3Sopenharmony_ci                acc_.DeleteGate(gate);
2074514f5e3Sopenharmony_ci                break;
2084514f5e3Sopenharmony_ci            }
2094514f5e3Sopenharmony_ci            case OpCode::LOOP_EXIT_DEPEND:
2104514f5e3Sopenharmony_ci            case OpCode::LOOP_EXIT_VALUE: {
2114514f5e3Sopenharmony_ci                acc_.UpdateAllUses(gate, acc_.GetIn(gate, 1));
2124514f5e3Sopenharmony_ci                acc_.DeleteGate(gate);
2134514f5e3Sopenharmony_ci                break;
2144514f5e3Sopenharmony_ci            }
2154514f5e3Sopenharmony_ci            default:
2164514f5e3Sopenharmony_ci                break;
2174514f5e3Sopenharmony_ci        }
2184514f5e3Sopenharmony_ci    }
2194514f5e3Sopenharmony_ci}
2204514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::kungfu
221