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 "utils/array_ref.h" 20 #include "base/bit_vector-inl.h" 21 #include "ssa_phi_elimination.h" 22 23 namespace art { 24 25 static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) { 26 ArenaVector<HBasicBlock*> worklist(graph->GetArena()->Adapter(kArenaAllocDCE)); 27 constexpr size_t kDefaultWorlistSize = 8; 28 worklist.reserve(kDefaultWorlistSize); 29 visited->SetBit(graph->GetEntryBlock()->GetBlockId()); 30 worklist.push_back(graph->GetEntryBlock()); 31 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()) { 44 if (condition->AsIntConstant()->IsTrue()) { 45 live_successors = live_successors.SubArray(0u, 1u); 46 DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor()); 47 } else { 48 DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue(); 49 live_successors = live_successors.SubArray(1u, 1u); 50 DCHECK_EQ(live_successors[0], if_instruction->IfFalseSuccessor()); 51 } 52 } 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(); 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); 64 if (switch_index < switch_instruction->GetNumEntries()) { 65 live_successors = live_successors.SubArray(switch_index, 1u); 66 DCHECK_EQ(live_successors[0], block->GetSuccessors()[switch_index]); 67 } else { 68 live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u); 69 DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock()); 70 } 71 } 72 } 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 } 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() { 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 } 98 // Classify blocks as reachable/unreachable. 99 ArenaAllocator* allocator = graph_->GetArena(); 100 ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE); 101 102 MarkReachableBlocks(graph_, &live_blocks); 103 bool removed_one_or_more_blocks = false; 104 bool rerun_dominance_and_loop_analysis = false; 105 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. 109 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) { 110 HBasicBlock* block = it.Current(); 111 int id = block->GetBlockId(); 112 if (!live_blocks.IsBitSet(id)) { 113 MaybeRecordDeadBlock(block); 114 block->DisconnectAndDelete(); 115 removed_one_or_more_blocks = true; 116 if (block->IsInLoop()) { 117 rerun_dominance_and_loop_analysis = true; 118 } 119 } 120 } 121 122 // If we removed at least one block, we need to recompute the full 123 // dominator tree and try block membership. 124 if (removed_one_or_more_blocks) { 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 } 134 } 135 136 // Connect successive blocks created by dead branches. Order does not matter. 137 for (HReversePostOrderIterator it(*graph_); !it.Done();) { 138 HBasicBlock* block = it.Current(); 139 if (block->IsEntryBlock() || !block->GetLastInstruction()->IsGoto()) { 140 it.Advance(); 141 continue; 142 } 143 HBasicBlock* successor = block->GetSingleSuccessor(); 144 if (successor->IsExitBlock() || successor->GetPredecessors().size() != 1u) { 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() { 155 // Process basic blocks in post-order in the dominator tree, so that 156 // a dead instruction depending on another dead instruction is removed. 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()); 168 if (!inst->HasSideEffects() 169 && !inst->CanThrow() 170 && !inst->IsSuspendCheck() 171 && !inst->IsNativeDebugInfo() 172 // If we added an explicit barrier then we should keep it. 173 && !inst->IsMemoryBarrier() 174 && !inst->IsParameterValue() 175 && !inst->HasUses()) { 176 block->RemoveInstruction(inst); 177 MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction); 178 } 179 } 180 } 181 } 182 183 void HDeadCodeElimination::Run() { 184 RemoveDeadBlocks(); 185 SsaRedundantPhiElimination(graph_).Run(); 186 RemoveDeadInstructions(); 187 } 188 189 } // namespace art 190