Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2014 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "dead_code_elimination.h" |
| 18 | |
| 19 | #include "base/bit_vector-inl.h" |
| 20 | |
| 21 | namespace art { |
| 22 | |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 23 | static void MarkReachableBlocks(HBasicBlock* block, ArenaBitVector* visited) { |
| 24 | int block_id = block->GetBlockId(); |
| 25 | if (visited->IsBitSet(block_id)) { |
| 26 | return; |
| 27 | } |
| 28 | visited->SetBit(block_id); |
| 29 | |
| 30 | HInstruction* last_instruction = block->GetLastInstruction(); |
| 31 | if (last_instruction->IsIf()) { |
| 32 | HIf* if_instruction = last_instruction->AsIf(); |
| 33 | HInstruction* condition = if_instruction->InputAt(0); |
| 34 | if (!condition->IsIntConstant()) { |
| 35 | MarkReachableBlocks(if_instruction->IfTrueSuccessor(), visited); |
| 36 | MarkReachableBlocks(if_instruction->IfFalseSuccessor(), visited); |
| 37 | } else if (condition->AsIntConstant()->IsOne()) { |
| 38 | MarkReachableBlocks(if_instruction->IfTrueSuccessor(), visited); |
| 39 | } else { |
| 40 | DCHECK(condition->AsIntConstant()->IsZero()); |
| 41 | MarkReachableBlocks(if_instruction->IfFalseSuccessor(), visited); |
| 42 | } |
| 43 | } else { |
| 44 | for (size_t i = 0, e = block->GetSuccessors().Size(); i < e; ++i) { |
| 45 | MarkReachableBlocks(block->GetSuccessors().Get(i), visited); |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) { |
| 51 | if (stats_ != nullptr) { |
| 52 | stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction, |
| 53 | block->GetPhis().CountSize() + block->GetInstructions().CountSize()); |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | void HDeadCodeElimination::RemoveDeadBlocks() { |
| 58 | // Classify blocks as reachable/unreachable. |
| 59 | ArenaAllocator* allocator = graph_->GetArena(); |
| 60 | ArenaBitVector live_blocks(allocator, graph_->GetBlocks().Size(), false); |
| 61 | MarkReachableBlocks(graph_->GetEntryBlock(), &live_blocks); |
| 62 | |
| 63 | // Remove all dead blocks. Process blocks in post-order, because removal needs |
| 64 | // the block's chain of dominators. |
| 65 | for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) { |
| 66 | HBasicBlock* block = it.Current(); |
| 67 | if (live_blocks.IsBitSet(block->GetBlockId())) { |
| 68 | continue; |
| 69 | } |
| 70 | MaybeRecordDeadBlock(block); |
| 71 | block->DisconnectAndDelete(); |
| 72 | } |
| 73 | |
| 74 | // Connect successive blocks created by dead branches. Order does not matter. |
| 75 | for (HReversePostOrderIterator it(*graph_); !it.Done();) { |
| 76 | HBasicBlock* block = it.Current(); |
| 77 | if (block->IsEntryBlock() || block->GetSuccessors().Size() != 1u) { |
| 78 | it.Advance(); |
| 79 | continue; |
| 80 | } |
| 81 | HBasicBlock* successor = block->GetSuccessors().Get(0); |
| 82 | if (successor->IsExitBlock() || successor->GetPredecessors().Size() != 1u) { |
| 83 | it.Advance(); |
| 84 | continue; |
| 85 | } |
| 86 | block->MergeWith(successor); |
| 87 | |
| 88 | // Reiterate on this block in case it can be merged with its new successor. |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | void HDeadCodeElimination::RemoveDeadInstructions() { |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 93 | // Process basic blocks in post-order in the dominator tree, so that |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 94 | // a dead instruction depending on another dead instruction is removed. |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 95 | for (HPostOrderIterator b(*graph_); !b.Done(); b.Advance()) { |
| 96 | HBasicBlock* block = b.Current(); |
| 97 | // Traverse this block's instructions in backward order and remove |
| 98 | // the unused ones. |
| 99 | HBackwardInstructionIterator i(block->GetInstructions()); |
| 100 | // Skip the first iteration, as the last instruction of a block is |
| 101 | // a branching instruction. |
| 102 | DCHECK(i.Current()->IsControlFlow()); |
| 103 | for (i.Advance(); !i.Done(); i.Advance()) { |
| 104 | HInstruction* inst = i.Current(); |
| 105 | DCHECK(!inst->IsControlFlow()); |
Roland Levillain | e161a2a | 2014-10-03 12:45:18 +0100 | [diff] [blame] | 106 | if (!inst->HasSideEffects() |
| 107 | && !inst->CanThrow() |
| 108 | && !inst->IsSuspendCheck() |
Calin Juravle | 27df758 | 2015-04-17 19:12:31 +0100 | [diff] [blame] | 109 | && !inst->IsMemoryBarrier() // If we added an explicit barrier then we should keep it. |
Roland Levillain | e161a2a | 2014-10-03 12:45:18 +0100 | [diff] [blame] | 110 | && !inst->HasUses()) { |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 111 | block->RemoveInstruction(inst); |
Calin Juravle | 8f20bdb | 2015-04-21 14:07:50 +0100 | [diff] [blame] | 112 | MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction); |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 113 | } |
| 114 | } |
| 115 | } |
| 116 | } |
| 117 | |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 118 | void HDeadCodeElimination::Run() { |
| 119 | RemoveDeadBlocks(); |
| 120 | RemoveDeadInstructions(); |
| 121 | } |
| 122 | |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 123 | } // namespace art |