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