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