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 | |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 19 | #include "utils/array_ref.h" |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 20 | #include "base/bit_vector-inl.h" |
David Brazdil | 84daae5 | 2015-05-18 12:06:52 +0100 | [diff] [blame] | 21 | #include "ssa_phi_elimination.h" |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 22 | |
| 23 | namespace art { |
| 24 | |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 25 | static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) { |
| 26 | ArenaVector<HBasicBlock*> worklist(graph->GetArena()->Adapter()); |
| 27 | constexpr size_t kDefaultWorlistSize = 8; |
| 28 | worklist.reserve(kDefaultWorlistSize); |
| 29 | visited->SetBit(graph->GetEntryBlock()->GetBlockId()); |
| 30 | worklist.push_back(graph->GetEntryBlock()); |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 31 | |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 32 | while (!worklist.empty()) { |
| 33 | HBasicBlock* block = worklist.back(); |
| 34 | worklist.pop_back(); |
| 35 | int block_id = block->GetBlockId(); |
| 36 | DCHECK(visited->IsBitSet(block_id)); |
| 37 | |
| 38 | ArrayRef<HBasicBlock* const> live_successors(block->GetSuccessors()); |
| 39 | HInstruction* last_instruction = block->GetLastInstruction(); |
| 40 | if (last_instruction->IsIf()) { |
| 41 | HIf* if_instruction = last_instruction->AsIf(); |
| 42 | HInstruction* condition = if_instruction->InputAt(0); |
| 43 | if (condition->IsIntConstant()) { |
Roland Levillain | 1a65388 | 2016-03-18 18:05:57 +0000 | [diff] [blame] | 44 | if (condition->AsIntConstant()->IsTrue()) { |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 45 | live_successors = live_successors.SubArray(0u, 1u); |
| 46 | DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor()); |
| 47 | } else { |
Roland Levillain | 1a65388 | 2016-03-18 18:05:57 +0000 | [diff] [blame] | 48 | DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue(); |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 49 | live_successors = live_successors.SubArray(1u, 1u); |
| 50 | DCHECK_EQ(live_successors[0], if_instruction->IfFalseSuccessor()); |
| 51 | } |
Mark Mendell | fe57faa | 2015-09-18 09:26:15 -0400 | [diff] [blame] | 52 | } |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 53 | } else if (last_instruction->IsPackedSwitch()) { |
| 54 | HPackedSwitch* switch_instruction = last_instruction->AsPackedSwitch(); |
| 55 | HInstruction* switch_input = switch_instruction->InputAt(0); |
| 56 | if (switch_input->IsIntConstant()) { |
| 57 | int32_t switch_value = switch_input->AsIntConstant()->GetValue(); |
| 58 | int32_t start_value = switch_instruction->GetStartValue(); |
Vladimir Marko | 430c4f5 | 2015-09-25 17:10:15 +0100 | [diff] [blame] | 59 | // Note: Though the spec forbids packed-switch values to wrap around, we leave |
| 60 | // that task to the verifier and use unsigned arithmetic with it's "modulo 2^32" |
| 61 | // semantics to check if the value is in range, wrapped or not. |
| 62 | uint32_t switch_index = |
| 63 | static_cast<uint32_t>(switch_value) - static_cast<uint32_t>(start_value); |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 64 | if (switch_index < switch_instruction->GetNumEntries()) { |
| 65 | live_successors = live_successors.SubArray(switch_index, 1u); |
Vladimir Marko | ec7802a | 2015-10-01 20:57:57 +0100 | [diff] [blame] | 66 | DCHECK_EQ(live_successors[0], block->GetSuccessors()[switch_index]); |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 67 | } else { |
| 68 | live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u); |
| 69 | DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock()); |
| 70 | } |
Mark Mendell | fe57faa | 2015-09-18 09:26:15 -0400 | [diff] [blame] | 71 | } |
| 72 | } |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 73 | |
| 74 | for (HBasicBlock* successor : live_successors) { |
| 75 | // Add only those successors that have not been visited yet. |
| 76 | if (!visited->IsBitSet(successor->GetBlockId())) { |
| 77 | visited->SetBit(successor->GetBlockId()); |
| 78 | worklist.push_back(successor); |
| 79 | } |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 80 | } |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) { |
| 85 | if (stats_ != nullptr) { |
| 86 | stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction, |
| 87 | block->GetPhis().CountSize() + block->GetInstructions().CountSize()); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | void HDeadCodeElimination::RemoveDeadBlocks() { |
Nicolas Geoffray | 09aa147 | 2016-01-19 10:52:54 +0000 | [diff] [blame] | 92 | if (graph_->HasIrreducibleLoops()) { |
| 93 | // Do not eliminate dead blocks if the graph has irreducible loops. We could |
| 94 | // support it, but that would require changes in our loop representation to handle |
| 95 | // multiple entry points. We decided it was not worth the complexity. |
| 96 | return; |
| 97 | } |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 98 | // Classify blocks as reachable/unreachable. |
| 99 | ArenaAllocator* allocator = graph_->GetArena(); |
Vladimir Marko | f6a35de | 2016-03-21 12:01:50 +0000 | [diff] [blame] | 100 | ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE); |
David Brazdil | a4b8c21 | 2015-05-07 09:59:30 +0100 | [diff] [blame] | 101 | |
Vladimir Marko | 211c211 | 2015-09-24 16:52:33 +0100 | [diff] [blame] | 102 | MarkReachableBlocks(graph_, &live_blocks); |
Nicolas Geoffray | 1f82ecc | 2015-06-24 12:20:24 +0100 | [diff] [blame] | 103 | bool removed_one_or_more_blocks = false; |
Nicolas Geoffray | 15bd228 | 2016-01-05 15:55:41 +0000 | [diff] [blame] | 104 | bool rerun_dominance_and_loop_analysis = false; |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 105 | |
David Brazdil | a4b8c21 | 2015-05-07 09:59:30 +0100 | [diff] [blame] | 106 | // Remove all dead blocks. Iterate in post order because removal needs the |
| 107 | // block's chain of dominators and nested loops need to be updated from the |
| 108 | // inside out. |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 109 | for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) { |
| 110 | HBasicBlock* block = it.Current(); |
David Brazdil | a4b8c21 | 2015-05-07 09:59:30 +0100 | [diff] [blame] | 111 | int id = block->GetBlockId(); |
Nicolas Geoffray | 15bd228 | 2016-01-05 15:55:41 +0000 | [diff] [blame] | 112 | if (!live_blocks.IsBitSet(id)) { |
David Brazdil | 69a2804 | 2015-04-29 17:16:07 +0100 | [diff] [blame] | 113 | MaybeRecordDeadBlock(block); |
| 114 | block->DisconnectAndDelete(); |
Nicolas Geoffray | 1f82ecc | 2015-06-24 12:20:24 +0100 | [diff] [blame] | 115 | removed_one_or_more_blocks = true; |
Nicolas Geoffray | 15bd228 | 2016-01-05 15:55:41 +0000 | [diff] [blame] | 116 | if (block->IsInLoop()) { |
| 117 | rerun_dominance_and_loop_analysis = true; |
| 118 | } |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 119 | } |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 120 | } |
| 121 | |
Nicolas Geoffray | 1f82ecc | 2015-06-24 12:20:24 +0100 | [diff] [blame] | 122 | // If we removed at least one block, we need to recompute the full |
David Brazdil | 8a7c0fe | 2015-11-02 20:24:55 +0000 | [diff] [blame] | 123 | // dominator tree and try block membership. |
Nicolas Geoffray | 1f82ecc | 2015-06-24 12:20:24 +0100 | [diff] [blame] | 124 | if (removed_one_or_more_blocks) { |
Nicolas Geoffray | 15bd228 | 2016-01-05 15:55:41 +0000 | [diff] [blame] | 125 | if (rerun_dominance_and_loop_analysis) { |
| 126 | graph_->ClearLoopInformation(); |
| 127 | graph_->ClearDominanceInformation(); |
| 128 | graph_->BuildDominatorTree(); |
| 129 | } else { |
| 130 | graph_->ClearDominanceInformation(); |
| 131 | graph_->ComputeDominanceInformation(); |
| 132 | graph_->ComputeTryBlockInformation(); |
| 133 | } |
Nicolas Geoffray | 1f82ecc | 2015-06-24 12:20:24 +0100 | [diff] [blame] | 134 | } |
| 135 | |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 136 | // Connect successive blocks created by dead branches. Order does not matter. |
| 137 | for (HReversePostOrderIterator it(*graph_); !it.Done();) { |
| 138 | HBasicBlock* block = it.Current(); |
David Brazdil | 8a7c0fe | 2015-11-02 20:24:55 +0000 | [diff] [blame] | 139 | if (block->IsEntryBlock() || !block->GetLastInstruction()->IsGoto()) { |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 140 | it.Advance(); |
| 141 | continue; |
| 142 | } |
David Brazdil | 8a7c0fe | 2015-11-02 20:24:55 +0000 | [diff] [blame] | 143 | HBasicBlock* successor = block->GetSingleSuccessor(); |
Vladimir Marko | 6058455 | 2015-09-03 13:35:12 +0000 | [diff] [blame] | 144 | if (successor->IsExitBlock() || successor->GetPredecessors().size() != 1u) { |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 145 | it.Advance(); |
| 146 | continue; |
| 147 | } |
| 148 | block->MergeWith(successor); |
| 149 | |
| 150 | // Reiterate on this block in case it can be merged with its new successor. |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | void HDeadCodeElimination::RemoveDeadInstructions() { |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 155 | // Process basic blocks in post-order in the dominator tree, so that |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 156 | // a dead instruction depending on another dead instruction is removed. |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 157 | for (HPostOrderIterator b(*graph_); !b.Done(); b.Advance()) { |
| 158 | HBasicBlock* block = b.Current(); |
| 159 | // Traverse this block's instructions in backward order and remove |
| 160 | // the unused ones. |
| 161 | HBackwardInstructionIterator i(block->GetInstructions()); |
| 162 | // Skip the first iteration, as the last instruction of a block is |
| 163 | // a branching instruction. |
| 164 | DCHECK(i.Current()->IsControlFlow()); |
| 165 | for (i.Advance(); !i.Done(); i.Advance()) { |
| 166 | HInstruction* inst = i.Current(); |
| 167 | DCHECK(!inst->IsControlFlow()); |
Alexandre Rames | 78e3ef6 | 2015-08-12 13:43:29 +0100 | [diff] [blame] | 168 | if (!inst->HasSideEffects() |
Roland Levillain | e161a2a | 2014-10-03 12:45:18 +0100 | [diff] [blame] | 169 | && !inst->CanThrow() |
| 170 | && !inst->IsSuspendCheck() |
David Srbecky | 0cf4493 | 2015-12-09 14:09:59 +0000 | [diff] [blame] | 171 | && !inst->IsNativeDebugInfo() |
Nicolas Geoffray | 839188b | 2015-06-02 10:38:12 +0100 | [diff] [blame] | 172 | // If we added an explicit barrier then we should keep it. |
| 173 | && !inst->IsMemoryBarrier() |
Nicolas Geoffray | e418dda | 2015-08-11 20:03:09 -0700 | [diff] [blame] | 174 | && !inst->IsParameterValue() |
Roland Levillain | e161a2a | 2014-10-03 12:45:18 +0100 | [diff] [blame] | 175 | && !inst->HasUses()) { |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 176 | block->RemoveInstruction(inst); |
Calin Juravle | 8f20bdb | 2015-04-21 14:07:50 +0100 | [diff] [blame] | 177 | MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction); |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 178 | } |
| 179 | } |
| 180 | } |
| 181 | } |
| 182 | |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 183 | void HDeadCodeElimination::Run() { |
David Brazdil | 8a7c0fe | 2015-11-02 20:24:55 +0000 | [diff] [blame] | 184 | RemoveDeadBlocks(); |
David Brazdil | 84daae5 | 2015-05-18 12:06:52 +0100 | [diff] [blame] | 185 | SsaRedundantPhiElimination(graph_).Run(); |
David Brazdil | 2d7352b | 2015-04-20 14:52:42 +0100 | [diff] [blame] | 186 | RemoveDeadInstructions(); |
| 187 | } |
| 188 | |
Roland Levillain | 72bceff | 2014-09-15 18:29:00 +0100 | [diff] [blame] | 189 | } // namespace art |