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