blob: adfe09ba9f7f200bf0185934c8dc9ac1cbce15ad [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
David Brazdild9c90372016-09-14 16:53:55 +010019#include "base/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) {
Vladimir Marko3ea5a972016-05-09 20:23:34 +010026 ArenaVector<HBasicBlock*> worklist(graph->GetArena()->Adapter(kArenaAllocDCE));
Vladimir Marko211c2112015-09-24 16:52:33 +010027 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()) {
Roland Levillain1a653882016-03-18 18:05:57 +000044 if (condition->AsIntConstant()->IsTrue()) {
Vladimir Marko211c2112015-09-24 16:52:33 +010045 live_successors = live_successors.SubArray(0u, 1u);
46 DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor());
47 } else {
Roland Levillain1a653882016-03-18 18:05:57 +000048 DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue();
Vladimir Marko211c2112015-09-24 16:52:33 +010049 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();
Vladimir Marko430c4f52015-09-25 17:10:15 +010059 // 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 Marko211c2112015-09-24 16:52:33 +010064 if (switch_index < switch_instruction->GetNumEntries()) {
65 live_successors = live_successors.SubArray(switch_index, 1u);
Vladimir Markoec7802a2015-10-01 20:57:57 +010066 DCHECK_EQ(live_successors[0], block->GetSuccessors()[switch_index]);
Vladimir Marko211c2112015-09-24 16:52:33 +010067 } else {
68 live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u);
69 DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock());
70 }
Mark Mendellfe57faa2015-09-18 09:26:15 -040071 }
72 }
Vladimir Marko211c2112015-09-24 16:52:33 +010073
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 Brazdil2d7352b2015-04-20 14:52:42 +010080 }
81 }
82}
83
84void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) {
85 if (stats_ != nullptr) {
86 stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction,
87 block->GetPhis().CountSize() + block->GetInstructions().CountSize());
88 }
89}
90
Nicolas Geoffraydac9b192016-07-15 10:46:17 +010091void HDeadCodeElimination::MaybeRecordSimplifyIf() {
92 if (stats_ != nullptr) {
93 stats_->RecordStat(MethodCompilationStat::kSimplifyIf);
Nicolas Geoffray09aa1472016-01-19 10:52:54 +000094 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +010095}
96
97static bool HasInput(HCondition* instruction, HInstruction* input) {
98 return (instruction->InputAt(0) == input) ||
99 (instruction->InputAt(1) == input);
100}
101
102static bool HasEquality(IfCondition condition) {
103 switch (condition) {
104 case kCondEQ:
105 case kCondLE:
106 case kCondGE:
107 case kCondBE:
108 case kCondAE:
109 return true;
110 case kCondNE:
111 case kCondLT:
112 case kCondGT:
113 case kCondB:
114 case kCondA:
115 return false;
116 }
117}
118
119static HConstant* Evaluate(HCondition* condition, HInstruction* left, HInstruction* right) {
120 if (left == right && !Primitive::IsFloatingPointType(left->GetType())) {
121 return condition->GetBlock()->GetGraph()->GetIntConstant(
122 HasEquality(condition->GetCondition()) ? 1 : 0);
123 }
124
125 if (!left->IsConstant() || !right->IsConstant()) {
126 return nullptr;
127 }
128
129 if (left->IsIntConstant()) {
130 return condition->Evaluate(left->AsIntConstant(), right->AsIntConstant());
131 } else if (left->IsNullConstant()) {
132 return condition->Evaluate(left->AsNullConstant(), right->AsNullConstant());
133 } else if (left->IsLongConstant()) {
134 return condition->Evaluate(left->AsLongConstant(), right->AsLongConstant());
135 } else if (left->IsFloatConstant()) {
136 return condition->Evaluate(left->AsFloatConstant(), right->AsFloatConstant());
137 } else {
138 DCHECK(left->IsDoubleConstant());
139 return condition->Evaluate(left->AsDoubleConstant(), right->AsDoubleConstant());
140 }
141}
142
143// Simplify the pattern:
144//
145// B1 B2 ...
146// goto goto goto
147// \ | /
148// \ | /
149// B3
150// i1 = phi(input, input)
151// (i2 = condition on i1)
152// if i1 (or i2)
153// / \
154// / \
155// B4 B5
156//
157// Into:
158//
159// B1 B2 ...
160// | | |
161// B4 B5 B?
162//
163// This simplification cannot be applied for loop headers, as they
164// contain a suspend check.
165//
166// Note that we rely on the dead code elimination to get rid of B3.
167bool HDeadCodeElimination::SimplifyIfs() {
168 bool simplified_one_or_more_ifs = false;
169 bool rerun_dominance_and_loop_analysis = false;
170
171 for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
172 HBasicBlock* block = it.Current();
173 HInstruction* last = block->GetLastInstruction();
174 HInstruction* first = block->GetFirstInstruction();
175 if (last->IsIf() &&
176 block->HasSinglePhi() &&
177 block->GetFirstPhi()->HasOnlyOneNonEnvironmentUse()) {
178 bool has_only_phi_and_if = (last == first) && (last->InputAt(0) == block->GetFirstPhi());
179 bool has_only_phi_condition_and_if =
180 !has_only_phi_and_if &&
181 first->IsCondition() &&
182 HasInput(first->AsCondition(), block->GetFirstPhi()) &&
183 (first->GetNext() == last) &&
184 (last->InputAt(0) == first) &&
185 first->HasOnlyOneNonEnvironmentUse();
186
187 if (has_only_phi_and_if || has_only_phi_condition_and_if) {
188 DCHECK(!block->IsLoopHeader());
189 HPhi* phi = block->GetFirstPhi()->AsPhi();
190 bool phi_input_is_left = (first->InputAt(0) == phi);
191
192 // Walk over all inputs of the phis and update the control flow of
193 // predecessors feeding constants to the phi.
194 // Note that phi->InputCount() may change inside the loop.
195 for (size_t i = 0; i < phi->InputCount();) {
196 HInstruction* input = phi->InputAt(i);
197 HInstruction* value_to_check = nullptr;
198 if (has_only_phi_and_if) {
199 if (input->IsIntConstant()) {
200 value_to_check = input;
201 }
202 } else {
203 DCHECK(has_only_phi_condition_and_if);
204 if (phi_input_is_left) {
205 value_to_check = Evaluate(first->AsCondition(), input, first->InputAt(1));
206 } else {
207 value_to_check = Evaluate(first->AsCondition(), first->InputAt(0), input);
208 }
209 }
210 if (value_to_check == nullptr) {
211 // Could not evaluate to a constant, continue iterating over the inputs.
212 ++i;
213 } else {
214 HBasicBlock* predecessor_to_update = block->GetPredecessors()[i];
215 HBasicBlock* successor_to_update = nullptr;
216 if (value_to_check->AsIntConstant()->IsTrue()) {
217 successor_to_update = last->AsIf()->IfTrueSuccessor();
218 } else {
219 DCHECK(value_to_check->AsIntConstant()->IsFalse())
220 << value_to_check->AsIntConstant()->GetValue();
221 successor_to_update = last->AsIf()->IfFalseSuccessor();
222 }
223 predecessor_to_update->ReplaceSuccessor(block, successor_to_update);
224 phi->RemoveInputAt(i);
225 simplified_one_or_more_ifs = true;
226 if (block->IsInLoop()) {
227 rerun_dominance_and_loop_analysis = true;
228 }
229 // For simplicity, don't create a dead block, let the dead code elimination
230 // pass deal with it.
231 if (phi->InputCount() == 1) {
232 break;
233 }
234 }
235 }
236 if (block->GetPredecessors().size() == 1) {
237 phi->ReplaceWith(phi->InputAt(0));
238 block->RemovePhi(phi);
239 if (has_only_phi_condition_and_if) {
240 // Evaluate here (and not wait for a constant folding pass) to open
241 // more opportunities for DCE.
242 HInstruction* result = first->AsCondition()->TryStaticEvaluation();
243 if (result != nullptr) {
244 first->ReplaceWith(result);
245 block->RemoveInstruction(first);
246 }
247 }
248 }
249 if (simplified_one_or_more_ifs) {
250 MaybeRecordSimplifyIf();
251 }
252 }
253 }
254 }
255 // We need to re-analyze the graph in order to run DCE afterwards.
256 if (simplified_one_or_more_ifs) {
257 if (rerun_dominance_and_loop_analysis) {
258 graph_->ClearLoopInformation();
259 graph_->ClearDominanceInformation();
260 graph_->BuildDominatorTree();
261 } else {
262 graph_->ClearDominanceInformation();
263 // We have introduced critical edges, remove them.
264 graph_->SimplifyCFG();
265 graph_->ComputeDominanceInformation();
266 graph_->ComputeTryBlockInformation();
267 }
268 }
269
270 return simplified_one_or_more_ifs;
271}
272
273void HDeadCodeElimination::ConnectSuccessiveBlocks() {
274 // Order does not matter.
275 for (HReversePostOrderIterator it(*graph_); !it.Done();) {
276 HBasicBlock* block = it.Current();
277 if (block->IsEntryBlock() || !block->GetLastInstruction()->IsGoto()) {
278 it.Advance();
279 continue;
280 }
281 HBasicBlock* successor = block->GetSingleSuccessor();
282 if (successor->IsExitBlock() || successor->GetPredecessors().size() != 1u) {
283 it.Advance();
284 continue;
285 }
286 block->MergeWith(successor);
287 // Reiterate on this block in case it can be merged with its new successor.
288 }
289}
290
291bool HDeadCodeElimination::RemoveDeadBlocks() {
David Brazdil2d7352b2015-04-20 14:52:42 +0100292 // Classify blocks as reachable/unreachable.
293 ArenaAllocator* allocator = graph_->GetArena();
Vladimir Markof6a35de2016-03-21 12:01:50 +0000294 ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE);
David Brazdila4b8c212015-05-07 09:59:30 +0100295
Vladimir Marko211c2112015-09-24 16:52:33 +0100296 MarkReachableBlocks(graph_, &live_blocks);
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100297 bool removed_one_or_more_blocks = false;
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000298 bool rerun_dominance_and_loop_analysis = false;
David Brazdil2d7352b2015-04-20 14:52:42 +0100299
David Brazdila4b8c212015-05-07 09:59:30 +0100300 // Remove all dead blocks. Iterate in post order because removal needs the
301 // block's chain of dominators and nested loops need to be updated from the
302 // inside out.
David Brazdil2d7352b2015-04-20 14:52:42 +0100303 for (HPostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
304 HBasicBlock* block = it.Current();
David Brazdila4b8c212015-05-07 09:59:30 +0100305 int id = block->GetBlockId();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000306 if (!live_blocks.IsBitSet(id)) {
David Brazdil69a28042015-04-29 17:16:07 +0100307 MaybeRecordDeadBlock(block);
308 block->DisconnectAndDelete();
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100309 removed_one_or_more_blocks = true;
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000310 if (block->IsInLoop()) {
311 rerun_dominance_and_loop_analysis = true;
312 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100313 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100314 }
315
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100316 // If we removed at least one block, we need to recompute the full
David Brazdil8a7c0fe2015-11-02 20:24:55 +0000317 // dominator tree and try block membership.
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100318 if (removed_one_or_more_blocks) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000319 if (rerun_dominance_and_loop_analysis) {
320 graph_->ClearLoopInformation();
321 graph_->ClearDominanceInformation();
322 graph_->BuildDominatorTree();
323 } else {
324 graph_->ClearDominanceInformation();
325 graph_->ComputeDominanceInformation();
326 graph_->ComputeTryBlockInformation();
327 }
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100328 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100329 return removed_one_or_more_blocks;
David Brazdil2d7352b2015-04-20 14:52:42 +0100330}
331
332void HDeadCodeElimination::RemoveDeadInstructions() {
Roland Levillain72bceff2014-09-15 18:29:00 +0100333 // Process basic blocks in post-order in the dominator tree, so that
David Brazdil2d7352b2015-04-20 14:52:42 +0100334 // a dead instruction depending on another dead instruction is removed.
Roland Levillain72bceff2014-09-15 18:29:00 +0100335 for (HPostOrderIterator b(*graph_); !b.Done(); b.Advance()) {
336 HBasicBlock* block = b.Current();
337 // Traverse this block's instructions in backward order and remove
338 // the unused ones.
339 HBackwardInstructionIterator i(block->GetInstructions());
340 // Skip the first iteration, as the last instruction of a block is
341 // a branching instruction.
342 DCHECK(i.Current()->IsControlFlow());
343 for (i.Advance(); !i.Done(); i.Advance()) {
344 HInstruction* inst = i.Current();
345 DCHECK(!inst->IsControlFlow());
Aart Bik482095d2016-10-10 15:39:10 -0700346 if (inst->IsDeadAndRemovable()) {
Roland Levillain72bceff2014-09-15 18:29:00 +0100347 block->RemoveInstruction(inst);
Calin Juravle8f20bdb2015-04-21 14:07:50 +0100348 MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction);
Roland Levillain72bceff2014-09-15 18:29:00 +0100349 }
350 }
351 }
352}
353
David Brazdil2d7352b2015-04-20 14:52:42 +0100354void HDeadCodeElimination::Run() {
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100355 // Do not eliminate dead blocks if the graph has irreducible loops. We could
356 // support it, but that would require changes in our loop representation to handle
357 // multiple entry points. We decided it was not worth the complexity.
358 if (!graph_->HasIrreducibleLoops()) {
359 // Simplify graph to generate more dead block patterns.
360 ConnectSuccessiveBlocks();
361 bool did_any_simplification = false;
362 did_any_simplification |= SimplifyIfs();
363 did_any_simplification |= RemoveDeadBlocks();
364 if (did_any_simplification) {
365 // Connect successive blocks created by dead branches.
366 ConnectSuccessiveBlocks();
367 }
368 }
David Brazdil84daae52015-05-18 12:06:52 +0100369 SsaRedundantPhiElimination(graph_).Run();
David Brazdil2d7352b2015-04-20 14:52:42 +0100370 RemoveDeadInstructions();
371}
372
Roland Levillain72bceff2014-09-15 18:29:00 +0100373} // namespace art