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