• 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/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