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