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