xref: /aosp_15_r20/art/compiler/optimizing/select_generator.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2016 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 "select_generator.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "optimizing/nodes.h"
20*795d594fSAndroid Build Coastguard Worker #include "reference_type_propagation.h"
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker static constexpr size_t kMaxInstructionsInBranch = 1u;
25*795d594fSAndroid Build Coastguard Worker 
HSelectGenerator(HGraph * graph,OptimizingCompilerStats * stats,const char * name)26*795d594fSAndroid Build Coastguard Worker HSelectGenerator::HSelectGenerator(HGraph* graph,
27*795d594fSAndroid Build Coastguard Worker                                    OptimizingCompilerStats* stats,
28*795d594fSAndroid Build Coastguard Worker                                    const char* name)
29*795d594fSAndroid Build Coastguard Worker     : HOptimization(graph, name, stats) {
30*795d594fSAndroid Build Coastguard Worker }
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker // Returns true if `block` has only one predecessor, ends with a Goto
33*795d594fSAndroid Build Coastguard Worker // or a Return and contains at most `kMaxInstructionsInBranch` other
34*795d594fSAndroid Build Coastguard Worker // movable instruction with no side-effects.
IsSimpleBlock(HBasicBlock * block)35*795d594fSAndroid Build Coastguard Worker static bool IsSimpleBlock(HBasicBlock* block) {
36*795d594fSAndroid Build Coastguard Worker   if (block->GetPredecessors().size() != 1u) {
37*795d594fSAndroid Build Coastguard Worker     return false;
38*795d594fSAndroid Build Coastguard Worker   }
39*795d594fSAndroid Build Coastguard Worker   DCHECK(block->GetPhis().IsEmpty());
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker   size_t num_instructions = 0u;
42*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
43*795d594fSAndroid Build Coastguard Worker     HInstruction* instruction = it.Current();
44*795d594fSAndroid Build Coastguard Worker     if (instruction->IsControlFlow()) {
45*795d594fSAndroid Build Coastguard Worker       return instruction->IsGoto() || instruction->IsReturn();
46*795d594fSAndroid Build Coastguard Worker     } else if (instruction->CanBeMoved() &&
47*795d594fSAndroid Build Coastguard Worker                !instruction->HasSideEffects() &&
48*795d594fSAndroid Build Coastguard Worker                !instruction->CanThrow()) {
49*795d594fSAndroid Build Coastguard Worker       if (instruction->IsSelect() && instruction->AsSelect()->GetCondition()->GetBlock() == block) {
50*795d594fSAndroid Build Coastguard Worker         // Count one HCondition and HSelect in the same block as a single instruction.
51*795d594fSAndroid Build Coastguard Worker         // This enables finding nested selects.
52*795d594fSAndroid Build Coastguard Worker         continue;
53*795d594fSAndroid Build Coastguard Worker       } else if (++num_instructions > kMaxInstructionsInBranch) {
54*795d594fSAndroid Build Coastguard Worker         return false;  // bail as soon as we exceed number of allowed instructions
55*795d594fSAndroid Build Coastguard Worker       }
56*795d594fSAndroid Build Coastguard Worker     } else {
57*795d594fSAndroid Build Coastguard Worker       return false;
58*795d594fSAndroid Build Coastguard Worker     }
59*795d594fSAndroid Build Coastguard Worker   }
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker   LOG(FATAL) << "Unreachable";
62*795d594fSAndroid Build Coastguard Worker   UNREACHABLE();
63*795d594fSAndroid Build Coastguard Worker }
64*795d594fSAndroid Build Coastguard Worker 
65*795d594fSAndroid Build Coastguard Worker // Returns true if 'block1' and 'block2' are empty and merge into the
66*795d594fSAndroid Build Coastguard Worker // same single successor.
BlocksMergeTogether(HBasicBlock * block1,HBasicBlock * block2)67*795d594fSAndroid Build Coastguard Worker static bool BlocksMergeTogether(HBasicBlock* block1, HBasicBlock* block2) {
68*795d594fSAndroid Build Coastguard Worker   return block1->GetSingleSuccessor() == block2->GetSingleSuccessor();
69*795d594fSAndroid Build Coastguard Worker }
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker // Returns nullptr if `block` has either no phis or there is more than one phi. Otherwise returns
72*795d594fSAndroid Build Coastguard Worker // that phi.
GetSinglePhi(HBasicBlock * block,size_t index1,size_t index2)73*795d594fSAndroid Build Coastguard Worker static HPhi* GetSinglePhi(HBasicBlock* block, size_t index1, size_t index2) {
74*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(index1, index2);
75*795d594fSAndroid Build Coastguard Worker 
76*795d594fSAndroid Build Coastguard Worker   HPhi* select_phi = nullptr;
77*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
78*795d594fSAndroid Build Coastguard Worker     HPhi* phi = it.Current()->AsPhi();
79*795d594fSAndroid Build Coastguard Worker     if (select_phi == nullptr) {
80*795d594fSAndroid Build Coastguard Worker       // First phi found.
81*795d594fSAndroid Build Coastguard Worker       select_phi = phi;
82*795d594fSAndroid Build Coastguard Worker     } else {
83*795d594fSAndroid Build Coastguard Worker       // More than one phi found, return null.
84*795d594fSAndroid Build Coastguard Worker       return nullptr;
85*795d594fSAndroid Build Coastguard Worker     }
86*795d594fSAndroid Build Coastguard Worker   }
87*795d594fSAndroid Build Coastguard Worker   return select_phi;
88*795d594fSAndroid Build Coastguard Worker }
89*795d594fSAndroid Build Coastguard Worker 
TryGenerateSelectSimpleDiamondPattern(HBasicBlock * block,ScopedArenaSafeMap<HInstruction *,HSelect * > * cache)90*795d594fSAndroid Build Coastguard Worker bool HSelectGenerator::TryGenerateSelectSimpleDiamondPattern(
91*795d594fSAndroid Build Coastguard Worker     HBasicBlock* block, ScopedArenaSafeMap<HInstruction*, HSelect*>* cache) {
92*795d594fSAndroid Build Coastguard Worker   DCHECK(block->GetLastInstruction()->IsIf());
93*795d594fSAndroid Build Coastguard Worker   HIf* if_instruction = block->GetLastInstruction()->AsIf();
94*795d594fSAndroid Build Coastguard Worker   HBasicBlock* true_block = if_instruction->IfTrueSuccessor();
95*795d594fSAndroid Build Coastguard Worker   HBasicBlock* false_block = if_instruction->IfFalseSuccessor();
96*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(true_block, false_block);
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker   if (!IsSimpleBlock(true_block) ||
99*795d594fSAndroid Build Coastguard Worker       !IsSimpleBlock(false_block) ||
100*795d594fSAndroid Build Coastguard Worker       !BlocksMergeTogether(true_block, false_block)) {
101*795d594fSAndroid Build Coastguard Worker     return false;
102*795d594fSAndroid Build Coastguard Worker   }
103*795d594fSAndroid Build Coastguard Worker   HBasicBlock* merge_block = true_block->GetSingleSuccessor();
104*795d594fSAndroid Build Coastguard Worker 
105*795d594fSAndroid Build Coastguard Worker   // If the branches are not empty, move instructions in front of the If.
106*795d594fSAndroid Build Coastguard Worker   // TODO(dbrazdil): This puts an instruction between If and its condition.
107*795d594fSAndroid Build Coastguard Worker   //                 Implement moving of conditions to first users if possible.
108*795d594fSAndroid Build Coastguard Worker   while (!true_block->IsSingleGoto() && !true_block->IsSingleReturn()) {
109*795d594fSAndroid Build Coastguard Worker     HInstruction* instr = true_block->GetFirstInstruction();
110*795d594fSAndroid Build Coastguard Worker     DCHECK(!instr->CanThrow());
111*795d594fSAndroid Build Coastguard Worker     instr->MoveBefore(if_instruction);
112*795d594fSAndroid Build Coastguard Worker   }
113*795d594fSAndroid Build Coastguard Worker   while (!false_block->IsSingleGoto() && !false_block->IsSingleReturn()) {
114*795d594fSAndroid Build Coastguard Worker     HInstruction* instr = false_block->GetFirstInstruction();
115*795d594fSAndroid Build Coastguard Worker     DCHECK(!instr->CanThrow());
116*795d594fSAndroid Build Coastguard Worker     instr->MoveBefore(if_instruction);
117*795d594fSAndroid Build Coastguard Worker   }
118*795d594fSAndroid Build Coastguard Worker   DCHECK(true_block->IsSingleGoto() || true_block->IsSingleReturn());
119*795d594fSAndroid Build Coastguard Worker   DCHECK(false_block->IsSingleGoto() || false_block->IsSingleReturn());
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker   // Find the resulting true/false values.
122*795d594fSAndroid Build Coastguard Worker   size_t predecessor_index_true = merge_block->GetPredecessorIndexOf(true_block);
123*795d594fSAndroid Build Coastguard Worker   size_t predecessor_index_false = merge_block->GetPredecessorIndexOf(false_block);
124*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(predecessor_index_true, predecessor_index_false);
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker   bool both_successors_return = true_block->IsSingleReturn() && false_block->IsSingleReturn();
127*795d594fSAndroid Build Coastguard Worker   // TODO(solanes): Extend to support multiple phis? e.g.
128*795d594fSAndroid Build Coastguard Worker   //   int a, b;
129*795d594fSAndroid Build Coastguard Worker   //   if (bool) {
130*795d594fSAndroid Build Coastguard Worker   //     a = 0; b = 1;
131*795d594fSAndroid Build Coastguard Worker   //   } else {
132*795d594fSAndroid Build Coastguard Worker   //     a = 1; b = 2;
133*795d594fSAndroid Build Coastguard Worker   //   }
134*795d594fSAndroid Build Coastguard Worker   //   // use a and b
135*795d594fSAndroid Build Coastguard Worker   HPhi* phi = GetSinglePhi(merge_block, predecessor_index_true, predecessor_index_false);
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker   HInstruction* true_value = nullptr;
138*795d594fSAndroid Build Coastguard Worker   HInstruction* false_value = nullptr;
139*795d594fSAndroid Build Coastguard Worker   if (both_successors_return) {
140*795d594fSAndroid Build Coastguard Worker     true_value = true_block->GetFirstInstruction()->InputAt(0);
141*795d594fSAndroid Build Coastguard Worker     false_value = false_block->GetFirstInstruction()->InputAt(0);
142*795d594fSAndroid Build Coastguard Worker   } else if (phi != nullptr) {
143*795d594fSAndroid Build Coastguard Worker     true_value = phi->InputAt(predecessor_index_true);
144*795d594fSAndroid Build Coastguard Worker     false_value = phi->InputAt(predecessor_index_false);
145*795d594fSAndroid Build Coastguard Worker   } else {
146*795d594fSAndroid Build Coastguard Worker     return false;
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker   DCHECK(both_successors_return || phi != nullptr);
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker   // Create the Select instruction and insert it in front of the If.
151*795d594fSAndroid Build Coastguard Worker   HInstruction* condition = if_instruction->InputAt(0);
152*795d594fSAndroid Build Coastguard Worker   HSelect* select = new (graph_->GetAllocator()) HSelect(condition,
153*795d594fSAndroid Build Coastguard Worker                                                           true_value,
154*795d594fSAndroid Build Coastguard Worker                                                           false_value,
155*795d594fSAndroid Build Coastguard Worker                                                           if_instruction->GetDexPc());
156*795d594fSAndroid Build Coastguard Worker   if (both_successors_return) {
157*795d594fSAndroid Build Coastguard Worker     if (true_value->GetType() == DataType::Type::kReference) {
158*795d594fSAndroid Build Coastguard Worker       DCHECK(false_value->GetType() == DataType::Type::kReference);
159*795d594fSAndroid Build Coastguard Worker       ReferenceTypePropagation::FixUpSelectType(select, graph_->GetHandleCache());
160*795d594fSAndroid Build Coastguard Worker     }
161*795d594fSAndroid Build Coastguard Worker   } else if (phi->GetType() == DataType::Type::kReference) {
162*795d594fSAndroid Build Coastguard Worker     select->SetReferenceTypeInfoIfValid(phi->GetReferenceTypeInfo());
163*795d594fSAndroid Build Coastguard Worker   }
164*795d594fSAndroid Build Coastguard Worker   block->InsertInstructionBefore(select, if_instruction);
165*795d594fSAndroid Build Coastguard Worker 
166*795d594fSAndroid Build Coastguard Worker   // Remove the true branch which removes the corresponding Phi
167*795d594fSAndroid Build Coastguard Worker   // input if needed. If left only with the false branch, the Phi is
168*795d594fSAndroid Build Coastguard Worker   // automatically removed.
169*795d594fSAndroid Build Coastguard Worker   if (both_successors_return) {
170*795d594fSAndroid Build Coastguard Worker     false_block->GetFirstInstruction()->ReplaceInput(select, 0);
171*795d594fSAndroid Build Coastguard Worker   } else {
172*795d594fSAndroid Build Coastguard Worker     phi->ReplaceInput(select, predecessor_index_false);
173*795d594fSAndroid Build Coastguard Worker   }
174*795d594fSAndroid Build Coastguard Worker 
175*795d594fSAndroid Build Coastguard Worker   bool only_two_predecessors = (merge_block->GetPredecessors().size() == 2u);
176*795d594fSAndroid Build Coastguard Worker   true_block->DisconnectAndDelete();
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker   // Merge remaining blocks which are now connected with Goto.
179*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(block->GetSingleSuccessor(), false_block);
180*795d594fSAndroid Build Coastguard Worker   block->MergeWith(false_block);
181*795d594fSAndroid Build Coastguard Worker   if (!both_successors_return && only_two_predecessors) {
182*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(only_two_predecessors, phi->GetBlock() == nullptr);
183*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(block->GetSingleSuccessor(), merge_block);
184*795d594fSAndroid Build Coastguard Worker     block->MergeWith(merge_block);
185*795d594fSAndroid Build Coastguard Worker   }
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker   MaybeRecordStat(stats_, MethodCompilationStat::kSelectGenerated);
188*795d594fSAndroid Build Coastguard Worker 
189*795d594fSAndroid Build Coastguard Worker   // Very simple way of finding common subexpressions in the generated HSelect statements
190*795d594fSAndroid Build Coastguard Worker   // (since this runs after GVN). Lookup by condition, and reuse latest one if possible
191*795d594fSAndroid Build Coastguard Worker   // (due to post order, latest select is most likely replacement). If needed, we could
192*795d594fSAndroid Build Coastguard Worker   // improve this by e.g. using the operands in the map as well.
193*795d594fSAndroid Build Coastguard Worker   auto it = cache->find(condition);
194*795d594fSAndroid Build Coastguard Worker   if (it == cache->end()) {
195*795d594fSAndroid Build Coastguard Worker     cache->Put(condition, select);
196*795d594fSAndroid Build Coastguard Worker   } else {
197*795d594fSAndroid Build Coastguard Worker     // Found cached value. See if latest can replace cached in the HIR.
198*795d594fSAndroid Build Coastguard Worker     HSelect* cached_select = it->second;
199*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(cached_select->GetCondition(), select->GetCondition());
200*795d594fSAndroid Build Coastguard Worker     if (cached_select->GetTrueValue() == select->GetTrueValue() &&
201*795d594fSAndroid Build Coastguard Worker         cached_select->GetFalseValue() == select->GetFalseValue() &&
202*795d594fSAndroid Build Coastguard Worker         select->StrictlyDominates(cached_select)) {
203*795d594fSAndroid Build Coastguard Worker       cached_select->ReplaceWith(select);
204*795d594fSAndroid Build Coastguard Worker       cached_select->GetBlock()->RemoveInstruction(cached_select);
205*795d594fSAndroid Build Coastguard Worker     }
206*795d594fSAndroid Build Coastguard Worker     it->second = select;  // always cache latest
207*795d594fSAndroid Build Coastguard Worker   }
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker   // No need to update dominance information, as we are simplifying
210*795d594fSAndroid Build Coastguard Worker   // a simple diamond shape, where the join block is merged with the
211*795d594fSAndroid Build Coastguard Worker   // entry block. Any following blocks would have had the join block
212*795d594fSAndroid Build Coastguard Worker   // as a dominator, and `MergeWith` handles changing that to the
213*795d594fSAndroid Build Coastguard Worker   // entry block
214*795d594fSAndroid Build Coastguard Worker   return true;
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker 
TryFixupDoubleDiamondPattern(HBasicBlock * block)217*795d594fSAndroid Build Coastguard Worker HBasicBlock* HSelectGenerator::TryFixupDoubleDiamondPattern(HBasicBlock* block) {
218*795d594fSAndroid Build Coastguard Worker   DCHECK(block->GetLastInstruction()->IsIf());
219*795d594fSAndroid Build Coastguard Worker   HIf* if_instruction = block->GetLastInstruction()->AsIf();
220*795d594fSAndroid Build Coastguard Worker   HBasicBlock* true_block = if_instruction->IfTrueSuccessor();
221*795d594fSAndroid Build Coastguard Worker   HBasicBlock* false_block = if_instruction->IfFalseSuccessor();
222*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(true_block, false_block);
223*795d594fSAndroid Build Coastguard Worker 
224*795d594fSAndroid Build Coastguard Worker   // One branch must be a single goto, and the other one the inner if.
225*795d594fSAndroid Build Coastguard Worker   if (true_block->IsSingleGoto() == false_block->IsSingleGoto()) {
226*795d594fSAndroid Build Coastguard Worker     return nullptr;
227*795d594fSAndroid Build Coastguard Worker   }
228*795d594fSAndroid Build Coastguard Worker 
229*795d594fSAndroid Build Coastguard Worker   HBasicBlock* single_goto = true_block->IsSingleGoto() ? true_block : false_block;
230*795d594fSAndroid Build Coastguard Worker   HBasicBlock* inner_if_block = true_block->IsSingleGoto() ? false_block : true_block;
231*795d594fSAndroid Build Coastguard Worker 
232*795d594fSAndroid Build Coastguard Worker   // The innner if branch has to be a block with just a comparison and an if.
233*795d594fSAndroid Build Coastguard Worker   if (!inner_if_block->EndsWithIf() ||
234*795d594fSAndroid Build Coastguard Worker       inner_if_block->GetLastInstruction()->AsIf()->InputAt(0) !=
235*795d594fSAndroid Build Coastguard Worker           inner_if_block->GetFirstInstruction() ||
236*795d594fSAndroid Build Coastguard Worker       inner_if_block->GetLastInstruction()->GetPrevious() !=
237*795d594fSAndroid Build Coastguard Worker           inner_if_block->GetFirstInstruction() ||
238*795d594fSAndroid Build Coastguard Worker       !inner_if_block->GetFirstInstruction()->IsCondition()) {
239*795d594fSAndroid Build Coastguard Worker     return nullptr;
240*795d594fSAndroid Build Coastguard Worker   }
241*795d594fSAndroid Build Coastguard Worker 
242*795d594fSAndroid Build Coastguard Worker   HIf* inner_if_instruction = inner_if_block->GetLastInstruction()->AsIf();
243*795d594fSAndroid Build Coastguard Worker   HBasicBlock* inner_if_true_block = inner_if_instruction->IfTrueSuccessor();
244*795d594fSAndroid Build Coastguard Worker   HBasicBlock* inner_if_false_block = inner_if_instruction->IfFalseSuccessor();
245*795d594fSAndroid Build Coastguard Worker   if (!inner_if_true_block->IsSingleGoto() || !inner_if_false_block->IsSingleGoto()) {
246*795d594fSAndroid Build Coastguard Worker     return nullptr;
247*795d594fSAndroid Build Coastguard Worker   }
248*795d594fSAndroid Build Coastguard Worker 
249*795d594fSAndroid Build Coastguard Worker   // One must merge into the outer condition and the other must not.
250*795d594fSAndroid Build Coastguard Worker   if (BlocksMergeTogether(single_goto, inner_if_true_block) ==
251*795d594fSAndroid Build Coastguard Worker       BlocksMergeTogether(single_goto, inner_if_false_block)) {
252*795d594fSAndroid Build Coastguard Worker     return nullptr;
253*795d594fSAndroid Build Coastguard Worker   }
254*795d594fSAndroid Build Coastguard Worker 
255*795d594fSAndroid Build Coastguard Worker   // First merge merges the outer if with one of the inner if branches. The block must be a Phi and
256*795d594fSAndroid Build Coastguard Worker   // a Goto.
257*795d594fSAndroid Build Coastguard Worker   HBasicBlock* first_merge = single_goto->GetSingleSuccessor();
258*795d594fSAndroid Build Coastguard Worker   if (first_merge->GetNumberOfPredecessors() != 2 ||
259*795d594fSAndroid Build Coastguard Worker       first_merge->GetPhis().CountSize() != 1 ||
260*795d594fSAndroid Build Coastguard Worker       !first_merge->GetLastInstruction()->IsGoto() ||
261*795d594fSAndroid Build Coastguard Worker       first_merge->GetFirstInstruction() != first_merge->GetLastInstruction()) {
262*795d594fSAndroid Build Coastguard Worker     return nullptr;
263*795d594fSAndroid Build Coastguard Worker   }
264*795d594fSAndroid Build Coastguard Worker 
265*795d594fSAndroid Build Coastguard Worker   HPhi* first_phi = first_merge->GetFirstPhi()->AsPhi();
266*795d594fSAndroid Build Coastguard Worker 
267*795d594fSAndroid Build Coastguard Worker   // Second merge is first_merge and the remainder branch merging. It must be phi + goto, or phi +
268*795d594fSAndroid Build Coastguard Worker   // return. Depending on the first merge, we define the second merge.
269*795d594fSAndroid Build Coastguard Worker   HBasicBlock* merges_into_second_merge =
270*795d594fSAndroid Build Coastguard Worker     BlocksMergeTogether(single_goto, inner_if_true_block)
271*795d594fSAndroid Build Coastguard Worker       ? inner_if_false_block
272*795d594fSAndroid Build Coastguard Worker       : inner_if_true_block;
273*795d594fSAndroid Build Coastguard Worker   if (!BlocksMergeTogether(first_merge, merges_into_second_merge)) {
274*795d594fSAndroid Build Coastguard Worker     return nullptr;
275*795d594fSAndroid Build Coastguard Worker   }
276*795d594fSAndroid Build Coastguard Worker 
277*795d594fSAndroid Build Coastguard Worker   HBasicBlock* second_merge = merges_into_second_merge->GetSingleSuccessor();
278*795d594fSAndroid Build Coastguard Worker   if (second_merge->GetNumberOfPredecessors() != 2 ||
279*795d594fSAndroid Build Coastguard Worker       second_merge->GetPhis().CountSize() != 1 ||
280*795d594fSAndroid Build Coastguard Worker       !(second_merge->GetLastInstruction()->IsGoto() ||
281*795d594fSAndroid Build Coastguard Worker         second_merge->GetLastInstruction()->IsReturn()) ||
282*795d594fSAndroid Build Coastguard Worker       second_merge->GetFirstInstruction() != second_merge->GetLastInstruction()) {
283*795d594fSAndroid Build Coastguard Worker     return nullptr;
284*795d594fSAndroid Build Coastguard Worker   }
285*795d594fSAndroid Build Coastguard Worker 
286*795d594fSAndroid Build Coastguard Worker   size_t index = second_merge->GetPredecessorIndexOf(merges_into_second_merge);
287*795d594fSAndroid Build Coastguard Worker   HPhi* second_phi = second_merge->GetFirstPhi()->AsPhi();
288*795d594fSAndroid Build Coastguard Worker 
289*795d594fSAndroid Build Coastguard Worker   // Merge the phis.
290*795d594fSAndroid Build Coastguard Worker   first_phi->AddInput(second_phi->InputAt(index));
291*795d594fSAndroid Build Coastguard Worker   merges_into_second_merge->ReplaceSuccessor(second_merge, first_merge);
292*795d594fSAndroid Build Coastguard Worker   second_phi->ReplaceWith(first_phi);
293*795d594fSAndroid Build Coastguard Worker   second_merge->RemovePhi(second_phi);
294*795d594fSAndroid Build Coastguard Worker 
295*795d594fSAndroid Build Coastguard Worker   // Sort out the new domination before merging the blocks
296*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(second_merge->GetSinglePredecessor(), first_merge);
297*795d594fSAndroid Build Coastguard Worker   second_merge->GetDominator()->RemoveDominatedBlock(second_merge);
298*795d594fSAndroid Build Coastguard Worker   second_merge->SetDominator(first_merge);
299*795d594fSAndroid Build Coastguard Worker   first_merge->AddDominatedBlock(second_merge);
300*795d594fSAndroid Build Coastguard Worker   first_merge->MergeWith(second_merge);
301*795d594fSAndroid Build Coastguard Worker 
302*795d594fSAndroid Build Coastguard Worker   // No need to update dominance information. There's a chance that `merges_into_second_merge`
303*795d594fSAndroid Build Coastguard Worker   // doesn't come before `first_merge` but we don't need to fix it since `merges_into_second_merge`
304*795d594fSAndroid Build Coastguard Worker   // will disappear from the graph altogether when doing the follow-up
305*795d594fSAndroid Build Coastguard Worker   // TryGenerateSelectSimpleDiamondPattern.
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker   return inner_if_block;
308*795d594fSAndroid Build Coastguard Worker }
309*795d594fSAndroid Build Coastguard Worker 
Run()310*795d594fSAndroid Build Coastguard Worker bool HSelectGenerator::Run() {
311*795d594fSAndroid Build Coastguard Worker   bool did_select = false;
312*795d594fSAndroid Build Coastguard Worker   // Select cache with local allocator.
313*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(graph_->GetArenaStack());
314*795d594fSAndroid Build Coastguard Worker   ScopedArenaSafeMap<HInstruction*, HSelect*> cache(std::less<HInstruction*>(),
315*795d594fSAndroid Build Coastguard Worker                                                     allocator.Adapter(kArenaAllocSelectGenerator));
316*795d594fSAndroid Build Coastguard Worker 
317*795d594fSAndroid Build Coastguard Worker   // Iterate in post order in the unlikely case that removing one occurrence of
318*795d594fSAndroid Build Coastguard Worker   // the selection pattern empties a branch block of another occurrence.
319*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph_->GetPostOrder()) {
320*795d594fSAndroid Build Coastguard Worker     if (!block->EndsWithIf()) {
321*795d594fSAndroid Build Coastguard Worker       continue;
322*795d594fSAndroid Build Coastguard Worker     }
323*795d594fSAndroid Build Coastguard Worker 
324*795d594fSAndroid Build Coastguard Worker     if (TryGenerateSelectSimpleDiamondPattern(block, &cache)) {
325*795d594fSAndroid Build Coastguard Worker       did_select = true;
326*795d594fSAndroid Build Coastguard Worker     } else {
327*795d594fSAndroid Build Coastguard Worker       // Try to fix up the odd version of the double diamond pattern. If we could do it, it means
328*795d594fSAndroid Build Coastguard Worker       // that we can generate two selects.
329*795d594fSAndroid Build Coastguard Worker       HBasicBlock* inner_if_block = TryFixupDoubleDiamondPattern(block);
330*795d594fSAndroid Build Coastguard Worker       if (inner_if_block != nullptr) {
331*795d594fSAndroid Build Coastguard Worker         // Generate the selects now since `inner_if_block` should be after `block` in PostOrder.
332*795d594fSAndroid Build Coastguard Worker         bool result = TryGenerateSelectSimpleDiamondPattern(inner_if_block, &cache);
333*795d594fSAndroid Build Coastguard Worker         DCHECK(result);
334*795d594fSAndroid Build Coastguard Worker         result = TryGenerateSelectSimpleDiamondPattern(block, &cache);
335*795d594fSAndroid Build Coastguard Worker         DCHECK(result);
336*795d594fSAndroid Build Coastguard Worker         did_select = true;
337*795d594fSAndroid Build Coastguard Worker       }
338*795d594fSAndroid Build Coastguard Worker     }
339*795d594fSAndroid Build Coastguard Worker   }
340*795d594fSAndroid Build Coastguard Worker 
341*795d594fSAndroid Build Coastguard Worker   return did_select;
342*795d594fSAndroid Build Coastguard Worker }
343*795d594fSAndroid Build Coastguard Worker 
344*795d594fSAndroid Build Coastguard Worker }  // namespace art
345