14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2022 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#include "ecmascript/compiler/frame_states.h"
164514f5e3Sopenharmony_ci
174514f5e3Sopenharmony_ci#include <cstddef>
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include "ecmascript/compiler/bytecode_circuit_builder.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
224514f5e3Sopenharmony_ciFrameStateBuilder::FrameStateBuilder(BytecodeCircuitBuilder *builder,
234514f5e3Sopenharmony_ci    Circuit *circuit, const MethodLiteral *literal)
244514f5e3Sopenharmony_ci    : bcBuilder_(builder),
254514f5e3Sopenharmony_ci      pgoTypeRecorder_(builder->GetPGOTypeRecorder()),
264514f5e3Sopenharmony_ci      numVregs_(literal->GetNumberVRegs() + FIXED_ARGS),
274514f5e3Sopenharmony_ci      accumulatorIndex_(literal->GetNumberVRegs() + 1), // 1: acc
284514f5e3Sopenharmony_ci      envIndex_(literal->GetNumberVRegs()),
294514f5e3Sopenharmony_ci      circuit_(circuit),
304514f5e3Sopenharmony_ci      acc_(circuit),
314514f5e3Sopenharmony_ci      bcEndStateLiveouts_(circuit->chunk()),
324514f5e3Sopenharmony_ci      bbBeginStateLiveouts_(circuit->chunk()),
334514f5e3Sopenharmony_ci      bbFrameContext_(circuit->chunk()),
344514f5e3Sopenharmony_ci      loops_(circuit->chunk()),
354514f5e3Sopenharmony_ci      rpoList_(circuit->chunk()),
364514f5e3Sopenharmony_ci      postOrderList_(circuit->chunk())
374514f5e3Sopenharmony_ci{
384514f5e3Sopenharmony_ci}
394514f5e3Sopenharmony_ci
404514f5e3Sopenharmony_ciFrameStateBuilder::~FrameStateBuilder()
414514f5e3Sopenharmony_ci{
424514f5e3Sopenharmony_ci    liveOutResult_ = nullptr;
434514f5e3Sopenharmony_ci    bcEndStateLiveouts_.clear();
444514f5e3Sopenharmony_ci    bbBeginStateLiveouts_.clear();
454514f5e3Sopenharmony_ci    bbFrameContext_.clear();
464514f5e3Sopenharmony_ci    bcBuilder_ = nullptr;
474514f5e3Sopenharmony_ci}
484514f5e3Sopenharmony_ci
494514f5e3Sopenharmony_civoid FrameStateBuilder::BuildPostOrderList(size_t size)
504514f5e3Sopenharmony_ci{
514514f5e3Sopenharmony_ci    postOrderList_.clear();
524514f5e3Sopenharmony_ci    std::deque<size_t> pendingList;
534514f5e3Sopenharmony_ci    std::vector<bool> visited(size, false);
544514f5e3Sopenharmony_ci    // entry block (bbid=0) is a empty block, need skip
554514f5e3Sopenharmony_ci    auto firstBlockId = 1;
564514f5e3Sopenharmony_ci    pendingList.emplace_back(firstBlockId);
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_ci    while (!pendingList.empty()) {
594514f5e3Sopenharmony_ci        size_t curBlockId = pendingList.back();
604514f5e3Sopenharmony_ci        visited[curBlockId] = true;
614514f5e3Sopenharmony_ci
624514f5e3Sopenharmony_ci        bool change = false;
634514f5e3Sopenharmony_ci        auto &bb = bcBuilder_->GetBasicBlockById(curBlockId);
644514f5e3Sopenharmony_ci        for (const auto &succBlock: bb.succs) {
654514f5e3Sopenharmony_ci            if (!visited[succBlock->id]) {
664514f5e3Sopenharmony_ci                pendingList.emplace_back(succBlock->id);
674514f5e3Sopenharmony_ci                change = true;
684514f5e3Sopenharmony_ci                break;
694514f5e3Sopenharmony_ci            }
704514f5e3Sopenharmony_ci        }
714514f5e3Sopenharmony_ci        if (change) {
724514f5e3Sopenharmony_ci            continue;
734514f5e3Sopenharmony_ci        }
744514f5e3Sopenharmony_ci        for (const auto &succBlock: bb.catches) {
754514f5e3Sopenharmony_ci            if (!visited[succBlock->id]) {
764514f5e3Sopenharmony_ci                pendingList.emplace_back(succBlock->id);
774514f5e3Sopenharmony_ci                change = true;
784514f5e3Sopenharmony_ci                break;
794514f5e3Sopenharmony_ci            }
804514f5e3Sopenharmony_ci        }
814514f5e3Sopenharmony_ci        if (!change) {
824514f5e3Sopenharmony_ci            postOrderList_.emplace_back(curBlockId);
834514f5e3Sopenharmony_ci            pendingList.pop_back();
844514f5e3Sopenharmony_ci        }
854514f5e3Sopenharmony_ci    }
864514f5e3Sopenharmony_ci}
874514f5e3Sopenharmony_ci
884514f5e3Sopenharmony_cibool FrameStateBuilder::MergeIntoPredBC(uint32_t predPc)
894514f5e3Sopenharmony_ci{
904514f5e3Sopenharmony_ci    // liveout next
914514f5e3Sopenharmony_ci    auto liveout = GetOrOCreateBCEndLiveOut(predPc);
924514f5e3Sopenharmony_ci    FrameLiveOut *predliveOut = liveOutResult_;
934514f5e3Sopenharmony_ci    return liveout->MergeLiveout(predliveOut);
944514f5e3Sopenharmony_ci}
954514f5e3Sopenharmony_ci
964514f5e3Sopenharmony_cibool FrameStateBuilder::MergeFromSuccBB(size_t bbId)
974514f5e3Sopenharmony_ci{
984514f5e3Sopenharmony_ci    // liveout next
994514f5e3Sopenharmony_ci    auto liveout = GetOrOCreateBBLiveOut(bbId);
1004514f5e3Sopenharmony_ci    return liveOutResult_->MergeLiveout(liveout);
1014514f5e3Sopenharmony_ci}
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_civoid FrameStateBuilder::MergeFromCatchBB(size_t bbId)
1044514f5e3Sopenharmony_ci{
1054514f5e3Sopenharmony_ci    // liveout next
1064514f5e3Sopenharmony_ci    bool accumulatorIsLive = liveOutResult_->TestBit(accumulatorIndex_);
1074514f5e3Sopenharmony_ci    auto liveout = GetOrOCreateBBLiveOut(bbId);
1084514f5e3Sopenharmony_ci    liveOutResult_->MergeLiveout(liveout);
1094514f5e3Sopenharmony_ci    // accumulatorIndex_ is exeception object
1104514f5e3Sopenharmony_ci    if (!accumulatorIsLive) {
1114514f5e3Sopenharmony_ci        liveOutResult_->ClearBit(accumulatorIndex_);
1124514f5e3Sopenharmony_ci    }
1134514f5e3Sopenharmony_ci}
1144514f5e3Sopenharmony_ci
1154514f5e3Sopenharmony_cibool FrameStateBuilder::ComputeLiveOut(size_t bbId)
1164514f5e3Sopenharmony_ci{
1174514f5e3Sopenharmony_ci    auto &bb = bcBuilder_->GetBasicBlockById(bbId);
1184514f5e3Sopenharmony_ci    bool changed = false;
1194514f5e3Sopenharmony_ci    // iterator bc
1204514f5e3Sopenharmony_ci    auto &iterator = bb.GetBytecodeIterator();
1214514f5e3Sopenharmony_ci    iterator.GotoEnd();
1224514f5e3Sopenharmony_ci    ASSERT(bb.end == iterator.Index());
1234514f5e3Sopenharmony_ci    auto bbLiveout = GetOrOCreateBBLiveOut(bb.id);
1244514f5e3Sopenharmony_ci    auto liveout = GetOrOCreateBCEndLiveOut(bb.end);
1254514f5e3Sopenharmony_ci    liveOutResult_->CopyFrom(liveout);
1264514f5e3Sopenharmony_ci    // init frameContext
1274514f5e3Sopenharmony_ci    currentBBliveOut_ = bbLiveout;
1284514f5e3Sopenharmony_ci    while (true) {
1294514f5e3Sopenharmony_ci        auto &bytecodeInfo = iterator.GetBytecodeInfo();
1304514f5e3Sopenharmony_ci        if (!bb.catches.empty() && !bytecodeInfo.NoThrow()) {
1314514f5e3Sopenharmony_ci            ASSERT(bb.catches.size() == 1); // 1: one catch
1324514f5e3Sopenharmony_ci            MergeFromCatchBB(bb.catches.at(0)->id);
1334514f5e3Sopenharmony_ci        }
1344514f5e3Sopenharmony_ci        ComputeLiveOutBC(bytecodeInfo);
1354514f5e3Sopenharmony_ci        --iterator;
1364514f5e3Sopenharmony_ci        if (iterator.Done()) {
1374514f5e3Sopenharmony_ci            break;
1384514f5e3Sopenharmony_ci        }
1394514f5e3Sopenharmony_ci        auto prevPc = iterator.Index();
1404514f5e3Sopenharmony_ci        changed |= MergeIntoPredBC(prevPc);
1414514f5e3Sopenharmony_ci    }
1424514f5e3Sopenharmony_ci    if (!bb.trys.empty()) {
1434514f5e3Sopenharmony_ci        // clear GET_EXCEPTION gate if this is a catch block
1444514f5e3Sopenharmony_ci        liveOutResult_->ClearBit(accumulatorIndex_);
1454514f5e3Sopenharmony_ci    }
1464514f5e3Sopenharmony_ci    bbLiveout->CopyFrom(liveOutResult_);
1474514f5e3Sopenharmony_ci    // merge current into pred bb
1484514f5e3Sopenharmony_ci    for (auto bbPred : bb.preds) {
1494514f5e3Sopenharmony_ci        changed |= MergeIntoPredBC(bbPred->end);
1504514f5e3Sopenharmony_ci    }
1514514f5e3Sopenharmony_ci
1524514f5e3Sopenharmony_ci    return changed;
1534514f5e3Sopenharmony_ci}
1544514f5e3Sopenharmony_ci
1554514f5e3Sopenharmony_civoid FrameStateBuilder::ComputeLiveState()
1564514f5e3Sopenharmony_ci{
1574514f5e3Sopenharmony_ci    // recompute liveout
1584514f5e3Sopenharmony_ci    bool changed = true;
1594514f5e3Sopenharmony_ci    while (changed) {
1604514f5e3Sopenharmony_ci        changed = false;
1614514f5e3Sopenharmony_ci        for (size_t i = 0; i < postOrderList_.size(); i++) {
1624514f5e3Sopenharmony_ci            changed |= ComputeLiveOut(postOrderList_[i]);
1634514f5e3Sopenharmony_ci        }
1644514f5e3Sopenharmony_ci    }
1654514f5e3Sopenharmony_ci}
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_civoid FrameStateBuilder::DoBytecodeAnalysis()
1684514f5e3Sopenharmony_ci{
1694514f5e3Sopenharmony_ci    auto bcSize = bcBuilder_->GetLastBcIndex() + 1; // 1: +1 pcOffsets size
1704514f5e3Sopenharmony_ci    auto bbSize = bcBuilder_->GetBasicBlockCount();
1714514f5e3Sopenharmony_ci    bcEndStateLiveouts_.resize(bcSize, nullptr);
1724514f5e3Sopenharmony_ci    bbBeginStateLiveouts_.resize(bbSize, nullptr);
1734514f5e3Sopenharmony_ci    auto chunk = circuit_->chunk();
1744514f5e3Sopenharmony_ci    liveOutResult_ = chunk->New<FrameLiveOut>(chunk, numVregs_);
1754514f5e3Sopenharmony_ci    bbFrameContext_.resize(bbSize, nullptr);
1764514f5e3Sopenharmony_ci    BuildPostOrderList(bbSize);
1774514f5e3Sopenharmony_ci    ComputeLiveState();
1784514f5e3Sopenharmony_ci    if (bcBuilder_->IsLogEnabled()) {
1794514f5e3Sopenharmony_ci        DumpLiveState();
1804514f5e3Sopenharmony_ci    }
1814514f5e3Sopenharmony_ci    ComputeLoopInfo();
1824514f5e3Sopenharmony_ci}
1834514f5e3Sopenharmony_ci
1844514f5e3Sopenharmony_civoid FrameStateBuilder::ComputeLiveOutBC(const BytecodeInfo &bytecodeInfo)
1854514f5e3Sopenharmony_ci{
1864514f5e3Sopenharmony_ci    if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
1874514f5e3Sopenharmony_ci        currentBBliveOut_->defRegisters_.Union(liveOutResult_->liveout_);
1884514f5e3Sopenharmony_ci    }
1894514f5e3Sopenharmony_ci    // variable kill
1904514f5e3Sopenharmony_ci    if (bytecodeInfo.AccOut()) {
1914514f5e3Sopenharmony_ci        liveOutResult_->ClearBit(accumulatorIndex_);
1924514f5e3Sopenharmony_ci        currentBBliveOut_->defRegisters_.SetBit(accumulatorIndex_);
1934514f5e3Sopenharmony_ci    }
1944514f5e3Sopenharmony_ci    for (const auto &out: bytecodeInfo.vregOut) {
1954514f5e3Sopenharmony_ci        liveOutResult_->ClearBit(out);
1964514f5e3Sopenharmony_ci        currentBBliveOut_->defRegisters_.SetBit(out);
1974514f5e3Sopenharmony_ci    }
1984514f5e3Sopenharmony_ci
1994514f5e3Sopenharmony_ci    // variable use
2004514f5e3Sopenharmony_ci    if (bytecodeInfo.AccIn()) {
2014514f5e3Sopenharmony_ci        liveOutResult_->SetBit(accumulatorIndex_);
2024514f5e3Sopenharmony_ci    }
2034514f5e3Sopenharmony_ci    for (size_t i = 0; i < bytecodeInfo.inputs.size(); i++) {
2044514f5e3Sopenharmony_ci        auto in = bytecodeInfo.inputs[i];
2054514f5e3Sopenharmony_ci        if (std::holds_alternative<VirtualRegister>(in)) {
2064514f5e3Sopenharmony_ci            auto vreg = std::get<VirtualRegister>(in).GetId();
2074514f5e3Sopenharmony_ci            liveOutResult_->SetBit(vreg);
2084514f5e3Sopenharmony_ci        }
2094514f5e3Sopenharmony_ci    }
2104514f5e3Sopenharmony_ci}
2114514f5e3Sopenharmony_ci
2124514f5e3Sopenharmony_ciFrameLiveOut *FrameStateBuilder::GetOrOCreateBCEndLiveOut(uint32_t bcIndex)
2134514f5e3Sopenharmony_ci{
2144514f5e3Sopenharmony_ci    auto liveout = bcEndStateLiveouts_[bcIndex];
2154514f5e3Sopenharmony_ci    if (liveout == nullptr) {
2164514f5e3Sopenharmony_ci        auto chunk = circuit_->chunk();
2174514f5e3Sopenharmony_ci        liveout = chunk->New<FrameLiveOut>(chunk, numVregs_);
2184514f5e3Sopenharmony_ci        bcEndStateLiveouts_[bcIndex] = liveout;
2194514f5e3Sopenharmony_ci    }
2204514f5e3Sopenharmony_ci    return liveout;
2214514f5e3Sopenharmony_ci}
2224514f5e3Sopenharmony_ci
2234514f5e3Sopenharmony_ciFrameLiveOut *FrameStateBuilder::GetOrOCreateBBLiveOut(size_t bbIndex)
2244514f5e3Sopenharmony_ci{
2254514f5e3Sopenharmony_ci    // As BB0 is empty, its bbBeginStateLiveouts is the same as BB1.
2264514f5e3Sopenharmony_ci    if (bbIndex == 0) {
2274514f5e3Sopenharmony_ci        if (bcBuilder_->IsOSR()) {
2284514f5e3Sopenharmony_ci            bbIndex = GetOsrLoopHeadBBId();
2294514f5e3Sopenharmony_ci        } else {
2304514f5e3Sopenharmony_ci            bbIndex = 1;
2314514f5e3Sopenharmony_ci        }
2324514f5e3Sopenharmony_ci    }
2334514f5e3Sopenharmony_ci    auto liveout = bbBeginStateLiveouts_[bbIndex];
2344514f5e3Sopenharmony_ci    if (liveout == nullptr) {
2354514f5e3Sopenharmony_ci        auto chunk = circuit_->chunk();
2364514f5e3Sopenharmony_ci        liveout = chunk->New<FrameLiveOut>(chunk, numVregs_);
2374514f5e3Sopenharmony_ci        bbBeginStateLiveouts_[bbIndex] = liveout;
2384514f5e3Sopenharmony_ci    }
2394514f5e3Sopenharmony_ci    return liveout;
2404514f5e3Sopenharmony_ci}
2414514f5e3Sopenharmony_ci
2424514f5e3Sopenharmony_ciFrameContext *FrameStateBuilder::GetOrOCreateMergedContext(uint32_t bbIndex)
2434514f5e3Sopenharmony_ci{
2444514f5e3Sopenharmony_ci    auto context = bbFrameContext_[bbIndex];
2454514f5e3Sopenharmony_ci    if (context == nullptr) {
2464514f5e3Sopenharmony_ci        auto chunk = circuit_->chunk();
2474514f5e3Sopenharmony_ci        context = chunk->New<FrameContext>(chunk, numVregs_);
2484514f5e3Sopenharmony_ci        for (size_t i = 0; i < numVregs_; i++) {
2494514f5e3Sopenharmony_ci            context->SetValuesAt(i, Circuit::NullGate());
2504514f5e3Sopenharmony_ci        }
2514514f5e3Sopenharmony_ci        bbFrameContext_[bbIndex] = context;
2524514f5e3Sopenharmony_ci    }
2534514f5e3Sopenharmony_ci    return context;
2544514f5e3Sopenharmony_ci}
2554514f5e3Sopenharmony_ci
2564514f5e3Sopenharmony_civoid FrameStateBuilder::FillBcInputs(const BytecodeInfo &bytecodeInfo, GateRef gate)
2574514f5e3Sopenharmony_ci{
2584514f5e3Sopenharmony_ci    auto pgoType = pgoTypeRecorder_->GetPGOType(acc_.TryGetPcOffset(gate));
2594514f5e3Sopenharmony_ci    acc_.TrySetPGOType(gate, pgoType);
2604514f5e3Sopenharmony_ci
2614514f5e3Sopenharmony_ci    auto valueCount = acc_.GetInValueCount(gate);
2624514f5e3Sopenharmony_ci    [[maybe_unused]] size_t numValueInputs = bytecodeInfo.ComputeValueInputCount();
2634514f5e3Sopenharmony_ci    [[maybe_unused]] size_t numValueOutputs = bytecodeInfo.ComputeOutCount();
2644514f5e3Sopenharmony_ci    // RETURNUNDEFINED has value input, but not from acc
2654514f5e3Sopenharmony_ci    ASSERT(numValueInputs == valueCount || bytecodeInfo.GetOpcode() == EcmaOpcode::RETURNUNDEFINED);
2664514f5e3Sopenharmony_ci    ASSERT(numValueOutputs <= 1 + (bytecodeInfo.EnvOut() ? 1 : 0));
2674514f5e3Sopenharmony_ci    auto valueStarts = acc_.GetInValueStarts(gate);
2684514f5e3Sopenharmony_ci    for (size_t valueIdx = 0; valueIdx < valueCount; valueIdx++) {
2694514f5e3Sopenharmony_ci        auto inIdx = valueIdx + valueStarts;
2704514f5e3Sopenharmony_ci        if (!acc_.IsInGateNull(gate, inIdx)) {
2714514f5e3Sopenharmony_ci            continue;
2724514f5e3Sopenharmony_ci        }
2734514f5e3Sopenharmony_ci        if (valueIdx < bytecodeInfo.inputs.size()) {
2744514f5e3Sopenharmony_ci            auto vregId = std::get<VirtualRegister>(bytecodeInfo.inputs.at(valueIdx)).GetId();
2754514f5e3Sopenharmony_ci            GateRef defVreg = liveContext_->ValuesAt(vregId);
2764514f5e3Sopenharmony_ci            acc_.NewIn(gate, inIdx, defVreg);
2774514f5e3Sopenharmony_ci        } else {
2784514f5e3Sopenharmony_ci            GateRef defAcc = liveContext_->ValuesAt(accumulatorIndex_);
2794514f5e3Sopenharmony_ci            acc_.NewIn(gate, inIdx, defAcc);
2804514f5e3Sopenharmony_ci        }
2814514f5e3Sopenharmony_ci    }
2824514f5e3Sopenharmony_ci}
2834514f5e3Sopenharmony_ci
2844514f5e3Sopenharmony_civoid FrameStateBuilder::AdvanceToNextBc(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId)
2854514f5e3Sopenharmony_ci{
2864514f5e3Sopenharmony_ci    if (bytecodeInfo.IsGeneral()) {
2874514f5e3Sopenharmony_ci        BindStateSplitBefore(bytecodeInfo, liveout, bcId);
2884514f5e3Sopenharmony_ci        if (bytecodeInfo.GetOpcode() == EcmaOpcode::SUSPENDGENERATOR_V8 ||
2894514f5e3Sopenharmony_ci            bytecodeInfo.GetOpcode() == EcmaOpcode::ASYNCGENERATORRESOLVE_V8_V8_V8) {
2904514f5e3Sopenharmony_ci            auto hole = circuit_->GetConstantGate(MachineType::I64,
2914514f5e3Sopenharmony_ci                                                  JSTaggedValue::VALUE_HOLE,
2924514f5e3Sopenharmony_ci                                                  GateType::TaggedValue());
2934514f5e3Sopenharmony_ci            uint32_t numRegs = accumulatorIndex_;
2944514f5e3Sopenharmony_ci            std::vector<GateRef> vec(numRegs + 1, hole);
2954514f5e3Sopenharmony_ci            vec[0] = liveContext_->currentDepend_;
2964514f5e3Sopenharmony_ci            // accumulator is res
2974514f5e3Sopenharmony_ci            for (size_t i = 0; i < numRegs; i++) {
2984514f5e3Sopenharmony_ci                if (liveout->TestBit(i)) {
2994514f5e3Sopenharmony_ci                    vec[i + 1] = liveContext_->ValuesAt(i);  // 1: skip dep
3004514f5e3Sopenharmony_ci                } else {
3014514f5e3Sopenharmony_ci                    vec[i + 1] = hole; // 1: skip dep
3024514f5e3Sopenharmony_ci                }
3034514f5e3Sopenharmony_ci            }
3044514f5e3Sopenharmony_ci            auto res = circuit_->NewGate(circuit_->SaveRegister(numRegs), vec);
3054514f5e3Sopenharmony_ci            liveContext_->currentDepend_ = res;
3064514f5e3Sopenharmony_ci        }
3074514f5e3Sopenharmony_ci    }
3084514f5e3Sopenharmony_ci}
3094514f5e3Sopenharmony_ci
3104514f5e3Sopenharmony_civoid FrameStateBuilder::UpdateStateDepend(GateRef state, GateRef depend)
3114514f5e3Sopenharmony_ci{
3124514f5e3Sopenharmony_ci    liveContext_->currentState_ = state;
3134514f5e3Sopenharmony_ci    liveContext_->currentDepend_ = depend;
3144514f5e3Sopenharmony_ci}
3154514f5e3Sopenharmony_ci
3164514f5e3Sopenharmony_civoid FrameStateBuilder::UpdateMoveValues(const BytecodeInfo &bytecodeInfo)
3174514f5e3Sopenharmony_ci{
3184514f5e3Sopenharmony_ci    GateRef gate = Circuit::NullGate();
3194514f5e3Sopenharmony_ci    if (bytecodeInfo.AccIn()) {
3204514f5e3Sopenharmony_ci        gate = liveContext_->ValuesAt(accumulatorIndex_);
3214514f5e3Sopenharmony_ci    } else if (bytecodeInfo.inputs.size() != 0) {
3224514f5e3Sopenharmony_ci        auto vreg = std::get<VirtualRegister>(bytecodeInfo.inputs.at(0)).GetId();
3234514f5e3Sopenharmony_ci        gate = liveContext_->ValuesAt(vreg);
3244514f5e3Sopenharmony_ci    }
3254514f5e3Sopenharmony_ci    // variable kill
3264514f5e3Sopenharmony_ci    if (bytecodeInfo.AccOut()) {
3274514f5e3Sopenharmony_ci        liveContext_->SetValuesAt(accumulatorIndex_, gate);
3284514f5e3Sopenharmony_ci    } else if (bytecodeInfo.vregOut.size() != 0) {
3294514f5e3Sopenharmony_ci        auto vreg = bytecodeInfo.vregOut[0];
3304514f5e3Sopenharmony_ci        liveContext_->SetValuesAt(vreg, gate);
3314514f5e3Sopenharmony_ci    }
3324514f5e3Sopenharmony_ci}
3334514f5e3Sopenharmony_ci
3344514f5e3Sopenharmony_civoid FrameStateBuilder::UpdateFrameValues(const BytecodeInfo &bytecodeInfo,
3354514f5e3Sopenharmony_ci    uint32_t bcId, GateRef gate)
3364514f5e3Sopenharmony_ci{
3374514f5e3Sopenharmony_ci    ASSERT(!bytecodeInfo.IsDiscarded() && !bytecodeInfo.IsMov());
3384514f5e3Sopenharmony_ci    if (bytecodeInfo.IsSetConstant()) {
3394514f5e3Sopenharmony_ci        liveContext_->SetValuesAt(accumulatorIndex_, gate);
3404514f5e3Sopenharmony_ci        return;
3414514f5e3Sopenharmony_ci    }
3424514f5e3Sopenharmony_ci    // jump gate is null
3434514f5e3Sopenharmony_ci    if (IsGateNotEmpty(gate)) {
3444514f5e3Sopenharmony_ci        FillBcInputs(bytecodeInfo, gate);
3454514f5e3Sopenharmony_ci    }
3464514f5e3Sopenharmony_ci    auto liveout = GetFrameLiveoutAfter(bcId);
3474514f5e3Sopenharmony_ci    // variable kill
3484514f5e3Sopenharmony_ci    if (bytecodeInfo.AccOut()) {
3494514f5e3Sopenharmony_ci        liveContext_->SetValuesAt(accumulatorIndex_, gate);
3504514f5e3Sopenharmony_ci    }
3514514f5e3Sopenharmony_ci    for (const auto &out: bytecodeInfo.vregOut) {
3524514f5e3Sopenharmony_ci        liveContext_->SetValuesAt(out, gate);
3534514f5e3Sopenharmony_ci    }
3544514f5e3Sopenharmony_ci    if (bytecodeInfo.GetOpcode() == EcmaOpcode::RESUMEGENERATOR) {
3554514f5e3Sopenharmony_ci        // accumulator is generator object
3564514f5e3Sopenharmony_ci        for (size_t i = 0; i < accumulatorIndex_; i++) {
3574514f5e3Sopenharmony_ci            if (liveout->TestBit(i)) {
3584514f5e3Sopenharmony_ci                auto restore = circuit_->NewGate(circuit_->RestoreRegister(i),
3594514f5e3Sopenharmony_ci                    MachineType::I64, { gate }, GateType::AnyType());
3604514f5e3Sopenharmony_ci                liveContext_->SetValuesAt(i, restore);
3614514f5e3Sopenharmony_ci            }
3624514f5e3Sopenharmony_ci        }
3634514f5e3Sopenharmony_ci    }
3644514f5e3Sopenharmony_ci    BindStateSplitAfter(bytecodeInfo, bcId, gate);
3654514f5e3Sopenharmony_ci}
3664514f5e3Sopenharmony_ci
3674514f5e3Sopenharmony_civoid FrameStateBuilder::SetOsrLoopHeadBB(const BytecodeRegion &osrLoopBodyBB)
3684514f5e3Sopenharmony_ci{
3694514f5e3Sopenharmony_ci    auto *loopInfo = GetLoopInfoByLoopBody(osrLoopBodyBB);
3704514f5e3Sopenharmony_ci    if (loopInfo == nullptr) {
3714514f5e3Sopenharmony_ci        loopHeadOfOSR_ = nullptr;
3724514f5e3Sopenharmony_ci    } else {
3734514f5e3Sopenharmony_ci        loopHeadOfOSR_ = &(bcBuilder_->GetBasicBlockById(loopInfo->loopHeadId));
3744514f5e3Sopenharmony_ci    }
3754514f5e3Sopenharmony_ci    return;
3764514f5e3Sopenharmony_ci}
3774514f5e3Sopenharmony_ci
3784514f5e3Sopenharmony_cibool FrameStateBuilder::IsOsrLoopExit(const BytecodeRegion &curBB)
3794514f5e3Sopenharmony_ci{
3804514f5e3Sopenharmony_ci    if (loopHeadOfOSR_ == nullptr) {
3814514f5e3Sopenharmony_ci        return false;
3824514f5e3Sopenharmony_ci    }
3834514f5e3Sopenharmony_ci    auto *loopInfo = GetLoopInfoByLoopBody(*loopHeadOfOSR_);
3844514f5e3Sopenharmony_ci    if (!loopInfo || !loopInfo->loopExits) {
3854514f5e3Sopenharmony_ci        return false;
3864514f5e3Sopenharmony_ci    }
3874514f5e3Sopenharmony_ci    for (auto *exit : *loopInfo->loopExits) {
3884514f5e3Sopenharmony_ci        if (exit == &curBB) {
3894514f5e3Sopenharmony_ci            return true;
3904514f5e3Sopenharmony_ci        }
3914514f5e3Sopenharmony_ci    }
3924514f5e3Sopenharmony_ci    return false;
3934514f5e3Sopenharmony_ci}
3944514f5e3Sopenharmony_ci
3954514f5e3Sopenharmony_cibool FrameStateBuilder::OutOfOsrLoop(const BytecodeRegion &curBB)
3964514f5e3Sopenharmony_ci{
3974514f5e3Sopenharmony_ci    if (loopHeadOfOSR_ == nullptr) {
3984514f5e3Sopenharmony_ci        return false;
3994514f5e3Sopenharmony_ci    }
4004514f5e3Sopenharmony_ci    const LoopInfo &loopInfoOfOSR = GetLoopInfo(*loopHeadOfOSR_);
4014514f5e3Sopenharmony_ci    const LoopInfo *curLoop = GetLoopInfoByLoopBody(curBB);
4024514f5e3Sopenharmony_ci    while (curLoop != nullptr) {
4034514f5e3Sopenharmony_ci        if (curLoop == &loopInfoOfOSR) {
4044514f5e3Sopenharmony_ci            return false;
4054514f5e3Sopenharmony_ci        }
4064514f5e3Sopenharmony_ci        curLoop = curLoop->parentInfo;
4074514f5e3Sopenharmony_ci    }
4084514f5e3Sopenharmony_ci    return true;
4094514f5e3Sopenharmony_ci}
4104514f5e3Sopenharmony_ci
4114514f5e3Sopenharmony_cisize_t FrameStateBuilder::GetOsrLoopHeadBBId() const
4124514f5e3Sopenharmony_ci{
4134514f5e3Sopenharmony_ci    if (loopHeadOfOSR_ == nullptr) {
4144514f5e3Sopenharmony_ci        return -1;
4154514f5e3Sopenharmony_ci    }
4164514f5e3Sopenharmony_ci    return loopHeadOfOSR_->id;
4174514f5e3Sopenharmony_ci}
4184514f5e3Sopenharmony_ci
4194514f5e3Sopenharmony_civoid FrameStateBuilder::InitEntryBB(const BytecodeRegion &bb)
4204514f5e3Sopenharmony_ci{
4214514f5e3Sopenharmony_ci    auto frameContext = GetOrOCreateMergedContext(bb.id);
4224514f5e3Sopenharmony_ci    frameContext->currentState_ = circuit_->GetStateRoot();
4234514f5e3Sopenharmony_ci    frameContext->currentDepend_ = circuit_->GetDependRoot();
4244514f5e3Sopenharmony_ci    frameContext->needStateSplit_ = true;
4254514f5e3Sopenharmony_ci    // initialize argumnets
4264514f5e3Sopenharmony_ci    ASSERT(bcBuilder_->IsFirstBasicBlock(1)); // 1: is firstBlock
4274514f5e3Sopenharmony_ci    auto liveout = GetFrameLiveoutBefore(1); // 1: is firstBlock
4284514f5e3Sopenharmony_ci    GateRef frameArgs = bcBuilder_->GetFrameArgs();
4294514f5e3Sopenharmony_ci    if (liveout->TestBit(envIndex_)) {
4304514f5e3Sopenharmony_ci        GateRef jsFunc = acc_.GetValueIn(frameArgs, static_cast<size_t>(FrameArgIdx::FUNC));
4314514f5e3Sopenharmony_ci        auto env = acc_.GetInitialEnvGate(frameContext->currentDepend_, jsFunc);
4324514f5e3Sopenharmony_ci        frameContext->SetValuesAt(envIndex_, env);
4334514f5e3Sopenharmony_ci        frameContext->currentDepend_ = env;
4344514f5e3Sopenharmony_ci    }
4354514f5e3Sopenharmony_ci    auto holeGate = circuit_->GetConstantGate(MachineType::I64,
4364514f5e3Sopenharmony_ci                                              JSTaggedValue::VALUE_HOLE,
4374514f5e3Sopenharmony_ci                                              GateType::TaggedValue());
4384514f5e3Sopenharmony_ci    for (size_t i = 0; i < envIndex_; i++) {
4394514f5e3Sopenharmony_ci        if (liveout->TestBit(i)) {
4404514f5e3Sopenharmony_ci            if (bcBuilder_->ArgGateNotExisted(i)) {
4414514f5e3Sopenharmony_ci                frameContext->SetValuesAt(i, holeGate);
4424514f5e3Sopenharmony_ci            } else {
4434514f5e3Sopenharmony_ci                GateRef arg = bcBuilder_->GetArgGate(i);
4444514f5e3Sopenharmony_ci                frameContext->SetValuesAt(i, arg);
4454514f5e3Sopenharmony_ci            }
4464514f5e3Sopenharmony_ci        }
4474514f5e3Sopenharmony_ci    }
4484514f5e3Sopenharmony_ci
4494514f5e3Sopenharmony_ci    // init live interpreter registers
4504514f5e3Sopenharmony_ci    if (!bcBuilder_->IsOSR()) {
4514514f5e3Sopenharmony_ci        return;
4524514f5e3Sopenharmony_ci    }
4534514f5e3Sopenharmony_ci    auto *liveOut = GetFrameLiveoutBefore(GetOsrLoopHeadBBId());
4544514f5e3Sopenharmony_ci    for (size_t i = 0; i < envIndex_; i++) {
4554514f5e3Sopenharmony_ci        if (!liveOut->TestBit(i)) {
4564514f5e3Sopenharmony_ci            continue;
4574514f5e3Sopenharmony_ci        }
4584514f5e3Sopenharmony_ci        GateRef init = circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(i), MachineType::I64,
4594514f5e3Sopenharmony_ci                                         {circuit_->GetArgRoot()}, GateType::TaggedValue());
4604514f5e3Sopenharmony_ci        frameContext->SetValuesAt(i, init);
4614514f5e3Sopenharmony_ci    }
4624514f5e3Sopenharmony_ci    if (liveOut->TestBit(envIndex_)) {
4634514f5e3Sopenharmony_ci        // -7: env
4644514f5e3Sopenharmony_ci        GateRef env = circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ENV), MachineType::I64,
4654514f5e3Sopenharmony_ci                                        {circuit_->GetArgRoot()}, GateType::TaggedValue());
4664514f5e3Sopenharmony_ci        frameContext->SetValuesAt(envIndex_, env);
4674514f5e3Sopenharmony_ci    }
4684514f5e3Sopenharmony_ci}
4694514f5e3Sopenharmony_ci
4704514f5e3Sopenharmony_cibool FrameStateBuilder::IsLoopHead(const BytecodeRegion &bb)
4714514f5e3Sopenharmony_ci{
4724514f5e3Sopenharmony_ci    return !(bcBuilder_->IsOSR() && OutOfOsrLoop(bb)) && bb.loopNumber > 0;
4734514f5e3Sopenharmony_ci}
4744514f5e3Sopenharmony_ci
4754514f5e3Sopenharmony_cibool FrameStateBuilder::IfLoopNeedMerge(const BytecodeRegion &bb) const
4764514f5e3Sopenharmony_ci{
4774514f5e3Sopenharmony_ci    return !bcBuilder_->IsOSR() && bb.numOfStatePreds - bb.numOfLoopBack != 1; // 1: loop in
4784514f5e3Sopenharmony_ci}
4794514f5e3Sopenharmony_ci
4804514f5e3Sopenharmony_ciGateRef FrameStateBuilder::InitMerge(size_t numOfIns, bool isLoop)
4814514f5e3Sopenharmony_ci{
4824514f5e3Sopenharmony_ci    const GateMetaData *metaData = isLoop ? circuit_->LoopBegin(numOfIns) : circuit_->Merge(numOfIns);
4834514f5e3Sopenharmony_ci    return circuit_->NewGate(metaData, std::vector<GateRef>(numOfIns, Circuit::NullGate()));
4844514f5e3Sopenharmony_ci}
4854514f5e3Sopenharmony_ci
4864514f5e3Sopenharmony_cibool FrameStateBuilder::IsGateNotEmpty(GateRef gate) const
4874514f5e3Sopenharmony_ci{
4884514f5e3Sopenharmony_ci    return gate != Circuit::NullGate();
4894514f5e3Sopenharmony_ci}
4904514f5e3Sopenharmony_ci
4914514f5e3Sopenharmony_civoid FrameStateBuilder::NewMerge(const BytecodeRegion &bbNext)
4924514f5e3Sopenharmony_ci{
4934514f5e3Sopenharmony_ci    auto frameContext = GetMergedBbContext(bbNext.id);
4944514f5e3Sopenharmony_ci    size_t numOfIns = bbNext.numOfStatePreds;
4954514f5e3Sopenharmony_ci    if (IsOsrLoopExit(bbNext)) {
4964514f5e3Sopenharmony_ci        // Only the precursor within the OSR loop is required.
4974514f5e3Sopenharmony_ci        numOfIns = 0;
4984514f5e3Sopenharmony_ci        for (const BytecodeRegion *bb : bbNext.preds) {
4994514f5e3Sopenharmony_ci            if (OutOfOsrLoop(*bb)) {
5004514f5e3Sopenharmony_ci                continue;
5014514f5e3Sopenharmony_ci            }
5024514f5e3Sopenharmony_ci            numOfIns++;
5034514f5e3Sopenharmony_ci        }
5044514f5e3Sopenharmony_ci    }
5054514f5e3Sopenharmony_ci
5064514f5e3Sopenharmony_ci    bool isLoopHead = IsLoopHead(bbNext);
5074514f5e3Sopenharmony_ci    GateRef merge;
5084514f5e3Sopenharmony_ci    GateRef dependMerge;
5094514f5e3Sopenharmony_ci    if (isLoopHead) {
5104514f5e3Sopenharmony_ci        if (!IfLoopNeedMerge(bbNext)) {
5114514f5e3Sopenharmony_ci            // only generate loop begin
5124514f5e3Sopenharmony_ci            merge = InitMerge(numOfIns, true);
5134514f5e3Sopenharmony_ci            dependMerge = circuit_->NewGate(circuit_->DependSelector(numOfIns),
5144514f5e3Sopenharmony_ci                std::vector<GateRef>(numOfIns + 1, Circuit::NullGate())); // 1: merge
5154514f5e3Sopenharmony_ci        } else {
5164514f5e3Sopenharmony_ci            // generate both loop begin and merge
5174514f5e3Sopenharmony_ci            ASSERT(numOfIns - bbNext.numOfLoopBack > 1); // 1: loop in
5184514f5e3Sopenharmony_ci            size_t numOfLoopIns = bbNext.numOfLoopBack + 1; // 1: loop in
5194514f5e3Sopenharmony_ci            merge = InitMerge(numOfLoopIns, true);
5204514f5e3Sopenharmony_ci            dependMerge = circuit_->NewGate(circuit_->DependSelector(numOfLoopIns),
5214514f5e3Sopenharmony_ci                std::vector<GateRef>(numOfLoopIns + 1, Circuit::NullGate())); // 1: merge
5224514f5e3Sopenharmony_ci            size_t numOfMergeIns = numOfIns - bbNext.numOfLoopBack;
5234514f5e3Sopenharmony_ci            frameContext->mergeState_ = InitMerge(numOfMergeIns, false);
5244514f5e3Sopenharmony_ci            frameContext->mergeDepend_ = circuit_->NewGate(circuit_->DependSelector(numOfMergeIns),
5254514f5e3Sopenharmony_ci                std::vector<GateRef>(numOfMergeIns + 1, Circuit::NullGate())); // 1: merge
5264514f5e3Sopenharmony_ci            acc_.NewIn(frameContext->mergeDepend_, 0, frameContext->mergeState_);
5274514f5e3Sopenharmony_ci            acc_.NewIn(dependMerge, 1, frameContext->mergeDepend_); // 1: phi of merge
5284514f5e3Sopenharmony_ci            acc_.NewIn(merge, 0, frameContext->mergeState_);
5294514f5e3Sopenharmony_ci            frameContext->loopBackIndex_++;
5304514f5e3Sopenharmony_ci        }
5314514f5e3Sopenharmony_ci        frameContext->loopBackDepend_ = dependMerge;
5324514f5e3Sopenharmony_ci        frameContext->loopBackState_ = merge;
5334514f5e3Sopenharmony_ci    } else {
5344514f5e3Sopenharmony_ci        // only merge
5354514f5e3Sopenharmony_ci        merge = InitMerge(numOfIns, false);
5364514f5e3Sopenharmony_ci        dependMerge = circuit_->NewGate(circuit_->DependSelector(numOfIns),
5374514f5e3Sopenharmony_ci            std::vector<GateRef>(numOfIns + 1, Circuit::NullGate())); // 1: merge
5384514f5e3Sopenharmony_ci        frameContext->mergeDepend_ = dependMerge;
5394514f5e3Sopenharmony_ci        frameContext->mergeState_ = merge;
5404514f5e3Sopenharmony_ci    }
5414514f5e3Sopenharmony_ci    acc_.NewIn(dependMerge, 0, merge);  // 0: is state
5424514f5e3Sopenharmony_ci    // reset current state and depend
5434514f5e3Sopenharmony_ci    frameContext->currentState_ = merge;
5444514f5e3Sopenharmony_ci    frameContext->currentDepend_ = dependMerge;
5454514f5e3Sopenharmony_ci
5464514f5e3Sopenharmony_ci    if (isLoopHead) {
5474514f5e3Sopenharmony_ci        ChunkVector<GateRef>& headerGates = bcBuilder_->GetLoopHeaderGates();
5484514f5e3Sopenharmony_ci        auto& loopInfo = GetLoopInfo(bbNext);
5494514f5e3Sopenharmony_ci        headerGates[loopInfo.sortIndx] = merge;
5504514f5e3Sopenharmony_ci    }
5514514f5e3Sopenharmony_ci}
5524514f5e3Sopenharmony_ci
5534514f5e3Sopenharmony_civoid FrameStateBuilder::MergeStateDepend(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
5544514f5e3Sopenharmony_ci{
5554514f5e3Sopenharmony_ci    GateRef entryState = liveContext_->currentState_;
5564514f5e3Sopenharmony_ci    GateRef entryDepend = liveContext_->currentDepend_;
5574514f5e3Sopenharmony_ci    auto mergedContext = GetMergedBbContext(bbNext.id);
5584514f5e3Sopenharmony_ci    if (bbNext.numOfStatePreds == 1) { // 1: one entry edge
5594514f5e3Sopenharmony_ci        mergedContext->currentState_ = liveContext_->currentState_;
5604514f5e3Sopenharmony_ci        mergedContext->currentDepend_ = liveContext_->currentDepend_;
5614514f5e3Sopenharmony_ci        return;
5624514f5e3Sopenharmony_ci    }
5634514f5e3Sopenharmony_ci    auto index = mergedContext->currentIndex_;
5644514f5e3Sopenharmony_ci    // lazy first edge
5654514f5e3Sopenharmony_ci    if (index == 0) {
5664514f5e3Sopenharmony_ci        NewMerge(bbNext);
5674514f5e3Sopenharmony_ci    }
5684514f5e3Sopenharmony_ci    if (IsLoopBackEdge(bb, bbNext)) {
5694514f5e3Sopenharmony_ci        if (!(bcBuilder_->IsOSR() && IsOsrLoopExit(bbNext))) {
5704514f5e3Sopenharmony_ci            ASSERT(index != 0);
5714514f5e3Sopenharmony_ci        }
5724514f5e3Sopenharmony_ci        entryState = circuit_->NewGate(circuit_->LoopBack(), { entryState });
5734514f5e3Sopenharmony_ci    }
5744514f5e3Sopenharmony_ci    auto mergeInfo = GetCorrespondingState(bb, bbNext);
5754514f5e3Sopenharmony_ci    acc_.NewIn(mergeInfo.state, mergeInfo.index, entryState);
5764514f5e3Sopenharmony_ci    acc_.NewIn(mergeInfo.depend, mergeInfo.index + 1, entryDepend); // 1: skip state
5774514f5e3Sopenharmony_ci    mergedContext->needStateSplit_ = true;
5784514f5e3Sopenharmony_ci}
5794514f5e3Sopenharmony_ci
5804514f5e3Sopenharmony_cisize_t FrameStateBuilder::GetNumOfStatePreds(const BytecodeRegion &bb)
5814514f5e3Sopenharmony_ci{
5824514f5e3Sopenharmony_ci    size_t numOfIns = bb.numOfStatePreds;
5834514f5e3Sopenharmony_ci    if (bcBuilder_->IsOSR() && IsOsrLoopExit(bb)) {
5844514f5e3Sopenharmony_ci        numOfIns = 0;
5854514f5e3Sopenharmony_ci        for (const BytecodeRegion *b : bb.preds) {
5864514f5e3Sopenharmony_ci            if (OutOfOsrLoop(*b)) {
5874514f5e3Sopenharmony_ci                continue;
5884514f5e3Sopenharmony_ci            }
5894514f5e3Sopenharmony_ci            numOfIns++;
5904514f5e3Sopenharmony_ci        }
5914514f5e3Sopenharmony_ci    }
5924514f5e3Sopenharmony_ci    return numOfIns;
5934514f5e3Sopenharmony_ci}
5944514f5e3Sopenharmony_ci
5954514f5e3Sopenharmony_ciGateRef FrameStateBuilder::MergeValue(const BytecodeRegion &bb,
5964514f5e3Sopenharmony_ci    GateRef currentValue, GateRef nextValue, bool isLoopBack, bool changedInLoop)
5974514f5e3Sopenharmony_ci{
5984514f5e3Sopenharmony_ci    ASSERT(IsGateNotEmpty(currentValue));
5994514f5e3Sopenharmony_ci    auto mergedContext = GetMergedBbContext(bb.id);
6004514f5e3Sopenharmony_ci    GateRef result = currentValue;
6014514f5e3Sopenharmony_ci    GateRef mergeValueSelector;
6024514f5e3Sopenharmony_ci
6034514f5e3Sopenharmony_ci    // if already a merged gate
6044514f5e3Sopenharmony_ci    if (IsGateNotEmpty(nextValue) &&
6054514f5e3Sopenharmony_ci        (acc_.GetOpCode(nextValue) == OpCode::VALUE_SELECTOR &&
6064514f5e3Sopenharmony_ci        acc_.GetState(nextValue) == mergedContext->currentState_)) {
6074514f5e3Sopenharmony_ci        ASSERT(IsGateNotEmpty(currentValue));
6084514f5e3Sopenharmony_ci        if (isLoopBack) {
6094514f5e3Sopenharmony_ci            ASSERT(IsGateNotEmpty(mergedContext->loopBackState_));
6104514f5e3Sopenharmony_ci            acc_.NewIn(nextValue, mergedContext->loopBackIndex_ + 1, currentValue); // 1: merge
6114514f5e3Sopenharmony_ci        } else {
6124514f5e3Sopenharmony_ci            ASSERT(IsGateNotEmpty(mergedContext->mergeState_));
6134514f5e3Sopenharmony_ci            if (!IsGateNotEmpty(mergedContext->loopBackState_)) {
6144514f5e3Sopenharmony_ci                acc_.NewIn(nextValue, mergedContext->mergeIndex_ + 1, currentValue);  // 1: merge
6154514f5e3Sopenharmony_ci            } else {
6164514f5e3Sopenharmony_ci                mergeValueSelector = acc_.GetIn(nextValue, 1); // 1: index of phi of merge
6174514f5e3Sopenharmony_ci                acc_.NewIn(mergeValueSelector, mergedContext->mergeIndex_ + 1, currentValue); // 1: merge
6184514f5e3Sopenharmony_ci            }
6194514f5e3Sopenharmony_ci        }
6204514f5e3Sopenharmony_ci        result = nextValue;
6214514f5e3Sopenharmony_ci    } else if (currentValue != nextValue) {
6224514f5e3Sopenharmony_ci        bool needMergeValues = IsGateNotEmpty(mergedContext->mergeState_);
6234514f5e3Sopenharmony_ci        // build value selector for merge.
6244514f5e3Sopenharmony_ci        if (needMergeValues) {
6254514f5e3Sopenharmony_ci            size_t numOfIns = acc_.GetNumIns(mergedContext->mergeState_);
6264514f5e3Sopenharmony_ci            auto inList = std::vector<GateRef>(numOfIns + 1, Circuit::NullGate());  // 1: state
6274514f5e3Sopenharmony_ci            auto phi = circuit_->NewGate(
6284514f5e3Sopenharmony_ci                circuit_->ValueSelector(numOfIns), MachineType::I64, inList.size(), inList.data(),
6294514f5e3Sopenharmony_ci                GateType::AnyType());
6304514f5e3Sopenharmony_ci            acc_.NewIn(phi, 0, mergedContext->mergeState_);
6314514f5e3Sopenharmony_ci            for (size_t i = 0; i < mergedContext->mergeIndex_; i++) {
6324514f5e3Sopenharmony_ci                acc_.NewIn(phi, i + 1, nextValue);  // 1: merge
6334514f5e3Sopenharmony_ci            }
6344514f5e3Sopenharmony_ci            if (!isLoopBack) {
6354514f5e3Sopenharmony_ci                acc_.NewIn(phi, mergedContext->mergeIndex_ + 1, currentValue); // 1: merge
6364514f5e3Sopenharmony_ci            }
6374514f5e3Sopenharmony_ci            mergeValueSelector = result = phi;
6384514f5e3Sopenharmony_ci        }
6394514f5e3Sopenharmony_ci        // build value selector for loop begin.
6404514f5e3Sopenharmony_ci        // If the register value of the corresponding bit is changed in the loop or
6414514f5e3Sopenharmony_ci        // there is a state that needs to be merged (e.g.Multiple values or branches need to be merged into a phi node)
6424514f5e3Sopenharmony_ci        // need to create or update the phi node.
6434514f5e3Sopenharmony_ci        if (IsGateNotEmpty(mergedContext->loopBackState_) && (changedInLoop || needMergeValues)) {
6444514f5e3Sopenharmony_ci            size_t numOfIns = acc_.GetNumIns(mergedContext->loopBackState_);
6454514f5e3Sopenharmony_ci            auto inList = std::vector<GateRef>(numOfIns + 1, Circuit::NullGate());  // 1: state
6464514f5e3Sopenharmony_ci            auto phi = circuit_->NewGate(
6474514f5e3Sopenharmony_ci                circuit_->ValueSelector(numOfIns), MachineType::I64, inList.size(), inList.data(),
6484514f5e3Sopenharmony_ci                GateType::AnyType());
6494514f5e3Sopenharmony_ci            acc_.NewIn(phi, 0, mergedContext->loopBackState_);
6504514f5e3Sopenharmony_ci            if (IsGateNotEmpty(mergedContext->mergeState_)) {
6514514f5e3Sopenharmony_ci                acc_.NewIn(phi, 1, mergeValueSelector); // 1: merge
6524514f5e3Sopenharmony_ci            }
6534514f5e3Sopenharmony_ci            if (IsGateNotEmpty(nextValue)) {
6544514f5e3Sopenharmony_ci                for (size_t i = 0; i < mergedContext->loopBackIndex_; i++) {
6554514f5e3Sopenharmony_ci                    acc_.NewIn(phi, i + 1, nextValue); // 1: merge
6564514f5e3Sopenharmony_ci                }
6574514f5e3Sopenharmony_ci            }
6584514f5e3Sopenharmony_ci            if (isLoopBack || !IsGateNotEmpty(mergedContext->mergeState_)) {
6594514f5e3Sopenharmony_ci                acc_.NewIn(phi, mergedContext->loopBackIndex_ + 1, currentValue); // 1: merge
6604514f5e3Sopenharmony_ci            }
6614514f5e3Sopenharmony_ci            result = phi;
6624514f5e3Sopenharmony_ci        }
6634514f5e3Sopenharmony_ci    }
6644514f5e3Sopenharmony_ci    return result;
6654514f5e3Sopenharmony_ci}
6664514f5e3Sopenharmony_ci
6674514f5e3Sopenharmony_ciMergeStateDependInfo FrameStateBuilder::GetCorrespondingState(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
6684514f5e3Sopenharmony_ci{
6694514f5e3Sopenharmony_ci    auto mergedContext = GetMergedBbContext(bbNext.id);
6704514f5e3Sopenharmony_ci    if (IsLoopHead(bbNext)) {
6714514f5e3Sopenharmony_ci        if (!IfLoopNeedMerge(bbNext)) { // 1: only one loop in
6724514f5e3Sopenharmony_ci            ASSERT(!IsGateNotEmpty(mergedContext->mergeState_));
6734514f5e3Sopenharmony_ci            ASSERT(!IsGateNotEmpty(mergedContext->mergeDepend_));
6744514f5e3Sopenharmony_ci            return {mergedContext->loopBackState_, mergedContext->loopBackDepend_, mergedContext->loopBackIndex_};
6754514f5e3Sopenharmony_ci        }
6764514f5e3Sopenharmony_ci        if (bbNext.IsLoopBack(bb)) {
6774514f5e3Sopenharmony_ci            return {mergedContext->loopBackState_, mergedContext->loopBackDepend_, mergedContext->loopBackIndex_};
6784514f5e3Sopenharmony_ci        } else {
6794514f5e3Sopenharmony_ci            return {mergedContext->mergeState_, mergedContext->mergeDepend_, mergedContext->mergeIndex_};
6804514f5e3Sopenharmony_ci        }
6814514f5e3Sopenharmony_ci    } else {
6824514f5e3Sopenharmony_ci        ASSERT(!IsGateNotEmpty(mergedContext->loopBackState_));
6834514f5e3Sopenharmony_ci        ASSERT(!IsGateNotEmpty(mergedContext->loopBackDepend_));
6844514f5e3Sopenharmony_ci        return {mergedContext->mergeState_, mergedContext->mergeDepend_, mergedContext->mergeIndex_};
6854514f5e3Sopenharmony_ci    }
6864514f5e3Sopenharmony_ci}
6874514f5e3Sopenharmony_ci
6884514f5e3Sopenharmony_civoid FrameStateBuilder::MergeAssignment(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
6894514f5e3Sopenharmony_ci{
6904514f5e3Sopenharmony_ci    auto mergedContext = GetMergedBbContext(bbNext.id);
6914514f5e3Sopenharmony_ci    [[maybe_unused]] auto mergeInfo = GetCorrespondingState(bb, bbNext);
6924514f5e3Sopenharmony_ci    ASSERT(acc_.IsCFGMerge(mergeInfo.state));
6934514f5e3Sopenharmony_ci    auto liveout = GetFrameLiveoutBefore(bbNext.id);
6944514f5e3Sopenharmony_ci    auto *loopAssignment = GetLoopAssignment(bbNext);
6954514f5e3Sopenharmony_ci    for (size_t i = 0; i < numVregs_; i++) {
6964514f5e3Sopenharmony_ci        if (liveout->TestBit(i)) {
6974514f5e3Sopenharmony_ci            auto current = liveContext_->ValuesAt(i);
6984514f5e3Sopenharmony_ci            auto next = mergedContext->ValuesAt(i);
6994514f5e3Sopenharmony_ci            GateRef value = Circuit::NullGate();
7004514f5e3Sopenharmony_ci#ifndef NDEBUG
7014514f5e3Sopenharmony_ci            if (loopAssignment == nullptr) {
7024514f5e3Sopenharmony_ci                ASSERT(IsGateNotEmpty(current) && IsGateNotEmpty(next));
7034514f5e3Sopenharmony_ci            } else if (loopAssignment->TestBit(i)) {
7044514f5e3Sopenharmony_ci                // next is null or phi
7054514f5e3Sopenharmony_ci                ASSERT(!IsGateNotEmpty(next) ||
7064514f5e3Sopenharmony_ci                    ((acc_.GetOpCode(next) == OpCode::VALUE_SELECTOR) &&
7074514f5e3Sopenharmony_ci                    acc_.GetState(next) == mergedContext->currentState_));
7084514f5e3Sopenharmony_ci            } else if (!IsGateNotEmpty(mergedContext->mergeState_)) {
7094514f5e3Sopenharmony_ci                ASSERT(!IsGateNotEmpty(next) || current == next);
7104514f5e3Sopenharmony_ci            }
7114514f5e3Sopenharmony_ci#endif
7124514f5e3Sopenharmony_ci            bool changedInLoop = loopAssignment != nullptr && loopAssignment->TestBit(i);
7134514f5e3Sopenharmony_ci            value = MergeValue(bbNext, current, next, bbNext.IsLoopBack(bb), changedInLoop);
7144514f5e3Sopenharmony_ci            mergedContext->SetValuesAt(i, value);
7154514f5e3Sopenharmony_ci        }
7164514f5e3Sopenharmony_ci    }
7174514f5e3Sopenharmony_ci}
7184514f5e3Sopenharmony_ci
7194514f5e3Sopenharmony_civoid FrameStateBuilder::CopyLiveoutValues(const BytecodeRegion &bbNext,
7204514f5e3Sopenharmony_ci    FrameContext* dest, FrameContext* src)
7214514f5e3Sopenharmony_ci{
7224514f5e3Sopenharmony_ci    auto liveout = GetFrameLiveoutBefore(bbNext.id);
7234514f5e3Sopenharmony_ci    for (size_t i = 0; i < numVregs_; i++) {
7244514f5e3Sopenharmony_ci        if (liveout->TestBit(i)) {
7254514f5e3Sopenharmony_ci            auto value = src->ValuesAt(i);
7264514f5e3Sopenharmony_ci            dest->SetValuesAt(i, value);
7274514f5e3Sopenharmony_ci        } else {
7284514f5e3Sopenharmony_ci            dest->SetValuesAt(i, Circuit::NullGate());
7294514f5e3Sopenharmony_ci        }
7304514f5e3Sopenharmony_ci    }
7314514f5e3Sopenharmony_ci}
7324514f5e3Sopenharmony_ci
7334514f5e3Sopenharmony_ciFrameContext *FrameStateBuilder::GetCachedContext()
7344514f5e3Sopenharmony_ci{
7354514f5e3Sopenharmony_ci    // lazy init cachedContext
7364514f5e3Sopenharmony_ci    if (cachedContext_ == nullptr) {
7374514f5e3Sopenharmony_ci        auto chunk = circuit_->chunk();
7384514f5e3Sopenharmony_ci        cachedContext_ = chunk->New<FrameContext>(chunk, numVregs_);
7394514f5e3Sopenharmony_ci    }
7404514f5e3Sopenharmony_ci    auto result = cachedContext_;
7414514f5e3Sopenharmony_ci    if (cachedContext_ == liveContext_) {
7424514f5e3Sopenharmony_ci        if (cachedContextBackup_ == nullptr) {
7434514f5e3Sopenharmony_ci            auto chunk = circuit_->chunk();
7444514f5e3Sopenharmony_ci            cachedContextBackup_ = chunk->New<FrameContext>(chunk, numVregs_);
7454514f5e3Sopenharmony_ci        }
7464514f5e3Sopenharmony_ci        result = cachedContextBackup_;
7474514f5e3Sopenharmony_ci    }
7484514f5e3Sopenharmony_ci    return result;
7494514f5e3Sopenharmony_ci}
7504514f5e3Sopenharmony_ci
7514514f5e3Sopenharmony_civoid FrameStateBuilder::SaveCurrentContext(const BytecodeRegion &bb)
7524514f5e3Sopenharmony_ci{
7534514f5e3Sopenharmony_ci    auto newContext = GetCachedContext();
7544514f5e3Sopenharmony_ci    ASSERT(newContext != liveContext_);
7554514f5e3Sopenharmony_ci    newContext->CopyCurrentStatus(liveContext_);
7564514f5e3Sopenharmony_ci    CopyLiveoutValues(bb, newContext, liveContext_);
7574514f5e3Sopenharmony_ci    liveContext_ = newContext;
7584514f5e3Sopenharmony_ci}
7594514f5e3Sopenharmony_ci
7604514f5e3Sopenharmony_civoid FrameStateBuilder::NewLoopExit(const BytecodeRegion &bbNext, BitSet *loopAssignment)
7614514f5e3Sopenharmony_ci{
7624514f5e3Sopenharmony_ci    auto state = liveContext_->currentState_;
7634514f5e3Sopenharmony_ci    auto depend = liveContext_->currentDepend_;
7644514f5e3Sopenharmony_ci    auto loopExit = circuit_->NewGate(circuit_->LoopExit(), { state });
7654514f5e3Sopenharmony_ci    auto loopExitDepend = circuit_->NewGate(circuit_->LoopExitDepend(),
7664514f5e3Sopenharmony_ci        { loopExit, depend });
7674514f5e3Sopenharmony_ci    auto liveout = GetFrameLiveoutBefore(bbNext.id);
7684514f5e3Sopenharmony_ci    for (size_t i = 0; i < numVregs_; i++) {
7694514f5e3Sopenharmony_ci        if (liveout->TestBit(i)) {
7704514f5e3Sopenharmony_ci            auto current = liveContext_->ValuesAt(i);
7714514f5e3Sopenharmony_ci            if (loopAssignment->TestBit(i)) {
7724514f5e3Sopenharmony_ci                current = circuit_->NewGate(circuit_->LoopExitValue(), acc_.GetMachineType(current),
7734514f5e3Sopenharmony_ci                    {loopExit, current}, acc_.GetGateType(current));
7744514f5e3Sopenharmony_ci            }
7754514f5e3Sopenharmony_ci            liveContext_->SetValuesAt(i, current);
7764514f5e3Sopenharmony_ci        } else {
7774514f5e3Sopenharmony_ci            ASSERT(!IsGateNotEmpty(liveContext_->ValuesAt(i)));
7784514f5e3Sopenharmony_ci        }
7794514f5e3Sopenharmony_ci    }
7804514f5e3Sopenharmony_ci    liveContext_->currentState_ = loopExit;
7814514f5e3Sopenharmony_ci    liveContext_->currentDepend_ = loopExitDepend;
7824514f5e3Sopenharmony_ci    if (!bcBuilder_->IsTypeLoweringEnabled()) {
7834514f5e3Sopenharmony_ci        return;
7844514f5e3Sopenharmony_ci    }
7854514f5e3Sopenharmony_ci    auto stateSplit = BuildStateSplit(liveContext_, liveout, bbNext.start);
7864514f5e3Sopenharmony_ci    liveContext_->currentDepend_ = stateSplit;
7874514f5e3Sopenharmony_ci}
7884514f5e3Sopenharmony_ci
7894514f5e3Sopenharmony_civoid FrameStateBuilder::TryInsertLoopExit(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
7904514f5e3Sopenharmony_ci{
7914514f5e3Sopenharmony_ci    if (!bcBuilder_->EnableLoopOptimization() && !bcBuilder_->IsOSR()) {
7924514f5e3Sopenharmony_ci        return;
7934514f5e3Sopenharmony_ci    }
7944514f5e3Sopenharmony_ci    if (bcBuilder_->IsOSR() && bcBuilder_->IsCacheBBOfOSRLoop(bbNext)) {
7954514f5e3Sopenharmony_ci        return;
7964514f5e3Sopenharmony_ci    }
7974514f5e3Sopenharmony_ci    auto currentLoop = GetLoopInfoByLoopBody(bb);
7984514f5e3Sopenharmony_ci    if (currentLoop != nullptr && !currentLoop->loopBodys->TestBit(bbNext.id)) {
7994514f5e3Sopenharmony_ci        // use bbNext as merged values
8004514f5e3Sopenharmony_ci        SaveCurrentContext(bbNext);
8014514f5e3Sopenharmony_ci    }
8024514f5e3Sopenharmony_ci    while (currentLoop != nullptr && !currentLoop->loopBodys->TestBit(bbNext.id)) {
8034514f5e3Sopenharmony_ci        ASSERT(currentLoop->loopExits != nullptr);
8044514f5e3Sopenharmony_ci#ifndef NDEBUG
8054514f5e3Sopenharmony_ci        bool found = false;
8064514f5e3Sopenharmony_ci        for (auto current : *currentLoop->loopExits) {
8074514f5e3Sopenharmony_ci            if (current->id == bbNext.id) {
8084514f5e3Sopenharmony_ci                found = true;
8094514f5e3Sopenharmony_ci                break;
8104514f5e3Sopenharmony_ci            }
8114514f5e3Sopenharmony_ci        }
8124514f5e3Sopenharmony_ci        ASSERT(found);
8134514f5e3Sopenharmony_ci#endif
8144514f5e3Sopenharmony_ci        NewLoopExit(bbNext, currentLoop->loopAssignment);
8154514f5e3Sopenharmony_ci        currentLoop = currentLoop->parentInfo;
8164514f5e3Sopenharmony_ci    }
8174514f5e3Sopenharmony_ci}
8184514f5e3Sopenharmony_ci
8194514f5e3Sopenharmony_civoid FrameStateBuilder::AdvanceToNextBB(const BytecodeRegion &bb, bool isOsrLoopExit)
8204514f5e3Sopenharmony_ci{
8214514f5e3Sopenharmony_ci    liveContext_ = GetMergedBbContext(bb.id);
8224514f5e3Sopenharmony_ci    ASSERT(liveContext_ != nullptr);
8234514f5e3Sopenharmony_ci    if (bb.loopNumber > 0) {
8244514f5e3Sopenharmony_ci        // use bb as merged values
8254514f5e3Sopenharmony_ci        SaveCurrentContext(bb);
8264514f5e3Sopenharmony_ci    } else if (!isOsrLoopExit) {
8274514f5e3Sopenharmony_ci        // all input merged
8284514f5e3Sopenharmony_ci        ASSERT(liveContext_->currentIndex_ == bb.numOfStatePreds);
8294514f5e3Sopenharmony_ci    }
8304514f5e3Sopenharmony_ci    if (liveContext_->needStateSplit_) {
8314514f5e3Sopenharmony_ci        liveContext_->needStateSplit_ = false;
8324514f5e3Sopenharmony_ci        if (!bcBuilder_->IsTypeLoweringEnabled()) {
8334514f5e3Sopenharmony_ci            return;
8344514f5e3Sopenharmony_ci        }
8354514f5e3Sopenharmony_ci        auto liveout = GetOrOCreateBBLiveOut(bb.id);
8364514f5e3Sopenharmony_ci        auto stateSplit = BuildStateSplit(liveContext_, liveout, bb.start);
8374514f5e3Sopenharmony_ci        liveContext_->currentDepend_ = stateSplit;
8384514f5e3Sopenharmony_ci    }
8394514f5e3Sopenharmony_ci}
8404514f5e3Sopenharmony_ci
8414514f5e3Sopenharmony_ciclass SubContextScope {
8424514f5e3Sopenharmony_cipublic:
8434514f5e3Sopenharmony_ci    explicit SubContextScope(FrameStateBuilder* frameBuilder)
8444514f5e3Sopenharmony_ci        : frameBuilder_(frameBuilder)
8454514f5e3Sopenharmony_ci    {
8464514f5e3Sopenharmony_ci        originContext_ = frameBuilder->liveContext_;
8474514f5e3Sopenharmony_ci    }
8484514f5e3Sopenharmony_ci
8494514f5e3Sopenharmony_ci    ~SubContextScope()
8504514f5e3Sopenharmony_ci    {
8514514f5e3Sopenharmony_ci        frameBuilder_->liveContext_ = originContext_;
8524514f5e3Sopenharmony_ci    }
8534514f5e3Sopenharmony_ciprivate:
8544514f5e3Sopenharmony_ci    FrameContext* originContext_ {nullptr};
8554514f5e3Sopenharmony_ci    FrameStateBuilder* frameBuilder_ {nullptr};
8564514f5e3Sopenharmony_ci};
8574514f5e3Sopenharmony_ci
8584514f5e3Sopenharmony_civoid FrameStateBuilder::MergeIntoSuccessor(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
8594514f5e3Sopenharmony_ci{
8604514f5e3Sopenharmony_ci    [[maybe_unused]] SubContextScope scope(this);
8614514f5e3Sopenharmony_ci    TryInsertLoopExit(bb, bbNext);
8624514f5e3Sopenharmony_ci    auto mergedContext = GetOrOCreateMergedContext(bbNext.id);
8634514f5e3Sopenharmony_ci    MergeStateDepend(bb, bbNext);
8644514f5e3Sopenharmony_ci    if (mergedContext->currentIndex_ == 0) {
8654514f5e3Sopenharmony_ci        if (bbNext.loopNumber > 0) {
8664514f5e3Sopenharmony_ci            MergeAssignment(bb, bbNext);
8674514f5e3Sopenharmony_ci        } else {
8684514f5e3Sopenharmony_ci            CopyLiveoutValues(bbNext, mergedContext, liveContext_);
8694514f5e3Sopenharmony_ci        }
8704514f5e3Sopenharmony_ci    } else {
8714514f5e3Sopenharmony_ci        MergeAssignment(bb, bbNext);
8724514f5e3Sopenharmony_ci    }
8734514f5e3Sopenharmony_ci    // We should connect this gate to loop begin although it's not a loop back edge
8744514f5e3Sopenharmony_ci    // if there is no merge state, which means it's the sole loop in.
8754514f5e3Sopenharmony_ci    if (bbNext.IsLoopBack(bb) || !IsGateNotEmpty(mergedContext->mergeState_)) {
8764514f5e3Sopenharmony_ci        mergedContext->loopBackIndex_++;
8774514f5e3Sopenharmony_ci    } else {
8784514f5e3Sopenharmony_ci        mergedContext->mergeIndex_++;
8794514f5e3Sopenharmony_ci    }
8804514f5e3Sopenharmony_ci    mergedContext->currentIndex_++;
8814514f5e3Sopenharmony_ci}
8824514f5e3Sopenharmony_ci
8834514f5e3Sopenharmony_cibool FrameStateBuilder::IsLoopBackEdge(const BytecodeRegion &bb, const BytecodeRegion &bbNext)
8844514f5e3Sopenharmony_ci{
8854514f5e3Sopenharmony_ci    if (bcBuilder_->IsOSR() && OutOfOsrLoop(bbNext)) {
8864514f5e3Sopenharmony_ci        return false;
8874514f5e3Sopenharmony_ci    } else if (bbNext.loopNumber > 0) {
8884514f5e3Sopenharmony_ci        auto& loopInfo = GetLoopInfo(bbNext);
8894514f5e3Sopenharmony_ci        return loopInfo.loopBodys->TestBit(bb.id);
8904514f5e3Sopenharmony_ci    }
8914514f5e3Sopenharmony_ci    return false;
8924514f5e3Sopenharmony_ci}
8934514f5e3Sopenharmony_ci
8944514f5e3Sopenharmony_ciFrameStateBuilder::LoopInfo& FrameStateBuilder::GetLoopInfo(const BytecodeRegion &bb)
8954514f5e3Sopenharmony_ci{
8964514f5e3Sopenharmony_ci    ASSERT(bb.loopNumber > 0);
8974514f5e3Sopenharmony_ci    return loops_[bb.loopNumber - 1]; // -1: for index
8984514f5e3Sopenharmony_ci}
8994514f5e3Sopenharmony_ci
9004514f5e3Sopenharmony_ciFrameStateBuilder::LoopInfo& FrameStateBuilder::GetLoopInfo(BytecodeRegion &bb)
9014514f5e3Sopenharmony_ci{
9024514f5e3Sopenharmony_ci    ASSERT(bb.loopNumber > 0);
9034514f5e3Sopenharmony_ci    return loops_[bb.loopNumber - 1]; // -1: for index
9044514f5e3Sopenharmony_ci}
9054514f5e3Sopenharmony_ci
9064514f5e3Sopenharmony_ciFrameStateBuilder::LoopInfo* FrameStateBuilder::GetLoopInfoByLoopBody(const BytecodeRegion &bb)
9074514f5e3Sopenharmony_ci{
9084514f5e3Sopenharmony_ci    if (bb.loopIndex == 0) {
9094514f5e3Sopenharmony_ci        return nullptr;
9104514f5e3Sopenharmony_ci    }
9114514f5e3Sopenharmony_ci    auto& loopInfo = loops_[bb.loopIndex - 1];
9124514f5e3Sopenharmony_ci    ASSERT(loopInfo.loopBodys->TestBit(bb.id));
9134514f5e3Sopenharmony_ci    return &loopInfo;
9144514f5e3Sopenharmony_ci}
9154514f5e3Sopenharmony_ci
9164514f5e3Sopenharmony_ciBitSet *FrameStateBuilder::GetLoopAssignment(const BytecodeRegion &bb)
9174514f5e3Sopenharmony_ci{
9184514f5e3Sopenharmony_ci    if (bb.loopNumber > 0) {
9194514f5e3Sopenharmony_ci        auto& loopInfo = GetLoopInfo(bb);
9204514f5e3Sopenharmony_ci        return loopInfo.loopAssignment;
9214514f5e3Sopenharmony_ci    }
9224514f5e3Sopenharmony_ci    return nullptr;
9234514f5e3Sopenharmony_ci}
9244514f5e3Sopenharmony_ci
9254514f5e3Sopenharmony_civoid FrameStateBuilder::AddEmptyBlock(BytecodeRegion* bb)
9264514f5e3Sopenharmony_ci{
9274514f5e3Sopenharmony_ci    bbBeginStateLiveouts_.emplace_back(nullptr);
9284514f5e3Sopenharmony_ci    bbFrameContext_.emplace_back(nullptr);
9294514f5e3Sopenharmony_ci    auto liveout = GetOrOCreateBBLiveOut(bb->id);
9304514f5e3Sopenharmony_ci    liveout->CopyFrom(liveOutResult_);
9314514f5e3Sopenharmony_ci    GetOrOCreateMergedContext(bb->id);
9324514f5e3Sopenharmony_ci    bcBuilder_->AddBasicBlock(bb);
9334514f5e3Sopenharmony_ci}
9344514f5e3Sopenharmony_ci
9354514f5e3Sopenharmony_ciclass BlockLoopAnalysis {
9364514f5e3Sopenharmony_cipublic:
9374514f5e3Sopenharmony_ci    explicit BlockLoopAnalysis(FrameStateBuilder *builder, Chunk* chunk)
9384514f5e3Sopenharmony_ci        : frameBuilder_(builder), bcBuilder_(builder->bcBuilder_),
9394514f5e3Sopenharmony_ci        pendingList_(chunk), loopbacks_(chunk),
9404514f5e3Sopenharmony_ci        dfsStack_(chunk), visitState_(chunk), chunk_(chunk) {}
9414514f5e3Sopenharmony_ci
9424514f5e3Sopenharmony_ci    void Run()
9434514f5e3Sopenharmony_ci    {
9444514f5e3Sopenharmony_ci        ComputeLoopBack();
9454514f5e3Sopenharmony_ci        if (bcBuilder_->TerminateAnalysis()) {
9464514f5e3Sopenharmony_ci            return;
9474514f5e3Sopenharmony_ci        }
9484514f5e3Sopenharmony_ci        TryClearDeadBlock();
9494514f5e3Sopenharmony_ci        bcBuilder_->ComputeNumOfLoopBack();
9504514f5e3Sopenharmony_ci        frameBuilder_->numLoops_ = numLoops_;
9514514f5e3Sopenharmony_ci        if (numLoops_ > 0) {
9524514f5e3Sopenharmony_ci            ComputeLoopInfo();
9534514f5e3Sopenharmony_ci            if (bcBuilder_->IsLogEnabled()) {
9544514f5e3Sopenharmony_ci                for (size_t i = 0; i < numLoops_; i++) {
9554514f5e3Sopenharmony_ci                    auto& loopInfo = frameBuilder_->loops_[i];
9564514f5e3Sopenharmony_ci                    PrintLoop(loopInfo);
9574514f5e3Sopenharmony_ci                }
9584514f5e3Sopenharmony_ci            }
9594514f5e3Sopenharmony_ci        }
9604514f5e3Sopenharmony_ci    }
9614514f5e3Sopenharmony_ci
9624514f5e3Sopenharmony_ci    void CountLoopBackEdge(size_t fromId, size_t toId)
9634514f5e3Sopenharmony_ci    {
9644514f5e3Sopenharmony_ci        loopbacks_.push_back({fromId, toId});
9654514f5e3Sopenharmony_ci        auto &toBlock = bcBuilder_->GetBasicBlockById(toId);
9664514f5e3Sopenharmony_ci        toBlock.loopBacks.insert(fromId);
9674514f5e3Sopenharmony_ci        if (toBlock.loopNumber == 0) {
9684514f5e3Sopenharmony_ci            toBlock.loopNumber = ++numLoops_;
9694514f5e3Sopenharmony_ci        }
9704514f5e3Sopenharmony_ci    }
9714514f5e3Sopenharmony_ci
9724514f5e3Sopenharmony_ci    void CheckDominance()
9734514f5e3Sopenharmony_ci    {
9744514f5e3Sopenharmony_ci        for (size_t i = 0; i < loopbacks_.size(); i++) {
9754514f5e3Sopenharmony_ci            auto loopBackinfo = loopbacks_[i];
9764514f5e3Sopenharmony_ci            bool isDom = bcBuilder_->IsAncestor(loopBackinfo.toId, loopBackinfo.fromId);
9774514f5e3Sopenharmony_ci            if (!isDom) {
9784514f5e3Sopenharmony_ci                bcBuilder_->SetIrreducibleLoop();
9794514f5e3Sopenharmony_ci                LOG_COMPILER(INFO) << "CFG is not reducible. Compilation aborted.";
9804514f5e3Sopenharmony_ci                break;
9814514f5e3Sopenharmony_ci            }
9824514f5e3Sopenharmony_ci        }
9834514f5e3Sopenharmony_ci    }
9844514f5e3Sopenharmony_ci
9854514f5e3Sopenharmony_ci    void ComputeLoopBack()
9864514f5e3Sopenharmony_ci    {
9874514f5e3Sopenharmony_ci        auto size = bcBuilder_->GetBasicBlockCount();
9884514f5e3Sopenharmony_ci        visitState_.resize(size, MarkState::UNVISITED);
9894514f5e3Sopenharmony_ci        size_t entryId = 0; // entry id
9904514f5e3Sopenharmony_ci        VisitedInfo info = {0, false};
9914514f5e3Sopenharmony_ci        visitedInfo_.resize(size, info);
9924514f5e3Sopenharmony_ci        pendingList_.emplace_back(entryId);
9934514f5e3Sopenharmony_ci        while (!pendingList_.empty()) {
9944514f5e3Sopenharmony_ci            size_t bbId = pendingList_.back();
9954514f5e3Sopenharmony_ci            auto &bb = bcBuilder_->GetBasicBlockById(bbId);
9964514f5e3Sopenharmony_ci            bool allVisited = true;
9974514f5e3Sopenharmony_ci            visitState_[bbId] = MarkState::PENDING;
9984514f5e3Sopenharmony_ci            BytecodeRegion* catchBlock = bb.catches.empty() ? nullptr : bb.catches.at(0);
9994514f5e3Sopenharmony_ci            for (size_t i = visitedInfo_[bbId].needVisitIndex; i < bb.succs.size(); i++) {
10004514f5e3Sopenharmony_ci                BytecodeRegion* succBlock = bb.succs[i];
10014514f5e3Sopenharmony_ci                size_t succId = succBlock->id;
10024514f5e3Sopenharmony_ci                visitedInfo_[bbId].needVisitIndex = i + 1;
10034514f5e3Sopenharmony_ci                if (visitState_[succId] == MarkState::UNVISITED) {
10044514f5e3Sopenharmony_ci                    pendingList_.emplace_back(succId);
10054514f5e3Sopenharmony_ci                    visitState_[succId] = MarkState::ON_STACK;
10064514f5e3Sopenharmony_ci                    allVisited = false;
10074514f5e3Sopenharmony_ci                    break;
10084514f5e3Sopenharmony_ci                } else if (visitState_[succId] == MarkState::PENDING) {
10094514f5e3Sopenharmony_ci                    // back edge
10104514f5e3Sopenharmony_ci                    CountLoopBackEdge(bbId, succId);
10114514f5e3Sopenharmony_ci                }
10124514f5e3Sopenharmony_ci            }
10134514f5e3Sopenharmony_ci            // we consider catchBlock as a special succ, which means if we have visited a succ,
10144514f5e3Sopenharmony_ci            // visiting catchBlock is not allowed due to the rule of RPO.
10154514f5e3Sopenharmony_ci            if (allVisited && catchBlock != nullptr && !visitedInfo_[bbId].isVisitedCatchBlock) {
10164514f5e3Sopenharmony_ci                size_t catchId = catchBlock->id;
10174514f5e3Sopenharmony_ci                visitedInfo_[bbId].isVisitedCatchBlock = true;
10184514f5e3Sopenharmony_ci                if (visitState_[catchId] == MarkState::UNVISITED) {
10194514f5e3Sopenharmony_ci                    pendingList_.emplace_back(catchId);
10204514f5e3Sopenharmony_ci                    visitState_[catchId] = MarkState::ON_STACK;
10214514f5e3Sopenharmony_ci                    allVisited = false;
10224514f5e3Sopenharmony_ci                } else if (visitState_[catchId] == MarkState::PENDING) {
10234514f5e3Sopenharmony_ci                    // back edge
10244514f5e3Sopenharmony_ci                    CountLoopBackEdge(bbId, catchId);
10254514f5e3Sopenharmony_ci                }
10264514f5e3Sopenharmony_ci            }
10274514f5e3Sopenharmony_ci            if (allVisited) {
10284514f5e3Sopenharmony_ci                visitState_[bbId] = MarkState::VISITED;
10294514f5e3Sopenharmony_ci                pendingList_.pop_back();
10304514f5e3Sopenharmony_ci                frameBuilder_->rpoList_.push_front(bbId);
10314514f5e3Sopenharmony_ci            }
10324514f5e3Sopenharmony_ci        }
10334514f5e3Sopenharmony_ci
10344514f5e3Sopenharmony_ci        if (bcBuilder_->NeedIrreducibleLoopCheck()) {
10354514f5e3Sopenharmony_ci            CheckDominance();
10364514f5e3Sopenharmony_ci        }
10374514f5e3Sopenharmony_ci    }
10384514f5e3Sopenharmony_ci
10394514f5e3Sopenharmony_ci    void TryClearDeadBlock()
10404514f5e3Sopenharmony_ci    {
10414514f5e3Sopenharmony_ci        if (frameBuilder_->rpoList_.size() == bcBuilder_->NumberOfLiveBlock()) {
10424514f5e3Sopenharmony_ci            return;
10434514f5e3Sopenharmony_ci        }
10444514f5e3Sopenharmony_ci        auto size = bcBuilder_->GetBasicBlockCount();
10454514f5e3Sopenharmony_ci        for (size_t i = 0; i < size; i++) {
10464514f5e3Sopenharmony_ci            auto &bb = bcBuilder_->GetBasicBlockById(i);
10474514f5e3Sopenharmony_ci            if (bb.numOfStatePreds != 0 && visitState_[i] == MarkState::UNVISITED) {
10484514f5e3Sopenharmony_ci                bb.numOfStatePreds = 0;
10494514f5e3Sopenharmony_ci            }
10504514f5e3Sopenharmony_ci        }
10514514f5e3Sopenharmony_ci        bcBuilder_->RemoveUnreachableRegion();
10524514f5e3Sopenharmony_ci    }
10534514f5e3Sopenharmony_ci
10544514f5e3Sopenharmony_ci    void CountLoopBody(FrameStateBuilder::LoopInfo& loopInfo, size_t bbId)
10554514f5e3Sopenharmony_ci    {
10564514f5e3Sopenharmony_ci        if (bbId != loopInfo.loopHeadId && !loopInfo.loopBodys->TestBit(bbId)) {
10574514f5e3Sopenharmony_ci            loopInfo.loopBodys->SetBit(bbId);
10584514f5e3Sopenharmony_ci            pendingList_.emplace_back(bbId);
10594514f5e3Sopenharmony_ci            auto liveout = frameBuilder_->GetOrOCreateBBLiveOut(bbId);
10604514f5e3Sopenharmony_ci            ASSERT(liveout != nullptr);
10614514f5e3Sopenharmony_ci            loopInfo.loopAssignment->Union(liveout->defRegisters_);
10624514f5e3Sopenharmony_ci        }
10634514f5e3Sopenharmony_ci    }
10644514f5e3Sopenharmony_ci
10654514f5e3Sopenharmony_ci    void PropagateLoopBody(FrameStateBuilder::LoopInfo& loopInfo)
10664514f5e3Sopenharmony_ci    {
10674514f5e3Sopenharmony_ci        while (!pendingList_.empty()) {
10684514f5e3Sopenharmony_ci            auto cur = pendingList_.back();
10694514f5e3Sopenharmony_ci            auto &curBlock = bcBuilder_->GetBasicBlockById(cur);
10704514f5e3Sopenharmony_ci            pendingList_.pop_back();
10714514f5e3Sopenharmony_ci            for (auto pred : curBlock.preds) {
10724514f5e3Sopenharmony_ci                CountLoopBody(loopInfo, pred->id);
10734514f5e3Sopenharmony_ci            }
10744514f5e3Sopenharmony_ci            for (auto pred : curBlock.trys) {
10754514f5e3Sopenharmony_ci                CountLoopBody(loopInfo, pred->id);
10764514f5e3Sopenharmony_ci            }
10774514f5e3Sopenharmony_ci        }
10784514f5e3Sopenharmony_ci    }
10794514f5e3Sopenharmony_ci
10804514f5e3Sopenharmony_ci    void InitLoopInfo(FrameStateBuilder::LoopInfo& loopInfo, BytecodeRegion& loopHeader, size_t backId)
10814514f5e3Sopenharmony_ci    {
10824514f5e3Sopenharmony_ci        if (loopInfo.loopHeadId == 0) {
10834514f5e3Sopenharmony_ci            auto size = bcBuilder_->GetBasicBlockCount();
10844514f5e3Sopenharmony_ci            loopInfo.loopHeadId = loopHeader.id;
10854514f5e3Sopenharmony_ci            loopInfo.loopIndex = loopHeader.loopNumber;
10864514f5e3Sopenharmony_ci            loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
10874514f5e3Sopenharmony_ci            loopInfo.loopAssignment = chunk_->New<BitSet>(chunk_, frameBuilder_->numVregs_);
10884514f5e3Sopenharmony_ci            loopHeader.loopIndex = loopInfo.loopIndex;
10894514f5e3Sopenharmony_ci            loopInfo.loopBodys->SetBit(loopInfo.loopHeadId);
10904514f5e3Sopenharmony_ci            auto liveout = frameBuilder_->GetOrOCreateBBLiveOut(loopInfo.loopHeadId);
10914514f5e3Sopenharmony_ci            loopInfo.loopAssignment->Union(liveout->defRegisters_);
10924514f5e3Sopenharmony_ci            loopInfo.numLoopBacks = 1;
10934514f5e3Sopenharmony_ci            loopInfo.loopBodys->SetBit(backId);
10944514f5e3Sopenharmony_ci        } else {
10954514f5e3Sopenharmony_ci            if (!loopInfo.loopBodys->TestBit(backId)) {
10964514f5e3Sopenharmony_ci                loopInfo.loopBodys->SetBit(backId);
10974514f5e3Sopenharmony_ci            }
10984514f5e3Sopenharmony_ci            loopInfo.numLoopBacks++;
10994514f5e3Sopenharmony_ci        }
11004514f5e3Sopenharmony_ci    }
11014514f5e3Sopenharmony_ci
11024514f5e3Sopenharmony_ci    void ComputeLoopInfo()
11034514f5e3Sopenharmony_ci    {
11044514f5e3Sopenharmony_ci        frameBuilder_->loops_.resize(numLoops_, FrameStateBuilder::LoopInfo());
11054514f5e3Sopenharmony_ci        for (auto& info : loopbacks_) {
11064514f5e3Sopenharmony_ci            auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
11074514f5e3Sopenharmony_ci            auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
11084514f5e3Sopenharmony_ci            InitLoopInfo(loopInfo, toBlock, info.fromId);
11094514f5e3Sopenharmony_ci        }
11104514f5e3Sopenharmony_ci        TryMergeLoopEntry();
11114514f5e3Sopenharmony_ci        ResizeLoopBody(); // tryMerge will insert region, need resize loop body.
11124514f5e3Sopenharmony_ci        for (auto& info : loopbacks_) {
11134514f5e3Sopenharmony_ci            auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
11144514f5e3Sopenharmony_ci            auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
11154514f5e3Sopenharmony_ci            CountLoopBody(loopInfo, info.fromId);
11164514f5e3Sopenharmony_ci            PropagateLoopBody(loopInfo);
11174514f5e3Sopenharmony_ci        }
11184514f5e3Sopenharmony_ci
11194514f5e3Sopenharmony_ci        if (!bcBuilder_->EnableLoopOptimization() && !bcBuilder_->IsOSR()) {
11204514f5e3Sopenharmony_ci            return;
11214514f5e3Sopenharmony_ci        }
11224514f5e3Sopenharmony_ci
11234514f5e3Sopenharmony_ci        auto size = bcBuilder_->GetBasicBlockCount();
11244514f5e3Sopenharmony_ci        dfsStack_.resize(size, DFSState(0, 0));
11254514f5e3Sopenharmony_ci        ComputeLoopTree();
11264514f5e3Sopenharmony_ci    }
11274514f5e3Sopenharmony_ci
11284514f5e3Sopenharmony_ci    void InsertEmptyBytecodeRegion(FrameStateBuilder::LoopInfo& loopInfo,
11294514f5e3Sopenharmony_ci        BytecodeRegion& loopHeader, size_t numOfEntries)
11304514f5e3Sopenharmony_ci    {
11314514f5e3Sopenharmony_ci        auto size = bcBuilder_->GetBasicBlockCount();
11324514f5e3Sopenharmony_ci        auto block = chunk_->New<BytecodeRegion>(chunk_);
11334514f5e3Sopenharmony_ci        block->id = size;
11344514f5e3Sopenharmony_ci        block->numOfStatePreds = numOfEntries;
11354514f5e3Sopenharmony_ci        block->start = loopHeader.start;
11364514f5e3Sopenharmony_ci        ASSERT(loopHeader.start != 0);
11374514f5e3Sopenharmony_ci        block->end = BytecodeIterator::INVALID_INDEX;
11384514f5e3Sopenharmony_ci        block->bytecodeIterator_.Reset(bcBuilder_, block->start, block->end);
11394514f5e3Sopenharmony_ci
11404514f5e3Sopenharmony_ci        frameBuilder_->liveOutResult_->Reset();
11414514f5e3Sopenharmony_ci        for (auto it = loopHeader.preds.begin(); it != loopHeader.preds.end();) {
11424514f5e3Sopenharmony_ci            auto bbPred = *it;
11434514f5e3Sopenharmony_ci            // not loop back
11444514f5e3Sopenharmony_ci            if (!loopInfo.loopBodys->TestBit(bbPred->id)) {
11454514f5e3Sopenharmony_ci                it = loopHeader.preds.erase(it);
11464514f5e3Sopenharmony_ci                std::replace(bbPred->succs.begin(), bbPred->succs.end(), &loopHeader, block);
11474514f5e3Sopenharmony_ci                block->preds.emplace_back(bbPred);
11484514f5e3Sopenharmony_ci            } else {
11494514f5e3Sopenharmony_ci                it++;
11504514f5e3Sopenharmony_ci            }
11514514f5e3Sopenharmony_ci        }
11524514f5e3Sopenharmony_ci        frameBuilder_->MergeFromSuccBB(loopHeader.id);
11534514f5e3Sopenharmony_ci        block->succs.emplace_back(&loopHeader);
11544514f5e3Sopenharmony_ci        loopHeader.preds.insert(loopHeader.preds.begin(), block);
11554514f5e3Sopenharmony_ci        frameBuilder_->AddEmptyBlock(block);
11564514f5e3Sopenharmony_ci
11574514f5e3Sopenharmony_ci        ASSERT(loopHeader.trys.empty() && numOfEntries > 0);
11584514f5e3Sopenharmony_ci        loopHeader.numOfStatePreds -= (numOfEntries - 1); // 1: one entry
11594514f5e3Sopenharmony_ci        auto it = std::find(frameBuilder_->rpoList_.begin(), frameBuilder_->rpoList_.end(), loopHeader.id);
11604514f5e3Sopenharmony_ci        ASSERT(it != frameBuilder_->rpoList_.end());
11614514f5e3Sopenharmony_ci        frameBuilder_->rpoList_.insert(it, block->id);
11624514f5e3Sopenharmony_ci        visitState_.emplace_back(MarkState::UNVISITED1);
11634514f5e3Sopenharmony_ci    }
11644514f5e3Sopenharmony_ci
11654514f5e3Sopenharmony_ci    void TryMergeLoopEntry()
11664514f5e3Sopenharmony_ci    {
11674514f5e3Sopenharmony_ci        for (size_t i = 0; i < numLoops_; i++) {
11684514f5e3Sopenharmony_ci            auto& loopInfo = frameBuilder_->loops_[i];
11694514f5e3Sopenharmony_ci            auto& loopHeader = bcBuilder_->GetBasicBlockById(loopInfo.loopHeadId);
11704514f5e3Sopenharmony_ci            ASSERT(loopHeader.numOfStatePreds > loopInfo.numLoopBacks);
11714514f5e3Sopenharmony_ci            size_t numOfEntries = static_cast<size_t>(loopHeader.numOfStatePreds - loopInfo.numLoopBacks);
11724514f5e3Sopenharmony_ci            if (numOfEntries > 1 && loopHeader.trys.size() == 0) {
11734514f5e3Sopenharmony_ci                InsertEmptyBytecodeRegion(loopInfo, loopHeader, numOfEntries);
11744514f5e3Sopenharmony_ci            }
11754514f5e3Sopenharmony_ci            // clear loopback bits for visit body
11764514f5e3Sopenharmony_ci            loopInfo.loopBodys->Reset();
11774514f5e3Sopenharmony_ci            loopInfo.loopBodys->SetBit(loopInfo.loopHeadId);
11784514f5e3Sopenharmony_ci        }
11794514f5e3Sopenharmony_ci    }
11804514f5e3Sopenharmony_ci
11814514f5e3Sopenharmony_ci    void ResizeLoopBody()
11824514f5e3Sopenharmony_ci    {
11834514f5e3Sopenharmony_ci        for (auto& info : loopbacks_) {
11844514f5e3Sopenharmony_ci            auto size = bcBuilder_->GetBasicBlockCount();
11854514f5e3Sopenharmony_ci            auto& toBlock = bcBuilder_->GetBasicBlockById(info.toId);
11864514f5e3Sopenharmony_ci            auto& loopInfo = frameBuilder_->GetLoopInfo(toBlock);
11874514f5e3Sopenharmony_ci            if (loopInfo.loopBodys->ShouldExpand(size)) {
11884514f5e3Sopenharmony_ci                auto tmp = loopInfo.loopBodys;
11894514f5e3Sopenharmony_ci                loopInfo.loopBodys = chunk_->New<BitSet>(chunk_, size);
11904514f5e3Sopenharmony_ci                loopInfo.loopBodys->CopyDataFrom(*tmp);
11914514f5e3Sopenharmony_ci            }
11924514f5e3Sopenharmony_ci        }
11934514f5e3Sopenharmony_ci    }
11944514f5e3Sopenharmony_ci
11954514f5e3Sopenharmony_ci    FrameStateBuilder::LoopInfo* EnterInnerLoop(FrameStateBuilder::LoopInfo* loopInfo, size_t bbId)
11964514f5e3Sopenharmony_ci    {
11974514f5e3Sopenharmony_ci        auto &bb = bcBuilder_->GetBasicBlockById(bbId);
11984514f5e3Sopenharmony_ci        if (bb.loopNumber > 0) {
11994514f5e3Sopenharmony_ci            auto &innerInfo = frameBuilder_->GetLoopInfo(bb);
12004514f5e3Sopenharmony_ci            ASSERT(innerInfo.parentInfo == nullptr);
12014514f5e3Sopenharmony_ci            innerInfo.parentInfo = loopInfo;
12024514f5e3Sopenharmony_ci            innerInfo.sortIndx = frameBuilder_->sortIndx_++;
12034514f5e3Sopenharmony_ci            loopInfo = &innerInfo;
12044514f5e3Sopenharmony_ci        } else if (loopInfo != nullptr) {
12054514f5e3Sopenharmony_ci            bb.loopIndex = loopInfo->loopIndex;
12064514f5e3Sopenharmony_ci        }
12074514f5e3Sopenharmony_ci        return loopInfo;
12084514f5e3Sopenharmony_ci    }
12094514f5e3Sopenharmony_ci
12104514f5e3Sopenharmony_ci    void ComputeLoopTree()
12114514f5e3Sopenharmony_ci    {
12124514f5e3Sopenharmony_ci        FrameStateBuilder::LoopInfo* loopInfo = nullptr;
12134514f5e3Sopenharmony_ci        auto currentDepth = Push(0, 0); // entry id
12144514f5e3Sopenharmony_ci        while (currentDepth > 0) {
12154514f5e3Sopenharmony_ci            auto &curState = dfsStack_[currentDepth - 1]; // -1: for current
12164514f5e3Sopenharmony_ci            auto const &bb = bcBuilder_->GetBasicBlockById(curState.bbId);
12174514f5e3Sopenharmony_ci            if (!bcBuilder_->IsOSR()) {
12184514f5e3Sopenharmony_ci                ASSERT(bb.catches.empty());
12194514f5e3Sopenharmony_ci            }
12204514f5e3Sopenharmony_ci            auto index = curState.index;
12214514f5e3Sopenharmony_ci            BytecodeRegion* bbNext = nullptr;
12224514f5e3Sopenharmony_ci            if (index >= bb.succs.size()) {
12234514f5e3Sopenharmony_ci                if (bb.loopNumber > 0) {
12244514f5e3Sopenharmony_ci                    if (visitState_[curState.bbId] == MarkState::ON_STACK) {
12254514f5e3Sopenharmony_ci                        if (loopInfo == nullptr) {
12264514f5e3Sopenharmony_ci                            continue;
12274514f5e3Sopenharmony_ci                        }
12284514f5e3Sopenharmony_ci                        ASSERT(loopInfo->loopHeadId == curState.bbId);
12294514f5e3Sopenharmony_ci                        loopInfo = loopInfo->parentInfo;
12304514f5e3Sopenharmony_ci                        visitState_[curState.bbId] = MarkState::VISITED1;
12314514f5e3Sopenharmony_ci                    }
12324514f5e3Sopenharmony_ci                    bbNext = PushLoopExist(bb, currentDepth);
12334514f5e3Sopenharmony_ci                }
12344514f5e3Sopenharmony_ci            } else {
12354514f5e3Sopenharmony_ci                bbNext = bb.succs[curState.index++]; // 1: goto next
12364514f5e3Sopenharmony_ci            }
12374514f5e3Sopenharmony_ci            if (bbNext != nullptr) {
12384514f5e3Sopenharmony_ci                if (loopInfo != nullptr && !loopInfo->loopBodys->TestBit(bbNext->id)) {
12394514f5e3Sopenharmony_ci                    AddLoopExit(bbNext, loopInfo);
12404514f5e3Sopenharmony_ci                } else if (visitState_[bbNext->id] == MarkState::UNVISITED1) {
12414514f5e3Sopenharmony_ci                    currentDepth = Push(bbNext->id, currentDepth);
12424514f5e3Sopenharmony_ci                    loopInfo = EnterInnerLoop(loopInfo, bbNext->id);
12434514f5e3Sopenharmony_ci                }
12444514f5e3Sopenharmony_ci            } else {
12454514f5e3Sopenharmony_ci                if (bb.loopNumber == 0) {
12464514f5e3Sopenharmony_ci                    visitState_[curState.bbId] = MarkState::VISITED1;
12474514f5e3Sopenharmony_ci                }
12484514f5e3Sopenharmony_ci                currentDepth--;
12494514f5e3Sopenharmony_ci            }
12504514f5e3Sopenharmony_ci        }
12514514f5e3Sopenharmony_ci    }
12524514f5e3Sopenharmony_ci
12534514f5e3Sopenharmony_ci    size_t Push(size_t bbId, size_t depth)
12544514f5e3Sopenharmony_ci    {
12554514f5e3Sopenharmony_ci        if (visitState_[bbId] == MarkState::UNVISITED1) {
12564514f5e3Sopenharmony_ci            dfsStack_[depth].bbId = bbId;
12574514f5e3Sopenharmony_ci            dfsStack_[depth].index = 0;
12584514f5e3Sopenharmony_ci            visitState_[bbId] = MarkState::ON_STACK;
12594514f5e3Sopenharmony_ci            return depth + 1;
12604514f5e3Sopenharmony_ci        }
12614514f5e3Sopenharmony_ci        return depth;
12624514f5e3Sopenharmony_ci    }
12634514f5e3Sopenharmony_ci
12644514f5e3Sopenharmony_ci    BytecodeRegion* PushLoopExist(const BytecodeRegion& bb, size_t depth)
12654514f5e3Sopenharmony_ci    {
12664514f5e3Sopenharmony_ci        ASSERT(depth > 0);
12674514f5e3Sopenharmony_ci        auto &curState = dfsStack_[depth - 1]; // -1: for current
12684514f5e3Sopenharmony_ci        auto loopExitIndex = curState.index - bb.succs.size();
12694514f5e3Sopenharmony_ci        auto& currentInfo = frameBuilder_->GetLoopInfo(bb);
12704514f5e3Sopenharmony_ci        BytecodeRegion* bbNext = nullptr;
12714514f5e3Sopenharmony_ci        if (currentInfo.loopExits != nullptr && loopExitIndex < currentInfo.loopExits->size()) {
12724514f5e3Sopenharmony_ci            bbNext = currentInfo.loopExits->at(loopExitIndex);
12734514f5e3Sopenharmony_ci            curState.index++; // 1: goto next
12744514f5e3Sopenharmony_ci        }
12754514f5e3Sopenharmony_ci        return bbNext;
12764514f5e3Sopenharmony_ci    }
12774514f5e3Sopenharmony_ci
12784514f5e3Sopenharmony_ci    void AddLoopExit(BytecodeRegion *bb, FrameStateBuilder::LoopInfo *loopInfo)
12794514f5e3Sopenharmony_ci    {
12804514f5e3Sopenharmony_ci        if (loopInfo->loopExits == nullptr) {
12814514f5e3Sopenharmony_ci            loopInfo->loopExits = chunk_->New<ChunkVector<BytecodeRegion*>>(chunk_);
12824514f5e3Sopenharmony_ci        }
12834514f5e3Sopenharmony_ci        loopInfo->loopExits->emplace_back(bb);
12844514f5e3Sopenharmony_ci    }
12854514f5e3Sopenharmony_ci
12864514f5e3Sopenharmony_ci    void PrintLoop(FrameStateBuilder::LoopInfo& loopInfo)
12874514f5e3Sopenharmony_ci    {
12884514f5e3Sopenharmony_ci        auto size = bcBuilder_->GetBasicBlockCount();
12894514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "--------------------------------- LoopInfo Start ---------------------------------";
12904514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "LoopHead: " << loopInfo.loopHeadId;
12914514f5e3Sopenharmony_ci        if (loopInfo.parentInfo != nullptr) {
12924514f5e3Sopenharmony_ci            LOG_COMPILER(INFO) << "ParentLoopHead: " << loopInfo.parentInfo->loopHeadId;
12934514f5e3Sopenharmony_ci        }
12944514f5e3Sopenharmony_ci        std::string log = "Body: [";
12954514f5e3Sopenharmony_ci        for (size_t i = 0; i < size; i++) {
12964514f5e3Sopenharmony_ci            if (loopInfo.loopBodys->TestBit(i)) {
12974514f5e3Sopenharmony_ci                log += std::to_string(i) + ", ";
12984514f5e3Sopenharmony_ci            }
12994514f5e3Sopenharmony_ci        }
13004514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << log << "]";
13014514f5e3Sopenharmony_ci        std::string log1 = "Exit: [";
13024514f5e3Sopenharmony_ci        if (loopInfo.loopExits != nullptr) {
13034514f5e3Sopenharmony_ci            for (auto bb : *loopInfo.loopExits) {
13044514f5e3Sopenharmony_ci                log1 += std::to_string(bb->id) + ", ";
13054514f5e3Sopenharmony_ci            }
13064514f5e3Sopenharmony_ci        }
13074514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << log1 << "]";
13084514f5e3Sopenharmony_ci        std::string log2 = "LoopAssignment [";
13094514f5e3Sopenharmony_ci        bool firset = true;
13104514f5e3Sopenharmony_ci        for (size_t i = 0; i < frameBuilder_->numVregs_; i++) {
13114514f5e3Sopenharmony_ci            if (loopInfo.loopAssignment->TestBit(i)) {
13124514f5e3Sopenharmony_ci                if (!firset) {
13134514f5e3Sopenharmony_ci                    log2 += ",";
13144514f5e3Sopenharmony_ci                }
13154514f5e3Sopenharmony_ci                firset = false;
13164514f5e3Sopenharmony_ci                log2 += std::to_string(i);
13174514f5e3Sopenharmony_ci            }
13184514f5e3Sopenharmony_ci        }
13194514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << log2 << "]";
13204514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << "--------------------------------- LoopInfo End ---------------------------------";
13214514f5e3Sopenharmony_ci    }
13224514f5e3Sopenharmony_ci
13234514f5e3Sopenharmony_ciprivate:
13244514f5e3Sopenharmony_ci    struct EndToHead {
13254514f5e3Sopenharmony_ci        size_t fromId;
13264514f5e3Sopenharmony_ci        size_t toId;
13274514f5e3Sopenharmony_ci    };
13284514f5e3Sopenharmony_ci    struct DFSState {
13294514f5e3Sopenharmony_ci        DFSState(size_t bbId, size_t index)
13304514f5e3Sopenharmony_ci            : bbId(bbId), index(index) {}
13314514f5e3Sopenharmony_ci
13324514f5e3Sopenharmony_ci        size_t bbId;
13334514f5e3Sopenharmony_ci        size_t index;
13344514f5e3Sopenharmony_ci    };
13354514f5e3Sopenharmony_ci    struct VisitedInfo {
13364514f5e3Sopenharmony_ci        size_t needVisitIndex;
13374514f5e3Sopenharmony_ci        bool isVisitedCatchBlock = false;
13384514f5e3Sopenharmony_ci    };
13394514f5e3Sopenharmony_ci    enum class MarkState : uint8_t {
13404514f5e3Sopenharmony_ci        UNVISITED = 0,
13414514f5e3Sopenharmony_ci        ON_STACK,
13424514f5e3Sopenharmony_ci        PENDING,
13434514f5e3Sopenharmony_ci        VISITED,
13444514f5e3Sopenharmony_ci        VISITED1,
13454514f5e3Sopenharmony_ci        UNVISITED1 = VISITED
13464514f5e3Sopenharmony_ci    };
13474514f5e3Sopenharmony_ci    FrameStateBuilder* frameBuilder_ {nullptr};
13484514f5e3Sopenharmony_ci    BytecodeCircuitBuilder *bcBuilder_ {nullptr};
13494514f5e3Sopenharmony_ci    ChunkDeque<size_t> pendingList_;
13504514f5e3Sopenharmony_ci    ChunkVector<EndToHead> loopbacks_;
13514514f5e3Sopenharmony_ci    ChunkVector<DFSState> dfsStack_;
13524514f5e3Sopenharmony_ci    ChunkVector<MarkState> visitState_;
13534514f5e3Sopenharmony_ci    Chunk* chunk_ {nullptr};
13544514f5e3Sopenharmony_ci    size_t numLoops_ {0};
13554514f5e3Sopenharmony_ci    std::vector<VisitedInfo> visitedInfo_;
13564514f5e3Sopenharmony_ci};
13574514f5e3Sopenharmony_ci
13584514f5e3Sopenharmony_civoid FrameStateBuilder::ComputeLoopInfo()
13594514f5e3Sopenharmony_ci{
13604514f5e3Sopenharmony_ci    BlockLoopAnalysis loopAnalysis(this, circuit_->chunk());
13614514f5e3Sopenharmony_ci    loopAnalysis.Run();
13624514f5e3Sopenharmony_ci    if (numLoops_ != 0 && !bcBuilder_->HasIrreducibleLoop()) {
13634514f5e3Sopenharmony_ci        ChunkVector<GateRef>& headerGates = bcBuilder_->GetLoopHeaderGates();
13644514f5e3Sopenharmony_ci        headerGates.resize(numLoops_, Circuit::NullGate());
13654514f5e3Sopenharmony_ci    }
13664514f5e3Sopenharmony_ci}
13674514f5e3Sopenharmony_ci
13684514f5e3Sopenharmony_civoid FrameStateBuilder::DumpLiveState()
13694514f5e3Sopenharmony_ci{
13704514f5e3Sopenharmony_ci    LOG_COMPILER(INFO) << "DumpLiveState";
13714514f5e3Sopenharmony_ci    for (size_t i = 0; i < bcEndStateLiveouts_.size(); i++) {
13724514f5e3Sopenharmony_ci        auto liveout = GetFrameLiveoutAfter(i);
13734514f5e3Sopenharmony_ci        if (liveout == nullptr) {
13744514f5e3Sopenharmony_ci            continue;
13754514f5e3Sopenharmony_ci        }
13764514f5e3Sopenharmony_ci        std::string log = "BC: " + std::to_string(i) + " {";
13774514f5e3Sopenharmony_ci        bool firset = true;
13784514f5e3Sopenharmony_ci        for (size_t j = 0; j < numVregs_; j++) {
13794514f5e3Sopenharmony_ci            if (liveout->TestBit(j)) {
13804514f5e3Sopenharmony_ci                if (!firset) {
13814514f5e3Sopenharmony_ci                    log += ",";
13824514f5e3Sopenharmony_ci                }
13834514f5e3Sopenharmony_ci                firset = false;
13844514f5e3Sopenharmony_ci                log += std::to_string(j);
13854514f5e3Sopenharmony_ci            }
13864514f5e3Sopenharmony_ci        }
13874514f5e3Sopenharmony_ci        log += "}";
13884514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << log;
13894514f5e3Sopenharmony_ci    }
13904514f5e3Sopenharmony_ci    for (size_t i = 1; i < bbBeginStateLiveouts_.size(); i++) { // 1: skip entry
13914514f5e3Sopenharmony_ci        auto liveout = GetFrameLiveoutBefore(i);
13924514f5e3Sopenharmony_ci        if (liveout == nullptr) {
13934514f5e3Sopenharmony_ci            continue;
13944514f5e3Sopenharmony_ci        }
13954514f5e3Sopenharmony_ci        std::string log = "BB: " + std::to_string(i) + " {";
13964514f5e3Sopenharmony_ci        bool firset = true;
13974514f5e3Sopenharmony_ci        for (size_t j = 0; j < numVregs_; j++) {
13984514f5e3Sopenharmony_ci            if (liveout->TestBit(j)) {
13994514f5e3Sopenharmony_ci                if (!firset) {
14004514f5e3Sopenharmony_ci                    log += ",";
14014514f5e3Sopenharmony_ci                }
14024514f5e3Sopenharmony_ci                firset = false;
14034514f5e3Sopenharmony_ci                log += std::to_string(j);
14044514f5e3Sopenharmony_ci            }
14054514f5e3Sopenharmony_ci        }
14064514f5e3Sopenharmony_ci        log += "}";
14074514f5e3Sopenharmony_ci        LOG_COMPILER(INFO) << log;
14084514f5e3Sopenharmony_ci    }
14094514f5e3Sopenharmony_ci}
14104514f5e3Sopenharmony_ci
14114514f5e3Sopenharmony_ciGateRef FrameStateBuilder::BuildFrameState(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex)
14124514f5e3Sopenharmony_ci{
14134514f5e3Sopenharmony_ci    auto pcOffset = bcBuilder_->GetPcOffset(bcIndex);
14144514f5e3Sopenharmony_ci    GateRef gateValues = BuildFrameValues(frameContext, liveout);
14154514f5e3Sopenharmony_ci
14164514f5e3Sopenharmony_ci    GateRef frameArgs = bcBuilder_->GetFrameArgs();
14174514f5e3Sopenharmony_ci    GateRef preFrameState = bcBuilder_->GetPreFrameState();
14184514f5e3Sopenharmony_ci    UInt32PairAccessor accessor(static_cast<uint32_t>(pcOffset),
14194514f5e3Sopenharmony_ci        FrameStateOutput::Invalid().GetValue());
14204514f5e3Sopenharmony_ci    auto frameState = circuit_->NewGate(circuit_->FrameState(accessor.ToValue()),
14214514f5e3Sopenharmony_ci        {frameArgs, gateValues, preFrameState});
14224514f5e3Sopenharmony_ci    return frameState;
14234514f5e3Sopenharmony_ci}
14244514f5e3Sopenharmony_ci
14254514f5e3Sopenharmony_ciGateRef FrameStateBuilder::BuildStateSplit(FrameContext* frameContext, FrameLiveOut* liveout, size_t bcIndex)
14264514f5e3Sopenharmony_ci{
14274514f5e3Sopenharmony_ci    auto frameState = BuildFrameState(frameContext, liveout, bcIndex);
14284514f5e3Sopenharmony_ci    auto state = frameContext->currentState_;
14294514f5e3Sopenharmony_ci    auto depend = frameContext->currentDepend_;
14304514f5e3Sopenharmony_ci    ASSERT(IsGateNotEmpty(state));
14314514f5e3Sopenharmony_ci    ASSERT(IsGateNotEmpty(depend));
14324514f5e3Sopenharmony_ci    return circuit_->NewGate(circuit_->StateSplit(), {state, depend, frameState});
14334514f5e3Sopenharmony_ci}
14344514f5e3Sopenharmony_ci
14354514f5e3Sopenharmony_civoid FrameStateBuilder::BindStateSplitBefore(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId)
14364514f5e3Sopenharmony_ci{
14374514f5e3Sopenharmony_ci    if (!bcBuilder_->IsTypeLoweringEnabled()) {
14384514f5e3Sopenharmony_ci        return;
14394514f5e3Sopenharmony_ci    }
14404514f5e3Sopenharmony_ci    if (bytecodeInfo.IsCall() || bytecodeInfo.IsAccessorBC()) {
14414514f5e3Sopenharmony_ci        frameStateCache_ = BuildFrameState(liveContext_, liveout, bcId);
14424514f5e3Sopenharmony_ci    }
14434514f5e3Sopenharmony_ci    ASSERT(!liveContext_->needStateSplit_);
14444514f5e3Sopenharmony_ci}
14454514f5e3Sopenharmony_ci
14464514f5e3Sopenharmony_civoid FrameStateBuilder::BindStateSplitAfter(const BytecodeInfo &bytecodeInfo,
14474514f5e3Sopenharmony_ci    uint32_t bcId, GateRef gate)
14484514f5e3Sopenharmony_ci{
14494514f5e3Sopenharmony_ci    if (!bcBuilder_->IsTypeLoweringEnabled()) {
14504514f5e3Sopenharmony_ci        return;
14514514f5e3Sopenharmony_ci    }
14524514f5e3Sopenharmony_ci    if (bytecodeInfo.IsCall() || bytecodeInfo.IsAccessorBC()) {
14534514f5e3Sopenharmony_ci        auto frameState = GetBcFrameStateCache();
14544514f5e3Sopenharmony_ci        acc_.ReplaceFrameStateIn(gate, frameState);
14554514f5e3Sopenharmony_ci    }
14564514f5e3Sopenharmony_ci    if (!bytecodeInfo.NoSideEffects() && !bytecodeInfo.IsThrow()) {
14574514f5e3Sopenharmony_ci        auto stateSplit = BuildStateSplit(liveContext_, GetOrOCreateBCEndLiveOut(bcId), bcId + 1); // 1: for after
14584514f5e3Sopenharmony_ci        liveContext_->currentDepend_ = stateSplit;
14594514f5e3Sopenharmony_ci    }
14604514f5e3Sopenharmony_ci}
14614514f5e3Sopenharmony_ci
14624514f5e3Sopenharmony_ciGateRef FrameStateBuilder::BuildFrameValues(FrameContext* frameContext, FrameLiveOut* liveout)
14634514f5e3Sopenharmony_ci{
14644514f5e3Sopenharmony_ci    size_t frameStateInputs = numVregs_;
14654514f5e3Sopenharmony_ci    std::vector<GateRef> inList(frameStateInputs, Circuit::NullGate());
14664514f5e3Sopenharmony_ci    auto optimizedGate = circuit_->GetConstantGate(MachineType::I64,
14674514f5e3Sopenharmony_ci                                                   JSTaggedValue::VALUE_OPTIMIZED_OUT,
14684514f5e3Sopenharmony_ci                                                   GateType::TaggedValue());
14694514f5e3Sopenharmony_ci    for (size_t i = 0; i < numVregs_; i++) {
14704514f5e3Sopenharmony_ci        auto value = frameContext->ValuesAt(i);
14714514f5e3Sopenharmony_ci        if (!IsGateNotEmpty(value) || !liveout->TestBit(i)) {
14724514f5e3Sopenharmony_ci            value = optimizedGate;
14734514f5e3Sopenharmony_ci        }
14744514f5e3Sopenharmony_ci        inList[i] = value;
14754514f5e3Sopenharmony_ci    }
14764514f5e3Sopenharmony_ci    return circuit_->NewGate(circuit_->FrameValues(frameStateInputs), inList);
14774514f5e3Sopenharmony_ci}
14784514f5e3Sopenharmony_ci}
1479