blob: b322759a6c49c3eead3b7f552ce4b6afb4c6e86c [file] [log] [blame]
Roland Levillain72bceff2014-09-15 18:29:00 +01001/*
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 Marko211c2112015-09-24 16:52:33 +010019#include "utils/array_ref.h"
Roland Levillain72bceff2014-09-15 18:29:00 +010020#include "base/bit_vector-inl.h"
David Brazdil84daae52015-05-18 12:06:52 +010021#include "ssa_phi_elimination.h"
Roland Levillain72bceff2014-09-15 18:29:00 +010022
23namespace art {
24
Vladimir Marko211c2112015-09-24 16:52:33 +010025static 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 Brazdil2d7352b2015-04-20 14:52:42 +010031
Vladimir Marko211c2112015-09-24 16:52:33 +010032 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()->IsOne()) {
45 live_successors = live_successors.SubArray(0u, 1u);
46 DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor());
47 } else {
48 DCHECK(condition->AsIntConstant()->IsZero());
49 live_successors = live_successors.SubArray(1u, 1u);
50 DCHECK_EQ(live_successors[0], if_instruction->IfFalseSuccessor());
51 }
Mark Mendellfe57faa2015-09-18 09:26:15 -040052 }
Vladimir Marko211c2112015-09-24 16:52:33 +010053 } 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 uint32_t switch_index = static_cast<uint32_t>(switch_value - start_value);
60 if (switch_index < switch_instruction->GetNumEntries()) {
61 live_successors = live_successors.SubArray(switch_index, 1u);
62 DCHECK_EQ(live_successors[0], block->GetSuccessor(switch_index));
63 } else {
64 live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u);
65 DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock());
66 }
Mark Mendellfe57faa2015-09-18 09:26:15 -040067 }
68 }
Vladimir Marko211c2112015-09-24 16:52:33 +010069
70 for (HBasicBlock* successor : live_successors) {
71 // Add only those successors that have not been visited yet.
72 if (!visited->IsBitSet(successor->GetBlockId())) {
73 visited->SetBit(successor->GetBlockId());
74 worklist.push_back(successor);
75 }
David Brazdil2d7352b2015-04-20 14:52:42 +010076 }
77 }
78}
79
David Brazdila4b8c212015-05-07 09:59:30 +010080static void MarkLoopHeadersContaining(const HBasicBlock& block, ArenaBitVector* set) {
81 for (HLoopInformationOutwardIterator it(block); !it.Done(); it.Advance()) {
82 set->SetBit(it.Current()->GetHeader()->GetBlockId());
83 }
84}
85
David Brazdil2d7352b2015-04-20 14:52:42 +010086void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) {
87 if (stats_ != nullptr) {
88 stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction,
89 block->GetPhis().CountSize() + block->GetInstructions().CountSize());
90 }
91}
92
93void HDeadCodeElimination::RemoveDeadBlocks() {
94 // Classify blocks as reachable/unreachable.
95 ArenaAllocator* allocator = graph_->GetArena();
Vladimir Markofa6b93c2015-09-15 10:15:55 +010096 ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false);
97 ArenaBitVector affected_loops(allocator, graph_->GetBlocks().size(), false);
David Brazdila4b8c212015-05-07 09:59:30 +010098
Vladimir Marko211c2112015-09-24 16:52:33 +010099 MarkReachableBlocks(graph_, &live_blocks);
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100100 bool removed_one_or_more_blocks = false;
David Brazdil2d7352b2015-04-20 14:52:42 +0100101
David Brazdila4b8c212015-05-07 09:59:30 +0100102 // Remove all dead blocks. Iterate in post order because removal needs the
103 // block's chain of dominators and nested loops need to be updated from the
104 // inside out.
David Brazdil2d7352b2015-04-20 14:52:42 +0100105 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
106 HBasicBlock* block = it.Current();
David Brazdila4b8c212015-05-07 09:59:30 +0100107 int id = block->GetBlockId();
108 if (live_blocks.IsBitSet(id)) {
109 if (affected_loops.IsBitSet(id)) {
110 DCHECK(block->IsLoopHeader());
111 block->GetLoopInformation()->Update();
112 }
David Brazdil69a28042015-04-29 17:16:07 +0100113 } else {
114 MaybeRecordDeadBlock(block);
David Brazdila4b8c212015-05-07 09:59:30 +0100115 MarkLoopHeadersContaining(*block, &affected_loops);
David Brazdil69a28042015-04-29 17:16:07 +0100116 block->DisconnectAndDelete();
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100117 removed_one_or_more_blocks = true;
David Brazdil2d7352b2015-04-20 14:52:42 +0100118 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100119 }
120
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100121 // If we removed at least one block, we need to recompute the full
122 // dominator tree.
123 if (removed_one_or_more_blocks) {
124 graph_->ClearDominanceInformation();
125 graph_->ComputeDominanceInformation();
126 }
127
David Brazdil2d7352b2015-04-20 14:52:42 +0100128 // Connect successive blocks created by dead branches. Order does not matter.
129 for (HReversePostOrderIterator it(*graph_); !it.Done();) {
130 HBasicBlock* block = it.Current();
Vladimir Marko60584552015-09-03 13:35:12 +0000131 if (block->IsEntryBlock() || block->GetSuccessors().size() != 1u) {
David Brazdil2d7352b2015-04-20 14:52:42 +0100132 it.Advance();
133 continue;
134 }
Vladimir Marko60584552015-09-03 13:35:12 +0000135 HBasicBlock* successor = block->GetSuccessor(0);
136 if (successor->IsExitBlock() || successor->GetPredecessors().size() != 1u) {
David Brazdil2d7352b2015-04-20 14:52:42 +0100137 it.Advance();
138 continue;
139 }
140 block->MergeWith(successor);
141
142 // Reiterate on this block in case it can be merged with its new successor.
143 }
144}
145
146void HDeadCodeElimination::RemoveDeadInstructions() {
Roland Levillain72bceff2014-09-15 18:29:00 +0100147 // Process basic blocks in post-order in the dominator tree, so that
David Brazdil2d7352b2015-04-20 14:52:42 +0100148 // a dead instruction depending on another dead instruction is removed.
Roland Levillain72bceff2014-09-15 18:29:00 +0100149 for (HPostOrderIterator b(*graph_); !b.Done(); b.Advance()) {
150 HBasicBlock* block = b.Current();
151 // Traverse this block's instructions in backward order and remove
152 // the unused ones.
153 HBackwardInstructionIterator i(block->GetInstructions());
154 // Skip the first iteration, as the last instruction of a block is
155 // a branching instruction.
156 DCHECK(i.Current()->IsControlFlow());
157 for (i.Advance(); !i.Done(); i.Advance()) {
158 HInstruction* inst = i.Current();
159 DCHECK(!inst->IsControlFlow());
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100160 if (!inst->HasSideEffects()
Roland Levillaine161a2a2014-10-03 12:45:18 +0100161 && !inst->CanThrow()
162 && !inst->IsSuspendCheck()
Nicolas Geoffray839188b2015-06-02 10:38:12 +0100163 // If we added an explicit barrier then we should keep it.
164 && !inst->IsMemoryBarrier()
Nicolas Geoffraye418dda2015-08-11 20:03:09 -0700165 && !inst->IsParameterValue()
Roland Levillaine161a2a2014-10-03 12:45:18 +0100166 && !inst->HasUses()) {
Roland Levillain72bceff2014-09-15 18:29:00 +0100167 block->RemoveInstruction(inst);
Calin Juravle8f20bdb2015-04-21 14:07:50 +0100168 MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction);
Roland Levillain72bceff2014-09-15 18:29:00 +0100169 }
170 }
171 }
172}
173
David Brazdil2d7352b2015-04-20 14:52:42 +0100174void HDeadCodeElimination::Run() {
David Brazdilbbd733e2015-08-18 17:48:17 +0100175 if (!graph_->HasTryCatch()) {
176 // TODO: Update dead block elimination and enable for try/catch.
177 RemoveDeadBlocks();
178 }
David Brazdil84daae52015-05-18 12:06:52 +0100179 SsaRedundantPhiElimination(graph_).Run();
David Brazdil2d7352b2015-04-20 14:52:42 +0100180 RemoveDeadInstructions();
181}
182
Roland Levillain72bceff2014-09-15 18:29:00 +0100183} // namespace art