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