blob: cca1055ac8e828f94c5ff0ef6eac5bdb1edc419f [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"
Vladimir Marko009d1662017-10-10 13:21:15 +010021#include "base/scoped_arena_allocator.h"
22#include "base/scoped_arena_containers.h"
Vladimir Marko2c45bc92016-10-25 16:54:12 +010023#include "base/stl_util.h"
David Brazdil84daae52015-05-18 12:06:52 +010024#include "ssa_phi_elimination.h"
Roland Levillain72bceff2014-09-15 18:29:00 +010025
26namespace art {
27
Vladimir Marko211c2112015-09-24 16:52:33 +010028static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) {
Vladimir Marko009d1662017-10-10 13:21:15 +010029 // Use local allocator for allocating memory.
30 ScopedArenaAllocator allocator(graph->GetArenaStack());
31
32 ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocDCE));
Vladimir Marko211c2112015-09-24 16:52:33 +010033 constexpr size_t kDefaultWorlistSize = 8;
34 worklist.reserve(kDefaultWorlistSize);
35 visited->SetBit(graph->GetEntryBlock()->GetBlockId());
36 worklist.push_back(graph->GetEntryBlock());
David Brazdil2d7352b2015-04-20 14:52:42 +010037
Vladimir Marko211c2112015-09-24 16:52:33 +010038 while (!worklist.empty()) {
39 HBasicBlock* block = worklist.back();
40 worklist.pop_back();
41 int block_id = block->GetBlockId();
42 DCHECK(visited->IsBitSet(block_id));
43
44 ArrayRef<HBasicBlock* const> live_successors(block->GetSuccessors());
45 HInstruction* last_instruction = block->GetLastInstruction();
46 if (last_instruction->IsIf()) {
47 HIf* if_instruction = last_instruction->AsIf();
48 HInstruction* condition = if_instruction->InputAt(0);
49 if (condition->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +000050 if (condition->AsIntConstant()->IsTrue()) {
Vladimir Marko211c2112015-09-24 16:52:33 +010051 live_successors = live_successors.SubArray(0u, 1u);
52 DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor());
53 } else {
Roland Levillain1a653882016-03-18 18:05:57 +000054 DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue();
Vladimir Marko211c2112015-09-24 16:52:33 +010055 live_successors = live_successors.SubArray(1u, 1u);
56 DCHECK_EQ(live_successors[0], if_instruction->IfFalseSuccessor());
57 }
Mark Mendellfe57faa2015-09-18 09:26:15 -040058 }
Vladimir Marko211c2112015-09-24 16:52:33 +010059 } else if (last_instruction->IsPackedSwitch()) {
60 HPackedSwitch* switch_instruction = last_instruction->AsPackedSwitch();
61 HInstruction* switch_input = switch_instruction->InputAt(0);
62 if (switch_input->IsIntConstant()) {
63 int32_t switch_value = switch_input->AsIntConstant()->GetValue();
64 int32_t start_value = switch_instruction->GetStartValue();
Vladimir Marko430c4f52015-09-25 17:10:15 +010065 // Note: Though the spec forbids packed-switch values to wrap around, we leave
66 // that task to the verifier and use unsigned arithmetic with it's "modulo 2^32"
67 // semantics to check if the value is in range, wrapped or not.
68 uint32_t switch_index =
69 static_cast<uint32_t>(switch_value) - static_cast<uint32_t>(start_value);
Vladimir Marko211c2112015-09-24 16:52:33 +010070 if (switch_index < switch_instruction->GetNumEntries()) {
71 live_successors = live_successors.SubArray(switch_index, 1u);
Vladimir Markoec7802a2015-10-01 20:57:57 +010072 DCHECK_EQ(live_successors[0], block->GetSuccessors()[switch_index]);
Vladimir Marko211c2112015-09-24 16:52:33 +010073 } else {
74 live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u);
75 DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock());
76 }
Mark Mendellfe57faa2015-09-18 09:26:15 -040077 }
78 }
Vladimir Marko211c2112015-09-24 16:52:33 +010079
80 for (HBasicBlock* successor : live_successors) {
81 // Add only those successors that have not been visited yet.
82 if (!visited->IsBitSet(successor->GetBlockId())) {
83 visited->SetBit(successor->GetBlockId());
84 worklist.push_back(successor);
85 }
David Brazdil2d7352b2015-04-20 14:52:42 +010086 }
87 }
88}
89
90void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) {
91 if (stats_ != nullptr) {
92 stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction,
93 block->GetPhis().CountSize() + block->GetInstructions().CountSize());
94 }
95}
96
Nicolas Geoffraydac9b192016-07-15 10:46:17 +010097void HDeadCodeElimination::MaybeRecordSimplifyIf() {
98 if (stats_ != nullptr) {
99 stats_->RecordStat(MethodCompilationStat::kSimplifyIf);
Nicolas Geoffray09aa1472016-01-19 10:52:54 +0000100 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100101}
102
103static bool HasInput(HCondition* instruction, HInstruction* input) {
104 return (instruction->InputAt(0) == input) ||
105 (instruction->InputAt(1) == input);
106}
107
108static bool HasEquality(IfCondition condition) {
109 switch (condition) {
110 case kCondEQ:
111 case kCondLE:
112 case kCondGE:
113 case kCondBE:
114 case kCondAE:
115 return true;
116 case kCondNE:
117 case kCondLT:
118 case kCondGT:
119 case kCondB:
120 case kCondA:
121 return false;
122 }
123}
124
125static HConstant* Evaluate(HCondition* condition, HInstruction* left, HInstruction* right) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100126 if (left == right && !DataType::IsFloatingPointType(left->GetType())) {
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100127 return condition->GetBlock()->GetGraph()->GetIntConstant(
128 HasEquality(condition->GetCondition()) ? 1 : 0);
129 }
130
131 if (!left->IsConstant() || !right->IsConstant()) {
132 return nullptr;
133 }
134
135 if (left->IsIntConstant()) {
136 return condition->Evaluate(left->AsIntConstant(), right->AsIntConstant());
137 } else if (left->IsNullConstant()) {
138 return condition->Evaluate(left->AsNullConstant(), right->AsNullConstant());
139 } else if (left->IsLongConstant()) {
140 return condition->Evaluate(left->AsLongConstant(), right->AsLongConstant());
141 } else if (left->IsFloatConstant()) {
142 return condition->Evaluate(left->AsFloatConstant(), right->AsFloatConstant());
143 } else {
144 DCHECK(left->IsDoubleConstant());
145 return condition->Evaluate(left->AsDoubleConstant(), right->AsDoubleConstant());
146 }
147}
148
149// Simplify the pattern:
150//
Aart Bika8b8e9b2018-01-09 11:01:02 -0800151// B1
152// / \
153// | foo() // always throws
154// \ goto B2
155// \ /
156// B2
157//
158// Into:
159//
160// B1
161// / \
162// | foo()
163// | goto Exit
164// | |
165// B2 Exit
166//
167// Rationale:
168// Removal of the never taken edge to B2 may expose
169// other optimization opportunities, such as code sinking.
170bool HDeadCodeElimination::SimplifyAlwaysThrows() {
171 // Make sure exceptions go to exit.
172 if (graph_->HasTryCatch()) {
173 return false;
174 }
175 HBasicBlock* exit = graph_->GetExitBlock();
176 if (exit == nullptr) {
177 return false;
178 }
179
180 bool rerun_dominance_and_loop_analysis = false;
181
182 // Order does not matter, just pick one.
183 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
184 HInstruction* first = block->GetFirstInstruction();
185 HInstruction* last = block->GetLastInstruction();
186 // Ensure only one throwing instruction appears before goto.
187 if (first->AlwaysThrows() &&
188 first->GetNext() == last &&
189 last->IsGoto() &&
190 block->GetPhis().IsEmpty() &&
191 block->GetPredecessors().size() == 1u) {
192 DCHECK_EQ(block->GetSuccessors().size(), 1u);
193 HBasicBlock* pred = block->GetSinglePredecessor();
194 HBasicBlock* succ = block->GetSingleSuccessor();
195 // Ensure no computations are merged through throwing block.
196 // This does not prevent the optimization per se, but would
197 // require an elaborate clean up of the SSA graph.
198 if (succ != exit &&
199 !block->Dominates(pred) &&
200 pred->Dominates(succ) &&
201 succ->GetPredecessors().size() > 1u &&
202 succ->GetPhis().IsEmpty()) {
203 block->ReplaceSuccessor(succ, exit);
204 rerun_dominance_and_loop_analysis = true;
205 MaybeRecordStat(stats_, MethodCompilationStat::kSimplifyThrowingInvoke);
206 }
207 }
208 }
209
210 // We need to re-analyze the graph in order to run DCE afterwards.
211 if (rerun_dominance_and_loop_analysis) {
212 graph_->ClearLoopInformation();
213 graph_->ClearDominanceInformation();
214 graph_->BuildDominatorTree();
215 return true;
216 }
217 return false;
218}
219
220// Simplify the pattern:
221//
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100222// B1 B2 ...
223// goto goto goto
224// \ | /
225// \ | /
226// B3
227// i1 = phi(input, input)
228// (i2 = condition on i1)
229// if i1 (or i2)
230// / \
231// / \
232// B4 B5
233//
234// Into:
235//
236// B1 B2 ...
237// | | |
238// B4 B5 B?
239//
Vladimir Marko606c8f02016-11-03 13:01:28 +0000240// Note that individual edges can be redirected (for example B2->B3
241// can be redirected as B2->B5) without applying this optimization
242// to other incoming edges.
243//
244// This simplification cannot be applied to catch blocks, because
245// exception handler edges do not represent normal control flow.
246// Though in theory this could still apply to normal control flow
247// going directly to a catch block, we cannot support it at the
248// moment because the catch Phi's inputs do not correspond to the
249// catch block's predecessors, so we cannot identify which
250// predecessor corresponds to a given statically evaluated input.
251//
252// We do not apply this optimization to loop headers as this could
253// create irreducible loops. We rely on the suspend check in the
254// loop header to prevent the pattern match.
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100255//
256// Note that we rely on the dead code elimination to get rid of B3.
257bool HDeadCodeElimination::SimplifyIfs() {
258 bool simplified_one_or_more_ifs = false;
259 bool rerun_dominance_and_loop_analysis = false;
260
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100261 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100262 HInstruction* last = block->GetLastInstruction();
263 HInstruction* first = block->GetFirstInstruction();
Vladimir Marko606c8f02016-11-03 13:01:28 +0000264 if (!block->IsCatchBlock() &&
265 last->IsIf() &&
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100266 block->HasSinglePhi() &&
267 block->GetFirstPhi()->HasOnlyOneNonEnvironmentUse()) {
268 bool has_only_phi_and_if = (last == first) && (last->InputAt(0) == block->GetFirstPhi());
269 bool has_only_phi_condition_and_if =
270 !has_only_phi_and_if &&
271 first->IsCondition() &&
272 HasInput(first->AsCondition(), block->GetFirstPhi()) &&
273 (first->GetNext() == last) &&
274 (last->InputAt(0) == first) &&
275 first->HasOnlyOneNonEnvironmentUse();
276
277 if (has_only_phi_and_if || has_only_phi_condition_and_if) {
278 DCHECK(!block->IsLoopHeader());
279 HPhi* phi = block->GetFirstPhi()->AsPhi();
280 bool phi_input_is_left = (first->InputAt(0) == phi);
281
282 // Walk over all inputs of the phis and update the control flow of
283 // predecessors feeding constants to the phi.
284 // Note that phi->InputCount() may change inside the loop.
285 for (size_t i = 0; i < phi->InputCount();) {
286 HInstruction* input = phi->InputAt(i);
287 HInstruction* value_to_check = nullptr;
288 if (has_only_phi_and_if) {
289 if (input->IsIntConstant()) {
290 value_to_check = input;
291 }
292 } else {
293 DCHECK(has_only_phi_condition_and_if);
294 if (phi_input_is_left) {
295 value_to_check = Evaluate(first->AsCondition(), input, first->InputAt(1));
296 } else {
297 value_to_check = Evaluate(first->AsCondition(), first->InputAt(0), input);
298 }
299 }
300 if (value_to_check == nullptr) {
301 // Could not evaluate to a constant, continue iterating over the inputs.
302 ++i;
303 } else {
304 HBasicBlock* predecessor_to_update = block->GetPredecessors()[i];
305 HBasicBlock* successor_to_update = nullptr;
306 if (value_to_check->AsIntConstant()->IsTrue()) {
307 successor_to_update = last->AsIf()->IfTrueSuccessor();
308 } else {
309 DCHECK(value_to_check->AsIntConstant()->IsFalse())
310 << value_to_check->AsIntConstant()->GetValue();
311 successor_to_update = last->AsIf()->IfFalseSuccessor();
312 }
313 predecessor_to_update->ReplaceSuccessor(block, successor_to_update);
314 phi->RemoveInputAt(i);
315 simplified_one_or_more_ifs = true;
316 if (block->IsInLoop()) {
317 rerun_dominance_and_loop_analysis = true;
318 }
319 // For simplicity, don't create a dead block, let the dead code elimination
320 // pass deal with it.
321 if (phi->InputCount() == 1) {
322 break;
323 }
324 }
325 }
326 if (block->GetPredecessors().size() == 1) {
327 phi->ReplaceWith(phi->InputAt(0));
328 block->RemovePhi(phi);
329 if (has_only_phi_condition_and_if) {
330 // Evaluate here (and not wait for a constant folding pass) to open
331 // more opportunities for DCE.
332 HInstruction* result = first->AsCondition()->TryStaticEvaluation();
333 if (result != nullptr) {
334 first->ReplaceWith(result);
335 block->RemoveInstruction(first);
336 }
337 }
338 }
339 if (simplified_one_or_more_ifs) {
340 MaybeRecordSimplifyIf();
341 }
342 }
343 }
344 }
345 // We need to re-analyze the graph in order to run DCE afterwards.
346 if (simplified_one_or_more_ifs) {
347 if (rerun_dominance_and_loop_analysis) {
348 graph_->ClearLoopInformation();
349 graph_->ClearDominanceInformation();
350 graph_->BuildDominatorTree();
351 } else {
352 graph_->ClearDominanceInformation();
353 // We have introduced critical edges, remove them.
354 graph_->SimplifyCFG();
355 graph_->ComputeDominanceInformation();
356 graph_->ComputeTryBlockInformation();
357 }
358 }
359
360 return simplified_one_or_more_ifs;
361}
362
363void HDeadCodeElimination::ConnectSuccessiveBlocks() {
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100364 // Order does not matter. Skip the entry block by starting at index 1 in reverse post order.
365 for (size_t i = 1u, size = graph_->GetReversePostOrder().size(); i != size; ++i) {
366 HBasicBlock* block = graph_->GetReversePostOrder()[i];
367 DCHECK(!block->IsEntryBlock());
368 while (block->GetLastInstruction()->IsGoto()) {
369 HBasicBlock* successor = block->GetSingleSuccessor();
370 if (successor->IsExitBlock() || successor->GetPredecessors().size() != 1u) {
371 break;
372 }
373 DCHECK_LT(i, IndexOfElement(graph_->GetReversePostOrder(), successor));
374 block->MergeWith(successor);
375 --size;
376 DCHECK_EQ(size, graph_->GetReversePostOrder().size());
377 DCHECK_EQ(block, graph_->GetReversePostOrder()[i]);
378 // Reiterate on this block in case it can be merged with its new successor.
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100379 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100380 }
381}
382
383bool HDeadCodeElimination::RemoveDeadBlocks() {
Vladimir Marko009d1662017-10-10 13:21:15 +0100384 // Use local allocator for allocating memory.
385 ScopedArenaAllocator allocator(graph_->GetArenaStack());
386
David Brazdil2d7352b2015-04-20 14:52:42 +0100387 // Classify blocks as reachable/unreachable.
Vladimir Marko009d1662017-10-10 13:21:15 +0100388 ArenaBitVector live_blocks(&allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE);
389 live_blocks.ClearAllBits();
David Brazdila4b8c212015-05-07 09:59:30 +0100390
Vladimir Marko211c2112015-09-24 16:52:33 +0100391 MarkReachableBlocks(graph_, &live_blocks);
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100392 bool removed_one_or_more_blocks = false;
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000393 bool rerun_dominance_and_loop_analysis = false;
David Brazdil2d7352b2015-04-20 14:52:42 +0100394
David Brazdila4b8c212015-05-07 09:59:30 +0100395 // Remove all dead blocks. Iterate in post order because removal needs the
396 // block's chain of dominators and nested loops need to be updated from the
397 // inside out.
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100398 for (HBasicBlock* block : graph_->GetPostOrder()) {
David Brazdila4b8c212015-05-07 09:59:30 +0100399 int id = block->GetBlockId();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000400 if (!live_blocks.IsBitSet(id)) {
David Brazdil69a28042015-04-29 17:16:07 +0100401 MaybeRecordDeadBlock(block);
402 block->DisconnectAndDelete();
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100403 removed_one_or_more_blocks = true;
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000404 if (block->IsInLoop()) {
405 rerun_dominance_and_loop_analysis = true;
406 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100407 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100408 }
409
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100410 // If we removed at least one block, we need to recompute the full
David Brazdil8a7c0fe2015-11-02 20:24:55 +0000411 // dominator tree and try block membership.
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100412 if (removed_one_or_more_blocks) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000413 if (rerun_dominance_and_loop_analysis) {
414 graph_->ClearLoopInformation();
415 graph_->ClearDominanceInformation();
416 graph_->BuildDominatorTree();
417 } else {
418 graph_->ClearDominanceInformation();
419 graph_->ComputeDominanceInformation();
420 graph_->ComputeTryBlockInformation();
421 }
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100422 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100423 return removed_one_or_more_blocks;
David Brazdil2d7352b2015-04-20 14:52:42 +0100424}
425
426void HDeadCodeElimination::RemoveDeadInstructions() {
Roland Levillain72bceff2014-09-15 18:29:00 +0100427 // Process basic blocks in post-order in the dominator tree, so that
David Brazdil2d7352b2015-04-20 14:52:42 +0100428 // a dead instruction depending on another dead instruction is removed.
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100429 for (HBasicBlock* block : graph_->GetPostOrder()) {
Roland Levillain72bceff2014-09-15 18:29:00 +0100430 // Traverse this block's instructions in backward order and remove
431 // the unused ones.
432 HBackwardInstructionIterator i(block->GetInstructions());
433 // Skip the first iteration, as the last instruction of a block is
434 // a branching instruction.
435 DCHECK(i.Current()->IsControlFlow());
436 for (i.Advance(); !i.Done(); i.Advance()) {
437 HInstruction* inst = i.Current();
438 DCHECK(!inst->IsControlFlow());
Aart Bik482095d2016-10-10 15:39:10 -0700439 if (inst->IsDeadAndRemovable()) {
Roland Levillain72bceff2014-09-15 18:29:00 +0100440 block->RemoveInstruction(inst);
Igor Murashkin1e065a52017-08-09 13:20:34 -0700441 MaybeRecordStat(stats_, MethodCompilationStat::kRemovedDeadInstruction);
Roland Levillain72bceff2014-09-15 18:29:00 +0100442 }
443 }
444 }
445}
446
David Brazdil2d7352b2015-04-20 14:52:42 +0100447void HDeadCodeElimination::Run() {
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100448 // Do not eliminate dead blocks if the graph has irreducible loops. We could
449 // support it, but that would require changes in our loop representation to handle
450 // multiple entry points. We decided it was not worth the complexity.
451 if (!graph_->HasIrreducibleLoops()) {
452 // Simplify graph to generate more dead block patterns.
453 ConnectSuccessiveBlocks();
454 bool did_any_simplification = false;
Aart Bika8b8e9b2018-01-09 11:01:02 -0800455 did_any_simplification |= SimplifyAlwaysThrows();
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100456 did_any_simplification |= SimplifyIfs();
457 did_any_simplification |= RemoveDeadBlocks();
458 if (did_any_simplification) {
459 // Connect successive blocks created by dead branches.
460 ConnectSuccessiveBlocks();
461 }
462 }
David Brazdil84daae52015-05-18 12:06:52 +0100463 SsaRedundantPhiElimination(graph_).Run();
David Brazdil2d7352b2015-04-20 14:52:42 +0100464 RemoveDeadInstructions();
465}
466
Roland Levillain72bceff2014-09-15 18:29:00 +0100467} // namespace art