blob: c31c66a056ce8a30e3eea191ce1340e213b72284 [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 Marko2c45bc92016-10-25 16:54:12 +010021#include "base/stl_util.h"
David Brazdil84daae52015-05-18 12:06:52 +010022#include "ssa_phi_elimination.h"
Roland Levillain72bceff2014-09-15 18:29:00 +010023
24namespace art {
25
Vladimir Marko211c2112015-09-24 16:52:33 +010026static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) {
Vladimir Marko3ea5a972016-05-09 20:23:34 +010027 ArenaVector<HBasicBlock*> worklist(graph->GetArena()->Adapter(kArenaAllocDCE));
Vladimir Marko211c2112015-09-24 16:52:33 +010028 constexpr size_t kDefaultWorlistSize = 8;
29 worklist.reserve(kDefaultWorlistSize);
30 visited->SetBit(graph->GetEntryBlock()->GetBlockId());
31 worklist.push_back(graph->GetEntryBlock());
David Brazdil2d7352b2015-04-20 14:52:42 +010032
Vladimir Marko211c2112015-09-24 16:52:33 +010033 while (!worklist.empty()) {
34 HBasicBlock* block = worklist.back();
35 worklist.pop_back();
36 int block_id = block->GetBlockId();
37 DCHECK(visited->IsBitSet(block_id));
38
39 ArrayRef<HBasicBlock* const> live_successors(block->GetSuccessors());
40 HInstruction* last_instruction = block->GetLastInstruction();
41 if (last_instruction->IsIf()) {
42 HIf* if_instruction = last_instruction->AsIf();
43 HInstruction* condition = if_instruction->InputAt(0);
44 if (condition->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +000045 if (condition->AsIntConstant()->IsTrue()) {
Vladimir Marko211c2112015-09-24 16:52:33 +010046 live_successors = live_successors.SubArray(0u, 1u);
47 DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor());
48 } else {
Roland Levillain1a653882016-03-18 18:05:57 +000049 DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue();
Vladimir Marko211c2112015-09-24 16:52:33 +010050 live_successors = live_successors.SubArray(1u, 1u);
51 DCHECK_EQ(live_successors[0], if_instruction->IfFalseSuccessor());
52 }
Mark Mendellfe57faa2015-09-18 09:26:15 -040053 }
Vladimir Marko211c2112015-09-24 16:52:33 +010054 } else if (last_instruction->IsPackedSwitch()) {
55 HPackedSwitch* switch_instruction = last_instruction->AsPackedSwitch();
56 HInstruction* switch_input = switch_instruction->InputAt(0);
57 if (switch_input->IsIntConstant()) {
58 int32_t switch_value = switch_input->AsIntConstant()->GetValue();
59 int32_t start_value = switch_instruction->GetStartValue();
Vladimir Marko430c4f52015-09-25 17:10:15 +010060 // Note: Though the spec forbids packed-switch values to wrap around, we leave
61 // that task to the verifier and use unsigned arithmetic with it's "modulo 2^32"
62 // semantics to check if the value is in range, wrapped or not.
63 uint32_t switch_index =
64 static_cast<uint32_t>(switch_value) - static_cast<uint32_t>(start_value);
Vladimir Marko211c2112015-09-24 16:52:33 +010065 if (switch_index < switch_instruction->GetNumEntries()) {
66 live_successors = live_successors.SubArray(switch_index, 1u);
Vladimir Markoec7802a2015-10-01 20:57:57 +010067 DCHECK_EQ(live_successors[0], block->GetSuccessors()[switch_index]);
Vladimir Marko211c2112015-09-24 16:52:33 +010068 } else {
69 live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u);
70 DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock());
71 }
Mark Mendellfe57faa2015-09-18 09:26:15 -040072 }
73 }
Vladimir Marko211c2112015-09-24 16:52:33 +010074
75 for (HBasicBlock* successor : live_successors) {
76 // Add only those successors that have not been visited yet.
77 if (!visited->IsBitSet(successor->GetBlockId())) {
78 visited->SetBit(successor->GetBlockId());
79 worklist.push_back(successor);
80 }
David Brazdil2d7352b2015-04-20 14:52:42 +010081 }
82 }
83}
84
85void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) {
86 if (stats_ != nullptr) {
87 stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction,
88 block->GetPhis().CountSize() + block->GetInstructions().CountSize());
89 }
90}
91
Nicolas Geoffraydac9b192016-07-15 10:46:17 +010092void HDeadCodeElimination::MaybeRecordSimplifyIf() {
93 if (stats_ != nullptr) {
94 stats_->RecordStat(MethodCompilationStat::kSimplifyIf);
Nicolas Geoffray09aa1472016-01-19 10:52:54 +000095 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +010096}
97
98static bool HasInput(HCondition* instruction, HInstruction* input) {
99 return (instruction->InputAt(0) == input) ||
100 (instruction->InputAt(1) == input);
101}
102
103static bool HasEquality(IfCondition condition) {
104 switch (condition) {
105 case kCondEQ:
106 case kCondLE:
107 case kCondGE:
108 case kCondBE:
109 case kCondAE:
110 return true;
111 case kCondNE:
112 case kCondLT:
113 case kCondGT:
114 case kCondB:
115 case kCondA:
116 return false;
117 }
118}
119
120static HConstant* Evaluate(HCondition* condition, HInstruction* left, HInstruction* right) {
121 if (left == right && !Primitive::IsFloatingPointType(left->GetType())) {
122 return condition->GetBlock()->GetGraph()->GetIntConstant(
123 HasEquality(condition->GetCondition()) ? 1 : 0);
124 }
125
126 if (!left->IsConstant() || !right->IsConstant()) {
127 return nullptr;
128 }
129
130 if (left->IsIntConstant()) {
131 return condition->Evaluate(left->AsIntConstant(), right->AsIntConstant());
132 } else if (left->IsNullConstant()) {
133 return condition->Evaluate(left->AsNullConstant(), right->AsNullConstant());
134 } else if (left->IsLongConstant()) {
135 return condition->Evaluate(left->AsLongConstant(), right->AsLongConstant());
136 } else if (left->IsFloatConstant()) {
137 return condition->Evaluate(left->AsFloatConstant(), right->AsFloatConstant());
138 } else {
139 DCHECK(left->IsDoubleConstant());
140 return condition->Evaluate(left->AsDoubleConstant(), right->AsDoubleConstant());
141 }
142}
143
144// Simplify the pattern:
145//
146// B1 B2 ...
147// goto goto goto
148// \ | /
149// \ | /
150// B3
151// i1 = phi(input, input)
152// (i2 = condition on i1)
153// if i1 (or i2)
154// / \
155// / \
156// B4 B5
157//
158// Into:
159//
160// B1 B2 ...
161// | | |
162// B4 B5 B?
163//
Vladimir Marko606c8f02016-11-03 13:01:28 +0000164// Note that individual edges can be redirected (for example B2->B3
165// can be redirected as B2->B5) without applying this optimization
166// to other incoming edges.
167//
168// This simplification cannot be applied to catch blocks, because
169// exception handler edges do not represent normal control flow.
170// Though in theory this could still apply to normal control flow
171// going directly to a catch block, we cannot support it at the
172// moment because the catch Phi's inputs do not correspond to the
173// catch block's predecessors, so we cannot identify which
174// predecessor corresponds to a given statically evaluated input.
175//
176// We do not apply this optimization to loop headers as this could
177// create irreducible loops. We rely on the suspend check in the
178// loop header to prevent the pattern match.
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100179//
180// Note that we rely on the dead code elimination to get rid of B3.
181bool HDeadCodeElimination::SimplifyIfs() {
182 bool simplified_one_or_more_ifs = false;
183 bool rerun_dominance_and_loop_analysis = false;
184
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100185 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100186 HInstruction* last = block->GetLastInstruction();
187 HInstruction* first = block->GetFirstInstruction();
Vladimir Marko606c8f02016-11-03 13:01:28 +0000188 if (!block->IsCatchBlock() &&
189 last->IsIf() &&
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100190 block->HasSinglePhi() &&
191 block->GetFirstPhi()->HasOnlyOneNonEnvironmentUse()) {
192 bool has_only_phi_and_if = (last == first) && (last->InputAt(0) == block->GetFirstPhi());
193 bool has_only_phi_condition_and_if =
194 !has_only_phi_and_if &&
195 first->IsCondition() &&
196 HasInput(first->AsCondition(), block->GetFirstPhi()) &&
197 (first->GetNext() == last) &&
198 (last->InputAt(0) == first) &&
199 first->HasOnlyOneNonEnvironmentUse();
200
201 if (has_only_phi_and_if || has_only_phi_condition_and_if) {
202 DCHECK(!block->IsLoopHeader());
203 HPhi* phi = block->GetFirstPhi()->AsPhi();
204 bool phi_input_is_left = (first->InputAt(0) == phi);
205
206 // Walk over all inputs of the phis and update the control flow of
207 // predecessors feeding constants to the phi.
208 // Note that phi->InputCount() may change inside the loop.
209 for (size_t i = 0; i < phi->InputCount();) {
210 HInstruction* input = phi->InputAt(i);
211 HInstruction* value_to_check = nullptr;
212 if (has_only_phi_and_if) {
213 if (input->IsIntConstant()) {
214 value_to_check = input;
215 }
216 } else {
217 DCHECK(has_only_phi_condition_and_if);
218 if (phi_input_is_left) {
219 value_to_check = Evaluate(first->AsCondition(), input, first->InputAt(1));
220 } else {
221 value_to_check = Evaluate(first->AsCondition(), first->InputAt(0), input);
222 }
223 }
224 if (value_to_check == nullptr) {
225 // Could not evaluate to a constant, continue iterating over the inputs.
226 ++i;
227 } else {
228 HBasicBlock* predecessor_to_update = block->GetPredecessors()[i];
229 HBasicBlock* successor_to_update = nullptr;
230 if (value_to_check->AsIntConstant()->IsTrue()) {
231 successor_to_update = last->AsIf()->IfTrueSuccessor();
232 } else {
233 DCHECK(value_to_check->AsIntConstant()->IsFalse())
234 << value_to_check->AsIntConstant()->GetValue();
235 successor_to_update = last->AsIf()->IfFalseSuccessor();
236 }
237 predecessor_to_update->ReplaceSuccessor(block, successor_to_update);
238 phi->RemoveInputAt(i);
239 simplified_one_or_more_ifs = true;
240 if (block->IsInLoop()) {
241 rerun_dominance_and_loop_analysis = true;
242 }
243 // For simplicity, don't create a dead block, let the dead code elimination
244 // pass deal with it.
245 if (phi->InputCount() == 1) {
246 break;
247 }
248 }
249 }
250 if (block->GetPredecessors().size() == 1) {
251 phi->ReplaceWith(phi->InputAt(0));
252 block->RemovePhi(phi);
253 if (has_only_phi_condition_and_if) {
254 // Evaluate here (and not wait for a constant folding pass) to open
255 // more opportunities for DCE.
256 HInstruction* result = first->AsCondition()->TryStaticEvaluation();
257 if (result != nullptr) {
258 first->ReplaceWith(result);
259 block->RemoveInstruction(first);
260 }
261 }
262 }
263 if (simplified_one_or_more_ifs) {
264 MaybeRecordSimplifyIf();
265 }
266 }
267 }
268 }
269 // We need to re-analyze the graph in order to run DCE afterwards.
270 if (simplified_one_or_more_ifs) {
271 if (rerun_dominance_and_loop_analysis) {
272 graph_->ClearLoopInformation();
273 graph_->ClearDominanceInformation();
274 graph_->BuildDominatorTree();
275 } else {
276 graph_->ClearDominanceInformation();
277 // We have introduced critical edges, remove them.
278 graph_->SimplifyCFG();
279 graph_->ComputeDominanceInformation();
280 graph_->ComputeTryBlockInformation();
281 }
282 }
283
284 return simplified_one_or_more_ifs;
285}
286
287void HDeadCodeElimination::ConnectSuccessiveBlocks() {
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100288 // Order does not matter. Skip the entry block by starting at index 1 in reverse post order.
289 for (size_t i = 1u, size = graph_->GetReversePostOrder().size(); i != size; ++i) {
290 HBasicBlock* block = graph_->GetReversePostOrder()[i];
291 DCHECK(!block->IsEntryBlock());
292 while (block->GetLastInstruction()->IsGoto()) {
293 HBasicBlock* successor = block->GetSingleSuccessor();
294 if (successor->IsExitBlock() || successor->GetPredecessors().size() != 1u) {
295 break;
296 }
297 DCHECK_LT(i, IndexOfElement(graph_->GetReversePostOrder(), successor));
298 block->MergeWith(successor);
299 --size;
300 DCHECK_EQ(size, graph_->GetReversePostOrder().size());
301 DCHECK_EQ(block, graph_->GetReversePostOrder()[i]);
302 // Reiterate on this block in case it can be merged with its new successor.
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100303 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100304 }
305}
306
307bool HDeadCodeElimination::RemoveDeadBlocks() {
David Brazdil2d7352b2015-04-20 14:52:42 +0100308 // Classify blocks as reachable/unreachable.
309 ArenaAllocator* allocator = graph_->GetArena();
Vladimir Markof6a35de2016-03-21 12:01:50 +0000310 ArenaBitVector live_blocks(allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE);
David Brazdila4b8c212015-05-07 09:59:30 +0100311
Vladimir Marko211c2112015-09-24 16:52:33 +0100312 MarkReachableBlocks(graph_, &live_blocks);
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100313 bool removed_one_or_more_blocks = false;
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000314 bool rerun_dominance_and_loop_analysis = false;
David Brazdil2d7352b2015-04-20 14:52:42 +0100315
David Brazdila4b8c212015-05-07 09:59:30 +0100316 // Remove all dead blocks. Iterate in post order because removal needs the
317 // block's chain of dominators and nested loops need to be updated from the
318 // inside out.
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100319 for (HBasicBlock* block : graph_->GetPostOrder()) {
David Brazdila4b8c212015-05-07 09:59:30 +0100320 int id = block->GetBlockId();
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000321 if (!live_blocks.IsBitSet(id)) {
David Brazdil69a28042015-04-29 17:16:07 +0100322 MaybeRecordDeadBlock(block);
323 block->DisconnectAndDelete();
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100324 removed_one_or_more_blocks = true;
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000325 if (block->IsInLoop()) {
326 rerun_dominance_and_loop_analysis = true;
327 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100328 }
David Brazdil2d7352b2015-04-20 14:52:42 +0100329 }
330
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100331 // If we removed at least one block, we need to recompute the full
David Brazdil8a7c0fe2015-11-02 20:24:55 +0000332 // dominator tree and try block membership.
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100333 if (removed_one_or_more_blocks) {
Nicolas Geoffray15bd2282016-01-05 15:55:41 +0000334 if (rerun_dominance_and_loop_analysis) {
335 graph_->ClearLoopInformation();
336 graph_->ClearDominanceInformation();
337 graph_->BuildDominatorTree();
338 } else {
339 graph_->ClearDominanceInformation();
340 graph_->ComputeDominanceInformation();
341 graph_->ComputeTryBlockInformation();
342 }
Nicolas Geoffray1f82ecc2015-06-24 12:20:24 +0100343 }
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100344 return removed_one_or_more_blocks;
David Brazdil2d7352b2015-04-20 14:52:42 +0100345}
346
347void HDeadCodeElimination::RemoveDeadInstructions() {
Roland Levillain72bceff2014-09-15 18:29:00 +0100348 // Process basic blocks in post-order in the dominator tree, so that
David Brazdil2d7352b2015-04-20 14:52:42 +0100349 // a dead instruction depending on another dead instruction is removed.
Vladimir Marko2c45bc92016-10-25 16:54:12 +0100350 for (HBasicBlock* block : graph_->GetPostOrder()) {
Roland Levillain72bceff2014-09-15 18:29:00 +0100351 // Traverse this block's instructions in backward order and remove
352 // the unused ones.
353 HBackwardInstructionIterator i(block->GetInstructions());
354 // Skip the first iteration, as the last instruction of a block is
355 // a branching instruction.
356 DCHECK(i.Current()->IsControlFlow());
357 for (i.Advance(); !i.Done(); i.Advance()) {
358 HInstruction* inst = i.Current();
359 DCHECK(!inst->IsControlFlow());
Aart Bik482095d2016-10-10 15:39:10 -0700360 if (inst->IsDeadAndRemovable()) {
Roland Levillain72bceff2014-09-15 18:29:00 +0100361 block->RemoveInstruction(inst);
Calin Juravle8f20bdb2015-04-21 14:07:50 +0100362 MaybeRecordStat(MethodCompilationStat::kRemovedDeadInstruction);
Roland Levillain72bceff2014-09-15 18:29:00 +0100363 }
364 }
365 }
366}
367
David Brazdil2d7352b2015-04-20 14:52:42 +0100368void HDeadCodeElimination::Run() {
Nicolas Geoffraydac9b192016-07-15 10:46:17 +0100369 // Do not eliminate dead blocks if the graph has irreducible loops. We could
370 // support it, but that would require changes in our loop representation to handle
371 // multiple entry points. We decided it was not worth the complexity.
372 if (!graph_->HasIrreducibleLoops()) {
373 // Simplify graph to generate more dead block patterns.
374 ConnectSuccessiveBlocks();
375 bool did_any_simplification = false;
376 did_any_simplification |= SimplifyIfs();
377 did_any_simplification |= RemoveDeadBlocks();
378 if (did_any_simplification) {
379 // Connect successive blocks created by dead branches.
380 ConnectSuccessiveBlocks();
381 }
382 }
David Brazdil84daae52015-05-18 12:06:52 +0100383 SsaRedundantPhiElimination(graph_).Run();
David Brazdil2d7352b2015-04-20 14:52:42 +0100384 RemoveDeadInstructions();
385}
386
Roland Levillain72bceff2014-09-15 18:29:00 +0100387} // namespace art