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