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_peeling.h"
174514f5e3Sopenharmony_ci#include "ecmascript/compiler/circuit.h"
184514f5e3Sopenharmony_ci#include "ecmascript/compiler/share_gate_meta_data.h"
194514f5e3Sopenharmony_ci#include "ecmascript/compiler/number_gate_info.h"
204514f5e3Sopenharmony_ci#include "ecmascript/compiler/type.h"
214514f5e3Sopenharmony_ci
224514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
234514f5e3Sopenharmony_civoid LoopPeeling::CopyLoopExit()
244514f5e3Sopenharmony_ci{
254514f5e3Sopenharmony_ci    for (auto exit : loopInfo_->loopExits) {
264514f5e3Sopenharmony_ci        ASSERT(acc_.GetOpCode(exit) == OpCode::LOOP_EXIT);
274514f5e3Sopenharmony_ci        GateRef numIns = 2; // 2: num ins
284514f5e3Sopenharmony_ci        GateRef copyExit = GetCopy(acc_.GetState(exit));
294514f5e3Sopenharmony_ci        GateRef merge = circuit_->NewGate(circuit_->Merge(numIns), {exit, copyExit});
304514f5e3Sopenharmony_ci        auto exitUse = acc_.Uses(exit);
314514f5e3Sopenharmony_ci        for (auto it = exitUse.begin(); it != exitUse.end();) {
324514f5e3Sopenharmony_ci            if (acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_DEPEND) {
334514f5e3Sopenharmony_ci                GateRef depend = *it;
344514f5e3Sopenharmony_ci                GateRef copyDepend = GetCopy(acc_.GetDep(depend));
354514f5e3Sopenharmony_ci                GateRef selector = circuit_->NewGate(circuit_->DependSelector(numIns), {merge, depend, copyDepend});
364514f5e3Sopenharmony_ci                acc_.UpdateAllUses(depend, selector);
374514f5e3Sopenharmony_ci                acc_.ReplaceIn(selector, 1, depend);    // 0: index of exit depend
384514f5e3Sopenharmony_ci                ++it;
394514f5e3Sopenharmony_ci            } else if (acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_VALUE) {
404514f5e3Sopenharmony_ci                GateRef value = *it;
414514f5e3Sopenharmony_ci                GateRef copyValue = GetCopy(acc_.GetValueIn(value));
424514f5e3Sopenharmony_ci                ASSERT(acc_.GetMachineType(value) == acc_.GetMachineType(copyValue));
434514f5e3Sopenharmony_ci                GateRef selector = circuit_->NewGate(circuit_->ValueSelector(numIns), acc_.GetMachineType(value),
444514f5e3Sopenharmony_ci                                                     {merge, value, copyValue}, acc_.GetGateType(value));
454514f5e3Sopenharmony_ci                acc_.UpdateAllUses(value, selector);
464514f5e3Sopenharmony_ci                acc_.ReplaceIn(selector, 1, value);    // 0: index of exit depend
474514f5e3Sopenharmony_ci                ++it;
484514f5e3Sopenharmony_ci            } else if ((*it) == merge) {
494514f5e3Sopenharmony_ci                ++it;
504514f5e3Sopenharmony_ci            } else {
514514f5e3Sopenharmony_ci                it = acc_.ReplaceIn(it, merge);
524514f5e3Sopenharmony_ci            }
534514f5e3Sopenharmony_ci        }
544514f5e3Sopenharmony_ci    }
554514f5e3Sopenharmony_ci}
564514f5e3Sopenharmony_ci
574514f5e3Sopenharmony_civoid LoopPeeling::CopyLoopBody()
584514f5e3Sopenharmony_ci{
594514f5e3Sopenharmony_ci    for (auto gate : loopInfo_->loopBodys) {
604514f5e3Sopenharmony_ci        if ((gate == loopInfo_->loopHead) ||
614514f5e3Sopenharmony_ci            (acc_.IsSelector(gate) && acc_.GetState(gate) == loopInfo_->loopHead)) {
624514f5e3Sopenharmony_ci            continue;
634514f5e3Sopenharmony_ci        }
644514f5e3Sopenharmony_ci        GateRef copy = GetCopy(gate);
654514f5e3Sopenharmony_ci        size_t numIns = acc_.GetNumIns(gate);
664514f5e3Sopenharmony_ci        for (size_t i = 0; i < numIns; ++i) {
674514f5e3Sopenharmony_ci            GateRef in = acc_.GetIn(gate, i);
684514f5e3Sopenharmony_ci            GateRef copyIn = TryGetCopy(in);
694514f5e3Sopenharmony_ci            if (copyIn != Circuit::NullGate()) {
704514f5e3Sopenharmony_ci                acc_.NewIn(copy, i, copyIn);
714514f5e3Sopenharmony_ci            } else {
724514f5e3Sopenharmony_ci                acc_.NewIn(copy, i, in);
734514f5e3Sopenharmony_ci            }
744514f5e3Sopenharmony_ci        }
754514f5e3Sopenharmony_ci    }
764514f5e3Sopenharmony_ci}
774514f5e3Sopenharmony_ci
784514f5e3Sopenharmony_ciGateRef LoopPeeling::CopySelector(GateRef stateMerge, GateRef selector, size_t numLoopbacks)
794514f5e3Sopenharmony_ci{
804514f5e3Sopenharmony_ci    GateRef newGate = Circuit::NullGate();
814514f5e3Sopenharmony_ci    auto inList = std::vector<GateRef>(1 + numLoopbacks, Circuit::NullGate()); // 1: state
824514f5e3Sopenharmony_ci    if (acc_.IsValueSelector(selector)) {
834514f5e3Sopenharmony_ci        newGate = circuit_->NewGate(circuit_->ValueSelector(numLoopbacks),
844514f5e3Sopenharmony_ci            MachineType::I64, inList.size(), inList.data(), GateType::AnyType());
854514f5e3Sopenharmony_ci    } else {
864514f5e3Sopenharmony_ci        newGate = circuit_->NewGate(circuit_->DependSelector(numLoopbacks), inList);
874514f5e3Sopenharmony_ci    }
884514f5e3Sopenharmony_ci    acc_.NewIn(newGate, 0, stateMerge); // 0: is state
894514f5e3Sopenharmony_ci    auto numOfIns = acc_.GetNumIns(selector);
904514f5e3Sopenharmony_ci    const size_t skipValue = 2; // 2: state & entry value
914514f5e3Sopenharmony_ci    ASSERT(numOfIns == numLoopbacks + skipValue);
924514f5e3Sopenharmony_ci    for (size_t i = skipValue; i < numOfIns; i++) {
934514f5e3Sopenharmony_ci        auto input = acc_.GetIn(selector, i);
944514f5e3Sopenharmony_ci        acc_.NewIn(newGate, i - 1, GetCopy(input)); // 1: is state
954514f5e3Sopenharmony_ci    }
964514f5e3Sopenharmony_ci    return newGate;
974514f5e3Sopenharmony_ci}
984514f5e3Sopenharmony_ci
994514f5e3Sopenharmony_civoid LoopPeeling::CopyLoopHeader()
1004514f5e3Sopenharmony_ci{
1014514f5e3Sopenharmony_ci    auto numLoopbacks = loopInfo_->loopBacks.size();
1024514f5e3Sopenharmony_ci    if (numLoopbacks > 1) {
1034514f5e3Sopenharmony_ci        const size_t skipValue = 1; // 1: entry state
1044514f5e3Sopenharmony_ci        auto numOfIns = acc_.GetNumIns(loopInfo_->loopHead);
1054514f5e3Sopenharmony_ci        ASSERT(numOfIns == numLoopbacks + skipValue);
1064514f5e3Sopenharmony_ci        std::vector<GateRef> inList(numLoopbacks, Circuit::NullGate());
1074514f5e3Sopenharmony_ci        auto merge = circuit_->NewGate(circuit_->Merge(numLoopbacks), inList);
1084514f5e3Sopenharmony_ci        for (size_t i = skipValue; i < numOfIns; i++) { // 1: skip entry
1094514f5e3Sopenharmony_ci            auto input = acc_.GetIn(loopInfo_->loopHead, i);
1104514f5e3Sopenharmony_ci            acc_.NewIn(merge, i - skipValue, GetCopy(input));
1114514f5e3Sopenharmony_ci        }
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_ci        auto use = acc_.Uses(loopInfo_->loopHead);
1144514f5e3Sopenharmony_ci        for (auto it = use.begin(); it != use.end(); ++it) {
1154514f5e3Sopenharmony_ci            if (acc_.IsSelector(*it)) {
1164514f5e3Sopenharmony_ci                auto selector = CopySelector(merge, *it, numLoopbacks);
1174514f5e3Sopenharmony_ci                acc_.ReplaceIn(*it, 1, selector);
1184514f5e3Sopenharmony_ci            }
1194514f5e3Sopenharmony_ci        }
1204514f5e3Sopenharmony_ci        acc_.ReplaceIn(loopInfo_->loopHead, 0, merge);  // 0: index of state forward
1214514f5e3Sopenharmony_ci    } else {
1224514f5e3Sopenharmony_ci        // replace origin forwards with peeled loop back.
1234514f5e3Sopenharmony_ci        GateRef stateBack = acc_.GetState(loopInfo_->loopHead, 1); // 1: index of state back
1244514f5e3Sopenharmony_ci        acc_.ReplaceIn(loopInfo_->loopHead, 0, GetCopy(stateBack));  // 0: index of state forward
1254514f5e3Sopenharmony_ci        auto use = acc_.Uses(loopInfo_->loopHead);
1264514f5e3Sopenharmony_ci        for (auto it = use.begin(); it != use.end(); ++it) {
1274514f5e3Sopenharmony_ci            if (acc_.IsSelector(*it)) {
1284514f5e3Sopenharmony_ci                GateRef backward = acc_.GetIn(*it, 2);  // 2: index of depend or value back
1294514f5e3Sopenharmony_ci                acc_.ReplaceIn(*it, 1, GetCopy(backward)); // 1: index of depend or value forward
1304514f5e3Sopenharmony_ci            }
1314514f5e3Sopenharmony_ci        }
1324514f5e3Sopenharmony_ci    }
1334514f5e3Sopenharmony_ci}
1344514f5e3Sopenharmony_ci
1354514f5e3Sopenharmony_civoid LoopPeeling::Peel()
1364514f5e3Sopenharmony_ci{
1374514f5e3Sopenharmony_ci    SetCopy(loopInfo_->loopHead);
1384514f5e3Sopenharmony_ci    for (auto gate : loopInfo_->loopBodys) {
1394514f5e3Sopenharmony_ci        SetCopy(gate);
1404514f5e3Sopenharmony_ci    }
1414514f5e3Sopenharmony_ci    for (auto gate : loopInfo_->loopBacks) {
1424514f5e3Sopenharmony_ci        copies_[gate] = GetCopy(acc_.GetState(gate));
1434514f5e3Sopenharmony_ci    }
1444514f5e3Sopenharmony_ci    CopyLoopBody();
1454514f5e3Sopenharmony_ci    CopyLoopHeader();
1464514f5e3Sopenharmony_ci    CopyLoopExit();
1474514f5e3Sopenharmony_ci
1484514f5e3Sopenharmony_ci    if (bcBuilder_) {
1494514f5e3Sopenharmony_ci        auto asyncList = bcBuilder_->GetAsyncRelatedGates();
1504514f5e3Sopenharmony_ci        ChunkVector<GateRef> list(chunk_);
1514514f5e3Sopenharmony_ci        for (auto gate : asyncList) {
1524514f5e3Sopenharmony_ci            auto copyAsync = TryGetCopy(gate);
1534514f5e3Sopenharmony_ci            if (copyAsync == Circuit::NullGate()) {
1544514f5e3Sopenharmony_ci                list.emplace_back(copyAsync);
1554514f5e3Sopenharmony_ci            }
1564514f5e3Sopenharmony_ci        }
1574514f5e3Sopenharmony_ci        for (auto gate : asyncList) {
1584514f5e3Sopenharmony_ci            bcBuilder_->UpdateAsyncRelatedGate(gate);
1594514f5e3Sopenharmony_ci        }
1604514f5e3Sopenharmony_ci    }
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ci    Print();
1634514f5e3Sopenharmony_ci}
1644514f5e3Sopenharmony_ci
1654514f5e3Sopenharmony_civoid LoopPeeling::SetCopy(GateRef gate)
1664514f5e3Sopenharmony_ci{
1674514f5e3Sopenharmony_ci    ASSERT(copies_.count(gate) == 0);
1684514f5e3Sopenharmony_ci    if (gate == loopInfo_->loopHead) {
1694514f5e3Sopenharmony_ci        // copy of head is forward
1704514f5e3Sopenharmony_ci        copies_[gate] = acc_.GetState(gate);
1714514f5e3Sopenharmony_ci        return;
1724514f5e3Sopenharmony_ci    }
1734514f5e3Sopenharmony_ci    if (acc_.IsSelector(gate) && acc_.GetState(gate) == loopInfo_->loopHead) {
1744514f5e3Sopenharmony_ci        // copy of head is forward
1754514f5e3Sopenharmony_ci        copies_[gate] = acc_.GetIn(gate, 1); // 1: index of forward
1764514f5e3Sopenharmony_ci        return;
1774514f5e3Sopenharmony_ci    }
1784514f5e3Sopenharmony_ci
1794514f5e3Sopenharmony_ci    std::vector<GateRef> inList(acc_.GetNumIns(gate), Circuit::NullGate());
1804514f5e3Sopenharmony_ci    GateRef newGate = circuit_->NewGate(acc_.GetMetaData(gate), inList);
1814514f5e3Sopenharmony_ci    acc_.SetGateType(newGate, acc_.GetGateType(gate));
1824514f5e3Sopenharmony_ci    acc_.SetMachineType(newGate, acc_.GetMachineType(gate));
1834514f5e3Sopenharmony_ci    copies_[gate] = newGate;
1844514f5e3Sopenharmony_ci    if (acc_.GetOpCode(gate) == OpCode::JS_BYTECODE) {
1854514f5e3Sopenharmony_ci        bcBuilder_->UpdateBcIndexGate(newGate, bcBuilder_->GetBcIndexByGate(gate));
1864514f5e3Sopenharmony_ci    }
1874514f5e3Sopenharmony_ci}
1884514f5e3Sopenharmony_ci
1894514f5e3Sopenharmony_ciGateRef LoopPeeling::GetCopy(GateRef gate) const
1904514f5e3Sopenharmony_ci{
1914514f5e3Sopenharmony_ci    if (copies_.count(gate)) {
1924514f5e3Sopenharmony_ci        return copies_.at(gate);
1934514f5e3Sopenharmony_ci    }
1944514f5e3Sopenharmony_ci    return gate;
1954514f5e3Sopenharmony_ci}
1964514f5e3Sopenharmony_ci
1974514f5e3Sopenharmony_ciGateRef LoopPeeling::TryGetCopy(GateRef gate) const
1984514f5e3Sopenharmony_ci{
1994514f5e3Sopenharmony_ci    if (copies_.count(gate) > 0) {
2004514f5e3Sopenharmony_ci        return copies_.at(gate);
2014514f5e3Sopenharmony_ci    }
2024514f5e3Sopenharmony_ci    return Circuit::NullGate();
2034514f5e3Sopenharmony_ci}
2044514f5e3Sopenharmony_ci
2054514f5e3Sopenharmony_civoid LoopPeeling::Print() const
2064514f5e3Sopenharmony_ci{
2074514f5e3Sopenharmony_ci    if (IsLogEnabled()) {
2084514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "";
2094514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "\033[34m"
2104514f5e3Sopenharmony_ci                           << "===================="
2114514f5e3Sopenharmony_ci                           << " After loop peeling "
2124514f5e3Sopenharmony_ci                           << "[" << GetMethodName() << "]"
2134514f5e3Sopenharmony_ci                           << "===================="
2144514f5e3Sopenharmony_ci                           << "\033[0m";
2154514f5e3Sopenharmony_ci        circuit_->PrintAllGatesWithBytecode();
2164514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
2174514f5e3Sopenharmony_ci    }
2184514f5e3Sopenharmony_ci}
2194514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::kungfu