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