• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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