• 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/early_elimination.h"
17 
18 namespace panda::ecmascript::kungfu {
19 
Run()20 void EarlyElimination::Run()
21 {
22     dependChains_.resize(circuit_->GetMaxGateId() + 1, nullptr); // 1: +1 for size
23     renames_.resize(circuit_->GetMaxGateId() + 1, Circuit::NullGate()); // 1: +1 for size
24     GateRef entry = acc_.GetDependRoot();
25     VisitDependEntry(entry);
26     VisitGraph();
27 
28     if (IsLogEnabled()) {
29         LOG_COMPILER(INFO) << "";
30         LOG_COMPILER(INFO) << "\033[34m"
31                            << "===================="
32                            << " After early elimination "
33                            << "[" << GetMethodName() << "]"
34                            << "===================="
35                            << "\033[0m";
36         circuit_->PrintAllGatesWithBytecode();
37         LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m";
38     }
39 }
40 
GetLoopDependInfo(GateRef depend)41 DependInfoNode* EarlyElimination::GetLoopDependInfo(GateRef depend)
42 {
43     auto depIn = acc_.GetDep(depend);
44     auto dependChain = GetDependChain(depIn);
45     if (dependChain == nullptr) {
46         return nullptr;
47     }
48     auto newChain = new (chunk_) DependInfoNode(chunk_);
49     newChain->CopyFrom(dependChain);
50     ChunkSet<GateRef> visited(chunk_);
51     ChunkQueue<GateRef> workList(chunk_);
52     workList.push(depend);
53     visited.insert(acc_.GetDep(depend));
54     while (!workList.empty()) {
55         auto curDep = workList.front();
56         workList.pop();
57         if (visited.count(curDep)) {
58             continue;
59         }
60         if (!acc_.IsNotWrite(curDep)) {
61             newChain = UpdateWrite(curDep, newChain);
62         }
63         visited.insert(curDep);
64         auto depCount = acc_.GetDependCount(curDep);
65         for (size_t i = 0; i < depCount; ++i) {
66             workList.push(acc_.GetDep(curDep, i));
67         }
68     }
69     return newChain;
70 }
71 
VisitDependEntry(GateRef gate)72 GateRef EarlyElimination::VisitDependEntry(GateRef gate)
73 {
74     auto empty = new (chunk_) DependInfoNode(chunk_);
75     return UpdateDependChain(gate, empty);
76 }
77 
VisitGate(GateRef gate)78 GateRef EarlyElimination::VisitGate(GateRef gate)
79 {
80     auto opcode = acc_.GetOpCode(gate);
81     switch (opcode) {
82         case OpCode::LOAD_PROPERTY:
83         case OpCode::LOAD_ELEMENT:
84         case OpCode::LOAD_ARRAY_LENGTH:
85         case OpCode::LOAD_TYPED_ARRAY_LENGTH:
86         case OpCode::TYPED_ARRAY_CHECK:
87         case OpCode::OBJECT_TYPE_CHECK:
88         case OpCode::OBJECT_TYPE_COMPARE:
89         case OpCode::STABLE_ARRAY_CHECK:
90         case OpCode::INDEX_CHECK:
91         case OpCode::TYPED_CALL_CHECK:
92         case OpCode::LOAD_CONST_OFFSET:
93         case OpCode::TYPED_BINARY_OP:
94         case OpCode::TYPED_UNARY_OP:
95         case OpCode::JSINLINETARGET_TYPE_CHECK:
96         case OpCode::INLINE_ACCESSOR_CHECK:
97             return TryEliminateGate(gate);
98         case OpCode::STATE_SPLIT:
99             return TryEliminateFrameState(gate);
100         case OpCode::DEPEND_SELECTOR:
101             return TryEliminateDependSelector(gate);
102         default:
103             if (acc_.GetDependCount(gate) == 1) { // 1: depend in is 1
104                 return TryEliminateOther(gate);
105             }
106     }
107     return Circuit::NullGate();
108 }
109 
TryEliminateOther(GateRef gate)110 GateRef EarlyElimination::TryEliminateOther(GateRef gate)
111 {
112     ASSERT(acc_.GetDependCount(gate) >= 1);
113     auto depIn = acc_.GetDep(gate);
114     auto dependChain = GetDependChain(depIn);
115     if (dependChain == nullptr) {
116         return Circuit::NullGate();
117     }
118 
119     if (!acc_.IsNotWrite(gate)) {
120         dependChain = UpdateWrite(gate, dependChain);
121     }
122 
123     return UpdateDependChain(gate, dependChain);
124 }
125 
TryEliminateGate(GateRef gate)126 GateRef EarlyElimination::TryEliminateGate(GateRef gate)
127 {
128     ASSERT(acc_.GetDependCount(gate) == 1);
129     auto depIn = acc_.GetDep(gate);
130     auto dependChain = GetDependChain(depIn);
131     // dependChain is null
132     if (dependChain == nullptr) {
133         return Circuit::NullGate();
134     }
135 
136     if (!acc_.IsNotWrite(gate)) {
137         dependChain = UpdateWrite(gate, dependChain);
138         return UpdateDependChain(gate, dependChain);
139     }
140 
141     auto numIns = acc_.GetNumValueIn(gate);
142     for (size_t i = 0; i < numIns; ++i) {
143         auto origin = acc_.GetValueIn(gate, i);
144         auto checkd = dependChain->LookupCheckedNode(this, origin);
145         if (origin != checkd) {
146             acc_.ReplaceValueIn(gate, checkd, i);
147         }
148     }
149 
150     // lookup gate, replace
151     auto preGate = dependChain->LookupNode(this, gate);
152     if (preGate != Circuit::NullGate()) {
153         return preGate;
154     }
155     // update gate, for others elimination
156     dependChain = dependChain->UpdateNode(gate);
157     return UpdateDependChain(gate, dependChain);
158 }
159 
TryEliminateFrameState(GateRef gate)160 GateRef EarlyElimination::TryEliminateFrameState(GateRef gate)
161 {
162     ASSERT(acc_.GetOpCode(gate) == OpCode::STATE_SPLIT);
163     auto depIn = acc_.GetDep(gate);
164     auto dependChain = GetDependChain(depIn);
165     // dependChain is null
166     if (dependChain == nullptr) {
167         return Circuit::NullGate();
168     }
169     // lookup gate, replace
170     auto preFrame = dependChain->LookupFrameState();
171     auto curFrame = acc_.GetFrameState(gate);
172     if ((preFrame != Circuit::NullGate()) && (preFrame != curFrame) &&
173         acc_.GetFrameState(preFrame) == acc_.GetFrameState(curFrame)) {
174         acc_.UpdateAllUses(curFrame, preFrame);
175         auto frameValues = acc_.GetValueIn(curFrame, 1); // 1: frameValues
176         acc_.DeleteGate(frameValues);
177         acc_.DeleteGate(curFrame);
178         return depIn;
179     } else {
180         dependChain = dependChain->UpdateFrameState(curFrame);
181     }
182     // update gate, for others elimination
183 
184     return UpdateDependChain(gate, dependChain);
185 }
186 
TryEliminateDependSelector(GateRef gate)187 GateRef EarlyElimination::TryEliminateDependSelector(GateRef gate)
188 {
189     auto state = acc_.GetState(gate);
190     if (acc_.IsLoopHead(state)) {
191         auto dependChain = GetLoopDependInfo(gate);
192         if (dependChain == nullptr) {
193             return Circuit::NullGate();
194         }
195         return UpdateDependChain(gate, dependChain);
196     }
197 
198     auto dependCount = acc_.GetDependCount(gate);
199     for (size_t i = 0; i < dependCount; ++i) {
200         auto depend = acc_.GetDep(gate, i);
201         auto dependChain = GetDependChain(depend);
202         if (dependChain == nullptr) {
203             return Circuit::NullGate();
204         }
205     }
206 
207     // all depend done.
208     auto depend = acc_.GetDep(gate);
209     auto dependChain = GetDependChain(depend);
210     DependInfoNode* copy = new (chunk_) DependInfoNode(chunk_);
211     copy->CopyFrom(dependChain);
212     for (size_t i = 1; i < dependCount; ++i) { // 1: second in
213         auto dependIn = acc_.GetDep(gate, i);
214         auto tempChain = GetDependChain(dependIn);
215         copy->Merge(this, tempChain);
216     }
217     return UpdateDependChain(gate, copy);
218 }
219 
UpdateDependChain(GateRef gate,DependInfoNode * dependChain)220 GateRef EarlyElimination::UpdateDependChain(GateRef gate, DependInfoNode* dependChain)
221 {
222     ASSERT(dependChain != nullptr);
223     auto oldDependChain = GetDependChain(gate);
224     if (dependChain->Equals(oldDependChain)) {
225         return Circuit::NullGate();
226     }
227     dependChains_[acc_.GetId(gate)] = dependChain;
228     return gate;
229 }
230 
UpdateWrite(GateRef gate,DependInfoNode * dependInfo)231 DependInfoNode* EarlyElimination::UpdateWrite(GateRef gate, DependInfoNode* dependInfo)
232 {
233     auto op = acc_.GetOpCode(gate);
234     switch (op) {
235         case OpCode::STORE_PROPERTY:
236         case OpCode::STORE_PROPERTY_NO_BARRIER:
237         case OpCode::STORE_CONST_OFFSET:
238         case OpCode::STORE_ELEMENT:
239         case OpCode::STORE_MEMORY:
240             return dependInfo->UpdateStoreProperty(this, gate);
241         default:
242             return new (chunk_) DependInfoNode(chunk_);
243     }
244 }
245 
MayAccessOneMemory(GateRef lhs,GateRef rhs)246 bool EarlyElimination::MayAccessOneMemory(GateRef lhs, GateRef rhs)
247 {
248     auto rop = acc_.GetOpCode(rhs);
249     auto lop = acc_.GetOpCode(lhs);
250     switch (rop) {
251         case OpCode::STORE_MEMORY:
252             ASSERT(acc_.GetMemoryType(rhs) == MemoryType::ELEMENT_TYPE);
253             return acc_.GetOpCode(lhs) == OpCode::LOAD_ELEMENT;
254         case OpCode::STORE_ELEMENT: {
255             if (lop == OpCode::LOAD_ELEMENT) {
256                 auto lopIsTypedArray = acc_.GetTypedLoadOp(lhs) >= TypedLoadOp::TYPED_ARRAY_FIRST;
257                 auto ropIsTypedArray = acc_.GetTypedStoreOp(rhs) >= TypedStoreOp::TYPED_ARRAY_FIRST;
258                 return lopIsTypedArray == ropIsTypedArray;
259             }
260             return false;
261         }
262         case OpCode::STORE_PROPERTY:
263         case OpCode::STORE_PROPERTY_NO_BARRIER: {
264             if (lop == OpCode::LOAD_PROPERTY) {
265                 auto loff = acc_.GetValueIn(lhs, 1);
266                 auto roff = acc_.GetValueIn(rhs, 1);
267                 ASSERT(acc_.GetOpCode(loff) == OpCode::CONSTANT);
268                 ASSERT(acc_.GetOpCode(roff) == OpCode::CONSTANT);
269                 return loff == roff;
270             }
271             break;
272         }
273         case OpCode::STORE_CONST_OFFSET: {
274             if (lop == OpCode::LOAD_CONST_OFFSET) {
275                 auto loff = acc_.GetOffset(lhs);
276                 auto roff = acc_.GetOffset(rhs);
277                 return loff == roff;
278             }
279             break;
280         }
281         default:
282             break;
283     }
284     return false;
285 }
286 
CompareOrder(GateRef lhs,GateRef rhs)287 bool EarlyElimination::CompareOrder(GateRef lhs, GateRef rhs)
288 {
289     return GetGateOrder(lhs) < GetGateOrder(rhs);
290 }
291 
CheckReplacement(GateRef lhs,GateRef rhs)292 bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs)
293 {
294     if (!acc_.MetaDataEqu(lhs, rhs)) {
295         if (acc_.GetOpCode(lhs) != acc_.GetOpCode(rhs)) {
296             return false;
297         }
298     }
299 
300     size_t valueCount = acc_.GetNumValueIn(lhs);
301     for (size_t i = 0; i < valueCount; i++) {
302         if (Rename(acc_.GetValueIn(lhs, i)) != Rename(acc_.GetValueIn(rhs, i))) {
303             return false;
304         }
305     }
306 
307     auto opcode = acc_.GetOpCode(lhs);
308     switch (opcode) {
309         case OpCode::LOAD_ELEMENT: {
310             if (acc_.GetTypedLoadOp(lhs) != acc_.GetTypedLoadOp(rhs)) {
311                 return false;
312             }
313             break;
314         }
315         case OpCode::TYPED_BINARY_OP: {
316             auto lhsOp = acc_.GetTypedBinaryOp(lhs);
317             auto rhsOp = acc_.GetTypedBinaryOp(rhs);
318             if (lhsOp != rhsOp) {
319                 return false;
320             }
321             break;
322         }
323         case OpCode::TYPED_UNARY_OP: {
324             auto lhsOp = acc_.GetTypedUnAccessor(lhs).GetTypedUnOp();
325             auto rhsOp = acc_.GetTypedUnAccessor(rhs).GetTypedUnOp();
326             if (lhsOp != rhsOp) {
327                 return false;
328             }
329             break;
330         }
331         case OpCode::TYPED_ARRAY_CHECK:
332         case OpCode::INDEX_CHECK: {
333             if (acc_.GetParamGateType(lhs) != acc_.GetParamGateType(rhs)) {
334                 return false;
335             }
336             break;
337         }
338         case OpCode::OBJECT_TYPE_CHECK:
339         case OpCode::OBJECT_TYPE_COMPARE: {
340             if (acc_.GetObjectTypeAccessor(lhs).GetType() != acc_.GetObjectTypeAccessor(rhs).GetType()) {
341                 return false;
342             }
343             break;
344         }
345         case OpCode::LOAD_CONST_OFFSET: {
346             if (acc_.GetOffset(lhs) != acc_.GetOffset(rhs)) {
347                 return false;
348             }
349             break;
350         }
351         case OpCode::JSINLINETARGET_TYPE_CHECK: {
352             if (acc_.GetFuncGT(lhs) != acc_.GetFuncGT(rhs)) {
353                 return false;
354             }
355             break;
356         }
357         default:
358             break;
359     }
360     return true;
361 }
362 
CheckRenameReplacement(GateRef lhs,GateRef rhs)363 bool EarlyElimination::CheckRenameReplacement(GateRef lhs, GateRef rhs)
364 {
365     auto opcode = acc_.GetOpCode(lhs);
366     switch (opcode) {
367         case OpCode::INDEX_CHECK: {
368             auto index = acc_.GetValueIn(lhs, 1);
369             if (Rename(index) == Rename(rhs)) {
370                 return true;
371             }
372             break;
373         }
374         default:
375             break;
376     }
377     return false;
378 }
379 
Rename(GateRef gate)380 GateRef EarlyElimination::Rename(GateRef gate)
381 {
382     ChunkStack<GateRef> gateStack(chunk_);
383     while (true) {
384         auto op = acc_.GetOpCode(gate);
385         bool renamed = false;
386         switch (op) {
387             case OpCode::INDEX_CHECK: {
388                 GateRef ans = renames_[acc_.GetId(gate)];
389                 if (ans == Circuit::NullGate()) {
390                     renamed = true;
391                     gateStack.push(gate);
392                     gate = acc_.GetValueIn(gate, 1);
393                 } else {
394                     gate = ans;
395                 }
396                 break;
397             }
398             default:
399                 break;
400         }
401         if (!renamed) {
402             break;
403         }
404     }
405     while (!gateStack.empty()) {
406         auto topGate = gateStack.top();
407         gateStack.pop();
408         renames_[acc_.GetId(topGate)] = gate;
409     }
410     return gate;
411 }
412 
Merge(EarlyElimination * elimination,DependInfoNode * that)413 void DependInfoNode::Merge(EarlyElimination* elimination, DependInfoNode* that)
414 {
415     auto siz = this->size_; // size of lhs-chain
416     auto lhs = this->head_;
417     auto rhs = that->head_;
418     ChunkStack<GateRef> gateStack(chunk_);
419     while (lhs != rhs) {
420         if (lhs == nullptr || rhs == nullptr) {
421             siz = 0;
422             lhs = nullptr;
423             break;
424         } else if (lhs->gate == rhs->gate) {
425             gateStack.push(lhs->gate);
426             siz--;
427             lhs = lhs->next;
428             rhs = rhs->next;
429         } else if (elimination->CompareOrder(lhs->gate, rhs->gate)) {
430             rhs = rhs->next;
431         } else {
432             siz--;
433             lhs = lhs->next;
434         }
435     }
436     // lhs : common suffix of lhs-chain and rhs-chain
437     this->head_ = lhs;
438     this->size_ = siz;
439     while (!gateStack.empty()) {
440         Node* node = chunk_->New<Node>(gateStack.top(), head_);
441         gateStack.pop();
442         this->size_++;
443         this->head_ = node;
444     }
445     if (this->frameState_ != that->frameState_) {
446         this->frameState_ = Circuit::NullGate();
447     }
448 }
449 
Equals(DependInfoNode * that)450 bool DependInfoNode::Equals(DependInfoNode* that)
451 {
452     if (that == nullptr) {
453         return false;
454     }
455     if (size_ != that->size_ || frameState_ != that->frameState_) {
456         return false;
457     }
458     auto lhs = this->head_;
459     auto rhs = that->head_;
460     while (lhs != rhs) {
461         if (lhs->gate != rhs->gate) {
462             return false;
463         }
464         lhs = lhs->next;
465         rhs = rhs->next;
466     }
467     return true;
468 }
469 
LookupFrameState() const470 GateRef DependInfoNode::LookupFrameState() const
471 {
472     return frameState_;
473 }
474 
LookupCheckedNode(EarlyElimination * elimination,GateRef gate)475 GateRef DependInfoNode::LookupCheckedNode(EarlyElimination* elimination, GateRef gate)
476 {
477     for (Node* node = head_; node != nullptr; node = node->next) {
478         if (elimination->CheckRenameReplacement(node->gate, gate)) {
479             return node->gate;
480         }
481     }
482     return gate;
483 }
484 
GetGates(std::vector<GateRef> & gates) const485 void DependInfoNode::GetGates(std::vector<GateRef>& gates) const
486 {
487     ChunkStack<GateRef> st(chunk_);
488     for (Node* node = head_; node != nullptr; node = node->next) {
489         st.push(node->gate);
490     }
491     while (!st.empty()) {
492         gates.emplace_back(st.top());
493         st.pop();
494     }
495 }
496 
LookupNode(EarlyElimination * elimination,GateRef gate)497 GateRef DependInfoNode::LookupNode(EarlyElimination* elimination, GateRef gate)
498 {
499     for (Node* node = head_; node != nullptr; node = node->next) {
500         if (elimination->CheckReplacement(node->gate, gate)) {
501             return node->gate;
502         }
503     }
504     return Circuit::NullGate();
505 }
506 
UpdateNode(GateRef gate)507 DependInfoNode* DependInfoNode::UpdateNode(GateRef gate)
508 {
509     // assign node->next to head
510     Node* node = chunk_->New<Node>(gate, head_);
511     DependInfoNode* that = new (chunk_) DependInfoNode(chunk_);
512     // assign head to node
513     that->head_ = node;
514     that->size_ = size_ + 1;
515     that->frameState_ = frameState_;
516     return that;
517 }
518 
UpdateFrameState(GateRef framestate)519 DependInfoNode* DependInfoNode::UpdateFrameState(GateRef framestate)
520 {
521     // assign node->next to head
522     DependInfoNode* that = new (chunk_) DependInfoNode(chunk_);
523     // assign head to node
524     that->head_ = head_;
525     that->size_ = size_;
526     that->frameState_ = framestate;
527     return that;
528 }
529 
UpdateStoreProperty(EarlyElimination * elimination,GateRef gate)530 DependInfoNode* DependInfoNode::UpdateStoreProperty(EarlyElimination* elimination, GateRef gate)
531 {
532     DependInfoNode* that = new (chunk_) DependInfoNode(chunk_);
533     ChunkStack<GateRef> gateStack(chunk_);
534     for (Node* node = head_; node != nullptr; node = node->next) {
535         if (!elimination->MayAccessOneMemory(node->gate, gate)) {
536             gateStack.push(node->gate);
537         }
538     }
539     while (!gateStack.empty()) {
540         that = that->UpdateNode(gateStack.top());
541         gateStack.pop();
542     }
543     return that;
544 }
545 }  // namespace panda::ecmascript::kungfu
546