xref: /aosp_15_r20/art/compiler/optimizing/scheduler.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 "scheduler.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include <string>
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
23*795d594fSAndroid Build Coastguard Worker #include "data_type-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "optimizing/load_store_analysis.h"
25*795d594fSAndroid Build Coastguard Worker #include "prepare_for_register_allocation.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker #ifdef ART_ENABLE_CODEGEN_arm64
28*795d594fSAndroid Build Coastguard Worker #include "scheduler_arm64.h"
29*795d594fSAndroid Build Coastguard Worker #endif
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker #ifdef ART_ENABLE_CODEGEN_arm
32*795d594fSAndroid Build Coastguard Worker #include "scheduler_arm.h"
33*795d594fSAndroid Build Coastguard Worker #endif
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
36*795d594fSAndroid Build Coastguard Worker 
AddDependency(SchedulingNode * node,SchedulingNode * dependency,bool is_data_dependency)37*795d594fSAndroid Build Coastguard Worker void SchedulingGraph::AddDependency(SchedulingNode* node,
38*795d594fSAndroid Build Coastguard Worker                                     SchedulingNode* dependency,
39*795d594fSAndroid Build Coastguard Worker                                     bool is_data_dependency) {
40*795d594fSAndroid Build Coastguard Worker   if (node == nullptr || dependency == nullptr) {
41*795d594fSAndroid Build Coastguard Worker     // A `nullptr` node indicates an instruction out of scheduling range (eg. in
42*795d594fSAndroid Build Coastguard Worker     // an other block), so we do not need to add a dependency edge to the graph.
43*795d594fSAndroid Build Coastguard Worker     return;
44*795d594fSAndroid Build Coastguard Worker   }
45*795d594fSAndroid Build Coastguard Worker 
46*795d594fSAndroid Build Coastguard Worker   if (is_data_dependency) {
47*795d594fSAndroid Build Coastguard Worker     node->AddDataPredecessor(dependency);
48*795d594fSAndroid Build Coastguard Worker   } else {
49*795d594fSAndroid Build Coastguard Worker     node->AddOtherPredecessor(dependency);
50*795d594fSAndroid Build Coastguard Worker   }
51*795d594fSAndroid Build Coastguard Worker }
52*795d594fSAndroid Build Coastguard Worker 
HasReorderingDependency(const HInstruction * instr1,const HInstruction * instr2)53*795d594fSAndroid Build Coastguard Worker bool SideEffectDependencyAnalysis::HasReorderingDependency(const HInstruction* instr1,
54*795d594fSAndroid Build Coastguard Worker                                                            const HInstruction* instr2) {
55*795d594fSAndroid Build Coastguard Worker   SideEffects instr1_side_effects = instr1->GetSideEffects();
56*795d594fSAndroid Build Coastguard Worker   SideEffects instr2_side_effects = instr2->GetSideEffects();
57*795d594fSAndroid Build Coastguard Worker 
58*795d594fSAndroid Build Coastguard Worker   // Read after write.
59*795d594fSAndroid Build Coastguard Worker   if (instr1_side_effects.MayDependOn(instr2_side_effects)) {
60*795d594fSAndroid Build Coastguard Worker     return true;
61*795d594fSAndroid Build Coastguard Worker   }
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   // Write after read.
64*795d594fSAndroid Build Coastguard Worker   if (instr2_side_effects.MayDependOn(instr1_side_effects)) {
65*795d594fSAndroid Build Coastguard Worker     return true;
66*795d594fSAndroid Build Coastguard Worker   }
67*795d594fSAndroid Build Coastguard Worker 
68*795d594fSAndroid Build Coastguard Worker   // Memory write after write.
69*795d594fSAndroid Build Coastguard Worker   if (instr1_side_effects.DoesAnyWrite() && instr2_side_effects.DoesAnyWrite()) {
70*795d594fSAndroid Build Coastguard Worker     return true;
71*795d594fSAndroid Build Coastguard Worker   }
72*795d594fSAndroid Build Coastguard Worker 
73*795d594fSAndroid Build Coastguard Worker   return false;
74*795d594fSAndroid Build Coastguard Worker }
75*795d594fSAndroid Build Coastguard Worker 
ArrayAccessHeapLocation(HInstruction * instruction) const76*795d594fSAndroid Build Coastguard Worker size_t SideEffectDependencyAnalysis::MemoryDependencyAnalysis::ArrayAccessHeapLocation(
77*795d594fSAndroid Build Coastguard Worker     HInstruction* instruction) const {
78*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_location_collector_ != nullptr);
79*795d594fSAndroid Build Coastguard Worker   size_t heap_loc = heap_location_collector_->GetArrayHeapLocation(instruction);
80*795d594fSAndroid Build Coastguard Worker   // This array access should be analyzed and added to HeapLocationCollector before.
81*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_loc != HeapLocationCollector::kHeapLocationNotFound);
82*795d594fSAndroid Build Coastguard Worker   return heap_loc;
83*795d594fSAndroid Build Coastguard Worker }
84*795d594fSAndroid Build Coastguard Worker 
ArrayAccessMayAlias(HInstruction * instr1,HInstruction * instr2) const85*795d594fSAndroid Build Coastguard Worker bool SideEffectDependencyAnalysis::MemoryDependencyAnalysis::ArrayAccessMayAlias(
86*795d594fSAndroid Build Coastguard Worker     HInstruction* instr1, HInstruction* instr2) const {
87*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_location_collector_ != nullptr);
88*795d594fSAndroid Build Coastguard Worker   size_t instr1_heap_loc = ArrayAccessHeapLocation(instr1);
89*795d594fSAndroid Build Coastguard Worker   size_t instr2_heap_loc = ArrayAccessHeapLocation(instr2);
90*795d594fSAndroid Build Coastguard Worker 
91*795d594fSAndroid Build Coastguard Worker   // For example: arr[0] and arr[0]
92*795d594fSAndroid Build Coastguard Worker   if (instr1_heap_loc == instr2_heap_loc) {
93*795d594fSAndroid Build Coastguard Worker     return true;
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker 
96*795d594fSAndroid Build Coastguard Worker   // For example: arr[0] and arr[i]
97*795d594fSAndroid Build Coastguard Worker   if (heap_location_collector_->MayAlias(instr1_heap_loc, instr2_heap_loc)) {
98*795d594fSAndroid Build Coastguard Worker     return true;
99*795d594fSAndroid Build Coastguard Worker   }
100*795d594fSAndroid Build Coastguard Worker 
101*795d594fSAndroid Build Coastguard Worker   return false;
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker 
IsArrayAccess(const HInstruction * instruction)104*795d594fSAndroid Build Coastguard Worker static bool IsArrayAccess(const HInstruction* instruction) {
105*795d594fSAndroid Build Coastguard Worker   return instruction->IsArrayGet() || instruction->IsArraySet();
106*795d594fSAndroid Build Coastguard Worker }
107*795d594fSAndroid Build Coastguard Worker 
IsInstanceFieldAccess(const HInstruction * instruction)108*795d594fSAndroid Build Coastguard Worker static bool IsInstanceFieldAccess(const HInstruction* instruction) {
109*795d594fSAndroid Build Coastguard Worker   return instruction->IsInstanceFieldGet() || instruction->IsInstanceFieldSet();
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker 
IsStaticFieldAccess(const HInstruction * instruction)112*795d594fSAndroid Build Coastguard Worker static bool IsStaticFieldAccess(const HInstruction* instruction) {
113*795d594fSAndroid Build Coastguard Worker   return instruction->IsStaticFieldGet() || instruction->IsStaticFieldSet();
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker 
IsFieldAccess(const HInstruction * instruction)116*795d594fSAndroid Build Coastguard Worker static bool IsFieldAccess(const HInstruction* instruction) {
117*795d594fSAndroid Build Coastguard Worker   return IsInstanceFieldAccess(instruction) || IsStaticFieldAccess(instruction);
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker 
GetFieldInfo(const HInstruction * instruction)120*795d594fSAndroid Build Coastguard Worker static const FieldInfo* GetFieldInfo(const HInstruction* instruction) {
121*795d594fSAndroid Build Coastguard Worker   return &instruction->GetFieldInfo();
122*795d594fSAndroid Build Coastguard Worker }
123*795d594fSAndroid Build Coastguard Worker 
FieldAccessHeapLocation(const HInstruction * instr) const124*795d594fSAndroid Build Coastguard Worker size_t SideEffectDependencyAnalysis::MemoryDependencyAnalysis::FieldAccessHeapLocation(
125*795d594fSAndroid Build Coastguard Worker     const HInstruction* instr) const {
126*795d594fSAndroid Build Coastguard Worker   DCHECK(instr != nullptr);
127*795d594fSAndroid Build Coastguard Worker   DCHECK(GetFieldInfo(instr) != nullptr);
128*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_location_collector_ != nullptr);
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker   HInstruction* ref = instr->InputAt(0);
131*795d594fSAndroid Build Coastguard Worker   size_t heap_loc = heap_location_collector_->GetFieldHeapLocation(ref, GetFieldInfo(instr));
132*795d594fSAndroid Build Coastguard Worker   // This field access should be analyzed and added to HeapLocationCollector before.
133*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_loc != HeapLocationCollector::kHeapLocationNotFound);
134*795d594fSAndroid Build Coastguard Worker 
135*795d594fSAndroid Build Coastguard Worker   return heap_loc;
136*795d594fSAndroid Build Coastguard Worker }
137*795d594fSAndroid Build Coastguard Worker 
FieldAccessMayAlias(const HInstruction * instr1,const HInstruction * instr2) const138*795d594fSAndroid Build Coastguard Worker bool SideEffectDependencyAnalysis::MemoryDependencyAnalysis::FieldAccessMayAlias(
139*795d594fSAndroid Build Coastguard Worker     const HInstruction* instr1, const HInstruction* instr2) const {
140*795d594fSAndroid Build Coastguard Worker   DCHECK(heap_location_collector_ != nullptr);
141*795d594fSAndroid Build Coastguard Worker 
142*795d594fSAndroid Build Coastguard Worker   // Static and instance field accesses should not alias.
143*795d594fSAndroid Build Coastguard Worker   if ((IsInstanceFieldAccess(instr1) && IsStaticFieldAccess(instr2)) ||
144*795d594fSAndroid Build Coastguard Worker       (IsStaticFieldAccess(instr1) && IsInstanceFieldAccess(instr2))) {
145*795d594fSAndroid Build Coastguard Worker     return false;
146*795d594fSAndroid Build Coastguard Worker   }
147*795d594fSAndroid Build Coastguard Worker 
148*795d594fSAndroid Build Coastguard Worker   // If both fields accesses are resolved.
149*795d594fSAndroid Build Coastguard Worker   size_t instr1_field_access_heap_loc = FieldAccessHeapLocation(instr1);
150*795d594fSAndroid Build Coastguard Worker   size_t instr2_field_access_heap_loc = FieldAccessHeapLocation(instr2);
151*795d594fSAndroid Build Coastguard Worker 
152*795d594fSAndroid Build Coastguard Worker   if (instr1_field_access_heap_loc == instr2_field_access_heap_loc) {
153*795d594fSAndroid Build Coastguard Worker     return true;
154*795d594fSAndroid Build Coastguard Worker   }
155*795d594fSAndroid Build Coastguard Worker 
156*795d594fSAndroid Build Coastguard Worker   if (!heap_location_collector_->MayAlias(instr1_field_access_heap_loc,
157*795d594fSAndroid Build Coastguard Worker                                           instr2_field_access_heap_loc)) {
158*795d594fSAndroid Build Coastguard Worker     return false;
159*795d594fSAndroid Build Coastguard Worker   }
160*795d594fSAndroid Build Coastguard Worker 
161*795d594fSAndroid Build Coastguard Worker   return true;
162*795d594fSAndroid Build Coastguard Worker }
163*795d594fSAndroid Build Coastguard Worker 
HasMemoryDependency(HInstruction * instr1,HInstruction * instr2) const164*795d594fSAndroid Build Coastguard Worker bool SideEffectDependencyAnalysis::MemoryDependencyAnalysis::HasMemoryDependency(
165*795d594fSAndroid Build Coastguard Worker     HInstruction* instr1, HInstruction* instr2) const {
166*795d594fSAndroid Build Coastguard Worker   if (!HasReorderingDependency(instr1, instr2)) {
167*795d594fSAndroid Build Coastguard Worker     return false;
168*795d594fSAndroid Build Coastguard Worker   }
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker   if (heap_location_collector_ == nullptr ||
171*795d594fSAndroid Build Coastguard Worker       heap_location_collector_->GetNumberOfHeapLocations() == 0) {
172*795d594fSAndroid Build Coastguard Worker     // Without HeapLocation information from load store analysis,
173*795d594fSAndroid Build Coastguard Worker     // we cannot do further disambiguation analysis on these two instructions.
174*795d594fSAndroid Build Coastguard Worker     // Just simply say that those two instructions have memory dependency.
175*795d594fSAndroid Build Coastguard Worker     return true;
176*795d594fSAndroid Build Coastguard Worker   }
177*795d594fSAndroid Build Coastguard Worker 
178*795d594fSAndroid Build Coastguard Worker   // Note: Unresolved field access instructions are currently marked as not schedulable.
179*795d594fSAndroid Build Coastguard Worker   // If we change that, we should still keep in mind that these instructions can throw and
180*795d594fSAndroid Build Coastguard Worker   // read or write volatile fields and, if static, cause class initialization and write to
181*795d594fSAndroid Build Coastguard Worker   // arbitrary heap locations, and therefore cannot be reordered with any other field or
182*795d594fSAndroid Build Coastguard Worker   // array access to preserve the observable behavior. The only exception is access to
183*795d594fSAndroid Build Coastguard Worker   // singleton members that could actually be reodered across these instructions but we
184*795d594fSAndroid Build Coastguard Worker   // currently do not analyze singletons here anyway.
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker   if (IsArrayAccess(instr1) && IsArrayAccess(instr2)) {
187*795d594fSAndroid Build Coastguard Worker     return ArrayAccessMayAlias(instr1, instr2);
188*795d594fSAndroid Build Coastguard Worker   }
189*795d594fSAndroid Build Coastguard Worker   if (IsFieldAccess(instr1) && IsFieldAccess(instr2)) {
190*795d594fSAndroid Build Coastguard Worker     return FieldAccessMayAlias(instr1, instr2);
191*795d594fSAndroid Build Coastguard Worker   }
192*795d594fSAndroid Build Coastguard Worker 
193*795d594fSAndroid Build Coastguard Worker   // TODO(xueliang): LSA to support alias analysis among HVecLoad, HVecStore and ArrayAccess
194*795d594fSAndroid Build Coastguard Worker   if (instr1->IsVecMemoryOperation() && instr2->IsVecMemoryOperation()) {
195*795d594fSAndroid Build Coastguard Worker     return true;
196*795d594fSAndroid Build Coastguard Worker   }
197*795d594fSAndroid Build Coastguard Worker   if (instr1->IsVecMemoryOperation() && IsArrayAccess(instr2)) {
198*795d594fSAndroid Build Coastguard Worker     return true;
199*795d594fSAndroid Build Coastguard Worker   }
200*795d594fSAndroid Build Coastguard Worker   if (IsArrayAccess(instr1) && instr2->IsVecMemoryOperation()) {
201*795d594fSAndroid Build Coastguard Worker     return true;
202*795d594fSAndroid Build Coastguard Worker   }
203*795d594fSAndroid Build Coastguard Worker 
204*795d594fSAndroid Build Coastguard Worker   // Heap accesses of different kinds should not alias.
205*795d594fSAndroid Build Coastguard Worker   if (IsArrayAccess(instr1) && IsFieldAccess(instr2)) {
206*795d594fSAndroid Build Coastguard Worker     return false;
207*795d594fSAndroid Build Coastguard Worker   }
208*795d594fSAndroid Build Coastguard Worker   if (IsFieldAccess(instr1) && IsArrayAccess(instr2)) {
209*795d594fSAndroid Build Coastguard Worker     return false;
210*795d594fSAndroid Build Coastguard Worker   }
211*795d594fSAndroid Build Coastguard Worker   if (instr1->IsVecMemoryOperation() && IsFieldAccess(instr2)) {
212*795d594fSAndroid Build Coastguard Worker     return false;
213*795d594fSAndroid Build Coastguard Worker   }
214*795d594fSAndroid Build Coastguard Worker   if (IsFieldAccess(instr1) && instr2->IsVecMemoryOperation()) {
215*795d594fSAndroid Build Coastguard Worker     return false;
216*795d594fSAndroid Build Coastguard Worker   }
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker   // We conservatively treat all other cases having dependency,
219*795d594fSAndroid Build Coastguard Worker   // for example, Invoke and ArrayGet.
220*795d594fSAndroid Build Coastguard Worker   return true;
221*795d594fSAndroid Build Coastguard Worker }
222*795d594fSAndroid Build Coastguard Worker 
HasExceptionDependency(const HInstruction * instr1,const HInstruction * instr2)223*795d594fSAndroid Build Coastguard Worker bool SideEffectDependencyAnalysis::HasExceptionDependency(const HInstruction* instr1,
224*795d594fSAndroid Build Coastguard Worker                                                           const HInstruction* instr2) {
225*795d594fSAndroid Build Coastguard Worker   if (instr2->CanThrow() && instr1->GetSideEffects().DoesAnyWrite()) {
226*795d594fSAndroid Build Coastguard Worker     return true;
227*795d594fSAndroid Build Coastguard Worker   }
228*795d594fSAndroid Build Coastguard Worker   if (instr2->GetSideEffects().DoesAnyWrite() && instr1->CanThrow()) {
229*795d594fSAndroid Build Coastguard Worker     return true;
230*795d594fSAndroid Build Coastguard Worker   }
231*795d594fSAndroid Build Coastguard Worker   if (instr2->CanThrow() && instr1->CanThrow()) {
232*795d594fSAndroid Build Coastguard Worker     return true;
233*795d594fSAndroid Build Coastguard Worker   }
234*795d594fSAndroid Build Coastguard Worker 
235*795d594fSAndroid Build Coastguard Worker   // Above checks should cover all cases where we cannot reorder two
236*795d594fSAndroid Build Coastguard Worker   // instructions which may throw exception.
237*795d594fSAndroid Build Coastguard Worker   return false;
238*795d594fSAndroid Build Coastguard Worker }
239*795d594fSAndroid Build Coastguard Worker 
240*795d594fSAndroid Build Coastguard Worker // Check if the specified instruction is a better candidate which more likely will
241*795d594fSAndroid Build Coastguard Worker // have other instructions depending on it.
IsBetterCandidateWithMoreLikelyDependencies(HInstruction * new_candidate,HInstruction * old_candidate)242*795d594fSAndroid Build Coastguard Worker static bool IsBetterCandidateWithMoreLikelyDependencies(HInstruction* new_candidate,
243*795d594fSAndroid Build Coastguard Worker                                                         HInstruction* old_candidate) {
244*795d594fSAndroid Build Coastguard Worker   if (!new_candidate->GetSideEffects().Includes(old_candidate->GetSideEffects())) {
245*795d594fSAndroid Build Coastguard Worker     // Weaker side effects.
246*795d594fSAndroid Build Coastguard Worker     return false;
247*795d594fSAndroid Build Coastguard Worker   }
248*795d594fSAndroid Build Coastguard Worker   if (old_candidate->GetSideEffects().Includes(new_candidate->GetSideEffects())) {
249*795d594fSAndroid Build Coastguard Worker     // Same side effects, check if `new_candidate` has stronger `CanThrow()`.
250*795d594fSAndroid Build Coastguard Worker     return new_candidate->CanThrow() && !old_candidate->CanThrow();
251*795d594fSAndroid Build Coastguard Worker   } else {
252*795d594fSAndroid Build Coastguard Worker     // Stronger side effects, check if `new_candidate` has at least as strong `CanThrow()`.
253*795d594fSAndroid Build Coastguard Worker     return new_candidate->CanThrow() || !old_candidate->CanThrow();
254*795d594fSAndroid Build Coastguard Worker   }
255*795d594fSAndroid Build Coastguard Worker }
256*795d594fSAndroid Build Coastguard Worker 
AddCrossIterationDependencies(SchedulingNode * node)257*795d594fSAndroid Build Coastguard Worker void SchedulingGraph::AddCrossIterationDependencies(SchedulingNode* node) {
258*795d594fSAndroid Build Coastguard Worker   for (HInstruction* instruction : node->GetInstruction()->GetInputs()) {
259*795d594fSAndroid Build Coastguard Worker     // Having a phi-function from a loop header as an input means the current node of the
260*795d594fSAndroid Build Coastguard Worker     // scheduling graph has a cross-iteration dependency because such phi-functions bring values
261*795d594fSAndroid Build Coastguard Worker     // from the previous iteration to the current iteration.
262*795d594fSAndroid Build Coastguard Worker     if (!instruction->IsLoopHeaderPhi()) {
263*795d594fSAndroid Build Coastguard Worker       continue;
264*795d594fSAndroid Build Coastguard Worker     }
265*795d594fSAndroid Build Coastguard Worker     for (HInstruction* phi_input : instruction->GetInputs()) {
266*795d594fSAndroid Build Coastguard Worker       // As a scheduling graph of the current basic block is built by
267*795d594fSAndroid Build Coastguard Worker       // processing instructions bottom-up, nullptr returned by GetNode means
268*795d594fSAndroid Build Coastguard Worker       // an instruction defining a value for the phi is either before the
269*795d594fSAndroid Build Coastguard Worker       // instruction represented by node or it is in a different basic block.
270*795d594fSAndroid Build Coastguard Worker       SchedulingNode* def_node = GetNode(phi_input);
271*795d594fSAndroid Build Coastguard Worker 
272*795d594fSAndroid Build Coastguard Worker       // We don't create a dependency if there are uses besides the use in phi.
273*795d594fSAndroid Build Coastguard Worker       // In such cases a register to hold phi_input is usually allocated and
274*795d594fSAndroid Build Coastguard Worker       // a MOV instruction is generated. In cases with multiple uses and no MOV
275*795d594fSAndroid Build Coastguard Worker       // instruction, reordering creating a MOV instruction can improve
276*795d594fSAndroid Build Coastguard Worker       // performance more than an attempt to avoid a MOV instruction.
277*795d594fSAndroid Build Coastguard Worker       if (def_node != nullptr && def_node != node && phi_input->GetUses().HasExactlyOneElement()) {
278*795d594fSAndroid Build Coastguard Worker         // We have an implicit data dependency between node and def_node.
279*795d594fSAndroid Build Coastguard Worker         // AddAddDataDependency cannot be used because it is for explicit data dependencies.
280*795d594fSAndroid Build Coastguard Worker         // So AddOtherDependency is used.
281*795d594fSAndroid Build Coastguard Worker         AddOtherDependency(def_node, node);
282*795d594fSAndroid Build Coastguard Worker       }
283*795d594fSAndroid Build Coastguard Worker     }
284*795d594fSAndroid Build Coastguard Worker   }
285*795d594fSAndroid Build Coastguard Worker }
286*795d594fSAndroid Build Coastguard Worker 
AddDependencies(SchedulingNode * instruction_node,bool is_scheduling_barrier)287*795d594fSAndroid Build Coastguard Worker void SchedulingGraph::AddDependencies(SchedulingNode* instruction_node,
288*795d594fSAndroid Build Coastguard Worker                                       bool is_scheduling_barrier) {
289*795d594fSAndroid Build Coastguard Worker   HInstruction* instruction = instruction_node->GetInstruction();
290*795d594fSAndroid Build Coastguard Worker 
291*795d594fSAndroid Build Coastguard Worker   // Define-use dependencies.
292*795d594fSAndroid Build Coastguard Worker   for (const HUseListNode<HInstruction*>& use : instruction->GetUses()) {
293*795d594fSAndroid Build Coastguard Worker     AddDataDependency(GetNode(use.GetUser()), instruction_node);
294*795d594fSAndroid Build Coastguard Worker   }
295*795d594fSAndroid Build Coastguard Worker 
296*795d594fSAndroid Build Coastguard Worker   // Scheduling barrier dependencies.
297*795d594fSAndroid Build Coastguard Worker   DCHECK_IMPLIES(is_scheduling_barrier, contains_scheduling_barrier_);
298*795d594fSAndroid Build Coastguard Worker   if (contains_scheduling_barrier_) {
299*795d594fSAndroid Build Coastguard Worker     // A barrier depends on instructions after it. And instructions before the
300*795d594fSAndroid Build Coastguard Worker     // barrier depend on it.
301*795d594fSAndroid Build Coastguard Worker     for (HInstruction* other = instruction->GetNext(); other != nullptr; other = other->GetNext()) {
302*795d594fSAndroid Build Coastguard Worker       SchedulingNode* other_node = GetNode(other);
303*795d594fSAndroid Build Coastguard Worker       CHECK(other_node != nullptr)
304*795d594fSAndroid Build Coastguard Worker           << other->DebugName()
305*795d594fSAndroid Build Coastguard Worker           << " is in block " << other->GetBlock()->GetBlockId()
306*795d594fSAndroid Build Coastguard Worker           << ", and expected in block " << instruction->GetBlock()->GetBlockId();
307*795d594fSAndroid Build Coastguard Worker       bool other_is_barrier = other_node->IsSchedulingBarrier();
308*795d594fSAndroid Build Coastguard Worker       if (is_scheduling_barrier || other_is_barrier) {
309*795d594fSAndroid Build Coastguard Worker         AddOtherDependency(other_node, instruction_node);
310*795d594fSAndroid Build Coastguard Worker       }
311*795d594fSAndroid Build Coastguard Worker       if (other_is_barrier) {
312*795d594fSAndroid Build Coastguard Worker         // This other scheduling barrier guarantees ordering of instructions after
313*795d594fSAndroid Build Coastguard Worker         // it, so avoid creating additional useless dependencies in the graph.
314*795d594fSAndroid Build Coastguard Worker         // For example if we have
315*795d594fSAndroid Build Coastguard Worker         //     instr_1
316*795d594fSAndroid Build Coastguard Worker         //     barrier_2
317*795d594fSAndroid Build Coastguard Worker         //     instr_3
318*795d594fSAndroid Build Coastguard Worker         //     barrier_4
319*795d594fSAndroid Build Coastguard Worker         //     instr_5
320*795d594fSAndroid Build Coastguard Worker         // we only create the following non-data dependencies
321*795d594fSAndroid Build Coastguard Worker         //     1 -> 2
322*795d594fSAndroid Build Coastguard Worker         //     2 -> 3
323*795d594fSAndroid Build Coastguard Worker         //     2 -> 4
324*795d594fSAndroid Build Coastguard Worker         //     3 -> 4
325*795d594fSAndroid Build Coastguard Worker         //     4 -> 5
326*795d594fSAndroid Build Coastguard Worker         // and do not create
327*795d594fSAndroid Build Coastguard Worker         //     1 -> 4
328*795d594fSAndroid Build Coastguard Worker         //     2 -> 5
329*795d594fSAndroid Build Coastguard Worker         // Note that in this example we could also avoid creating the dependency
330*795d594fSAndroid Build Coastguard Worker         // `2 -> 4`.  But if we remove `instr_3` that dependency is required to
331*795d594fSAndroid Build Coastguard Worker         // order the barriers. So we generate it to avoid a special case.
332*795d594fSAndroid Build Coastguard Worker         break;
333*795d594fSAndroid Build Coastguard Worker       }
334*795d594fSAndroid Build Coastguard Worker     }
335*795d594fSAndroid Build Coastguard Worker   }
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker   // Side effect dependencies.
338*795d594fSAndroid Build Coastguard Worker   if (!instruction->GetSideEffects().DoesNothing() || instruction->CanThrow()) {
339*795d594fSAndroid Build Coastguard Worker     HInstruction* dep_chain_candidate = nullptr;
340*795d594fSAndroid Build Coastguard Worker     for (HInstruction* other = instruction->GetNext(); other != nullptr; other = other->GetNext()) {
341*795d594fSAndroid Build Coastguard Worker       SchedulingNode* other_node = GetNode(other);
342*795d594fSAndroid Build Coastguard Worker       if (other_node->IsSchedulingBarrier()) {
343*795d594fSAndroid Build Coastguard Worker         // We have reached a scheduling barrier so we can stop further
344*795d594fSAndroid Build Coastguard Worker         // processing.
345*795d594fSAndroid Build Coastguard Worker         //
346*795d594fSAndroid Build Coastguard Worker         // As a "other" dependency is not set up if a data dependency exists, we need to check that
347*795d594fSAndroid Build Coastguard Worker         // one of them must exist.
348*795d594fSAndroid Build Coastguard Worker         DCHECK(other_node->HasOtherDependency(instruction_node)
349*795d594fSAndroid Build Coastguard Worker                || other_node->HasDataDependency(instruction_node));
350*795d594fSAndroid Build Coastguard Worker         break;
351*795d594fSAndroid Build Coastguard Worker       }
352*795d594fSAndroid Build Coastguard Worker       if (side_effect_dependency_analysis_.HasSideEffectDependency(other, instruction)) {
353*795d594fSAndroid Build Coastguard Worker         if (dep_chain_candidate != nullptr &&
354*795d594fSAndroid Build Coastguard Worker             side_effect_dependency_analysis_.HasSideEffectDependency(other, dep_chain_candidate)) {
355*795d594fSAndroid Build Coastguard Worker           // Skip an explicit dependency to reduce memory usage, rely on the transitive dependency.
356*795d594fSAndroid Build Coastguard Worker         } else {
357*795d594fSAndroid Build Coastguard Worker           AddOtherDependency(other_node, instruction_node);
358*795d594fSAndroid Build Coastguard Worker         }
359*795d594fSAndroid Build Coastguard Worker         // Check if `other` is a better candidate which more likely will have other instructions
360*795d594fSAndroid Build Coastguard Worker         // depending on it.
361*795d594fSAndroid Build Coastguard Worker         if (dep_chain_candidate == nullptr ||
362*795d594fSAndroid Build Coastguard Worker             IsBetterCandidateWithMoreLikelyDependencies(other, dep_chain_candidate)) {
363*795d594fSAndroid Build Coastguard Worker           dep_chain_candidate = other;
364*795d594fSAndroid Build Coastguard Worker         }
365*795d594fSAndroid Build Coastguard Worker       }
366*795d594fSAndroid Build Coastguard Worker     }
367*795d594fSAndroid Build Coastguard Worker   }
368*795d594fSAndroid Build Coastguard Worker 
369*795d594fSAndroid Build Coastguard Worker   // Environment dependencies.
370*795d594fSAndroid Build Coastguard Worker   // We do not need to process those if the instruction is a scheduling barrier,
371*795d594fSAndroid Build Coastguard Worker   // since the barrier already has non-data dependencies on all following
372*795d594fSAndroid Build Coastguard Worker   // instructions.
373*795d594fSAndroid Build Coastguard Worker   if (!is_scheduling_barrier) {
374*795d594fSAndroid Build Coastguard Worker     for (const HUseListNode<HEnvironment*>& use : instruction->GetEnvUses()) {
375*795d594fSAndroid Build Coastguard Worker       // Note that here we could stop processing if the environment holder is
376*795d594fSAndroid Build Coastguard Worker       // across a scheduling barrier. But checking this would likely require
377*795d594fSAndroid Build Coastguard Worker       // more work than simply iterating through environment uses.
378*795d594fSAndroid Build Coastguard Worker       AddOtherDependency(GetNode(use.GetUser()->GetHolder()), instruction_node);
379*795d594fSAndroid Build Coastguard Worker     }
380*795d594fSAndroid Build Coastguard Worker   }
381*795d594fSAndroid Build Coastguard Worker 
382*795d594fSAndroid Build Coastguard Worker   AddCrossIterationDependencies(instruction_node);
383*795d594fSAndroid Build Coastguard Worker }
384*795d594fSAndroid Build Coastguard Worker 
InstructionTypeId(const HInstruction * instruction)385*795d594fSAndroid Build Coastguard Worker static const std::string InstructionTypeId(const HInstruction* instruction) {
386*795d594fSAndroid Build Coastguard Worker   return DataType::TypeId(instruction->GetType()) + std::to_string(instruction->GetId());
387*795d594fSAndroid Build Coastguard Worker }
388*795d594fSAndroid Build Coastguard Worker 
389*795d594fSAndroid Build Coastguard Worker // Ideally we would reuse the graph visualizer code, but it is not available
390*795d594fSAndroid Build Coastguard Worker // from here and it is not worth moving all that code only for our use.
DumpAsDotNode(std::ostream & output,const SchedulingNode * node)391*795d594fSAndroid Build Coastguard Worker static void DumpAsDotNode(std::ostream& output, const SchedulingNode* node) {
392*795d594fSAndroid Build Coastguard Worker   const HInstruction* instruction = node->GetInstruction();
393*795d594fSAndroid Build Coastguard Worker   // Use the instruction typed id as the node identifier.
394*795d594fSAndroid Build Coastguard Worker   std::string instruction_id = InstructionTypeId(instruction);
395*795d594fSAndroid Build Coastguard Worker   output << instruction_id << "[shape=record, label=\""
396*795d594fSAndroid Build Coastguard Worker       << instruction_id << ' ' << instruction->DebugName() << " [";
397*795d594fSAndroid Build Coastguard Worker   // List the instruction's inputs in its description. When visualizing the
398*795d594fSAndroid Build Coastguard Worker   // graph this helps differentiating data inputs from other dependencies.
399*795d594fSAndroid Build Coastguard Worker   const char* seperator = "";
400*795d594fSAndroid Build Coastguard Worker   for (const HInstruction* input : instruction->GetInputs()) {
401*795d594fSAndroid Build Coastguard Worker     output << seperator << InstructionTypeId(input);
402*795d594fSAndroid Build Coastguard Worker     seperator = ",";
403*795d594fSAndroid Build Coastguard Worker   }
404*795d594fSAndroid Build Coastguard Worker   output << "]";
405*795d594fSAndroid Build Coastguard Worker   // Other properties of the node.
406*795d594fSAndroid Build Coastguard Worker   output << "\\ninternal_latency: " << node->GetInternalLatency();
407*795d594fSAndroid Build Coastguard Worker   output << "\\ncritical_path: " << node->GetCriticalPath();
408*795d594fSAndroid Build Coastguard Worker   if (node->IsSchedulingBarrier()) {
409*795d594fSAndroid Build Coastguard Worker     output << "\\n(barrier)";
410*795d594fSAndroid Build Coastguard Worker   }
411*795d594fSAndroid Build Coastguard Worker   output << "\"];\n";
412*795d594fSAndroid Build Coastguard Worker   // We want program order to go from top to bottom in the graph output, so we
413*795d594fSAndroid Build Coastguard Worker   // reverse the edges and specify `dir=back`.
414*795d594fSAndroid Build Coastguard Worker   for (const SchedulingNode* predecessor : node->GetDataPredecessors()) {
415*795d594fSAndroid Build Coastguard Worker     const HInstruction* predecessor_instruction = predecessor->GetInstruction();
416*795d594fSAndroid Build Coastguard Worker     output << InstructionTypeId(predecessor_instruction) << ":s -> " << instruction_id << ":n "
417*795d594fSAndroid Build Coastguard Worker         << "[label=\"" << predecessor->GetLatency() << "\",dir=back]\n";
418*795d594fSAndroid Build Coastguard Worker   }
419*795d594fSAndroid Build Coastguard Worker   for (const SchedulingNode* predecessor : node->GetOtherPredecessors()) {
420*795d594fSAndroid Build Coastguard Worker     const HInstruction* predecessor_instruction = predecessor->GetInstruction();
421*795d594fSAndroid Build Coastguard Worker     output << InstructionTypeId(predecessor_instruction) << ":s -> " << instruction_id << ":n "
422*795d594fSAndroid Build Coastguard Worker         << "[dir=back,color=blue]\n";
423*795d594fSAndroid Build Coastguard Worker   }
424*795d594fSAndroid Build Coastguard Worker }
425*795d594fSAndroid Build Coastguard Worker 
DumpAsDotGraph(const std::string & description,const ScopedArenaVector<SchedulingNode * > & initial_candidates)426*795d594fSAndroid Build Coastguard Worker void SchedulingGraph::DumpAsDotGraph(const std::string& description,
427*795d594fSAndroid Build Coastguard Worker                                      const ScopedArenaVector<SchedulingNode*>& initial_candidates) {
428*795d594fSAndroid Build Coastguard Worker   // TODO(xueliang): ideally we should move scheduling information into HInstruction, after that
429*795d594fSAndroid Build Coastguard Worker   // we should move this dotty graph dump feature to visualizer, and have a compiler option for it.
430*795d594fSAndroid Build Coastguard Worker   std::ofstream output("scheduling_graphs.dot", std::ofstream::out | std::ofstream::app);
431*795d594fSAndroid Build Coastguard Worker   // Description of this graph, as a comment.
432*795d594fSAndroid Build Coastguard Worker   output << "// " << description << "\n";
433*795d594fSAndroid Build Coastguard Worker   // Start the dot graph. Use an increasing index for easier differentiation.
434*795d594fSAndroid Build Coastguard Worker   output << "digraph G {\n";
435*795d594fSAndroid Build Coastguard Worker   for (const auto& entry : nodes_map_) {
436*795d594fSAndroid Build Coastguard Worker     SchedulingNode* node = entry.second.get();
437*795d594fSAndroid Build Coastguard Worker     DumpAsDotNode(output, node);
438*795d594fSAndroid Build Coastguard Worker   }
439*795d594fSAndroid Build Coastguard Worker   // Create a fake 'end_of_scheduling' node to help visualization of critical_paths.
440*795d594fSAndroid Build Coastguard Worker   for (SchedulingNode* node : initial_candidates) {
441*795d594fSAndroid Build Coastguard Worker     const HInstruction* instruction = node->GetInstruction();
442*795d594fSAndroid Build Coastguard Worker     output << InstructionTypeId(instruction) << ":s -> end_of_scheduling:n "
443*795d594fSAndroid Build Coastguard Worker       << "[label=\"" << node->GetLatency() << "\",dir=back]\n";
444*795d594fSAndroid Build Coastguard Worker   }
445*795d594fSAndroid Build Coastguard Worker   // End of the dot graph.
446*795d594fSAndroid Build Coastguard Worker   output << "}\n";
447*795d594fSAndroid Build Coastguard Worker   output.close();
448*795d594fSAndroid Build Coastguard Worker }
449*795d594fSAndroid Build Coastguard Worker 
SelectMaterializedCondition(ScopedArenaVector<SchedulingNode * > * nodes,const SchedulingGraph & graph) const450*795d594fSAndroid Build Coastguard Worker SchedulingNode* CriticalPathSchedulingNodeSelector::SelectMaterializedCondition(
451*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<SchedulingNode*>* nodes, const SchedulingGraph& graph) const {
452*795d594fSAndroid Build Coastguard Worker   // Schedule condition inputs that can be materialized immediately before their use.
453*795d594fSAndroid Build Coastguard Worker   // In following example, after we've scheduled HSelect, we want LessThan to be scheduled
454*795d594fSAndroid Build Coastguard Worker   // immediately, because it is a materialized condition, and will be emitted right before HSelect
455*795d594fSAndroid Build Coastguard Worker   // in codegen phase.
456*795d594fSAndroid Build Coastguard Worker   //
457*795d594fSAndroid Build Coastguard Worker   // i20 HLessThan [...]                  HLessThan    HAdd      HAdd
458*795d594fSAndroid Build Coastguard Worker   // i21 HAdd [...]                ===>      |          |         |
459*795d594fSAndroid Build Coastguard Worker   // i22 HAdd [...]                          +----------+---------+
460*795d594fSAndroid Build Coastguard Worker   // i23 HSelect [i21, i22, i20]                     HSelect
461*795d594fSAndroid Build Coastguard Worker 
462*795d594fSAndroid Build Coastguard Worker   if (prev_select_ == nullptr) {
463*795d594fSAndroid Build Coastguard Worker     return nullptr;
464*795d594fSAndroid Build Coastguard Worker   }
465*795d594fSAndroid Build Coastguard Worker 
466*795d594fSAndroid Build Coastguard Worker   const HInstruction* instruction = prev_select_->GetInstruction();
467*795d594fSAndroid Build Coastguard Worker   const HCondition* condition = nullptr;
468*795d594fSAndroid Build Coastguard Worker   DCHECK(instruction != nullptr);
469*795d594fSAndroid Build Coastguard Worker 
470*795d594fSAndroid Build Coastguard Worker   if (instruction->IsIf()) {
471*795d594fSAndroid Build Coastguard Worker     condition = instruction->AsIf()->InputAt(0)->AsConditionOrNull();
472*795d594fSAndroid Build Coastguard Worker   } else if (instruction->IsSelect()) {
473*795d594fSAndroid Build Coastguard Worker     condition = instruction->AsSelect()->GetCondition()->AsConditionOrNull();
474*795d594fSAndroid Build Coastguard Worker   }
475*795d594fSAndroid Build Coastguard Worker 
476*795d594fSAndroid Build Coastguard Worker   SchedulingNode* condition_node = (condition != nullptr) ? graph.GetNode(condition) : nullptr;
477*795d594fSAndroid Build Coastguard Worker 
478*795d594fSAndroid Build Coastguard Worker   if ((condition_node != nullptr) &&
479*795d594fSAndroid Build Coastguard Worker       condition->HasOnlyOneNonEnvironmentUse() &&
480*795d594fSAndroid Build Coastguard Worker       ContainsElement(*nodes, condition_node)) {
481*795d594fSAndroid Build Coastguard Worker     DCHECK(!condition_node->HasUnscheduledSuccessors());
482*795d594fSAndroid Build Coastguard Worker     // Remove the condition from the list of candidates and schedule it.
483*795d594fSAndroid Build Coastguard Worker     RemoveElement(*nodes, condition_node);
484*795d594fSAndroid Build Coastguard Worker     return condition_node;
485*795d594fSAndroid Build Coastguard Worker   }
486*795d594fSAndroid Build Coastguard Worker 
487*795d594fSAndroid Build Coastguard Worker   return nullptr;
488*795d594fSAndroid Build Coastguard Worker }
489*795d594fSAndroid Build Coastguard Worker 
PopHighestPriorityNode(ScopedArenaVector<SchedulingNode * > * nodes,const SchedulingGraph & graph)490*795d594fSAndroid Build Coastguard Worker SchedulingNode* CriticalPathSchedulingNodeSelector::PopHighestPriorityNode(
491*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<SchedulingNode*>* nodes, const SchedulingGraph& graph) {
492*795d594fSAndroid Build Coastguard Worker   DCHECK(!nodes->empty());
493*795d594fSAndroid Build Coastguard Worker   SchedulingNode* select_node = nullptr;
494*795d594fSAndroid Build Coastguard Worker 
495*795d594fSAndroid Build Coastguard Worker   // Optimize for materialized condition and its emit before use scenario.
496*795d594fSAndroid Build Coastguard Worker   select_node = SelectMaterializedCondition(nodes, graph);
497*795d594fSAndroid Build Coastguard Worker 
498*795d594fSAndroid Build Coastguard Worker   if (select_node == nullptr) {
499*795d594fSAndroid Build Coastguard Worker     // Get highest priority node based on critical path information.
500*795d594fSAndroid Build Coastguard Worker     select_node = (*nodes)[0];
501*795d594fSAndroid Build Coastguard Worker     size_t select = 0;
502*795d594fSAndroid Build Coastguard Worker     for (size_t i = 1, e = nodes->size(); i < e; i++) {
503*795d594fSAndroid Build Coastguard Worker       SchedulingNode* check = (*nodes)[i];
504*795d594fSAndroid Build Coastguard Worker       SchedulingNode* candidate = (*nodes)[select];
505*795d594fSAndroid Build Coastguard Worker       select_node = GetHigherPrioritySchedulingNode(candidate, check);
506*795d594fSAndroid Build Coastguard Worker       if (select_node == check) {
507*795d594fSAndroid Build Coastguard Worker         select = i;
508*795d594fSAndroid Build Coastguard Worker       }
509*795d594fSAndroid Build Coastguard Worker     }
510*795d594fSAndroid Build Coastguard Worker     DeleteNodeAtIndex(nodes, select);
511*795d594fSAndroid Build Coastguard Worker   }
512*795d594fSAndroid Build Coastguard Worker 
513*795d594fSAndroid Build Coastguard Worker   prev_select_ = select_node;
514*795d594fSAndroid Build Coastguard Worker   return select_node;
515*795d594fSAndroid Build Coastguard Worker }
516*795d594fSAndroid Build Coastguard Worker 
GetHigherPrioritySchedulingNode(SchedulingNode * candidate,SchedulingNode * check) const517*795d594fSAndroid Build Coastguard Worker SchedulingNode* CriticalPathSchedulingNodeSelector::GetHigherPrioritySchedulingNode(
518*795d594fSAndroid Build Coastguard Worker     SchedulingNode* candidate, SchedulingNode* check) const {
519*795d594fSAndroid Build Coastguard Worker   uint32_t candidate_path = candidate->GetCriticalPath();
520*795d594fSAndroid Build Coastguard Worker   uint32_t check_path = check->GetCriticalPath();
521*795d594fSAndroid Build Coastguard Worker   // First look at the critical_path.
522*795d594fSAndroid Build Coastguard Worker   if (check_path != candidate_path) {
523*795d594fSAndroid Build Coastguard Worker     return check_path < candidate_path ? check : candidate;
524*795d594fSAndroid Build Coastguard Worker   }
525*795d594fSAndroid Build Coastguard Worker   // If both critical paths are equal, schedule instructions with a higher latency
526*795d594fSAndroid Build Coastguard Worker   // first in program order.
527*795d594fSAndroid Build Coastguard Worker   return check->GetLatency() < candidate->GetLatency() ? check : candidate;
528*795d594fSAndroid Build Coastguard Worker }
529*795d594fSAndroid Build Coastguard Worker 
Schedule(HGraph * graph)530*795d594fSAndroid Build Coastguard Worker void HScheduler::Schedule(HGraph* graph) {
531*795d594fSAndroid Build Coastguard Worker   // We run lsa here instead of in a separate pass to better control whether we
532*795d594fSAndroid Build Coastguard Worker   // should run the analysis or not.
533*795d594fSAndroid Build Coastguard Worker   const HeapLocationCollector* heap_location_collector = nullptr;
534*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(graph->GetArenaStack());
535*795d594fSAndroid Build Coastguard Worker   LoadStoreAnalysis lsa(graph, /*stats=*/nullptr, &allocator);
536*795d594fSAndroid Build Coastguard Worker   if (!only_optimize_loop_blocks_ || graph->HasLoops()) {
537*795d594fSAndroid Build Coastguard Worker     lsa.Run();
538*795d594fSAndroid Build Coastguard Worker     heap_location_collector = &lsa.GetHeapLocationCollector();
539*795d594fSAndroid Build Coastguard Worker   }
540*795d594fSAndroid Build Coastguard Worker 
541*795d594fSAndroid Build Coastguard Worker   for (HBasicBlock* block : graph->GetReversePostOrder()) {
542*795d594fSAndroid Build Coastguard Worker     if (IsSchedulable(block)) {
543*795d594fSAndroid Build Coastguard Worker       Schedule(block, heap_location_collector);
544*795d594fSAndroid Build Coastguard Worker     }
545*795d594fSAndroid Build Coastguard Worker   }
546*795d594fSAndroid Build Coastguard Worker }
547*795d594fSAndroid Build Coastguard Worker 
Schedule(HBasicBlock * block,const HeapLocationCollector * heap_location_collector)548*795d594fSAndroid Build Coastguard Worker void HScheduler::Schedule(HBasicBlock* block,
549*795d594fSAndroid Build Coastguard Worker                           const HeapLocationCollector* heap_location_collector) {
550*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator allocator(block->GetGraph()->GetArenaStack());
551*795d594fSAndroid Build Coastguard Worker 
552*795d594fSAndroid Build Coastguard Worker   // Build the scheduling graph.
553*795d594fSAndroid Build Coastguard Worker   auto [scheduling_graph, scheduling_nodes] =
554*795d594fSAndroid Build Coastguard Worker       BuildSchedulingGraph(block, &allocator, heap_location_collector);
555*795d594fSAndroid Build Coastguard Worker 
556*795d594fSAndroid Build Coastguard Worker   if (scheduling_graph.Size() <= 1) {
557*795d594fSAndroid Build Coastguard Worker     return;
558*795d594fSAndroid Build Coastguard Worker   }
559*795d594fSAndroid Build Coastguard Worker 
560*795d594fSAndroid Build Coastguard Worker   cursor_ = block->GetLastInstruction();
561*795d594fSAndroid Build Coastguard Worker 
562*795d594fSAndroid Build Coastguard Worker   // The list of candidates for scheduling. A node becomes a candidate when all
563*795d594fSAndroid Build Coastguard Worker   // its predecessors have been scheduled.
564*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<SchedulingNode*> candidates(allocator.Adapter(kArenaAllocScheduler));
565*795d594fSAndroid Build Coastguard Worker 
566*795d594fSAndroid Build Coastguard Worker   // Find the initial candidates for scheduling.
567*795d594fSAndroid Build Coastguard Worker   for (SchedulingNode* node : scheduling_nodes) {
568*795d594fSAndroid Build Coastguard Worker     if (!node->HasUnscheduledSuccessors()) {
569*795d594fSAndroid Build Coastguard Worker       node->MaybeUpdateCriticalPath(node->GetLatency());
570*795d594fSAndroid Build Coastguard Worker       candidates.push_back(node);
571*795d594fSAndroid Build Coastguard Worker     }
572*795d594fSAndroid Build Coastguard Worker   }
573*795d594fSAndroid Build Coastguard Worker 
574*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<SchedulingNode*> initial_candidates(allocator.Adapter(kArenaAllocScheduler));
575*795d594fSAndroid Build Coastguard Worker   if (kDumpDotSchedulingGraphs) {
576*795d594fSAndroid Build Coastguard Worker     // Remember the list of initial candidates for debug output purposes.
577*795d594fSAndroid Build Coastguard Worker     initial_candidates.assign(candidates.begin(), candidates.end());
578*795d594fSAndroid Build Coastguard Worker   }
579*795d594fSAndroid Build Coastguard Worker 
580*795d594fSAndroid Build Coastguard Worker   // Schedule all nodes.
581*795d594fSAndroid Build Coastguard Worker   selector_->Reset();
582*795d594fSAndroid Build Coastguard Worker   while (!candidates.empty()) {
583*795d594fSAndroid Build Coastguard Worker     SchedulingNode* node = selector_->PopHighestPriorityNode(&candidates, scheduling_graph);
584*795d594fSAndroid Build Coastguard Worker     Schedule(node, &candidates);
585*795d594fSAndroid Build Coastguard Worker   }
586*795d594fSAndroid Build Coastguard Worker 
587*795d594fSAndroid Build Coastguard Worker   if (kDumpDotSchedulingGraphs) {
588*795d594fSAndroid Build Coastguard Worker     // Dump the graph in `dot` format.
589*795d594fSAndroid Build Coastguard Worker     HGraph* graph = block->GetGraph();
590*795d594fSAndroid Build Coastguard Worker     std::stringstream description;
591*795d594fSAndroid Build Coastguard Worker     description << graph->GetDexFile().PrettyMethod(graph->GetMethodIdx())
592*795d594fSAndroid Build Coastguard Worker         << " B" << block->GetBlockId();
593*795d594fSAndroid Build Coastguard Worker     scheduling_graph.DumpAsDotGraph(description.str(), initial_candidates);
594*795d594fSAndroid Build Coastguard Worker   }
595*795d594fSAndroid Build Coastguard Worker }
596*795d594fSAndroid Build Coastguard Worker 
Schedule(SchedulingNode * scheduling_node,ScopedArenaVector<SchedulingNode * > * candidates)597*795d594fSAndroid Build Coastguard Worker void HScheduler::Schedule(SchedulingNode* scheduling_node,
598*795d594fSAndroid Build Coastguard Worker                           /*inout*/ ScopedArenaVector<SchedulingNode*>* candidates) {
599*795d594fSAndroid Build Coastguard Worker   // Check whether any of the node's predecessors will be valid candidates after
600*795d594fSAndroid Build Coastguard Worker   // this node is scheduled.
601*795d594fSAndroid Build Coastguard Worker   uint32_t path_to_node = scheduling_node->GetCriticalPath();
602*795d594fSAndroid Build Coastguard Worker   for (SchedulingNode* predecessor : scheduling_node->GetDataPredecessors()) {
603*795d594fSAndroid Build Coastguard Worker     predecessor->MaybeUpdateCriticalPath(
604*795d594fSAndroid Build Coastguard Worker         path_to_node + predecessor->GetInternalLatency() + predecessor->GetLatency());
605*795d594fSAndroid Build Coastguard Worker     predecessor->DecrementNumberOfUnscheduledSuccessors();
606*795d594fSAndroid Build Coastguard Worker     if (!predecessor->HasUnscheduledSuccessors()) {
607*795d594fSAndroid Build Coastguard Worker       candidates->push_back(predecessor);
608*795d594fSAndroid Build Coastguard Worker     }
609*795d594fSAndroid Build Coastguard Worker   }
610*795d594fSAndroid Build Coastguard Worker   for (SchedulingNode* predecessor : scheduling_node->GetOtherPredecessors()) {
611*795d594fSAndroid Build Coastguard Worker     // Do not update the critical path.
612*795d594fSAndroid Build Coastguard Worker     // The 'other' (so 'non-data') dependencies (usually) do not represent a
613*795d594fSAndroid Build Coastguard Worker     // 'material' dependency of nodes on others. They exist for program
614*795d594fSAndroid Build Coastguard Worker     // correctness. So we do not use them to compute the critical path.
615*795d594fSAndroid Build Coastguard Worker     predecessor->DecrementNumberOfUnscheduledSuccessors();
616*795d594fSAndroid Build Coastguard Worker     if (!predecessor->HasUnscheduledSuccessors()) {
617*795d594fSAndroid Build Coastguard Worker       candidates->push_back(predecessor);
618*795d594fSAndroid Build Coastguard Worker     }
619*795d594fSAndroid Build Coastguard Worker   }
620*795d594fSAndroid Build Coastguard Worker 
621*795d594fSAndroid Build Coastguard Worker   Schedule(scheduling_node->GetInstruction());
622*795d594fSAndroid Build Coastguard Worker }
623*795d594fSAndroid Build Coastguard Worker 
624*795d594fSAndroid Build Coastguard Worker // Move an instruction after cursor instruction inside one basic block.
MoveAfterInBlock(HInstruction * instruction,HInstruction * cursor)625*795d594fSAndroid Build Coastguard Worker static void MoveAfterInBlock(HInstruction* instruction, HInstruction* cursor) {
626*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(instruction->GetBlock(), cursor->GetBlock());
627*795d594fSAndroid Build Coastguard Worker   DCHECK_NE(cursor, cursor->GetBlock()->GetLastInstruction());
628*795d594fSAndroid Build Coastguard Worker   DCHECK(!instruction->IsControlFlow());
629*795d594fSAndroid Build Coastguard Worker   DCHECK(!cursor->IsControlFlow());
630*795d594fSAndroid Build Coastguard Worker   instruction->MoveBefore(cursor->GetNext(), /* do_checks= */ false);
631*795d594fSAndroid Build Coastguard Worker }
632*795d594fSAndroid Build Coastguard Worker 
Schedule(HInstruction * instruction)633*795d594fSAndroid Build Coastguard Worker void HScheduler::Schedule(HInstruction* instruction) {
634*795d594fSAndroid Build Coastguard Worker   if (instruction == cursor_) {
635*795d594fSAndroid Build Coastguard Worker     cursor_ = cursor_->GetPrevious();
636*795d594fSAndroid Build Coastguard Worker   } else {
637*795d594fSAndroid Build Coastguard Worker     MoveAfterInBlock(instruction, cursor_);
638*795d594fSAndroid Build Coastguard Worker   }
639*795d594fSAndroid Build Coastguard Worker }
640*795d594fSAndroid Build Coastguard Worker 
IsSchedulable(const HInstruction * instruction) const641*795d594fSAndroid Build Coastguard Worker bool HScheduler::IsSchedulable(const HInstruction* instruction) const {
642*795d594fSAndroid Build Coastguard Worker   // We want to avoid exhaustively listing all instructions, so we first check
643*795d594fSAndroid Build Coastguard Worker   // for instruction categories that we know are safe.
644*795d594fSAndroid Build Coastguard Worker   if (instruction->IsControlFlow() ||
645*795d594fSAndroid Build Coastguard Worker       instruction->IsConstant()) {
646*795d594fSAndroid Build Coastguard Worker     return true;
647*795d594fSAndroid Build Coastguard Worker   }
648*795d594fSAndroid Build Coastguard Worker   // Currently all unary and binary operations are safe to schedule, so avoid
649*795d594fSAndroid Build Coastguard Worker   // checking for each of them individually.
650*795d594fSAndroid Build Coastguard Worker   // Since nothing prevents a new scheduling-unsafe HInstruction to subclass
651*795d594fSAndroid Build Coastguard Worker   // HUnaryOperation (or HBinaryOperation), check in debug mode that we have
652*795d594fSAndroid Build Coastguard Worker   // the exhaustive lists here.
653*795d594fSAndroid Build Coastguard Worker   if (instruction->IsUnaryOperation()) {
654*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction->IsAbs() ||
655*795d594fSAndroid Build Coastguard Worker            instruction->IsBooleanNot() ||
656*795d594fSAndroid Build Coastguard Worker            instruction->IsNot() ||
657*795d594fSAndroid Build Coastguard Worker            instruction->IsNeg()) << "unexpected instruction " << instruction->DebugName();
658*795d594fSAndroid Build Coastguard Worker     return true;
659*795d594fSAndroid Build Coastguard Worker   }
660*795d594fSAndroid Build Coastguard Worker   if (instruction->IsBinaryOperation()) {
661*795d594fSAndroid Build Coastguard Worker     DCHECK(instruction->IsAdd() ||
662*795d594fSAndroid Build Coastguard Worker            instruction->IsAnd() ||
663*795d594fSAndroid Build Coastguard Worker            instruction->IsCompare() ||
664*795d594fSAndroid Build Coastguard Worker            instruction->IsCondition() ||
665*795d594fSAndroid Build Coastguard Worker            instruction->IsDiv() ||
666*795d594fSAndroid Build Coastguard Worker            instruction->IsMin() ||
667*795d594fSAndroid Build Coastguard Worker            instruction->IsMax() ||
668*795d594fSAndroid Build Coastguard Worker            instruction->IsMul() ||
669*795d594fSAndroid Build Coastguard Worker            instruction->IsOr() ||
670*795d594fSAndroid Build Coastguard Worker            instruction->IsRem() ||
671*795d594fSAndroid Build Coastguard Worker            instruction->IsRor() ||
672*795d594fSAndroid Build Coastguard Worker            instruction->IsShl() ||
673*795d594fSAndroid Build Coastguard Worker            instruction->IsShr() ||
674*795d594fSAndroid Build Coastguard Worker            instruction->IsSub() ||
675*795d594fSAndroid Build Coastguard Worker            instruction->IsUShr() ||
676*795d594fSAndroid Build Coastguard Worker            instruction->IsXor()) << "unexpected instruction " << instruction->DebugName();
677*795d594fSAndroid Build Coastguard Worker     return true;
678*795d594fSAndroid Build Coastguard Worker   }
679*795d594fSAndroid Build Coastguard Worker   // The scheduler should not see any of these.
680*795d594fSAndroid Build Coastguard Worker   DCHECK(!instruction->IsParallelMove()) << "unexpected instruction " << instruction->DebugName();
681*795d594fSAndroid Build Coastguard Worker   // List of instructions explicitly excluded:
682*795d594fSAndroid Build Coastguard Worker   //    HClearException
683*795d594fSAndroid Build Coastguard Worker   //    HClinitCheck
684*795d594fSAndroid Build Coastguard Worker   //    HDeoptimize
685*795d594fSAndroid Build Coastguard Worker   //    HLoadClass
686*795d594fSAndroid Build Coastguard Worker   //    HLoadException
687*795d594fSAndroid Build Coastguard Worker   //    HMemoryBarrier
688*795d594fSAndroid Build Coastguard Worker   //    HMonitorOperation
689*795d594fSAndroid Build Coastguard Worker   //    HNop
690*795d594fSAndroid Build Coastguard Worker   //    HThrow
691*795d594fSAndroid Build Coastguard Worker   //    HTryBoundary
692*795d594fSAndroid Build Coastguard Worker   //    All unresolved field access instructions
693*795d594fSAndroid Build Coastguard Worker   //    All volatile field access instructions, e.g. HInstanceFieldGet
694*795d594fSAndroid Build Coastguard Worker   // TODO: Some of the instructions above may be safe to schedule (maybe as
695*795d594fSAndroid Build Coastguard Worker   // scheduling barriers).
696*795d594fSAndroid Build Coastguard Worker   return instruction->IsArrayGet() ||
697*795d594fSAndroid Build Coastguard Worker          instruction->IsArraySet() ||
698*795d594fSAndroid Build Coastguard Worker          instruction->IsArrayLength() ||
699*795d594fSAndroid Build Coastguard Worker          instruction->IsBoundType() ||
700*795d594fSAndroid Build Coastguard Worker          instruction->IsBoundsCheck() ||
701*795d594fSAndroid Build Coastguard Worker          instruction->IsCheckCast() ||
702*795d594fSAndroid Build Coastguard Worker          instruction->IsClassTableGet() ||
703*795d594fSAndroid Build Coastguard Worker          instruction->IsCurrentMethod() ||
704*795d594fSAndroid Build Coastguard Worker          instruction->IsDivZeroCheck() ||
705*795d594fSAndroid Build Coastguard Worker          (instruction->IsInstanceFieldGet() && !instruction->AsInstanceFieldGet()->IsVolatile()) ||
706*795d594fSAndroid Build Coastguard Worker          (instruction->IsInstanceFieldSet() && !instruction->AsInstanceFieldSet()->IsVolatile()) ||
707*795d594fSAndroid Build Coastguard Worker          instruction->IsInstanceOf() ||
708*795d594fSAndroid Build Coastguard Worker          instruction->IsInvokeInterface() ||
709*795d594fSAndroid Build Coastguard Worker          instruction->IsInvokeStaticOrDirect() ||
710*795d594fSAndroid Build Coastguard Worker          instruction->IsInvokeUnresolved() ||
711*795d594fSAndroid Build Coastguard Worker          instruction->IsInvokeVirtual() ||
712*795d594fSAndroid Build Coastguard Worker          instruction->IsLoadString() ||
713*795d594fSAndroid Build Coastguard Worker          instruction->IsNewArray() ||
714*795d594fSAndroid Build Coastguard Worker          instruction->IsNewInstance() ||
715*795d594fSAndroid Build Coastguard Worker          instruction->IsNullCheck() ||
716*795d594fSAndroid Build Coastguard Worker          instruction->IsPackedSwitch() ||
717*795d594fSAndroid Build Coastguard Worker          instruction->IsParameterValue() ||
718*795d594fSAndroid Build Coastguard Worker          instruction->IsPhi() ||
719*795d594fSAndroid Build Coastguard Worker          instruction->IsReturn() ||
720*795d594fSAndroid Build Coastguard Worker          instruction->IsReturnVoid() ||
721*795d594fSAndroid Build Coastguard Worker          instruction->IsSelect() ||
722*795d594fSAndroid Build Coastguard Worker          (instruction->IsStaticFieldGet() && !instruction->AsStaticFieldGet()->IsVolatile()) ||
723*795d594fSAndroid Build Coastguard Worker          (instruction->IsStaticFieldSet() && !instruction->AsStaticFieldSet()->IsVolatile()) ||
724*795d594fSAndroid Build Coastguard Worker          instruction->IsSuspendCheck() ||
725*795d594fSAndroid Build Coastguard Worker          instruction->IsTypeConversion();
726*795d594fSAndroid Build Coastguard Worker }
727*795d594fSAndroid Build Coastguard Worker 
IsSchedulable(const HBasicBlock * block) const728*795d594fSAndroid Build Coastguard Worker bool HScheduler::IsSchedulable(const HBasicBlock* block) const {
729*795d594fSAndroid Build Coastguard Worker   // We may be only interested in loop blocks.
730*795d594fSAndroid Build Coastguard Worker   if (only_optimize_loop_blocks_ && !block->IsInLoop()) {
731*795d594fSAndroid Build Coastguard Worker     return false;
732*795d594fSAndroid Build Coastguard Worker   }
733*795d594fSAndroid Build Coastguard Worker   if (block->GetTryCatchInformation() != nullptr) {
734*795d594fSAndroid Build Coastguard Worker     // Do not schedule blocks that are part of try-catch.
735*795d594fSAndroid Build Coastguard Worker     // Because scheduler cannot see if catch block has assumptions on the instruction order in
736*795d594fSAndroid Build Coastguard Worker     // the try block. In following example, if we enable scheduler for the try block,
737*795d594fSAndroid Build Coastguard Worker     // MulitiplyAccumulate may be scheduled before DivZeroCheck,
738*795d594fSAndroid Build Coastguard Worker     // which can result in an incorrect value in the catch block.
739*795d594fSAndroid Build Coastguard Worker     //   try {
740*795d594fSAndroid Build Coastguard Worker     //     a = a/b;    // DivZeroCheck
741*795d594fSAndroid Build Coastguard Worker     //                 // Div
742*795d594fSAndroid Build Coastguard Worker     //     c = c*d+e;  // MulitiplyAccumulate
743*795d594fSAndroid Build Coastguard Worker     //   } catch {System.out.print(c); }
744*795d594fSAndroid Build Coastguard Worker     return false;
745*795d594fSAndroid Build Coastguard Worker   }
746*795d594fSAndroid Build Coastguard Worker   // Check whether all instructions in this block are schedulable.
747*795d594fSAndroid Build Coastguard Worker   for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
748*795d594fSAndroid Build Coastguard Worker     if (!IsSchedulable(it.Current())) {
749*795d594fSAndroid Build Coastguard Worker       return false;
750*795d594fSAndroid Build Coastguard Worker     }
751*795d594fSAndroid Build Coastguard Worker   }
752*795d594fSAndroid Build Coastguard Worker   return true;
753*795d594fSAndroid Build Coastguard Worker }
754*795d594fSAndroid Build Coastguard Worker 
IsSchedulingBarrier(const HInstruction * instr) const755*795d594fSAndroid Build Coastguard Worker bool HScheduler::IsSchedulingBarrier(const HInstruction* instr) const {
756*795d594fSAndroid Build Coastguard Worker   return instr->IsControlFlow() ||
757*795d594fSAndroid Build Coastguard Worker       // Don't break calling convention.
758*795d594fSAndroid Build Coastguard Worker       instr->IsParameterValue() ||
759*795d594fSAndroid Build Coastguard Worker       // Code generation of goto relies on SuspendCheck's position.
760*795d594fSAndroid Build Coastguard Worker       instr->IsSuspendCheck();
761*795d594fSAndroid Build Coastguard Worker }
762*795d594fSAndroid Build Coastguard Worker 
Run(bool only_optimize_loop_blocks,bool schedule_randomly)763*795d594fSAndroid Build Coastguard Worker bool HInstructionScheduling::Run(bool only_optimize_loop_blocks,
764*795d594fSAndroid Build Coastguard Worker                                  bool schedule_randomly) {
765*795d594fSAndroid Build Coastguard Worker #if defined(ART_ENABLE_CODEGEN_arm64) || defined(ART_ENABLE_CODEGEN_arm)
766*795d594fSAndroid Build Coastguard Worker   // Phase-local allocator that allocates scheduler internal data structures like
767*795d594fSAndroid Build Coastguard Worker   // scheduling nodes, internel nodes map, dependencies, etc.
768*795d594fSAndroid Build Coastguard Worker   CriticalPathSchedulingNodeSelector critical_path_selector;
769*795d594fSAndroid Build Coastguard Worker   // Do not create the `RandomSchedulingNodeSelector` if not requested.
770*795d594fSAndroid Build Coastguard Worker   // The construction is expensive, including a call to `srand()`.
771*795d594fSAndroid Build Coastguard Worker   std::optional<RandomSchedulingNodeSelector> random_selector;
772*795d594fSAndroid Build Coastguard Worker   SchedulingNodeSelector* selector = &critical_path_selector;
773*795d594fSAndroid Build Coastguard Worker   if (schedule_randomly) {
774*795d594fSAndroid Build Coastguard Worker     random_selector.emplace();
775*795d594fSAndroid Build Coastguard Worker     selector = &random_selector.value();
776*795d594fSAndroid Build Coastguard Worker   }
777*795d594fSAndroid Build Coastguard Worker #else
778*795d594fSAndroid Build Coastguard Worker   // Avoid compilation error when compiling for unsupported instruction set.
779*795d594fSAndroid Build Coastguard Worker   UNUSED(only_optimize_loop_blocks);
780*795d594fSAndroid Build Coastguard Worker   UNUSED(schedule_randomly);
781*795d594fSAndroid Build Coastguard Worker   UNUSED(codegen_);
782*795d594fSAndroid Build Coastguard Worker #endif
783*795d594fSAndroid Build Coastguard Worker 
784*795d594fSAndroid Build Coastguard Worker   switch (instruction_set_) {
785*795d594fSAndroid Build Coastguard Worker #ifdef ART_ENABLE_CODEGEN_arm64
786*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm64: {
787*795d594fSAndroid Build Coastguard Worker       arm64::HSchedulerARM64 scheduler(selector);
788*795d594fSAndroid Build Coastguard Worker       scheduler.SetOnlyOptimizeLoopBlocks(only_optimize_loop_blocks);
789*795d594fSAndroid Build Coastguard Worker       scheduler.Schedule(graph_);
790*795d594fSAndroid Build Coastguard Worker       break;
791*795d594fSAndroid Build Coastguard Worker     }
792*795d594fSAndroid Build Coastguard Worker #endif
793*795d594fSAndroid Build Coastguard Worker #if defined(ART_ENABLE_CODEGEN_arm)
794*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kThumb2:
795*795d594fSAndroid Build Coastguard Worker     case InstructionSet::kArm: {
796*795d594fSAndroid Build Coastguard Worker       arm::HSchedulerARM scheduler(selector, codegen_);
797*795d594fSAndroid Build Coastguard Worker       scheduler.SetOnlyOptimizeLoopBlocks(only_optimize_loop_blocks);
798*795d594fSAndroid Build Coastguard Worker       scheduler.Schedule(graph_);
799*795d594fSAndroid Build Coastguard Worker       break;
800*795d594fSAndroid Build Coastguard Worker     }
801*795d594fSAndroid Build Coastguard Worker #endif
802*795d594fSAndroid Build Coastguard Worker     default:
803*795d594fSAndroid Build Coastguard Worker       break;
804*795d594fSAndroid Build Coastguard Worker   }
805*795d594fSAndroid Build Coastguard Worker   return true;
806*795d594fSAndroid Build Coastguard Worker }
807*795d594fSAndroid Build Coastguard Worker 
808*795d594fSAndroid Build Coastguard Worker }  // namespace art
809