1 /**
2 * Copyright (c) 2021-2022 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 "cleanup.h"
17
18 #include "compiler_logger.h"
19 #include "optimizer/analysis/alias_analysis.h"
20 #include "optimizer/analysis/bounds_analysis.h"
21 #include "optimizer/analysis/dominators_tree.h"
22 #include "optimizer/analysis/linear_order.h"
23 #include "optimizer/analysis/loop_analyzer.h"
24 #include "optimizer/ir/basicblock.h"
25
26 namespace panda::compiler {
27
SkipBasicBlock(BasicBlock * bb)28 static bool SkipBasicBlock(BasicBlock *bb)
29 {
30 // TODO (a.popov) Make empty catch-begin and try-end blocks removeable
31 return bb == nullptr || bb->IsStartBlock() || bb->IsEndBlock() || bb->IsCatchBegin() || bb->IsTryEnd();
32 }
33
34 /* Cleanup pass works like dead code elimination (DCE) and removes code which does not affect the program results.
35 * It also removes empty basic blocks when it is possible and merges a linear basic block sequence to one bigger
36 * basic block, thus simplifying control flow graph.
37 */
RunImpl()38 bool Cleanup::RunImpl()
39 {
40 GetGraph()->RunPass<DominatorsTree>();
41 GetGraph()->RunPass<LoopAnalyzer>();
42
43 // Two vectors to store basic blocks lists
44 auto empty_blocks = &empty1_;
45 auto new_empty_blocks = &empty2_;
46
47 bool modified = PhiChecker();
48
49 for (auto bb : GetGraph()->GetVectorBlocks()) {
50 if (!SkipBasicBlock(bb) && bb->IsEmpty()) {
51 empty_blocks->insert(bb);
52 }
53 }
54
55 bool first_run = true;
56 do {
57 modified |= RunOnce(empty_blocks, new_empty_blocks, !first_run);
58 first_run = false;
59 // Swap vectors pointers
60 auto temp = empty_blocks;
61 empty_blocks = new_empty_blocks;
62 new_empty_blocks = temp;
63 // Clean the "new" list
64 new_empty_blocks->clear();
65 } while (!empty_blocks->empty());
66
67 empty1_.clear();
68 empty2_.clear();
69
70 /* Merge linear sectors.
71 * For merging possibility a block must have one successor, and its successor must have one predecessor.
72 * EXAMPLE:
73 * [1]
74 * |
75 * [2]
76 * |
77 * [3]
78 * |
79 * [4]
80 *
81 * turns into this:
82 * [1']
83 */
84 for (auto bb : GetGraph()->GetVectorBlocks()) {
85 if (bb == nullptr || bb->IsPseudoControlFlowBlock()) {
86 continue;
87 }
88
89 while (bb->GetSuccsBlocks().size() == 1 && bb->GetSuccessor(0)->GetPredsBlocks().size() == 1 &&
90 !bb->GetSuccessor(0)->IsPseudoControlFlowBlock() && bb->IsTry() == bb->GetSuccessor(0)->IsTry()) {
91 ASSERT(!bb->GetSuccessor(0)->HasPhi());
92 COMPILER_LOG(DEBUG, CLEANUP) << "Merged block " << bb->GetSuccessor(0)->GetId() << " into " << bb->GetId();
93 bb->JoinSuccessorBlock();
94 modified = true;
95 }
96 }
97 return modified;
98 }
99
RunOnce(ArenaSet<BasicBlock * > * empty_blocks,ArenaSet<BasicBlock * > * new_empty_blocks,bool simple_dce)100 bool Cleanup::RunOnce(ArenaSet<BasicBlock *> *empty_blocks, ArenaSet<BasicBlock *> *new_empty_blocks, bool simple_dce)
101 {
102 bool modified = false;
103 auto marker_holder = MarkerHolder(GetGraph());
104 auto dead_mrk = marker_holder.GetMarker();
105
106 // Check all basic blocks in "old" list
107 for (auto bb : *empty_blocks) {
108 // In some tricky cases block may be already deleted in previous iteration
109 if (bb->GetGraph() == nullptr) {
110 continue;
111 }
112
113 auto succ = bb->GetSuccessor(0);
114
115 // Strange infinite loop with only one empty block, or loop pre-header - lets bail out
116 if (succ == bb || succ->GetLoop()->GetPreHeader() == bb) {
117 continue;
118 }
119
120 #ifndef NDEBUG
121 // Now we know that 'bb' is not a loop pre-header, so if both 'bb' and 'succ' have many predecessors
122 // all 'bb' Phi(s) must have user only in successor Phis
123 if (succ->GetPredsBlocks().size() > 1) {
124 for (auto phi : bb->PhiInsts()) {
125 for (auto &user_item : phi->GetUsers()) {
126 auto user = user_item.GetInst();
127 ASSERT((user->GetBasicBlock() == succ && user->IsPhi()) || user->IsCatchPhi());
128 }
129 }
130 }
131 #endif
132 modified |= ProcessBB(bb, dead_mrk, new_empty_blocks);
133 }
134
135 if (simple_dce) {
136 modified |= SimpleDce(dead_mrk, new_empty_blocks);
137 } else {
138 modified |= Dce(dead_mrk, new_empty_blocks);
139 }
140 dead_.clear();
141
142 return modified;
143 }
144
145 // Check around for special triangle case
CheckSpecialTriangle(BasicBlock * bb)146 bool Cleanup::CheckSpecialTriangle(BasicBlock *bb)
147 {
148 auto succ = bb->GetSuccessor(0);
149 size_t i = 0;
150 for (auto pred : bb->GetPredsBlocks()) {
151 if (pred->GetSuccessor(0) == succ ||
152 (pred->GetSuccsBlocks().size() == MAX_SUCCS_NUM && pred->GetSuccessor(1) == succ)) {
153 // Checking all Phis
154 for (auto phi : succ->PhiInsts()) {
155 size_t index_bb = phi->CastToPhi()->GetPredBlockIndex(bb);
156 size_t index_pred = phi->CastToPhi()->GetPredBlockIndex(pred);
157 ASSERT(index_bb != index_pred);
158
159 auto inst_pred = phi->GetInput(index_pred).GetInst();
160 auto inst_bb = phi->GetInput(index_bb).GetInst();
161 // If phi input is in 'bb', check input of that phi instead
162 if (inst_bb->GetBasicBlock() == bb) {
163 ASSERT(inst_bb->IsPhi());
164 inst_bb = inst_bb->CastToPhi()->GetInput(i).GetInst();
165 }
166 if (inst_bb != inst_pred) {
167 return true;
168 }
169 }
170 // Would fully remove 'straight' pred->succ edge, and second one would stay after 'bb' removal
171 saved_preds_.push_back(pred);
172 }
173 i++;
174 }
175 return false;
176 }
177
RemoveDeadPhi(BasicBlock * bb,ArenaSet<BasicBlock * > * new_empty_blocks)178 void Cleanup::RemoveDeadPhi(BasicBlock *bb, ArenaSet<BasicBlock *> *new_empty_blocks)
179 {
180 for (auto phi : bb->PhiInstsSafe()) {
181 if (!phi->GetUsers().Empty()) {
182 continue;
183 }
184 bb->RemoveInst(phi);
185 COMPILER_LOG(DEBUG, CLEANUP) << "Dead Phi removed " << phi->GetId();
186 GetGraph()->GetEventWriter().EventCleanup(phi->GetId(), phi->GetPc());
187
188 for (auto pred : bb->GetPredsBlocks()) {
189 if (pred->IsEmpty() && !SkipBasicBlock(pred)) {
190 COMPILER_LOG(DEBUG, CLEANUP) << "Would re-check empty block " << pred->GetId();
191 new_empty_blocks->insert(pred);
192 }
193 }
194 }
195 }
196
ProcessBB(BasicBlock * bb,Marker dead_mrk,ArenaSet<BasicBlock * > * new_empty_blocks)197 bool Cleanup::ProcessBB(BasicBlock *bb, Marker dead_mrk, ArenaSet<BasicBlock *> *new_empty_blocks)
198 {
199 auto succ = bb->GetSuccessor(0);
200 if (CheckSpecialTriangle(bb)) {
201 return false;
202 }
203 // Remove dead Phi(s)
204 RemoveDeadPhi(bb, new_empty_blocks);
205 // Process saved predecessors
206 for (auto pred : saved_preds_) {
207 ASSERT(pred->GetSuccsBlocks().size() == MAX_SUCCS_NUM);
208 constexpr auto PREDS_BLOCK_NUM = 2;
209 ASSERT(succ->GetPredsBlocks().size() >= PREDS_BLOCK_NUM);
210
211 auto last = pred->GetLastInst();
212 if (last->GetOpcode() == Opcode::If || last->GetOpcode() == Opcode::IfImm ||
213 last->GetOpcode() == Opcode::AddOverflow || last->GetOpcode() == Opcode::SubOverflow) {
214 last->SetMarker(dead_mrk);
215 dead_.push_back(last);
216 } else {
217 ASSERT(last->GetOpcode() == Opcode::Try);
218 }
219 pred->RemoveSucc(succ);
220 if (succ->GetPredsBlocks().size() == PREDS_BLOCK_NUM) {
221 for (auto phi : succ->PhiInstsSafe()) {
222 auto rm_index = phi->CastToPhi()->GetPredBlockIndex(pred);
223 auto remaining_inst = phi->GetInputs()[1 - rm_index].GetInst();
224 phi->ReplaceUsers(remaining_inst);
225 succ->RemoveInst(phi);
226 }
227 } else { // more than 2 predecessors
228 for (auto phi : succ->PhiInstsSafe()) {
229 auto rm_index = phi->CastToPhi()->GetPredBlockIndex(pred);
230 phi->CastToPhi()->RemoveInput(rm_index);
231 }
232 }
233 succ->RemovePred(pred);
234 // Fixing LoopAnalysis or DomTree is no necessary here, because there would be another edge
235 }
236 saved_preds_.clear();
237 bool bad_loop = bb->GetLoop()->IsIrreducible();
238 GetGraph()->RemoveEmptyBlockWithPhis(bb, bad_loop);
239 if (bad_loop) {
240 GetGraph()->InvalidateAnalysis<LoopAnalyzer>();
241 GetGraph()->RunPass<LoopAnalyzer>();
242 }
243 COMPILER_LOG(DEBUG, CLEANUP) << "Removed empty block: " << bb->GetId();
244 return true;
245 }
246
247 // Mark instructions that have the NOT_REMOVABLE property
248 // and recursively mark all their inputs
MarkLiveRec(Marker live_mrk,Inst * inst)249 void Cleanup::MarkLiveRec(Marker live_mrk, Inst *inst)
250 {
251 // No recursion for one-input case, otherwise got stackoverflow on TSAN job
252 bool marked = false;
253 while (inst->GetInputsCount() == 1) {
254 marked = inst->SetMarker(live_mrk);
255 if (marked) {
256 break;
257 }
258 inst = inst->GetInput(0).GetInst();
259 }
260 if (!marked && !inst->SetMarker(live_mrk)) {
261 for (auto input : inst->GetInputs()) {
262 MarkLiveRec(live_mrk, input.GetInst());
263 }
264 }
265 }
266
Dce(Marker dead_mrk,ArenaSet<BasicBlock * > * new_empty_blocks)267 bool Cleanup::Dce(Marker dead_mrk, ArenaSet<BasicBlock *> *new_empty_blocks)
268 {
269 bool modified = false;
270 auto marker_holder = MarkerHolder(GetGraph());
271 auto live_mrk = marker_holder.GetMarker();
272
273 // Mark live instructions
274 for (auto bb : GetGraph()->GetBlocksRPO()) {
275 for (auto inst : bb->AllInsts()) {
276 if (inst->IsNotRemovable() && !inst->IsMarked(dead_mrk)) {
277 MarkLiveRec(live_mrk, inst);
278 }
279 }
280 }
281 // Remove non-live instructions
282 for (auto bb : GetGraph()->GetBlocksRPO()) {
283 for (auto inst : bb->AllInstsSafe()) {
284 if (inst->IsMarked(live_mrk)) {
285 continue;
286 }
287 bool is_phi = inst->IsPhi();
288 bb->RemoveInst(inst);
289 COMPILER_LOG(DEBUG, CLEANUP) << "Dead instruction " << inst->GetId();
290 GetGraph()->GetEventWriter().EventCleanup(inst->GetId(), inst->GetPc());
291 modified = true;
292
293 if (is_phi) {
294 for (auto pred : bb->GetPredsBlocks()) {
295 if (pred->IsEmpty() && !SkipBasicBlock(pred)) {
296 COMPILER_LOG(DEBUG, CLEANUP) << "Would re-check empty block " << pred->GetId();
297 new_empty_blocks->insert(pred);
298 }
299 }
300 } else if (bb->IsEmpty() && !SkipBasicBlock(bb)) {
301 COMPILER_LOG(DEBUG, CLEANUP) << "No more non-Phi instructions in block " << bb->GetId();
302 new_empty_blocks->insert(bb);
303 }
304 }
305 }
306 return modified;
307 }
308
SetLiveRec(Inst * inst,Marker mrk,Marker live_mrk)309 void Cleanup::SetLiveRec(Inst *inst, Marker mrk, Marker live_mrk)
310 {
311 for (auto input_item : inst->GetInputs()) {
312 auto input = input_item.GetInst();
313 if (!input->IsMarked(live_mrk) && input->IsMarked(mrk)) {
314 input->ResetMarker(mrk);
315 input->SetMarker(live_mrk);
316 SetLiveRec(input, mrk, live_mrk);
317 }
318 }
319 }
320
LiveUserSearchRec(Inst * inst,Marker mrk,Marker live_mrk,Marker dead_mrk)321 void Cleanup::LiveUserSearchRec(Inst *inst, Marker mrk, Marker live_mrk, Marker dead_mrk)
322 {
323 ASSERT(!inst->IsMarked(mrk));
324 ASSERT(!inst->IsMarked(dead_mrk));
325 if (inst->IsMarked(live_mrk)) {
326 SetLiveRec(inst, mrk, live_mrk);
327 return;
328 }
329 if (inst->IsNotRemovable()) {
330 inst->SetMarker(live_mrk);
331 SetLiveRec(inst, mrk, live_mrk);
332 return;
333 }
334 inst->SetMarker(mrk);
335 temp_.push_back(inst);
336 bool unknown = false;
337 for (auto &user_item : inst->GetUsers()) {
338 auto user = user_item.GetInst();
339 if (user->IsMarked(mrk)) {
340 unknown = true;
341 continue;
342 }
343 if (user->IsMarked(dead_mrk)) {
344 continue;
345 }
346 LiveUserSearchRec(user, mrk, live_mrk, dead_mrk);
347 if (user->IsMarked(live_mrk)) {
348 ASSERT(!inst->IsMarked(mrk) && inst->IsMarked(live_mrk));
349 return;
350 }
351 ASSERT(inst->IsMarked(mrk));
352 if (user->IsMarked(mrk)) {
353 ASSERT(!user->IsMarked(live_mrk) && !user->IsMarked(dead_mrk));
354 unknown = true;
355 } else {
356 ASSERT(user->IsMarked(dead_mrk));
357 }
358 }
359 if (!unknown) {
360 inst->ResetMarker(mrk);
361 inst->SetMarker(dead_mrk);
362 dead_.push_back(inst);
363 }
364 }
365
Marking(Marker dead_mrk,Marker mrk,Marker live_mrk)366 void Cleanup::Marking(Marker dead_mrk, Marker mrk, Marker live_mrk)
367 {
368 size_t i = 0;
369 while (i < dead_.size()) {
370 auto inst = dead_.at(i);
371 for (auto input_item : inst->GetInputs()) {
372 auto input = input_item.GetInst();
373 if (input->IsMarked(dead_mrk) || input->IsMarked(mrk)) {
374 continue;
375 }
376 LiveUserSearchRec(input, mrk, live_mrk, dead_mrk);
377 for (auto temp : temp_) {
378 if (temp->IsMarked(mrk)) {
379 ASSERT(!temp->IsMarked(live_mrk) && !temp->IsMarked(dead_mrk));
380 inst->ResetMarker(mrk);
381 inst->SetMarker(dead_mrk);
382 dead_.push_back(inst);
383 }
384 }
385 temp_.clear();
386 }
387 i++;
388 }
389 }
390
Removal(ArenaSet<BasicBlock * > * new_empty_blocks)391 bool Cleanup::Removal(ArenaSet<BasicBlock *> *new_empty_blocks)
392 {
393 bool modified = false;
394
395 for (auto inst : dead_) {
396 inst->ClearMarkers();
397 auto bb = inst->GetBasicBlock();
398 if (bb == nullptr) {
399 continue;
400 }
401 bb->RemoveInst(inst);
402 COMPILER_LOG(DEBUG, CLEANUP) << "Dead instruction " << inst->GetId();
403 GetGraph()->GetEventWriter().EventCleanup(inst->GetId(), inst->GetPc());
404 modified = true;
405
406 if (inst->IsPhi()) {
407 for (auto pred : bb->GetPredsBlocks()) {
408 if (pred->IsEmpty() && !SkipBasicBlock(pred)) {
409 COMPILER_LOG(DEBUG, CLEANUP) << "Would re-check empty block " << pred->GetId();
410 new_empty_blocks->insert(pred);
411 }
412 }
413 } else {
414 if (bb->IsEmpty() && !SkipBasicBlock(bb)) {
415 COMPILER_LOG(DEBUG, CLEANUP) << "No more non-Phi instructions in block " << bb->GetId();
416 new_empty_blocks->insert(bb);
417 }
418 }
419 }
420 return modified;
421 }
422
SimpleDce(Marker dead_mrk,ArenaSet<BasicBlock * > * new_empty_blocks)423 bool Cleanup::SimpleDce(Marker dead_mrk, ArenaSet<BasicBlock *> *new_empty_blocks)
424 {
425 auto marker_holder = MarkerHolder(GetGraph());
426 auto mrk = marker_holder.GetMarker();
427 auto live_marker_holder = MarkerHolder(GetGraph());
428 auto live_mrk = live_marker_holder.GetMarker();
429
430 // Step 1. Marking
431 Marking(dead_mrk, mrk, live_mrk);
432
433 // Step 2. Removal
434 return Removal(new_empty_blocks);
435 }
436
BuildDominators()437 void Cleanup::BuildDominators()
438 {
439 size_t amount = 0;
440 fake_root_ = reinterpret_cast<Inst *>(sizeof(Inst *));
441 map_.insert({fake_root_, amount});
442 for (auto bb : GetGraph()->GetBlocksRPO()) {
443 for (auto inst : bb->PhiInsts()) {
444 amount++;
445 map_.insert({inst, amount});
446 for (auto input : inst->GetInputs()) {
447 auto pred = input.GetInst();
448 if (!pred->IsPhi() && map_.count(pred) == 0) {
449 amount++;
450 map_.insert({pred, amount});
451 }
452 }
453 }
454 }
455 Init(amount + 1);
456 SetVertex(0, fake_root_);
457 for (auto bb : GetGraph()->GetBlocksRPO()) {
458 for (auto inst : bb->Insts()) {
459 if (map_.count(inst) > 0 && GetSemi(inst) == DEFAULT_DFS_VAL) {
460 SetParent(inst, fake_root_);
461 DfsNumbering(inst);
462 }
463 }
464 }
465 ASSERT(static_cast<size_t>(dfs_num_) == amount);
466
467 for (size_t i = amount; i > 0; i--) {
468 ComputeImmediateDominators(GetVertex(i));
469 }
470
471 for (size_t i = 1; i <= amount; i++) {
472 AdjustImmediateDominators(GetVertex(i));
473 }
474 }
475
476 /*
477 * Adjust immediate dominators,
478 * Update dominator information for 'inst'
479 */
AdjustImmediateDominators(Inst * inst)480 void Cleanup::AdjustImmediateDominators(Inst *inst)
481 {
482 ASSERT(inst != nullptr);
483
484 if (GetIdom(inst) != GetVertex(GetSemi(inst))) {
485 SetIdom(inst, GetIdom(GetIdom(inst)));
486 }
487 }
488
489 /*
490 * Compute initial values for semidominators,
491 * store instructions with the same semidominator in the same bucket,
492 * compute immediate dominators for instructions in the bucket of 'inst' parent
493 */
ComputeImmediateDominators(Inst * inst)494 void Cleanup::ComputeImmediateDominators(Inst *inst)
495 {
496 ASSERT(inst != nullptr);
497
498 if (inst->IsPhi()) {
499 for (auto input : inst->GetInputs()) {
500 auto pred = input.GetInst();
501 auto eval = Eval(pred);
502 if (GetSemi(eval) < GetSemi(inst)) {
503 SetSemi(inst, GetSemi(eval));
504 }
505 }
506 } else {
507 auto eval = fake_root_;
508 if (GetSemi(eval) < GetSemi(inst)) {
509 SetSemi(inst, GetSemi(eval));
510 }
511 }
512
513 auto vertex = GetVertex(GetSemi(inst));
514 GetBucket(vertex).push_back(inst);
515 auto parent = GetParent(inst);
516 SetAncestor(inst, parent);
517
518 auto &bucket = GetBucket(parent);
519 while (!bucket.empty()) {
520 auto v = *bucket.rbegin();
521 auto eval = Eval(v);
522 if (GetSemi(eval) < GetSemi(v)) {
523 SetIdom(v, eval);
524 } else {
525 SetIdom(v, parent);
526 }
527 bucket.pop_back();
528 }
529 }
530
531 /*
532 * Compress ancestor path to 'inst' to the instruction whose label has the maximal semidominator number
533 */
Compress(Inst * inst)534 void Cleanup::Compress(Inst *inst)
535 {
536 auto anc = GetAncestor(inst);
537 ASSERT(anc != nullptr);
538
539 if (GetAncestor(anc) != nullptr) {
540 Compress(anc);
541 if (GetSemi(GetLabel(anc)) < GetSemi(GetLabel(inst))) {
542 SetLabel(inst, GetLabel(anc));
543 }
544 SetAncestor(inst, GetAncestor(anc));
545 }
546 }
547
548 /*
549 * Depth-first search with numbering instruction in order they are reaching
550 */
DfsNumbering(Inst * inst)551 void Cleanup::DfsNumbering(Inst *inst)
552 {
553 ASSERT(inst != nullptr || inst != fake_root_);
554 dfs_num_++;
555 ASSERT_PRINT(static_cast<size_t>(dfs_num_) < vertices_.size(), "DFS-number overflow");
556
557 SetVertex(dfs_num_, inst);
558 SetLabel(inst, inst);
559 SetSemi(inst, dfs_num_);
560 SetAncestor(inst, nullptr);
561
562 for (auto &user : inst->GetUsers()) {
563 auto succ = user.GetInst();
564 if (succ->IsPhi() && GetSemi(succ) == DEFAULT_DFS_VAL) {
565 SetParent(succ, inst);
566 DfsNumbering(succ);
567 }
568 }
569 }
570
571 /*
572 * Return 'inst' if it is the root of a tree
573 * Otherwise, after tree compressing
574 * return the instruction in the ancestors chain with the minimal semidominator DFS-number
575 */
Eval(Inst * inst)576 Inst *Cleanup::Eval(Inst *inst)
577 {
578 ASSERT(inst != nullptr);
579 if (GetAncestor(inst) == nullptr) {
580 return inst;
581 }
582 Compress(inst);
583 return GetLabel(inst);
584 }
585
586 /*
587 * Initialize data structures to start DFS
588 */
Init(size_t count)589 void Cleanup::Init(size_t count)
590 {
591 ancestors_.clear();
592 idoms_.clear();
593 labels_.clear();
594 parents_.clear();
595 vertices_.clear();
596 semi_.clear();
597
598 ancestors_.resize(count);
599 idoms_.resize(count);
600 labels_.resize(count);
601 parents_.resize(count);
602 vertices_.resize(count);
603 semi_.resize(count);
604
605 std::fill(vertices_.begin(), vertices_.end(), nullptr);
606 std::fill(semi_.begin(), semi_.end(), DEFAULT_DFS_VAL);
607
608 if (buckets_.size() < count) {
609 buckets_.resize(count, InstVector(GetGraph()->GetLocalAllocator()->Adapter()));
610 }
611 for (auto &bucket : buckets_) {
612 bucket.clear();
613 }
614 dfs_num_ = DEFAULT_DFS_VAL;
615 }
616
617 /*
618 * Selecting phi instructions that can be deleted
619 * and replaced with a single instruction for all uses
620 *
621 * Example
622 * ...
623 * 6p.u64 Phi v2(bb4), v2(bb3)
624 * 7.u64 Return v6p
625 *
626 * Removing instruction 6 and replacing use with v2
627 *
628 * ...
629 * 7.u64 Return v2
630 */
PhiChecker()631 bool Cleanup::PhiChecker()
632 {
633 BuildDominators();
634 bool modified = false;
635 for (auto bb : GetGraph()->GetBlocksRPO()) {
636 for (auto phi : bb->PhiInstsSafe()) {
637 auto change = GetIdom(phi);
638 if (change == fake_root_) {
639 continue;
640 }
641 while (GetIdom(change) != fake_root_) {
642 change = GetIdom(change);
643 }
644 auto basic_block = phi->GetBasicBlock();
645 phi->ReplaceUsers(change);
646 basic_block->RemoveInst(phi);
647 modified = true;
648 }
649 }
650 map_.clear();
651 return modified;
652 }
653
InvalidateAnalyses()654 void Cleanup::InvalidateAnalyses()
655 {
656 GetGraph()->InvalidateAnalysis<LinearOrder>();
657 GetGraph()->InvalidateAnalysis<BoundsAnalysis>();
658 GetGraph()->InvalidateAnalysis<AliasAnalysis>();
659 }
660 } // namespace panda::compiler
661