xref: /aosp_15_r20/art/compiler/optimizing/dead_code_elimination.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2014 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "dead_code_elimination.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "android-base/logging.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/array_ref.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/bit_vector-inl.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/logging.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
26*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes.h"
27*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes_vector.h"
28*795d594fSAndroid Build Coastguard Worker #include "ssa_phi_elimination.h"
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
31*795d594fSAndroid Build Coastguard Worker 
MarkReachableBlocks(HGraph * graph,ArenaBitVector * visited)32*795d594fSAndroid Build Coastguard Worker static void MarkReachableBlocks(HGraph* graph, ArenaBitVector* visited) {
33*795d594fSAndroid Build Coastguard Worker   // Use local allocator for allocating memory.
34*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(graph->GetArenaStack());
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<HBasicBlock*> worklist(allocator.Adapter(kArenaAllocDCE));
37*795d594fSAndroid Build Coastguard Worker   constexpr size_t kDefaultWorlistSize = 8;
38*795d594fSAndroid Build Coastguard Worker   worklist.reserve(kDefaultWorlistSize);
39*795d594fSAndroid Build Coastguard Worker   visited->SetBit(graph->GetEntryBlock()->GetBlockId());
40*795d594fSAndroid Build Coastguard Worker   worklist.push_back(graph->GetEntryBlock());
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker   while (!worklist.empty()) {
43*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = worklist.back();
44*795d594fSAndroid Build Coastguard Worker     worklist.pop_back();
45*795d594fSAndroid Build Coastguard Worker     int block_id = block->GetBlockId();
46*795d594fSAndroid Build Coastguard Worker     DCHECK(visited->IsBitSet(block_id));
47*795d594fSAndroid Build Coastguard Worker 
48*795d594fSAndroid Build Coastguard Worker     ArrayRef<HBasicBlock* const> live_successors(block->GetSuccessors());
49*795d594fSAndroid Build Coastguard Worker     HInstruction* last_instruction = block->GetLastInstruction();
50*795d594fSAndroid Build Coastguard Worker     if (last_instruction->IsIf()) {
51*795d594fSAndroid Build Coastguard Worker       HIf* if_instruction = last_instruction->AsIf();
52*795d594fSAndroid Build Coastguard Worker       HInstruction* condition = if_instruction->InputAt(0);
53*795d594fSAndroid Build Coastguard Worker       if (condition->IsIntConstant()) {
54*795d594fSAndroid Build Coastguard Worker         if (condition->AsIntConstant()->IsTrue()) {
55*795d594fSAndroid Build Coastguard Worker           live_successors = live_successors.SubArray(0u, 1u);
56*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(live_successors[0], if_instruction->IfTrueSuccessor());
57*795d594fSAndroid Build Coastguard Worker         } else {
58*795d594fSAndroid Build Coastguard Worker           DCHECK(condition->AsIntConstant()->IsFalse()) << condition->AsIntConstant()->GetValue();
59*795d594fSAndroid Build Coastguard Worker           live_successors = live_successors.SubArray(1u, 1u);
60*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(live_successors[0], if_instruction->IfFalseSuccessor());
61*795d594fSAndroid Build Coastguard Worker         }
62*795d594fSAndroid Build Coastguard Worker       }
63*795d594fSAndroid Build Coastguard Worker     } else if (last_instruction->IsPackedSwitch()) {
64*795d594fSAndroid Build Coastguard Worker       HPackedSwitch* switch_instruction = last_instruction->AsPackedSwitch();
65*795d594fSAndroid Build Coastguard Worker       HInstruction* switch_input = switch_instruction->InputAt(0);
66*795d594fSAndroid Build Coastguard Worker       if (switch_input->IsIntConstant()) {
67*795d594fSAndroid Build Coastguard Worker         int32_t switch_value = switch_input->AsIntConstant()->GetValue();
68*795d594fSAndroid Build Coastguard Worker         int32_t start_value = switch_instruction->GetStartValue();
69*795d594fSAndroid Build Coastguard Worker         // Note: Though the spec forbids packed-switch values to wrap around, we leave
70*795d594fSAndroid Build Coastguard Worker         // that task to the verifier and use unsigned arithmetic with it's "modulo 2^32"
71*795d594fSAndroid Build Coastguard Worker         // semantics to check if the value is in range, wrapped or not.
72*795d594fSAndroid Build Coastguard Worker         uint32_t switch_index =
73*795d594fSAndroid Build Coastguard Worker             static_cast<uint32_t>(switch_value) - static_cast<uint32_t>(start_value);
74*795d594fSAndroid Build Coastguard Worker         if (switch_index < switch_instruction->GetNumEntries()) {
75*795d594fSAndroid Build Coastguard Worker           live_successors = live_successors.SubArray(switch_index, 1u);
76*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(live_successors[0], block->GetSuccessors()[switch_index]);
77*795d594fSAndroid Build Coastguard Worker         } else {
78*795d594fSAndroid Build Coastguard Worker           live_successors = live_successors.SubArray(switch_instruction->GetNumEntries(), 1u);
79*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(live_successors[0], switch_instruction->GetDefaultBlock());
80*795d594fSAndroid Build Coastguard Worker         }
81*795d594fSAndroid Build Coastguard Worker       }
82*795d594fSAndroid Build Coastguard Worker     }
83*795d594fSAndroid Build Coastguard Worker 
84*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* successor : live_successors) {
85*795d594fSAndroid Build Coastguard Worker       // Add only those successors that have not been visited yet.
86*795d594fSAndroid Build Coastguard Worker       if (!visited->IsBitSet(successor->GetBlockId())) {
87*795d594fSAndroid Build Coastguard Worker         visited->SetBit(successor->GetBlockId());
88*795d594fSAndroid Build Coastguard Worker         worklist.push_back(successor);
89*795d594fSAndroid Build Coastguard Worker       }
90*795d594fSAndroid Build Coastguard Worker     }
91*795d594fSAndroid Build Coastguard Worker   }
92*795d594fSAndroid Build Coastguard Worker }
93*795d594fSAndroid Build Coastguard Worker 
MaybeRecordDeadBlock(HBasicBlock * block)94*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::MaybeRecordDeadBlock(HBasicBlock* block) {
95*795d594fSAndroid Build Coastguard Worker   if (stats_ != nullptr) {
96*795d594fSAndroid Build Coastguard Worker     stats_->RecordStat(MethodCompilationStat::kRemovedDeadInstruction,
97*795d594fSAndroid Build Coastguard Worker                        block->GetPhis().CountSize() + block->GetInstructions().CountSize());
98*795d594fSAndroid Build Coastguard Worker   }
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker 
MaybeRecordSimplifyIf()101*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::MaybeRecordSimplifyIf() {
102*795d594fSAndroid Build Coastguard Worker   if (stats_ != nullptr) {
103*795d594fSAndroid Build Coastguard Worker     stats_->RecordStat(MethodCompilationStat::kSimplifyIf);
104*795d594fSAndroid Build Coastguard Worker   }
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker 
HasInput(HCondition * instruction,HInstruction * input)107*795d594fSAndroid Build Coastguard Worker static bool HasInput(HCondition* instruction, HInstruction* input) {
108*795d594fSAndroid Build Coastguard Worker   return (instruction->InputAt(0) == input) ||
109*795d594fSAndroid Build Coastguard Worker          (instruction->InputAt(1) == input);
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker 
HasEquality(IfCondition condition)112*795d594fSAndroid Build Coastguard Worker static bool HasEquality(IfCondition condition) {
113*795d594fSAndroid Build Coastguard Worker   switch (condition) {
114*795d594fSAndroid Build Coastguard Worker     case kCondEQ:
115*795d594fSAndroid Build Coastguard Worker     case kCondLE:
116*795d594fSAndroid Build Coastguard Worker     case kCondGE:
117*795d594fSAndroid Build Coastguard Worker     case kCondBE:
118*795d594fSAndroid Build Coastguard Worker     case kCondAE:
119*795d594fSAndroid Build Coastguard Worker       return true;
120*795d594fSAndroid Build Coastguard Worker     case kCondNE:
121*795d594fSAndroid Build Coastguard Worker     case kCondLT:
122*795d594fSAndroid Build Coastguard Worker     case kCondGT:
123*795d594fSAndroid Build Coastguard Worker     case kCondB:
124*795d594fSAndroid Build Coastguard Worker     case kCondA:
125*795d594fSAndroid Build Coastguard Worker       return false;
126*795d594fSAndroid Build Coastguard Worker   }
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker 
Evaluate(HCondition * condition,HInstruction * left,HInstruction * right)129*795d594fSAndroid Build Coastguard Worker static HConstant* Evaluate(HCondition* condition, HInstruction* left, HInstruction* right) {
130*795d594fSAndroid Build Coastguard Worker   if (left == right && !DataType::IsFloatingPointType(left->GetType())) {
131*795d594fSAndroid Build Coastguard Worker     return condition->GetBlock()->GetGraph()->GetIntConstant(
132*795d594fSAndroid Build Coastguard Worker         HasEquality(condition->GetCondition()) ? 1 : 0);
133*795d594fSAndroid Build Coastguard Worker   }
134*795d594fSAndroid Build Coastguard Worker 
135*795d594fSAndroid Build Coastguard Worker   if (!left->IsConstant() || !right->IsConstant()) {
136*795d594fSAndroid Build Coastguard Worker     return nullptr;
137*795d594fSAndroid Build Coastguard Worker   }
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker   if (left->IsIntConstant()) {
140*795d594fSAndroid Build Coastguard Worker     return condition->Evaluate(left->AsIntConstant(), right->AsIntConstant());
141*795d594fSAndroid Build Coastguard Worker   } else if (left->IsNullConstant()) {
142*795d594fSAndroid Build Coastguard Worker     return condition->Evaluate(left->AsNullConstant(), right->AsNullConstant());
143*795d594fSAndroid Build Coastguard Worker   } else if (left->IsLongConstant()) {
144*795d594fSAndroid Build Coastguard Worker     return condition->Evaluate(left->AsLongConstant(), right->AsLongConstant());
145*795d594fSAndroid Build Coastguard Worker   } else if (left->IsFloatConstant()) {
146*795d594fSAndroid Build Coastguard Worker     return condition->Evaluate(left->AsFloatConstant(), right->AsFloatConstant());
147*795d594fSAndroid Build Coastguard Worker   } else {
148*795d594fSAndroid Build Coastguard Worker     DCHECK(left->IsDoubleConstant());
149*795d594fSAndroid Build Coastguard Worker     return condition->Evaluate(left->AsDoubleConstant(), right->AsDoubleConstant());
150*795d594fSAndroid Build Coastguard Worker   }
151*795d594fSAndroid Build Coastguard Worker }
152*795d594fSAndroid Build Coastguard Worker 
RemoveNonNullControlDependences(HBasicBlock * block,HBasicBlock * throws)153*795d594fSAndroid Build Coastguard Worker static bool RemoveNonNullControlDependences(HBasicBlock* block, HBasicBlock* throws) {
154*795d594fSAndroid Build Coastguard Worker   // Test for an if as last statement.
155*795d594fSAndroid Build Coastguard Worker   if (!block->EndsWithIf()) {
156*795d594fSAndroid Build Coastguard Worker     return false;
157*795d594fSAndroid Build Coastguard Worker   }
158*795d594fSAndroid Build Coastguard Worker   HIf* ifs = block->GetLastInstruction()->AsIf();
159*795d594fSAndroid Build Coastguard Worker   // Find either:
160*795d594fSAndroid Build Coastguard Worker   //   if obj == null
161*795d594fSAndroid Build Coastguard Worker   //     throws
162*795d594fSAndroid Build Coastguard Worker   //   else
163*795d594fSAndroid Build Coastguard Worker   //     not_throws
164*795d594fSAndroid Build Coastguard Worker   // or:
165*795d594fSAndroid Build Coastguard Worker   //   if obj != null
166*795d594fSAndroid Build Coastguard Worker   //     not_throws
167*795d594fSAndroid Build Coastguard Worker   //   else
168*795d594fSAndroid Build Coastguard Worker   //     throws
169*795d594fSAndroid Build Coastguard Worker   HInstruction* cond = ifs->InputAt(0);
170*795d594fSAndroid Build Coastguard Worker   HBasicBlock* not_throws = nullptr;
171*795d594fSAndroid Build Coastguard Worker   if (throws == ifs->IfTrueSuccessor() && cond->IsEqual()) {
172*795d594fSAndroid Build Coastguard Worker     not_throws = ifs->IfFalseSuccessor();
173*795d594fSAndroid Build Coastguard Worker   } else if (throws == ifs->IfFalseSuccessor() && cond->IsNotEqual()) {
174*795d594fSAndroid Build Coastguard Worker     not_throws = ifs->IfTrueSuccessor();
175*795d594fSAndroid Build Coastguard Worker   } else {
176*795d594fSAndroid Build Coastguard Worker     return false;
177*795d594fSAndroid Build Coastguard Worker   }
178*795d594fSAndroid Build Coastguard Worker   DCHECK(cond->IsEqual() || cond->IsNotEqual());
179*795d594fSAndroid Build Coastguard Worker   HInstruction* obj = cond->InputAt(1);
180*795d594fSAndroid Build Coastguard Worker   if (obj->IsNullConstant()) {
181*795d594fSAndroid Build Coastguard Worker     obj = cond->InputAt(0);
182*795d594fSAndroid Build Coastguard Worker   } else if (!cond->InputAt(0)->IsNullConstant()) {
183*795d594fSAndroid Build Coastguard Worker     return false;
184*795d594fSAndroid Build Coastguard Worker   }
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   // We can't create a BoundType for an object with an invalid RTI.
187*795d594fSAndroid Build Coastguard Worker   const ReferenceTypeInfo ti = obj->GetReferenceTypeInfo();
188*795d594fSAndroid Build Coastguard Worker   if (!ti.IsValid()) {
189*795d594fSAndroid Build Coastguard Worker     return false;
190*795d594fSAndroid Build Coastguard Worker   }
191*795d594fSAndroid Build Coastguard Worker 
192*795d594fSAndroid Build Coastguard Worker   // Scan all uses of obj and find null check under control dependence.
193*795d594fSAndroid Build Coastguard Worker   HBoundType* bound = nullptr;
194*795d594fSAndroid Build Coastguard Worker   const HUseList<HInstruction*>& uses = obj->GetUses();
195*795d594fSAndroid Build Coastguard Worker   for (auto it = uses.begin(), end = uses.end(); it != end;) {
196*795d594fSAndroid Build Coastguard Worker     HInstruction* user = it->GetUser();
197*795d594fSAndroid Build Coastguard Worker     ++it;  // increment before possibly replacing
198*795d594fSAndroid Build Coastguard Worker     if (user->IsNullCheck()) {
199*795d594fSAndroid Build Coastguard Worker       HBasicBlock* user_block = user->GetBlock();
200*795d594fSAndroid Build Coastguard Worker       if (user_block != block &&
201*795d594fSAndroid Build Coastguard Worker           user_block != throws &&
202*795d594fSAndroid Build Coastguard Worker           block->Dominates(user_block)) {
203*795d594fSAndroid Build Coastguard Worker         if (bound == nullptr) {
204*795d594fSAndroid Build Coastguard Worker           bound = new (obj->GetBlock()->GetGraph()->GetAllocator()) HBoundType(obj);
205*795d594fSAndroid Build Coastguard Worker           bound->SetUpperBound(ti, /*can_be_null*/ false);
206*795d594fSAndroid Build Coastguard Worker           bound->SetReferenceTypeInfo(ti);
207*795d594fSAndroid Build Coastguard Worker           bound->SetCanBeNull(false);
208*795d594fSAndroid Build Coastguard Worker           not_throws->InsertInstructionBefore(bound, not_throws->GetFirstInstruction());
209*795d594fSAndroid Build Coastguard Worker         }
210*795d594fSAndroid Build Coastguard Worker         user->ReplaceWith(bound);
211*795d594fSAndroid Build Coastguard Worker         user_block->RemoveInstruction(user);
212*795d594fSAndroid Build Coastguard Worker       }
213*795d594fSAndroid Build Coastguard Worker     }
214*795d594fSAndroid Build Coastguard Worker   }
215*795d594fSAndroid Build Coastguard Worker   return bound != nullptr;
216*795d594fSAndroid Build Coastguard Worker }
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker // Simplify the pattern:
219*795d594fSAndroid Build Coastguard Worker //
220*795d594fSAndroid Build Coastguard Worker //           B1
221*795d594fSAndroid Build Coastguard Worker //          /  \
222*795d594fSAndroid Build Coastguard Worker //          |   instr_1
223*795d594fSAndroid Build Coastguard Worker //          |   ...
224*795d594fSAndroid Build Coastguard Worker //          |   instr_n
225*795d594fSAndroid Build Coastguard Worker //          |   foo()  // always throws
226*795d594fSAndroid Build Coastguard Worker //          |   instr_n+2
227*795d594fSAndroid Build Coastguard Worker //          |   ...
228*795d594fSAndroid Build Coastguard Worker //          |   instr_n+m
229*795d594fSAndroid Build Coastguard Worker //          \   goto B2
230*795d594fSAndroid Build Coastguard Worker //           \ /
231*795d594fSAndroid Build Coastguard Worker //            B2
232*795d594fSAndroid Build Coastguard Worker //
233*795d594fSAndroid Build Coastguard Worker // Into:
234*795d594fSAndroid Build Coastguard Worker //
235*795d594fSAndroid Build Coastguard Worker //           B1
236*795d594fSAndroid Build Coastguard Worker //          /  \
237*795d594fSAndroid Build Coastguard Worker //          |  instr_1
238*795d594fSAndroid Build Coastguard Worker //          |  ...
239*795d594fSAndroid Build Coastguard Worker //          |  instr_n
240*795d594fSAndroid Build Coastguard Worker //          |  foo()
241*795d594fSAndroid Build Coastguard Worker //          |  goto Exit
242*795d594fSAndroid Build Coastguard Worker //          |   |
243*795d594fSAndroid Build Coastguard Worker //         B2  Exit
244*795d594fSAndroid Build Coastguard Worker //
245*795d594fSAndroid Build Coastguard Worker // Rationale:
246*795d594fSAndroid Build Coastguard Worker // Removal of the never taken edge to B2 may expose other optimization opportunities, such as code
247*795d594fSAndroid Build Coastguard Worker // sinking.
248*795d594fSAndroid Build Coastguard Worker //
249*795d594fSAndroid Build Coastguard Worker // Note: The example above is a simple one that uses a `goto` but we could end the block with an If,
250*795d594fSAndroid Build Coastguard Worker // for example.
SimplifyAlwaysThrows()251*795d594fSAndroid Build Coastguard Worker bool HDeadCodeElimination::SimplifyAlwaysThrows() {
252*795d594fSAndroid Build Coastguard Worker   HBasicBlock* exit = graph_->GetExitBlock();
253*795d594fSAndroid Build Coastguard Worker   if (!graph_->HasAlwaysThrowingInvokes() || exit == nullptr) {
254*795d594fSAndroid Build Coastguard Worker     return false;
255*795d594fSAndroid Build Coastguard Worker   }
256*795d594fSAndroid Build Coastguard Worker 
257*795d594fSAndroid Build Coastguard Worker   bool rerun_dominance_and_loop_analysis = false;
258*795d594fSAndroid Build Coastguard Worker 
259*795d594fSAndroid Build Coastguard Worker   // Order does not matter, just pick one.
260*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
261*795d594fSAndroid Build Coastguard Worker     if (block->IsTryBlock()) {
262*795d594fSAndroid Build Coastguard Worker       // We don't want to perform the simplify always throws optimizations for throws inside of
263*795d594fSAndroid Build Coastguard Worker       // tries since those throws might not go to the exit block.
264*795d594fSAndroid Build Coastguard Worker       continue;
265*795d594fSAndroid Build Coastguard Worker     }
266*795d594fSAndroid Build Coastguard Worker 
267*795d594fSAndroid Build Coastguard Worker     // We iterate to find the first instruction that always throws. If two instructions always
268*795d594fSAndroid Build Coastguard Worker     // throw, the first one will throw and the second one will never be reached.
269*795d594fSAndroid Build Coastguard Worker     HInstruction* throwing_invoke = nullptr;
270*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
271*795d594fSAndroid Build Coastguard Worker       if (it.Current()->IsInvoke() && it.Current()->AsInvoke()->AlwaysThrows()) {
272*795d594fSAndroid Build Coastguard Worker         throwing_invoke = it.Current();
273*795d594fSAndroid Build Coastguard Worker         break;
274*795d594fSAndroid Build Coastguard Worker       }
275*795d594fSAndroid Build Coastguard Worker     }
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker     if (throwing_invoke == nullptr) {
278*795d594fSAndroid Build Coastguard Worker       // No always-throwing instruction found. Continue with the rest of the blocks.
279*795d594fSAndroid Build Coastguard Worker       continue;
280*795d594fSAndroid Build Coastguard Worker     }
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker     // If we are already pointing at the exit block we could still remove the instructions
283*795d594fSAndroid Build Coastguard Worker     // between the always throwing instruction, and the exit block. If we have no other
284*795d594fSAndroid Build Coastguard Worker     // instructions, just continue since there's nothing to do.
285*795d594fSAndroid Build Coastguard Worker     if (block->GetSuccessors().size() == 1 &&
286*795d594fSAndroid Build Coastguard Worker         block->GetSingleSuccessor() == exit &&
287*795d594fSAndroid Build Coastguard Worker         block->GetLastInstruction()->GetPrevious() == throwing_invoke) {
288*795d594fSAndroid Build Coastguard Worker       continue;
289*795d594fSAndroid Build Coastguard Worker     }
290*795d594fSAndroid Build Coastguard Worker 
291*795d594fSAndroid Build Coastguard Worker     // We split the block at the throwing instruction, and the instructions after the throwing
292*795d594fSAndroid Build Coastguard Worker     // instructions will be disconnected from the graph after `block` points to the exit.
293*795d594fSAndroid Build Coastguard Worker     // `RemoveDeadBlocks` will take care of removing this new block and its instructions.
294*795d594fSAndroid Build Coastguard Worker     // Even though `SplitBefore` doesn't guarantee the graph to remain in SSA form, it is fine
295*795d594fSAndroid Build Coastguard Worker     // since we do not break it.
296*795d594fSAndroid Build Coastguard Worker     HBasicBlock* new_block = block->SplitBefore(throwing_invoke->GetNext(),
297*795d594fSAndroid Build Coastguard Worker                                                 /* require_graph_not_in_ssa_form= */ false);
298*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(block->GetSingleSuccessor(), new_block);
299*795d594fSAndroid Build Coastguard Worker     block->ReplaceSuccessor(new_block, exit);
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker     rerun_dominance_and_loop_analysis = true;
302*795d594fSAndroid Build Coastguard Worker     MaybeRecordStat(stats_, MethodCompilationStat::kSimplifyThrowingInvoke);
303*795d594fSAndroid Build Coastguard Worker     // Perform a quick follow up optimization on object != null control dependences
304*795d594fSAndroid Build Coastguard Worker     // that is much cheaper to perform now than in a later phase.
305*795d594fSAndroid Build Coastguard Worker     // If there are multiple predecessors, none may end with a HIf as required in
306*795d594fSAndroid Build Coastguard Worker     // RemoveNonNullControlDependences because we split critical edges.
307*795d594fSAndroid Build Coastguard Worker     if (block->GetPredecessors().size() == 1u &&
308*795d594fSAndroid Build Coastguard Worker         RemoveNonNullControlDependences(block->GetSinglePredecessor(), block)) {
309*795d594fSAndroid Build Coastguard Worker       MaybeRecordStat(stats_, MethodCompilationStat::kRemovedNullCheck);
310*795d594fSAndroid Build Coastguard Worker     }
311*795d594fSAndroid Build Coastguard Worker   }
312*795d594fSAndroid Build Coastguard Worker 
313*795d594fSAndroid Build Coastguard Worker   // We need to re-analyze the graph in order to run DCE afterwards.
314*795d594fSAndroid Build Coastguard Worker   if (rerun_dominance_and_loop_analysis) {
315*795d594fSAndroid Build Coastguard Worker     graph_->RecomputeDominatorTree();
316*795d594fSAndroid Build Coastguard Worker     return true;
317*795d594fSAndroid Build Coastguard Worker   }
318*795d594fSAndroid Build Coastguard Worker   return false;
319*795d594fSAndroid Build Coastguard Worker }
320*795d594fSAndroid Build Coastguard Worker 
SimplifyIfs()321*795d594fSAndroid Build Coastguard Worker bool HDeadCodeElimination::SimplifyIfs() {
322*795d594fSAndroid Build Coastguard Worker   bool simplified_one_or_more_ifs = false;
323*795d594fSAndroid Build Coastguard Worker   bool rerun_dominance_and_loop_analysis = false;
324*795d594fSAndroid Build Coastguard Worker 
325*795d594fSAndroid Build Coastguard Worker   // Iterating in PostOrder it's better for MaybeAddPhi as it can add a Phi for multiple If
326*795d594fSAndroid Build Coastguard Worker   // instructions in a chain without updating the dominator chain. The branch redirection itself can
327*795d594fSAndroid Build Coastguard Worker   // work in PostOrder or ReversePostOrder without issues.
328*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
329*795d594fSAndroid Build Coastguard Worker     if (block->IsCatchBlock()) {
330*795d594fSAndroid Build Coastguard Worker       // This simplification cannot be applied to catch blocks, because exception handler edges do
331*795d594fSAndroid Build Coastguard Worker       // not represent normal control flow. Though in theory this could still apply to normal
332*795d594fSAndroid Build Coastguard Worker       // control flow going directly to a catch block, we cannot support it at the moment because
333*795d594fSAndroid Build Coastguard Worker       // the catch Phi's inputs do not correspond to the catch block's predecessors, so we cannot
334*795d594fSAndroid Build Coastguard Worker       // identify which predecessor corresponds to a given statically evaluated input.
335*795d594fSAndroid Build Coastguard Worker       continue;
336*795d594fSAndroid Build Coastguard Worker     }
337*795d594fSAndroid Build Coastguard Worker 
338*795d594fSAndroid Build Coastguard Worker     HInstruction* last = block->GetLastInstruction();
339*795d594fSAndroid Build Coastguard Worker     if (!last->IsIf()) {
340*795d594fSAndroid Build Coastguard Worker       continue;
341*795d594fSAndroid Build Coastguard Worker     }
342*795d594fSAndroid Build Coastguard Worker 
343*795d594fSAndroid Build Coastguard Worker     if (block->IsLoopHeader()) {
344*795d594fSAndroid Build Coastguard Worker       // We do not apply this optimization to loop headers as this could create irreducible loops.
345*795d594fSAndroid Build Coastguard Worker       continue;
346*795d594fSAndroid Build Coastguard Worker     }
347*795d594fSAndroid Build Coastguard Worker 
348*795d594fSAndroid Build Coastguard Worker     // We will add a Phi which allows the simplification to take place in cases where it wouldn't.
349*795d594fSAndroid Build Coastguard Worker     MaybeAddPhi(block);
350*795d594fSAndroid Build Coastguard Worker 
351*795d594fSAndroid Build Coastguard Worker     // TODO(solanes): Investigate support for multiple phis in `block`. We can potentially "push
352*795d594fSAndroid Build Coastguard Worker     // downwards" existing Phis into the true/false branches. For example, let's say we have another
353*795d594fSAndroid Build Coastguard Worker     // Phi: Phi(x1,x2,x3,x4,x5,x6). This could turn into Phi(x1,x2) in the true branch, Phi(x3,x4)
354*795d594fSAndroid Build Coastguard Worker     // in the false branch, and remain as Phi(x5,x6) in `block` (for edges that we couldn't
355*795d594fSAndroid Build Coastguard Worker     // redirect). We might even be able to remove some phis altogether as they will have only one
356*795d594fSAndroid Build Coastguard Worker     // value.
357*795d594fSAndroid Build Coastguard Worker     if (block->HasSinglePhi() &&
358*795d594fSAndroid Build Coastguard Worker         block->GetFirstPhi()->HasOnlyOneNonEnvironmentUse()) {
359*795d594fSAndroid Build Coastguard Worker       HInstruction* first = block->GetFirstInstruction();
360*795d594fSAndroid Build Coastguard Worker       bool has_only_phi_and_if = (last == first) && (last->InputAt(0) == block->GetFirstPhi());
361*795d594fSAndroid Build Coastguard Worker       bool has_only_phi_condition_and_if =
362*795d594fSAndroid Build Coastguard Worker           !has_only_phi_and_if &&
363*795d594fSAndroid Build Coastguard Worker           first->IsCondition() &&
364*795d594fSAndroid Build Coastguard Worker           HasInput(first->AsCondition(), block->GetFirstPhi()) &&
365*795d594fSAndroid Build Coastguard Worker           (first->GetNext() == last) &&
366*795d594fSAndroid Build Coastguard Worker           (last->InputAt(0) == first) &&
367*795d594fSAndroid Build Coastguard Worker           first->HasOnlyOneNonEnvironmentUse();
368*795d594fSAndroid Build Coastguard Worker 
369*795d594fSAndroid Build Coastguard Worker       if (has_only_phi_and_if || has_only_phi_condition_and_if) {
370*795d594fSAndroid Build Coastguard Worker         HPhi* phi = block->GetFirstPhi()->AsPhi();
371*795d594fSAndroid Build Coastguard Worker         bool phi_input_is_left = (first->InputAt(0) == phi);
372*795d594fSAndroid Build Coastguard Worker 
373*795d594fSAndroid Build Coastguard Worker         // Walk over all inputs of the phis and update the control flow of
374*795d594fSAndroid Build Coastguard Worker         // predecessors feeding constants to the phi.
375*795d594fSAndroid Build Coastguard Worker         // Note that phi->InputCount() may change inside the loop.
376*795d594fSAndroid Build Coastguard Worker         for (size_t i = 0; i < phi->InputCount();) {
377*795d594fSAndroid Build Coastguard Worker           HInstruction* input = phi->InputAt(i);
378*795d594fSAndroid Build Coastguard Worker           HInstruction* value_to_check = nullptr;
379*795d594fSAndroid Build Coastguard Worker           if (has_only_phi_and_if) {
380*795d594fSAndroid Build Coastguard Worker             if (input->IsIntConstant()) {
381*795d594fSAndroid Build Coastguard Worker               value_to_check = input;
382*795d594fSAndroid Build Coastguard Worker             }
383*795d594fSAndroid Build Coastguard Worker           } else {
384*795d594fSAndroid Build Coastguard Worker             DCHECK(has_only_phi_condition_and_if);
385*795d594fSAndroid Build Coastguard Worker             if (phi_input_is_left) {
386*795d594fSAndroid Build Coastguard Worker               value_to_check = Evaluate(first->AsCondition(), input, first->InputAt(1));
387*795d594fSAndroid Build Coastguard Worker             } else {
388*795d594fSAndroid Build Coastguard Worker               value_to_check = Evaluate(first->AsCondition(), first->InputAt(0), input);
389*795d594fSAndroid Build Coastguard Worker             }
390*795d594fSAndroid Build Coastguard Worker           }
391*795d594fSAndroid Build Coastguard Worker           if (value_to_check == nullptr) {
392*795d594fSAndroid Build Coastguard Worker             // Could not evaluate to a constant, continue iterating over the inputs.
393*795d594fSAndroid Build Coastguard Worker             ++i;
394*795d594fSAndroid Build Coastguard Worker           } else {
395*795d594fSAndroid Build Coastguard Worker             HBasicBlock* predecessor_to_update = block->GetPredecessors()[i];
396*795d594fSAndroid Build Coastguard Worker             HBasicBlock* successor_to_update = nullptr;
397*795d594fSAndroid Build Coastguard Worker             if (value_to_check->AsIntConstant()->IsTrue()) {
398*795d594fSAndroid Build Coastguard Worker               successor_to_update = last->AsIf()->IfTrueSuccessor();
399*795d594fSAndroid Build Coastguard Worker             } else {
400*795d594fSAndroid Build Coastguard Worker               DCHECK(value_to_check->AsIntConstant()->IsFalse())
401*795d594fSAndroid Build Coastguard Worker                   << value_to_check->AsIntConstant()->GetValue();
402*795d594fSAndroid Build Coastguard Worker               successor_to_update = last->AsIf()->IfFalseSuccessor();
403*795d594fSAndroid Build Coastguard Worker             }
404*795d594fSAndroid Build Coastguard Worker             predecessor_to_update->ReplaceSuccessor(block, successor_to_update);
405*795d594fSAndroid Build Coastguard Worker             phi->RemoveInputAt(i);
406*795d594fSAndroid Build Coastguard Worker             simplified_one_or_more_ifs = true;
407*795d594fSAndroid Build Coastguard Worker             if (block->IsInLoop()) {
408*795d594fSAndroid Build Coastguard Worker               rerun_dominance_and_loop_analysis = true;
409*795d594fSAndroid Build Coastguard Worker             }
410*795d594fSAndroid Build Coastguard Worker             // For simplicity, don't create a dead block, let the dead code elimination
411*795d594fSAndroid Build Coastguard Worker             // pass deal with it.
412*795d594fSAndroid Build Coastguard Worker             if (phi->InputCount() == 1) {
413*795d594fSAndroid Build Coastguard Worker               break;
414*795d594fSAndroid Build Coastguard Worker             }
415*795d594fSAndroid Build Coastguard Worker           }
416*795d594fSAndroid Build Coastguard Worker         }
417*795d594fSAndroid Build Coastguard Worker         if (block->GetPredecessors().size() == 1) {
418*795d594fSAndroid Build Coastguard Worker           phi->ReplaceWith(phi->InputAt(0));
419*795d594fSAndroid Build Coastguard Worker           block->RemovePhi(phi);
420*795d594fSAndroid Build Coastguard Worker           if (has_only_phi_condition_and_if) {
421*795d594fSAndroid Build Coastguard Worker             // Evaluate here (and not wait for a constant folding pass) to open
422*795d594fSAndroid Build Coastguard Worker             // more opportunities for DCE.
423*795d594fSAndroid Build Coastguard Worker             HInstruction* result = first->AsCondition()->TryStaticEvaluation();
424*795d594fSAndroid Build Coastguard Worker             if (result != nullptr) {
425*795d594fSAndroid Build Coastguard Worker               first->ReplaceWith(result);
426*795d594fSAndroid Build Coastguard Worker               block->RemoveInstruction(first);
427*795d594fSAndroid Build Coastguard Worker             }
428*795d594fSAndroid Build Coastguard Worker           }
429*795d594fSAndroid Build Coastguard Worker         }
430*795d594fSAndroid Build Coastguard Worker         if (simplified_one_or_more_ifs) {
431*795d594fSAndroid Build Coastguard Worker           MaybeRecordSimplifyIf();
432*795d594fSAndroid Build Coastguard Worker         }
433*795d594fSAndroid Build Coastguard Worker       }
434*795d594fSAndroid Build Coastguard Worker     }
435*795d594fSAndroid Build Coastguard Worker   }
436*795d594fSAndroid Build Coastguard Worker   // We need to re-analyze the graph in order to run DCE afterwards.
437*795d594fSAndroid Build Coastguard Worker   if (simplified_one_or_more_ifs) {
438*795d594fSAndroid Build Coastguard Worker     if (rerun_dominance_and_loop_analysis) {
439*795d594fSAndroid Build Coastguard Worker       graph_->RecomputeDominatorTree();
440*795d594fSAndroid Build Coastguard Worker     } else {
441*795d594fSAndroid Build Coastguard Worker       graph_->ClearDominanceInformation();
442*795d594fSAndroid Build Coastguard Worker       // We have introduced critical edges, remove them.
443*795d594fSAndroid Build Coastguard Worker       graph_->SimplifyCFG();
444*795d594fSAndroid Build Coastguard Worker       graph_->ComputeDominanceInformation();
445*795d594fSAndroid Build Coastguard Worker       graph_->ComputeTryBlockInformation();
446*795d594fSAndroid Build Coastguard Worker     }
447*795d594fSAndroid Build Coastguard Worker   }
448*795d594fSAndroid Build Coastguard Worker 
449*795d594fSAndroid Build Coastguard Worker   return simplified_one_or_more_ifs;
450*795d594fSAndroid Build Coastguard Worker }
451*795d594fSAndroid Build Coastguard Worker 
MaybeAddPhi(HBasicBlock * block)452*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::MaybeAddPhi(HBasicBlock* block) {
453*795d594fSAndroid Build Coastguard Worker   DCHECK(block->GetLastInstruction()->IsIf());
454*795d594fSAndroid Build Coastguard Worker   HIf* if_instruction = block->GetLastInstruction()->AsIf();
455*795d594fSAndroid Build Coastguard Worker   if (if_instruction->InputAt(0)->IsConstant()) {
456*795d594fSAndroid Build Coastguard Worker     // Constant values are handled in RemoveDeadBlocks.
457*795d594fSAndroid Build Coastguard Worker     return;
458*795d594fSAndroid Build Coastguard Worker   }
459*795d594fSAndroid Build Coastguard Worker 
460*795d594fSAndroid Build Coastguard Worker   if (block->GetNumberOfPredecessors() < 2u) {
461*795d594fSAndroid Build Coastguard Worker     // Nothing to redirect.
462*795d594fSAndroid Build Coastguard Worker     return;
463*795d594fSAndroid Build Coastguard Worker   }
464*795d594fSAndroid Build Coastguard Worker 
465*795d594fSAndroid Build Coastguard Worker   if (!block->GetPhis().IsEmpty()) {
466*795d594fSAndroid Build Coastguard Worker     // SimplifyIf doesn't currently work with multiple phis. Adding a phi here won't help that
467*795d594fSAndroid Build Coastguard Worker     // optimization.
468*795d594fSAndroid Build Coastguard Worker     return;
469*795d594fSAndroid Build Coastguard Worker   }
470*795d594fSAndroid Build Coastguard Worker 
471*795d594fSAndroid Build Coastguard Worker   HBasicBlock* dominator = block->GetDominator();
472*795d594fSAndroid Build Coastguard Worker   if (!dominator->EndsWithIf()) {
473*795d594fSAndroid Build Coastguard Worker     return;
474*795d594fSAndroid Build Coastguard Worker   }
475*795d594fSAndroid Build Coastguard Worker 
476*795d594fSAndroid Build Coastguard Worker   HInstruction* input = if_instruction->InputAt(0);
477*795d594fSAndroid Build Coastguard Worker   HInstruction* dominator_input = dominator->GetLastInstruction()->AsIf()->InputAt(0);
478*795d594fSAndroid Build Coastguard Worker   const bool same_input = dominator_input == input;
479*795d594fSAndroid Build Coastguard Worker   if (!same_input) {
480*795d594fSAndroid Build Coastguard Worker     // Try to see if the dominator has the opposite input (e.g. if(cond) and if(!cond)). If that's
481*795d594fSAndroid Build Coastguard Worker     // the case, we can perform the optimization with the false and true branches reversed.
482*795d594fSAndroid Build Coastguard Worker     if (!dominator_input->IsCondition() || !input->IsCondition()) {
483*795d594fSAndroid Build Coastguard Worker       return;
484*795d594fSAndroid Build Coastguard Worker     }
485*795d594fSAndroid Build Coastguard Worker 
486*795d594fSAndroid Build Coastguard Worker     HCondition* block_cond = input->AsCondition();
487*795d594fSAndroid Build Coastguard Worker     HCondition* dominator_cond = dominator_input->AsCondition();
488*795d594fSAndroid Build Coastguard Worker 
489*795d594fSAndroid Build Coastguard Worker     if (block_cond->GetLeft() != dominator_cond->GetLeft() ||
490*795d594fSAndroid Build Coastguard Worker         block_cond->GetRight() != dominator_cond->GetRight() ||
491*795d594fSAndroid Build Coastguard Worker         block_cond->GetOppositeCondition() != dominator_cond->GetCondition()) {
492*795d594fSAndroid Build Coastguard Worker       return;
493*795d594fSAndroid Build Coastguard Worker     }
494*795d594fSAndroid Build Coastguard Worker   }
495*795d594fSAndroid Build Coastguard Worker 
496*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
497*795d594fSAndroid Build Coastguard Worker     // `block`'s successors should have only one predecessor. Otherwise, we have a critical edge in
498*795d594fSAndroid Build Coastguard Worker     // the graph.
499*795d594fSAndroid Build Coastguard Worker     for (HBasicBlock* succ : block->GetSuccessors()) {
500*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(succ->GetNumberOfPredecessors(), 1u);
501*795d594fSAndroid Build Coastguard Worker     }
502*795d594fSAndroid Build Coastguard Worker   }
503*795d594fSAndroid Build Coastguard Worker 
504*795d594fSAndroid Build Coastguard Worker   const size_t pred_size = block->GetNumberOfPredecessors();
505*795d594fSAndroid Build Coastguard Worker   HPhi* new_phi = new (graph_->GetAllocator())
506*795d594fSAndroid Build Coastguard Worker       HPhi(graph_->GetAllocator(), kNoRegNumber, pred_size, DataType::Type::kInt32);
507*795d594fSAndroid Build Coastguard Worker 
508*795d594fSAndroid Build Coastguard Worker   for (size_t index = 0; index < pred_size; index++) {
509*795d594fSAndroid Build Coastguard Worker     HBasicBlock* pred = block->GetPredecessors()[index];
510*795d594fSAndroid Build Coastguard Worker     const bool dominated_by_true =
511*795d594fSAndroid Build Coastguard Worker         dominator->GetLastInstruction()->AsIf()->IfTrueSuccessor()->Dominates(pred);
512*795d594fSAndroid Build Coastguard Worker     const bool dominated_by_false =
513*795d594fSAndroid Build Coastguard Worker         dominator->GetLastInstruction()->AsIf()->IfFalseSuccessor()->Dominates(pred);
514*795d594fSAndroid Build Coastguard Worker     if (dominated_by_true == dominated_by_false) {
515*795d594fSAndroid Build Coastguard Worker       // In this case, we can't know if we are coming from the true branch, or the false branch. It
516*795d594fSAndroid Build Coastguard Worker       // happens in cases like:
517*795d594fSAndroid Build Coastguard Worker       //      1 (outer if)
518*795d594fSAndroid Build Coastguard Worker       //     / \
519*795d594fSAndroid Build Coastguard Worker       //    2   3 (inner if)
520*795d594fSAndroid Build Coastguard Worker       //    |  / \
521*795d594fSAndroid Build Coastguard Worker       //    | 4  5
522*795d594fSAndroid Build Coastguard Worker       //     \/  |
523*795d594fSAndroid Build Coastguard Worker       //      6  |
524*795d594fSAndroid Build Coastguard Worker       //       \ |
525*795d594fSAndroid Build Coastguard Worker       //         7 (has the same if(cond) as 1)
526*795d594fSAndroid Build Coastguard Worker       //         |
527*795d594fSAndroid Build Coastguard Worker       //         8
528*795d594fSAndroid Build Coastguard Worker       // `7` (which would be `block` in this example), and `6` will come from both the true path and
529*795d594fSAndroid Build Coastguard Worker       // the false path of `1`. We bumped into something similar in SelectGenerator. See
530*795d594fSAndroid Build Coastguard Worker       // HSelectGenerator::TryFixupDoubleDiamondPattern.
531*795d594fSAndroid Build Coastguard Worker       // TODO(solanes): Figure out if we can fix up the graph into a double diamond in a generic way
532*795d594fSAndroid Build Coastguard Worker       // so that DeadCodeElimination and SelectGenerator can take advantage of it.
533*795d594fSAndroid Build Coastguard Worker 
534*795d594fSAndroid Build Coastguard Worker       if (!same_input) {
535*795d594fSAndroid Build Coastguard Worker         // `1` and `7` having the opposite condition is a case we are missing. We could potentially
536*795d594fSAndroid Build Coastguard Worker         // add a BooleanNot instruction to be able to add the Phi, but it seems like overkill since
537*795d594fSAndroid Build Coastguard Worker         // this case is not that common.
538*795d594fSAndroid Build Coastguard Worker         return;
539*795d594fSAndroid Build Coastguard Worker       }
540*795d594fSAndroid Build Coastguard Worker 
541*795d594fSAndroid Build Coastguard Worker       // The Phi will have `0`, `1`, and `cond` as inputs. If SimplifyIf redirects 0s and 1s, we
542*795d594fSAndroid Build Coastguard Worker       // will end up with Phi(cond,...,cond) which will be replaced by `cond`. Effectively, we will
543*795d594fSAndroid Build Coastguard Worker       // redirect edges that we are able to redirect and the rest will remain as before (i.e. we
544*795d594fSAndroid Build Coastguard Worker       // won't have an extra Phi).
545*795d594fSAndroid Build Coastguard Worker       new_phi->SetRawInputAt(index, input);
546*795d594fSAndroid Build Coastguard Worker     } else {
547*795d594fSAndroid Build Coastguard Worker       // Redirect to either the true branch (1), or the false branch (0).
548*795d594fSAndroid Build Coastguard Worker       // Given that `dominated_by_true` is the exact opposite of `dominated_by_false`,
549*795d594fSAndroid Build Coastguard Worker       // `(same_input && dominated_by_true) || (!same_input && dominated_by_false)` is equivalent to
550*795d594fSAndroid Build Coastguard Worker       // `same_input == dominated_by_true`.
551*795d594fSAndroid Build Coastguard Worker       new_phi->SetRawInputAt(
552*795d594fSAndroid Build Coastguard Worker           index,
553*795d594fSAndroid Build Coastguard Worker           same_input == dominated_by_true ? graph_->GetIntConstant(1) : graph_->GetIntConstant(0));
554*795d594fSAndroid Build Coastguard Worker     }
555*795d594fSAndroid Build Coastguard Worker   }
556*795d594fSAndroid Build Coastguard Worker 
557*795d594fSAndroid Build Coastguard Worker   block->AddPhi(new_phi);
558*795d594fSAndroid Build Coastguard Worker   if_instruction->ReplaceInput(new_phi, 0);
559*795d594fSAndroid Build Coastguard Worker 
560*795d594fSAndroid Build Coastguard Worker   // Remove the old input now, if possible. This allows the branch redirection in SimplifyIf to
561*795d594fSAndroid Build Coastguard Worker   // work without waiting for another pass of DCE.
562*795d594fSAndroid Build Coastguard Worker   if (input->IsDeadAndRemovable()) {
563*795d594fSAndroid Build Coastguard Worker     DCHECK(!same_input)
564*795d594fSAndroid Build Coastguard Worker         << " if both blocks have the same condition, it shouldn't be dead and removable since the "
565*795d594fSAndroid Build Coastguard Worker         << "dominator block's If instruction would be using that condition.";
566*795d594fSAndroid Build Coastguard Worker     input->GetBlock()->RemoveInstruction(input);
567*795d594fSAndroid Build Coastguard Worker   }
568*795d594fSAndroid Build Coastguard Worker   MaybeRecordStat(stats_, MethodCompilationStat::kSimplifyIfAddedPhi);
569*795d594fSAndroid Build Coastguard Worker }
570*795d594fSAndroid Build Coastguard Worker 
ConnectSuccessiveBlocks()571*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::ConnectSuccessiveBlocks() {
572*795d594fSAndroid Build Coastguard Worker   // Order does not matter. Skip the entry block by starting at index 1 in reverse post order.
573*795d594fSAndroid Build Coastguard Worker   for (size_t i = 1u, size = graph_->GetReversePostOrder().size(); i != size; ++i) {
574*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block  = graph_->GetReversePostOrder()[i];
575*795d594fSAndroid Build Coastguard Worker     DCHECK(!block->IsEntryBlock());
576*795d594fSAndroid Build Coastguard Worker     while (block->GetLastInstruction()->IsGoto()) {
577*795d594fSAndroid Build Coastguard Worker       HBasicBlock* successor = block->GetSingleSuccessor();
578*795d594fSAndroid Build Coastguard Worker       if (successor->IsExitBlock() || successor->GetPredecessors().size() != 1u) {
579*795d594fSAndroid Build Coastguard Worker         break;
580*795d594fSAndroid Build Coastguard Worker       }
581*795d594fSAndroid Build Coastguard Worker       DCHECK_LT(i, IndexOfElement(graph_->GetReversePostOrder(), successor));
582*795d594fSAndroid Build Coastguard Worker       block->MergeWith(successor);
583*795d594fSAndroid Build Coastguard Worker       --size;
584*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(size, graph_->GetReversePostOrder().size());
585*795d594fSAndroid Build Coastguard Worker       DCHECK_EQ(block, graph_->GetReversePostOrder()[i]);
586*795d594fSAndroid Build Coastguard Worker       // Reiterate on this block in case it can be merged with its new successor.
587*795d594fSAndroid Build Coastguard Worker     }
588*795d594fSAndroid Build Coastguard Worker   }
589*795d594fSAndroid Build Coastguard Worker }
590*795d594fSAndroid Build Coastguard Worker 
591*795d594fSAndroid Build Coastguard Worker struct HDeadCodeElimination::TryBelongingInformation {
TryBelongingInformationart::HDeadCodeElimination::TryBelongingInformation592*795d594fSAndroid Build Coastguard Worker   TryBelongingInformation(HGraph* graph, ScopedArenaAllocator* allocator)
593*795d594fSAndroid Build Coastguard Worker       : blocks_in_try(allocator, graph->GetBlocks().size(), /*expandable=*/false, kArenaAllocDCE),
594*795d594fSAndroid Build Coastguard Worker         coalesced_try_entries(
595*795d594fSAndroid Build Coastguard Worker             allocator, graph->GetBlocks().size(), /*expandable=*/false, kArenaAllocDCE) {}
596*795d594fSAndroid Build Coastguard Worker 
597*795d594fSAndroid Build Coastguard Worker   // Which blocks belong in the try.
598*795d594fSAndroid Build Coastguard Worker   ArenaBitVector blocks_in_try;
599*795d594fSAndroid Build Coastguard Worker   // Which other try entries are referencing this same try.
600*795d594fSAndroid Build Coastguard Worker   ArenaBitVector coalesced_try_entries;
601*795d594fSAndroid Build Coastguard Worker };
602*795d594fSAndroid Build Coastguard Worker 
CanPerformTryRemoval(const TryBelongingInformation & try_belonging_info)603*795d594fSAndroid Build Coastguard Worker bool HDeadCodeElimination::CanPerformTryRemoval(const TryBelongingInformation& try_belonging_info) {
604*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = graph_->GetBlocks();
605*795d594fSAndroid Build Coastguard Worker   for (uint32_t i : try_belonging_info.blocks_in_try.Indexes()) {
606*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(blocks[i]->GetInstructions()); !it.Done(); it.Advance()) {
607*795d594fSAndroid Build Coastguard Worker       if (it.Current()->CanThrow()) {
608*795d594fSAndroid Build Coastguard Worker         return false;
609*795d594fSAndroid Build Coastguard Worker       }
610*795d594fSAndroid Build Coastguard Worker     }
611*795d594fSAndroid Build Coastguard Worker   }
612*795d594fSAndroid Build Coastguard Worker   return true;
613*795d594fSAndroid Build Coastguard Worker }
614*795d594fSAndroid Build Coastguard Worker 
DisconnectHandlersAndUpdateTryBoundary(HBasicBlock * block,bool * any_block_in_loop)615*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::DisconnectHandlersAndUpdateTryBoundary(
616*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block,
617*795d594fSAndroid Build Coastguard Worker     /* out */ bool* any_block_in_loop) {
618*795d594fSAndroid Build Coastguard Worker   if (block->IsInLoop()) {
619*795d594fSAndroid Build Coastguard Worker     *any_block_in_loop = true;
620*795d594fSAndroid Build Coastguard Worker   }
621*795d594fSAndroid Build Coastguard Worker 
622*795d594fSAndroid Build Coastguard Worker   // Disconnect the handlers.
623*795d594fSAndroid Build Coastguard Worker   while (block->GetSuccessors().size() > 1) {
624*795d594fSAndroid Build Coastguard Worker     HBasicBlock* handler = block->GetSuccessors()[1];
625*795d594fSAndroid Build Coastguard Worker     DCHECK(handler->IsCatchBlock());
626*795d594fSAndroid Build Coastguard Worker     block->RemoveSuccessor(handler);
627*795d594fSAndroid Build Coastguard Worker     handler->RemovePredecessor(block);
628*795d594fSAndroid Build Coastguard Worker     if (handler->IsInLoop()) {
629*795d594fSAndroid Build Coastguard Worker       *any_block_in_loop = true;
630*795d594fSAndroid Build Coastguard Worker     }
631*795d594fSAndroid Build Coastguard Worker   }
632*795d594fSAndroid Build Coastguard Worker 
633*795d594fSAndroid Build Coastguard Worker   // Change TryBoundary to Goto.
634*795d594fSAndroid Build Coastguard Worker   DCHECK(block->EndsWithTryBoundary());
635*795d594fSAndroid Build Coastguard Worker   HInstruction* last = block->GetLastInstruction();
636*795d594fSAndroid Build Coastguard Worker   block->RemoveInstruction(last);
637*795d594fSAndroid Build Coastguard Worker   block->AddInstruction(new (graph_->GetAllocator()) HGoto(last->GetDexPc()));
638*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(block->GetSuccessors().size(), 1u);
639*795d594fSAndroid Build Coastguard Worker }
640*795d594fSAndroid Build Coastguard Worker 
RemoveTry(HBasicBlock * try_entry,const TryBelongingInformation & try_belonging_info,bool * any_block_in_loop)641*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::RemoveTry(HBasicBlock* try_entry,
642*795d594fSAndroid Build Coastguard Worker                                      const TryBelongingInformation& try_belonging_info,
643*795d594fSAndroid Build Coastguard Worker                                      /* out */ bool* any_block_in_loop) {
644*795d594fSAndroid Build Coastguard Worker   // Update all try entries.
645*795d594fSAndroid Build Coastguard Worker   DCHECK(try_entry->EndsWithTryBoundary());
646*795d594fSAndroid Build Coastguard Worker   DCHECK(try_entry->GetLastInstruction()->AsTryBoundary()->IsEntry());
647*795d594fSAndroid Build Coastguard Worker   DisconnectHandlersAndUpdateTryBoundary(try_entry, any_block_in_loop);
648*795d594fSAndroid Build Coastguard Worker 
649*795d594fSAndroid Build Coastguard Worker   const ArenaVector<HBasicBlock*>& blocks = graph_->GetBlocks();
650*795d594fSAndroid Build Coastguard Worker   for (uint32_t i : try_belonging_info.coalesced_try_entries.Indexes()) {
651*795d594fSAndroid Build Coastguard Worker     HBasicBlock* other_try_entry = blocks[i];
652*795d594fSAndroid Build Coastguard Worker     DCHECK(other_try_entry->EndsWithTryBoundary());
653*795d594fSAndroid Build Coastguard Worker     DCHECK(other_try_entry->GetLastInstruction()->AsTryBoundary()->IsEntry());
654*795d594fSAndroid Build Coastguard Worker     DisconnectHandlersAndUpdateTryBoundary(other_try_entry, any_block_in_loop);
655*795d594fSAndroid Build Coastguard Worker   }
656*795d594fSAndroid Build Coastguard Worker 
657*795d594fSAndroid Build Coastguard Worker   // Update the blocks in the try.
658*795d594fSAndroid Build Coastguard Worker   for (uint32_t i : try_belonging_info.blocks_in_try.Indexes()) {
659*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = blocks[i];
660*795d594fSAndroid Build Coastguard Worker     // Update the try catch information since now the try doesn't exist.
661*795d594fSAndroid Build Coastguard Worker     block->SetTryCatchInformation(nullptr);
662*795d594fSAndroid Build Coastguard Worker     if (block->IsInLoop()) {
663*795d594fSAndroid Build Coastguard Worker       *any_block_in_loop = true;
664*795d594fSAndroid Build Coastguard Worker     }
665*795d594fSAndroid Build Coastguard Worker 
666*795d594fSAndroid Build Coastguard Worker     if (block->EndsWithTryBoundary()) {
667*795d594fSAndroid Build Coastguard Worker       // Try exits.
668*795d594fSAndroid Build Coastguard Worker       DCHECK(!block->GetLastInstruction()->AsTryBoundary()->IsEntry());
669*795d594fSAndroid Build Coastguard Worker       DisconnectHandlersAndUpdateTryBoundary(block, any_block_in_loop);
670*795d594fSAndroid Build Coastguard Worker 
671*795d594fSAndroid Build Coastguard Worker       if (block->GetSingleSuccessor()->IsExitBlock()) {
672*795d594fSAndroid Build Coastguard Worker         // `block` used to be a single exit TryBoundary that got turned into a Goto. It
673*795d594fSAndroid Build Coastguard Worker         // is now pointing to the exit which we don't allow. To fix it, we disconnect
674*795d594fSAndroid Build Coastguard Worker         // `block` from its predecessor and RemoveDeadBlocks will remove it from the
675*795d594fSAndroid Build Coastguard Worker         // graph.
676*795d594fSAndroid Build Coastguard Worker         DCHECK(block->IsSingleGoto());
677*795d594fSAndroid Build Coastguard Worker         HBasicBlock* predecessor = block->GetSinglePredecessor();
678*795d594fSAndroid Build Coastguard Worker         predecessor->ReplaceSuccessor(block, graph_->GetExitBlock());
679*795d594fSAndroid Build Coastguard Worker 
680*795d594fSAndroid Build Coastguard Worker         if (!block->GetDominatedBlocks().empty()) {
681*795d594fSAndroid Build Coastguard Worker           // Update domination tree if `block` dominates a block to keep the graph consistent.
682*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(block->GetDominatedBlocks().size(), 1u);
683*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(graph_->GetExitBlock()->GetDominator(), block);
684*795d594fSAndroid Build Coastguard Worker           predecessor->AddDominatedBlock(graph_->GetExitBlock());
685*795d594fSAndroid Build Coastguard Worker           graph_->GetExitBlock()->SetDominator(predecessor);
686*795d594fSAndroid Build Coastguard Worker           block->RemoveDominatedBlock(graph_->GetExitBlock());
687*795d594fSAndroid Build Coastguard Worker         }
688*795d594fSAndroid Build Coastguard Worker       }
689*795d594fSAndroid Build Coastguard Worker     }
690*795d594fSAndroid Build Coastguard Worker   }
691*795d594fSAndroid Build Coastguard Worker }
692*795d594fSAndroid Build Coastguard Worker 
RemoveUnneededTries()693*795d594fSAndroid Build Coastguard Worker bool HDeadCodeElimination::RemoveUnneededTries() {
694*795d594fSAndroid Build Coastguard Worker   if (!graph_->HasTryCatch()) {
695*795d594fSAndroid Build Coastguard Worker     return false;
696*795d594fSAndroid Build Coastguard Worker   }
697*795d594fSAndroid Build Coastguard Worker 
698*795d594fSAndroid Build Coastguard Worker   // Use local allocator for allocating memory.
699*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(graph_->GetArenaStack());
700*795d594fSAndroid Build Coastguard Worker 
701*795d594fSAndroid Build Coastguard Worker   // Collect which blocks are part of which try.
702*795d594fSAndroid Build Coastguard Worker   ScopedArenaUnorderedMap<HBasicBlock*, TryBelongingInformation> tries(
703*795d594fSAndroid Build Coastguard Worker       allocator.Adapter(kArenaAllocDCE));
704*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrderSkipEntryBlock()) {
705*795d594fSAndroid Build Coastguard Worker     if (block->IsTryBlock()) {
706*795d594fSAndroid Build Coastguard Worker       HBasicBlock* key = block->GetTryCatchInformation()->GetTryEntry().GetBlock();
707*795d594fSAndroid Build Coastguard Worker       auto it = tries.find(key);
708*795d594fSAndroid Build Coastguard Worker       if (it == tries.end()) {
709*795d594fSAndroid Build Coastguard Worker         it = tries.insert({key, TryBelongingInformation(graph_, &allocator)}).first;
710*795d594fSAndroid Build Coastguard Worker       }
711*795d594fSAndroid Build Coastguard Worker       it->second.blocks_in_try.SetBit(block->GetBlockId());
712*795d594fSAndroid Build Coastguard Worker     }
713*795d594fSAndroid Build Coastguard Worker   }
714*795d594fSAndroid Build Coastguard Worker 
715*795d594fSAndroid Build Coastguard Worker   // Deduplicate the tries which have different try entries but they are really the same try.
716*795d594fSAndroid Build Coastguard Worker   for (auto it = tries.begin(); it != tries.end(); it++) {
717*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block = it->first;
718*795d594fSAndroid Build Coastguard Worker     DCHECK(block->EndsWithTryBoundary());
719*795d594fSAndroid Build Coastguard Worker     HTryBoundary* try_boundary = block->GetLastInstruction()->AsTryBoundary();
720*795d594fSAndroid Build Coastguard Worker     for (auto other_it = next(it); other_it != tries.end(); /*other_it++ in the loop*/) {
721*795d594fSAndroid Build Coastguard Worker       HBasicBlock* other_block = other_it->first;
722*795d594fSAndroid Build Coastguard Worker       DCHECK(other_block->EndsWithTryBoundary());
723*795d594fSAndroid Build Coastguard Worker       HTryBoundary* other_try_boundary = other_block->GetLastInstruction()->AsTryBoundary();
724*795d594fSAndroid Build Coastguard Worker       if (try_boundary->HasSameExceptionHandlersAs(*other_try_boundary)) {
725*795d594fSAndroid Build Coastguard Worker         // Merge the entries as they are really the same one.
726*795d594fSAndroid Build Coastguard Worker         // Block merging.
727*795d594fSAndroid Build Coastguard Worker         it->second.blocks_in_try.Union(&other_it->second.blocks_in_try);
728*795d594fSAndroid Build Coastguard Worker 
729*795d594fSAndroid Build Coastguard Worker         // Add the coalesced try entry to update it too.
730*795d594fSAndroid Build Coastguard Worker         it->second.coalesced_try_entries.SetBit(other_block->GetBlockId());
731*795d594fSAndroid Build Coastguard Worker 
732*795d594fSAndroid Build Coastguard Worker         // Erase the other entry.
733*795d594fSAndroid Build Coastguard Worker         other_it = tries.erase(other_it);
734*795d594fSAndroid Build Coastguard Worker       } else {
735*795d594fSAndroid Build Coastguard Worker         other_it++;
736*795d594fSAndroid Build Coastguard Worker       }
737*795d594fSAndroid Build Coastguard Worker     }
738*795d594fSAndroid Build Coastguard Worker   }
739*795d594fSAndroid Build Coastguard Worker 
740*795d594fSAndroid Build Coastguard Worker   size_t removed_tries = 0;
741*795d594fSAndroid Build Coastguard Worker   bool any_block_in_loop = false;
742*795d594fSAndroid Build Coastguard Worker 
743*795d594fSAndroid Build Coastguard Worker   // Check which tries contain throwing instructions.
744*795d594fSAndroid Build Coastguard Worker   for (const auto& entry : tries) {
745*795d594fSAndroid Build Coastguard Worker     if (CanPerformTryRemoval(entry.second)) {
746*795d594fSAndroid Build Coastguard Worker       ++removed_tries;
747*795d594fSAndroid Build Coastguard Worker       RemoveTry(entry.first, entry.second, &any_block_in_loop);
748*795d594fSAndroid Build Coastguard Worker     }
749*795d594fSAndroid Build Coastguard Worker   }
750*795d594fSAndroid Build Coastguard Worker 
751*795d594fSAndroid Build Coastguard Worker   if (removed_tries != 0) {
752*795d594fSAndroid Build Coastguard Worker     // We want to:
753*795d594fSAndroid Build Coastguard Worker     //   1) Update the dominance information
754*795d594fSAndroid Build Coastguard Worker     //   2) Remove catch block subtrees, if they are now unreachable.
755*795d594fSAndroid Build Coastguard Worker     // If we run the dominance recomputation without removing the code, those catch blocks will
756*795d594fSAndroid Build Coastguard Worker     // not be part of the post order and won't be removed. If we don't run the dominance
757*795d594fSAndroid Build Coastguard Worker     // recomputation, we risk RemoveDeadBlocks not running it and leaving the graph in an
758*795d594fSAndroid Build Coastguard Worker     // inconsistent state. So, what we can do is run RemoveDeadBlocks and force a recomputation.
759*795d594fSAndroid Build Coastguard Worker     // Note that we are not guaranteed to remove a catch block if we have nested try blocks:
760*795d594fSAndroid Build Coastguard Worker     //
761*795d594fSAndroid Build Coastguard Worker     //   try {
762*795d594fSAndroid Build Coastguard Worker     //     ... nothing can throw. TryBoundary A ...
763*795d594fSAndroid Build Coastguard Worker     //     try {
764*795d594fSAndroid Build Coastguard Worker     //       ... can throw. TryBoundary B...
765*795d594fSAndroid Build Coastguard Worker     //     } catch (Error e) {}
766*795d594fSAndroid Build Coastguard Worker     //   } catch (Exception e) {}
767*795d594fSAndroid Build Coastguard Worker     //
768*795d594fSAndroid Build Coastguard Worker     // In the example above, we can remove the TryBoundary A but the Exception catch cannot be
769*795d594fSAndroid Build Coastguard Worker     // removed as the TryBoundary B might still throw into that catch. TryBoundary A and B don't get
770*795d594fSAndroid Build Coastguard Worker     // coalesced since they have different catch handlers.
771*795d594fSAndroid Build Coastguard Worker 
772*795d594fSAndroid Build Coastguard Worker     RemoveDeadBlocks(/* force_recomputation= */ true, any_block_in_loop);
773*795d594fSAndroid Build Coastguard Worker     MaybeRecordStat(stats_, MethodCompilationStat::kRemovedTry, removed_tries);
774*795d594fSAndroid Build Coastguard Worker     return true;
775*795d594fSAndroid Build Coastguard Worker   } else {
776*795d594fSAndroid Build Coastguard Worker     return false;
777*795d594fSAndroid Build Coastguard Worker   }
778*795d594fSAndroid Build Coastguard Worker }
779*795d594fSAndroid Build Coastguard Worker 
RemoveEmptyIfs()780*795d594fSAndroid Build Coastguard Worker bool HDeadCodeElimination::RemoveEmptyIfs() {
781*795d594fSAndroid Build Coastguard Worker   bool did_opt = false;
782*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
783*795d594fSAndroid Build Coastguard Worker     if (!block->EndsWithIf()) {
784*795d594fSAndroid Build Coastguard Worker       continue;
785*795d594fSAndroid Build Coastguard Worker     }
786*795d594fSAndroid Build Coastguard Worker 
787*795d594fSAndroid Build Coastguard Worker     HIf* if_instr = block->GetLastInstruction()->AsIf();
788*795d594fSAndroid Build Coastguard Worker     HBasicBlock* true_block = if_instr->IfTrueSuccessor();
789*795d594fSAndroid Build Coastguard Worker     HBasicBlock* false_block = if_instr->IfFalseSuccessor();
790*795d594fSAndroid Build Coastguard Worker 
791*795d594fSAndroid Build Coastguard Worker     // We can use `visited_blocks` to detect cases like
792*795d594fSAndroid Build Coastguard Worker     //    1
793*795d594fSAndroid Build Coastguard Worker     //   / \
794*795d594fSAndroid Build Coastguard Worker     //  2  3
795*795d594fSAndroid Build Coastguard Worker     //  \ /
796*795d594fSAndroid Build Coastguard Worker     //   4  ...
797*795d594fSAndroid Build Coastguard Worker     //   | /
798*795d594fSAndroid Build Coastguard Worker     //   5
799*795d594fSAndroid Build Coastguard Worker     // where 2, 3, and 4 are single HGoto blocks, and block 5 has Phis.
800*795d594fSAndroid Build Coastguard Worker     ScopedArenaAllocator allocator(graph_->GetArenaStack());
801*795d594fSAndroid Build Coastguard Worker     ArenaBitVector visited_blocks(
802*795d594fSAndroid Build Coastguard Worker         &allocator, graph_->GetBlocks().size(), /*expandable=*/ false, kArenaAllocDCE);
803*795d594fSAndroid Build Coastguard Worker     HBasicBlock* merge_true = true_block;
804*795d594fSAndroid Build Coastguard Worker     visited_blocks.SetBit(merge_true->GetBlockId());
805*795d594fSAndroid Build Coastguard Worker     while (merge_true->IsSingleGoto()) {
806*795d594fSAndroid Build Coastguard Worker       merge_true = merge_true->GetSuccessors()[0];
807*795d594fSAndroid Build Coastguard Worker       visited_blocks.SetBit(merge_true->GetBlockId());
808*795d594fSAndroid Build Coastguard Worker     }
809*795d594fSAndroid Build Coastguard Worker 
810*795d594fSAndroid Build Coastguard Worker     HBasicBlock* merge_false = false_block;
811*795d594fSAndroid Build Coastguard Worker     while (!visited_blocks.IsBitSet(merge_false->GetBlockId()) && merge_false->IsSingleGoto()) {
812*795d594fSAndroid Build Coastguard Worker       merge_false = merge_false->GetSuccessors()[0];
813*795d594fSAndroid Build Coastguard Worker     }
814*795d594fSAndroid Build Coastguard Worker 
815*795d594fSAndroid Build Coastguard Worker     if (!visited_blocks.IsBitSet(merge_false->GetBlockId()) || !merge_false->GetPhis().IsEmpty()) {
816*795d594fSAndroid Build Coastguard Worker       // TODO(solanes): We could allow Phis iff both branches have the same value for all Phis. This
817*795d594fSAndroid Build Coastguard Worker       // may not be covered by SsaRedundantPhiElimination in cases like `HPhi[A,A,B]` where the Phi
818*795d594fSAndroid Build Coastguard Worker       // itself is not redundant for the general case but it is for a pair of branches.
819*795d594fSAndroid Build Coastguard Worker       continue;
820*795d594fSAndroid Build Coastguard Worker     }
821*795d594fSAndroid Build Coastguard Worker 
822*795d594fSAndroid Build Coastguard Worker     // Data structures to help remove now-dead instructions.
823*795d594fSAndroid Build Coastguard Worker     ScopedArenaQueue<HInstruction*> maybe_remove(allocator.Adapter(kArenaAllocDCE));
824*795d594fSAndroid Build Coastguard Worker     ArenaBitVector visited(
825*795d594fSAndroid Build Coastguard Worker         &allocator, graph_->GetCurrentInstructionId(), /*expandable=*/ false, kArenaAllocDCE);
826*795d594fSAndroid Build Coastguard Worker     maybe_remove.push(if_instr->InputAt(0));
827*795d594fSAndroid Build Coastguard Worker     visited.SetBit(if_instr->GetId());
828*795d594fSAndroid Build Coastguard Worker 
829*795d594fSAndroid Build Coastguard Worker     // Swap HIf with HGoto
830*795d594fSAndroid Build Coastguard Worker     block->ReplaceAndRemoveInstructionWith(
831*795d594fSAndroid Build Coastguard Worker         if_instr, new (graph_->GetAllocator()) HGoto(if_instr->GetDexPc()));
832*795d594fSAndroid Build Coastguard Worker 
833*795d594fSAndroid Build Coastguard Worker     // Reconnect blocks
834*795d594fSAndroid Build Coastguard Worker     block->RemoveSuccessor(true_block);
835*795d594fSAndroid Build Coastguard Worker     block->RemoveSuccessor(false_block);
836*795d594fSAndroid Build Coastguard Worker     true_block->RemovePredecessor(block);
837*795d594fSAndroid Build Coastguard Worker     false_block->RemovePredecessor(block);
838*795d594fSAndroid Build Coastguard Worker     block->AddSuccessor(merge_false);
839*795d594fSAndroid Build Coastguard Worker 
840*795d594fSAndroid Build Coastguard Worker     // Remove now dead instructions e.g. comparisons that are only used as input to the if
841*795d594fSAndroid Build Coastguard Worker     // instruction. This can allow for further removal of other empty ifs.
842*795d594fSAndroid Build Coastguard Worker     while (!maybe_remove.empty()) {
843*795d594fSAndroid Build Coastguard Worker       HInstruction* instr = maybe_remove.front();
844*795d594fSAndroid Build Coastguard Worker       maybe_remove.pop();
845*795d594fSAndroid Build Coastguard Worker       if (instr->IsDeadAndRemovable()) {
846*795d594fSAndroid Build Coastguard Worker         for (HInstruction* input : instr->GetInputs()) {
847*795d594fSAndroid Build Coastguard Worker           if (visited.IsBitSet(input->GetId())) {
848*795d594fSAndroid Build Coastguard Worker             continue;
849*795d594fSAndroid Build Coastguard Worker           }
850*795d594fSAndroid Build Coastguard Worker           visited.SetBit(input->GetId());
851*795d594fSAndroid Build Coastguard Worker           maybe_remove.push(input);
852*795d594fSAndroid Build Coastguard Worker         }
853*795d594fSAndroid Build Coastguard Worker         instr->GetBlock()->RemoveInstructionOrPhi(instr);
854*795d594fSAndroid Build Coastguard Worker         MaybeRecordStat(stats_, MethodCompilationStat::kRemovedDeadInstruction);
855*795d594fSAndroid Build Coastguard Worker       }
856*795d594fSAndroid Build Coastguard Worker     }
857*795d594fSAndroid Build Coastguard Worker 
858*795d594fSAndroid Build Coastguard Worker     did_opt = true;
859*795d594fSAndroid Build Coastguard Worker   }
860*795d594fSAndroid Build Coastguard Worker 
861*795d594fSAndroid Build Coastguard Worker   if (did_opt) {
862*795d594fSAndroid Build Coastguard Worker     graph_->RecomputeDominatorTree();
863*795d594fSAndroid Build Coastguard Worker   }
864*795d594fSAndroid Build Coastguard Worker 
865*795d594fSAndroid Build Coastguard Worker   return did_opt;
866*795d594fSAndroid Build Coastguard Worker }
867*795d594fSAndroid Build Coastguard Worker 
RemoveDeadBlocks(bool force_recomputation,bool force_loop_recomputation)868*795d594fSAndroid Build Coastguard Worker bool HDeadCodeElimination::RemoveDeadBlocks(bool force_recomputation,
869*795d594fSAndroid Build Coastguard Worker                                             bool force_loop_recomputation) {
870*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(force_loop_recomputation, force_recomputation);
871*795d594fSAndroid Build Coastguard Worker 
872*795d594fSAndroid Build Coastguard Worker   // Use local allocator for allocating memory.
873*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(graph_->GetArenaStack());
874*795d594fSAndroid Build Coastguard Worker 
875*795d594fSAndroid Build Coastguard Worker   // Classify blocks as reachable/unreachable.
876*795d594fSAndroid Build Coastguard Worker   ArenaBitVector live_blocks(&allocator, graph_->GetBlocks().size(), false, kArenaAllocDCE);
877*795d594fSAndroid Build Coastguard Worker 
878*795d594fSAndroid Build Coastguard Worker   MarkReachableBlocks(graph_, &live_blocks);
879*795d594fSAndroid Build Coastguard Worker   bool removed_one_or_more_blocks = false;
880*795d594fSAndroid Build Coastguard Worker   bool rerun_dominance_and_loop_analysis = false;
881*795d594fSAndroid Build Coastguard Worker 
882*795d594fSAndroid Build Coastguard Worker   // Remove all dead blocks. Iterate in post order because removal needs the
883*795d594fSAndroid Build Coastguard Worker   // block's chain of dominators and nested loops need to be updated from the
884*795d594fSAndroid Build Coastguard Worker   // inside out.
885*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
886*795d594fSAndroid Build Coastguard Worker     int id = block->GetBlockId();
887*795d594fSAndroid Build Coastguard Worker     if (!live_blocks.IsBitSet(id)) {
888*795d594fSAndroid Build Coastguard Worker       MaybeRecordDeadBlock(block);
889*795d594fSAndroid Build Coastguard Worker       block->DisconnectAndDelete();
890*795d594fSAndroid Build Coastguard Worker       removed_one_or_more_blocks = true;
891*795d594fSAndroid Build Coastguard Worker       if (block->IsInLoop()) {
892*795d594fSAndroid Build Coastguard Worker         rerun_dominance_and_loop_analysis = true;
893*795d594fSAndroid Build Coastguard Worker       }
894*795d594fSAndroid Build Coastguard Worker     }
895*795d594fSAndroid Build Coastguard Worker   }
896*795d594fSAndroid Build Coastguard Worker 
897*795d594fSAndroid Build Coastguard Worker   // If we removed at least one block, we need to recompute the full
898*795d594fSAndroid Build Coastguard Worker   // dominator tree and try block membership.
899*795d594fSAndroid Build Coastguard Worker   if (removed_one_or_more_blocks || force_recomputation) {
900*795d594fSAndroid Build Coastguard Worker     if (rerun_dominance_and_loop_analysis || force_loop_recomputation) {
901*795d594fSAndroid Build Coastguard Worker       graph_->RecomputeDominatorTree();
902*795d594fSAndroid Build Coastguard Worker     } else {
903*795d594fSAndroid Build Coastguard Worker       graph_->ClearDominanceInformation();
904*795d594fSAndroid Build Coastguard Worker       graph_->ComputeDominanceInformation();
905*795d594fSAndroid Build Coastguard Worker       graph_->ComputeTryBlockInformation();
906*795d594fSAndroid Build Coastguard Worker     }
907*795d594fSAndroid Build Coastguard Worker   }
908*795d594fSAndroid Build Coastguard Worker   return removed_one_or_more_blocks;
909*795d594fSAndroid Build Coastguard Worker }
910*795d594fSAndroid Build Coastguard Worker 
RemoveDeadInstructions()911*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::RemoveDeadInstructions() {
912*795d594fSAndroid Build Coastguard Worker   // Process basic blocks in post-order in the dominator tree, so that
913*795d594fSAndroid Build Coastguard Worker   // a dead instruction depending on another dead instruction is removed.
914*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
915*795d594fSAndroid Build Coastguard Worker     // Traverse this block's instructions in backward order and remove
916*795d594fSAndroid Build Coastguard Worker     // the unused ones.
917*795d594fSAndroid Build Coastguard Worker     HBackwardInstructionIterator i(block->GetInstructions());
918*795d594fSAndroid Build Coastguard Worker     // Skip the first iteration, as the last instruction of a block is
919*795d594fSAndroid Build Coastguard Worker     // a branching instruction.
920*795d594fSAndroid Build Coastguard Worker     DCHECK(i.Current()->IsControlFlow());
921*795d594fSAndroid Build Coastguard Worker     for (i.Advance(); !i.Done(); i.Advance()) {
922*795d594fSAndroid Build Coastguard Worker       HInstruction* inst = i.Current();
923*795d594fSAndroid Build Coastguard Worker       DCHECK(!inst->IsControlFlow());
924*795d594fSAndroid Build Coastguard Worker       if (inst->IsDeadAndRemovable()) {
925*795d594fSAndroid Build Coastguard Worker         block->RemoveInstruction(inst);
926*795d594fSAndroid Build Coastguard Worker         MaybeRecordStat(stats_, MethodCompilationStat::kRemovedDeadInstruction);
927*795d594fSAndroid Build Coastguard Worker       }
928*795d594fSAndroid Build Coastguard Worker     }
929*795d594fSAndroid Build Coastguard Worker 
930*795d594fSAndroid Build Coastguard Worker     // Same for Phis.
931*795d594fSAndroid Build Coastguard Worker     for (HBackwardInstructionIterator phi_it(block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
932*795d594fSAndroid Build Coastguard Worker       DCHECK(phi_it.Current()->IsPhi());
933*795d594fSAndroid Build Coastguard Worker       HPhi* phi = phi_it.Current()->AsPhi();
934*795d594fSAndroid Build Coastguard Worker       if (phi->IsPhiDeadAndRemovable()) {
935*795d594fSAndroid Build Coastguard Worker         block->RemovePhi(phi);
936*795d594fSAndroid Build Coastguard Worker         MaybeRecordStat(stats_, MethodCompilationStat::kRemovedDeadPhi);
937*795d594fSAndroid Build Coastguard Worker       }
938*795d594fSAndroid Build Coastguard Worker     }
939*795d594fSAndroid Build Coastguard Worker   }
940*795d594fSAndroid Build Coastguard Worker }
941*795d594fSAndroid Build Coastguard Worker 
UpdateGraphFlags()942*795d594fSAndroid Build Coastguard Worker void HDeadCodeElimination::UpdateGraphFlags() {
943*795d594fSAndroid Build Coastguard Worker   bool has_monitor_operations = false;
944*795d594fSAndroid Build Coastguard Worker   bool has_traditional_simd = false;
945*795d594fSAndroid Build Coastguard Worker   bool has_predicated_simd = false;
946*795d594fSAndroid Build Coastguard Worker   bool has_bounds_checks = false;
947*795d594fSAndroid Build Coastguard Worker   bool has_always_throwing_invokes = false;
948*795d594fSAndroid Build Coastguard Worker 
949*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetReversePostOrder()) {
950*795d594fSAndroid Build Coastguard Worker     for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
951*795d594fSAndroid Build Coastguard Worker       HInstruction* instruction = it.Current();
952*795d594fSAndroid Build Coastguard Worker       if (instruction->IsMonitorOperation()) {
953*795d594fSAndroid Build Coastguard Worker         has_monitor_operations = true;
954*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsVecOperation()) {
955*795d594fSAndroid Build Coastguard Worker         HVecOperation* vec_instruction = instruction->AsVecOperation();
956*795d594fSAndroid Build Coastguard Worker         if (vec_instruction->IsPredicated()) {
957*795d594fSAndroid Build Coastguard Worker           has_predicated_simd = true;
958*795d594fSAndroid Build Coastguard Worker         } else {
959*795d594fSAndroid Build Coastguard Worker           has_traditional_simd = true;
960*795d594fSAndroid Build Coastguard Worker         }
961*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsBoundsCheck()) {
962*795d594fSAndroid Build Coastguard Worker         has_bounds_checks = true;
963*795d594fSAndroid Build Coastguard Worker       } else if (instruction->IsInvoke() && instruction->AsInvoke()->AlwaysThrows()) {
964*795d594fSAndroid Build Coastguard Worker         has_always_throwing_invokes = true;
965*795d594fSAndroid Build Coastguard Worker       }
966*795d594fSAndroid Build Coastguard Worker     }
967*795d594fSAndroid Build Coastguard Worker   }
968*795d594fSAndroid Build Coastguard Worker 
969*795d594fSAndroid Build Coastguard Worker   graph_->SetHasMonitorOperations(has_monitor_operations);
970*795d594fSAndroid Build Coastguard Worker   graph_->SetHasTraditionalSIMD(has_traditional_simd);
971*795d594fSAndroid Build Coastguard Worker   graph_->SetHasPredicatedSIMD(has_predicated_simd);
972*795d594fSAndroid Build Coastguard Worker   graph_->SetHasBoundsChecks(has_bounds_checks);
973*795d594fSAndroid Build Coastguard Worker   graph_->SetHasAlwaysThrowingInvokes(has_always_throwing_invokes);
974*795d594fSAndroid Build Coastguard Worker }
975*795d594fSAndroid Build Coastguard Worker 
Run()976*795d594fSAndroid Build Coastguard Worker bool HDeadCodeElimination::Run() {
977*795d594fSAndroid Build Coastguard Worker   // Do not eliminate dead blocks if the graph has irreducible loops. We could
978*795d594fSAndroid Build Coastguard Worker   // support it, but that would require changes in our loop representation to handle
979*795d594fSAndroid Build Coastguard Worker   // multiple entry points. We decided it was not worth the complexity.
980*795d594fSAndroid Build Coastguard Worker   if (!graph_->HasIrreducibleLoops()) {
981*795d594fSAndroid Build Coastguard Worker     // Simplify graph to generate more dead block patterns.
982*795d594fSAndroid Build Coastguard Worker     ConnectSuccessiveBlocks();
983*795d594fSAndroid Build Coastguard Worker     bool did_any_simplification = false;
984*795d594fSAndroid Build Coastguard Worker     did_any_simplification |= SimplifyAlwaysThrows();
985*795d594fSAndroid Build Coastguard Worker     did_any_simplification |= SimplifyIfs();
986*795d594fSAndroid Build Coastguard Worker     did_any_simplification |= RemoveEmptyIfs();
987*795d594fSAndroid Build Coastguard Worker     did_any_simplification |= RemoveDeadBlocks();
988*795d594fSAndroid Build Coastguard Worker     // We call RemoveDeadBlocks before RemoveUnneededTries to remove the dead blocks from the
989*795d594fSAndroid Build Coastguard Worker     // previous optimizations. Otherwise, we might detect that a try has throwing instructions but
990*795d594fSAndroid Build Coastguard Worker     // they are actually dead code. RemoveUnneededTryBoundary will call RemoveDeadBlocks again if
991*795d594fSAndroid Build Coastguard Worker     // needed.
992*795d594fSAndroid Build Coastguard Worker     did_any_simplification |= RemoveUnneededTries();
993*795d594fSAndroid Build Coastguard Worker     if (did_any_simplification) {
994*795d594fSAndroid Build Coastguard Worker       // Connect successive blocks created by dead branches.
995*795d594fSAndroid Build Coastguard Worker       ConnectSuccessiveBlocks();
996*795d594fSAndroid Build Coastguard Worker     }
997*795d594fSAndroid Build Coastguard Worker   }
998*795d594fSAndroid Build Coastguard Worker   SsaRedundantPhiElimination(graph_).Run();
999*795d594fSAndroid Build Coastguard Worker   RemoveDeadInstructions();
1000*795d594fSAndroid Build Coastguard Worker   UpdateGraphFlags();
1001*795d594fSAndroid Build Coastguard Worker   return true;
1002*795d594fSAndroid Build Coastguard Worker }
1003*795d594fSAndroid Build Coastguard Worker 
1004*795d594fSAndroid Build Coastguard Worker }  // namespace art
1005