1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/compiler/loop_peeling.h"
17 #include "ecmascript/compiler/circuit.h"
18 #include "ecmascript/compiler/gate_meta_data.h"
19 #include "ecmascript/compiler/number_gate_info.h"
20 #include "ecmascript/compiler/type.h"
21
22 namespace panda::ecmascript::kungfu {
Peel()23 void LoopPeeling::Peel()
24 {
25 SetCopy(loopInfo_->loopHead);
26 for (auto gate : loopInfo_->loopBodys) {
27 SetCopy(gate);
28 }
29 for (auto gate : loopInfo_->loopBacks) {
30 copies_[gate] = GetCopy(acc_.GetState(gate));
31 }
32
33 for (auto gate : loopInfo_->loopBodys) {
34 if ((gate == loopInfo_->loopHead) ||
35 (acc_.IsSelector(gate) && acc_.GetState(gate) == loopInfo_->loopHead)) {
36 continue;
37 }
38 GateRef copy = GetCopy(gate);
39 size_t numIns = acc_.GetNumIns(gate);
40 for (size_t i = 0; i < numIns; ++i) {
41 GateRef in = acc_.GetIn(gate, i);
42 GateRef copyIn = TryGetCopy(in);
43 if (copyIn != Circuit::NullGate()) {
44 acc_.NewIn(copy, i, copyIn);
45 } else {
46 acc_.NewIn(copy, i, in);
47 }
48 }
49 }
50
51 // replace origin forwards with peeled loop back.
52 GateRef stateBack = acc_.GetState(loopInfo_->loopHead, 1); // 1: index of state back
53 acc_.ReplaceIn(loopInfo_->loopHead, 0, GetCopy(stateBack)); // 0: index of state forward
54 auto use = acc_.Uses(loopInfo_->loopHead);
55 for (auto it = use.begin(); it != use.end(); ++it) {
56 if (acc_.IsSelector(*it)) {
57 GateRef backward = acc_.GetIn(*it, 2); // 2: index of depend or value back
58 acc_.ReplaceIn(*it, 1, GetCopy(backward)); // 1: index of depend or value forward
59 }
60 }
61
62 for (auto exit : loopInfo_->loopExits) {
63 ASSERT(acc_.GetOpCode(exit) == OpCode::LOOP_EXIT);
64 GateRef numIns = 2;
65 GateRef copyExit = GetCopy(acc_.GetState(exit));
66 GateRef merge = circuit_->NewGate(circuit_->Merge(numIns), {exit, copyExit});
67 auto exitUse = acc_.Uses(exit);
68 for (auto it = exitUse.begin(); it != exitUse.end();) {
69 if (acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_DEPEND) {
70 GateRef depend = *it;
71 GateRef copyDepend = GetCopy(acc_.GetDep(depend));
72 GateRef selector = circuit_->NewGate(circuit_->DependSelector(numIns), {merge, depend, copyDepend});
73 acc_.UpdateAllUses(depend, selector);
74 acc_.ReplaceIn(selector, 1, depend); // 0: index of exit depend
75 ++it;
76 } else if (acc_.GetOpCode(*it) == OpCode::LOOP_EXIT_VALUE) {
77 GateRef value = *it;
78 GateRef copyValue = GetCopy(acc_.GetValueIn(value));
79 ASSERT(acc_.GetMachineType(value) == MachineType::I64);
80 ASSERT(acc_.GetMachineType(copyValue) == MachineType::I64);
81 GateRef selector = circuit_->NewGate(circuit_->ValueSelector(numIns), MachineType::I64,
82 {merge, value, copyValue}, GateType::AnyType());
83 acc_.UpdateAllUses(value, selector);
84 acc_.ReplaceIn(selector, 1, value); // 0: index of exit depend
85 ++it;
86 } else if ((*it) == merge) {
87 ++it;
88 } else {
89 it = acc_.ReplaceIn(it, merge);
90 }
91 }
92 }
93
94 auto asyncList = bcBuilder_->GetAsyncRelatedGates();
95 ChunkVector<GateRef> list(chunk_);
96 for (auto gate : asyncList) {
97 auto copyAsync = TryGetCopy(gate);
98 if (copyAsync == Circuit::NullGate()) {
99 list.emplace_back(copyAsync);
100 }
101 }
102 for (auto gate : asyncList) {
103 bcBuilder_->UpdateAsyncRelatedGate(gate);
104 }
105
106 Print();
107 }
108
SetCopy(GateRef gate)109 void LoopPeeling::SetCopy(GateRef gate)
110 {
111 ASSERT(copies_.count(gate) == 0);
112 if (gate == loopInfo_->loopHead) {
113 // copy of head is forward
114 copies_[gate] = acc_.GetState(gate);
115 return;
116 }
117 if (acc_.IsSelector(gate) && acc_.GetState(gate) == loopInfo_->loopHead) {
118 // copy of head is forward
119 copies_[gate] = acc_.GetIn(gate, 1); // 1: index of forward
120 return;
121 }
122
123 std::vector<GateRef> inList(acc_.GetNumIns(gate), Circuit::NullGate());
124 GateRef newGate = circuit_->NewGate(acc_.GetMetaData(gate), inList);
125 acc_.SetGateType(newGate, acc_.GetGateType(gate));
126 acc_.SetMachineType(newGate, acc_.GetMachineType(gate));
127 copies_[gate] = newGate;
128 if (acc_.GetOpCode(gate) == OpCode::JS_BYTECODE) {
129 bcBuilder_->UpdateBcIndexGate(newGate, bcBuilder_->GetBcIndexByGate(gate));
130 }
131 }
132
GetCopy(GateRef gate) const133 GateRef LoopPeeling::GetCopy(GateRef gate) const
134 {
135 if (copies_.count(gate)) {
136 return copies_.at(gate);
137 }
138 return gate;
139 }
140
TryGetCopy(GateRef gate) const141 GateRef LoopPeeling::TryGetCopy(GateRef gate) const
142 {
143 if (copies_.count(gate) > 0) {
144 return copies_.at(gate);
145 }
146 return Circuit::NullGate();
147 }
148
Print() const149 void LoopPeeling::Print() const
150 {
151 if (IsLogEnabled()) {
152 LOG_COMPILER(INFO) << "";
153 LOG_COMPILER(INFO) << "\033[34m"
154 << "===================="
155 << " After loop peeling "
156 << "[" << GetMethodName() << "]"
157 << "===================="
158 << "\033[0m";
159 circuit_->PrintAllGatesWithBytecode();
160 LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
161 }
162 }
163 } // namespace panda::ecmascript::kungfu