xref: /aosp_15_r20/art/compiler/optimizing/scheduler.h (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 #ifndef ART_COMPILER_OPTIMIZING_SCHEDULER_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_COMPILER_OPTIMIZING_SCHEDULER_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <fstream>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_allocator.h"
24*795d594fSAndroid Build Coastguard Worker #include "base/scoped_arena_containers.h"
25*795d594fSAndroid Build Coastguard Worker #include "base/stl_util.h"
26*795d594fSAndroid Build Coastguard Worker #include "base/time_utils.h"
27*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
28*795d594fSAndroid Build Coastguard Worker #include "load_store_analysis.h"
29*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
30*795d594fSAndroid Build Coastguard Worker #include "optimization.h"
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker // General description of instruction scheduling.
35*795d594fSAndroid Build Coastguard Worker //
36*795d594fSAndroid Build Coastguard Worker // This pass tries to improve the quality of the generated code by reordering
37*795d594fSAndroid Build Coastguard Worker // instructions in the graph to avoid execution delays caused by execution
38*795d594fSAndroid Build Coastguard Worker // dependencies.
39*795d594fSAndroid Build Coastguard Worker // Currently, scheduling is performed at the block level, so no `HInstruction`
40*795d594fSAndroid Build Coastguard Worker // ever leaves its block in this pass.
41*795d594fSAndroid Build Coastguard Worker //
42*795d594fSAndroid Build Coastguard Worker // The scheduling process iterates through blocks in the graph. For blocks that
43*795d594fSAndroid Build Coastguard Worker // we can and want to schedule:
44*795d594fSAndroid Build Coastguard Worker // 1) Build a dependency graph for instructions.
45*795d594fSAndroid Build Coastguard Worker //    It includes data dependencies (inputs/uses), but also environment
46*795d594fSAndroid Build Coastguard Worker //    dependencies and side-effect dependencies.
47*795d594fSAndroid Build Coastguard Worker // 2) Schedule the dependency graph.
48*795d594fSAndroid Build Coastguard Worker //    This is a topological sort of the dependency graph, using heuristics to
49*795d594fSAndroid Build Coastguard Worker //    decide what node to scheduler first when there are multiple candidates.
50*795d594fSAndroid Build Coastguard Worker //
51*795d594fSAndroid Build Coastguard Worker // A few factors impacting the quality of the scheduling are:
52*795d594fSAndroid Build Coastguard Worker // - The heuristics used to decide what node to schedule in the topological sort
53*795d594fSAndroid Build Coastguard Worker //   when there are multiple valid candidates. There is a wide range of
54*795d594fSAndroid Build Coastguard Worker //   complexity possible here, going from a simple model only considering
55*795d594fSAndroid Build Coastguard Worker //   latencies, to a super detailed CPU pipeline model.
56*795d594fSAndroid Build Coastguard Worker // - Fewer dependencies in the dependency graph give more freedom for the
57*795d594fSAndroid Build Coastguard Worker //   scheduling heuristics. For example de-aliasing can allow possibilities for
58*795d594fSAndroid Build Coastguard Worker //   reordering of memory accesses.
59*795d594fSAndroid Build Coastguard Worker // - The level of abstraction of the IR. It is easier to evaluate scheduling for
60*795d594fSAndroid Build Coastguard Worker //   IRs that translate to a single assembly instruction than for IRs
61*795d594fSAndroid Build Coastguard Worker //   that generate multiple assembly instructions or generate different code
62*795d594fSAndroid Build Coastguard Worker //   depending on properties of the IR.
63*795d594fSAndroid Build Coastguard Worker // - Scheduling is performed before register allocation, it is not aware of the
64*795d594fSAndroid Build Coastguard Worker //   impact of moving instructions on register allocation.
65*795d594fSAndroid Build Coastguard Worker //
66*795d594fSAndroid Build Coastguard Worker //
67*795d594fSAndroid Build Coastguard Worker // The scheduling code uses the terms predecessors, successors, and dependencies.
68*795d594fSAndroid Build Coastguard Worker // This can be confusing at times, so here are clarifications.
69*795d594fSAndroid Build Coastguard Worker // These terms are used from the point of view of the program dependency graph. So
70*795d594fSAndroid Build Coastguard Worker // the inputs of an instruction are part of its dependencies, and hence part its
71*795d594fSAndroid Build Coastguard Worker // predecessors. So the uses of an instruction are (part of) its successors.
72*795d594fSAndroid Build Coastguard Worker // (Side-effect dependencies can yield predecessors or successors that are not
73*795d594fSAndroid Build Coastguard Worker // inputs or uses.)
74*795d594fSAndroid Build Coastguard Worker //
75*795d594fSAndroid Build Coastguard Worker // Here is a trivial example. For the Java code:
76*795d594fSAndroid Build Coastguard Worker //
77*795d594fSAndroid Build Coastguard Worker //    int a = 1 + 2;
78*795d594fSAndroid Build Coastguard Worker //
79*795d594fSAndroid Build Coastguard Worker // we would have the instructions
80*795d594fSAndroid Build Coastguard Worker //
81*795d594fSAndroid Build Coastguard Worker //    i1 HIntConstant 1
82*795d594fSAndroid Build Coastguard Worker //    i2 HIntConstant 2
83*795d594fSAndroid Build Coastguard Worker //    i3 HAdd [i1,i2]
84*795d594fSAndroid Build Coastguard Worker //
85*795d594fSAndroid Build Coastguard Worker // `i1` and `i2` are predecessors of `i3`.
86*795d594fSAndroid Build Coastguard Worker // `i3` is a successor of `i1` and a successor of `i2`.
87*795d594fSAndroid Build Coastguard Worker // In a scheduling graph for this code we would have three nodes `n1`, `n2`,
88*795d594fSAndroid Build Coastguard Worker // and `n3` (respectively for instructions `i1`, `i1`, and `i3`).
89*795d594fSAndroid Build Coastguard Worker // Conceptually the program dependency graph for this would contain two edges
90*795d594fSAndroid Build Coastguard Worker //
91*795d594fSAndroid Build Coastguard Worker //    n1 -> n3
92*795d594fSAndroid Build Coastguard Worker //    n2 -> n3
93*795d594fSAndroid Build Coastguard Worker //
94*795d594fSAndroid Build Coastguard Worker // Since we schedule backwards (starting from the last instruction in each basic
95*795d594fSAndroid Build Coastguard Worker // block), the implementation of nodes keeps a list of pointers their
96*795d594fSAndroid Build Coastguard Worker // predecessors. So `n3` would keep pointers to its predecessors `n1` and `n2`.
97*795d594fSAndroid Build Coastguard Worker //
98*795d594fSAndroid Build Coastguard Worker // Node dependencies are also referred to from the program dependency graph
99*795d594fSAndroid Build Coastguard Worker // point of view: we say that node `B` immediately depends on `A` if there is an
100*795d594fSAndroid Build Coastguard Worker // edge from `A` to `B` in the program dependency graph. `A` is a predecessor of
101*795d594fSAndroid Build Coastguard Worker // `B`, `B` is a successor of `A`. In the example above `n3` depends on `n1` and
102*795d594fSAndroid Build Coastguard Worker // `n2`.
103*795d594fSAndroid Build Coastguard Worker // Since nodes in the scheduling graph keep a list of their predecessors, node
104*795d594fSAndroid Build Coastguard Worker // `B` will have a pointer to its predecessor `A`.
105*795d594fSAndroid Build Coastguard Worker // As we schedule backwards, `B` will be selected for scheduling before `A` is.
106*795d594fSAndroid Build Coastguard Worker //
107*795d594fSAndroid Build Coastguard Worker // So the scheduling for the example above could happen as follow
108*795d594fSAndroid Build Coastguard Worker //
109*795d594fSAndroid Build Coastguard Worker //    |---------------------------+------------------------|
110*795d594fSAndroid Build Coastguard Worker //    | candidates for scheduling | instructions scheduled |
111*795d594fSAndroid Build Coastguard Worker //    | --------------------------+------------------------|
112*795d594fSAndroid Build Coastguard Worker //
113*795d594fSAndroid Build Coastguard Worker // The only node without successors is `n3`, so it is the only initial
114*795d594fSAndroid Build Coastguard Worker // candidate.
115*795d594fSAndroid Build Coastguard Worker //
116*795d594fSAndroid Build Coastguard Worker //    | n3                        | (none)                 |
117*795d594fSAndroid Build Coastguard Worker //
118*795d594fSAndroid Build Coastguard Worker // We schedule `n3` as the last (and only) instruction. All its predecessors
119*795d594fSAndroid Build Coastguard Worker // that do not have any unscheduled successors become candidate. That is, `n1`
120*795d594fSAndroid Build Coastguard Worker // and `n2` become candidates.
121*795d594fSAndroid Build Coastguard Worker //
122*795d594fSAndroid Build Coastguard Worker //    | n1, n2                    | n3                     |
123*795d594fSAndroid Build Coastguard Worker //
124*795d594fSAndroid Build Coastguard Worker // One of the candidates is selected. In practice this is where scheduling
125*795d594fSAndroid Build Coastguard Worker // heuristics kick in, to decide which of the candidates should be selected.
126*795d594fSAndroid Build Coastguard Worker // In this example, let it be `n1`. It is scheduled before previously scheduled
127*795d594fSAndroid Build Coastguard Worker // nodes (in program order). There are no other nodes to add to the list of
128*795d594fSAndroid Build Coastguard Worker // candidates.
129*795d594fSAndroid Build Coastguard Worker //
130*795d594fSAndroid Build Coastguard Worker //    | n2                        | n1                     |
131*795d594fSAndroid Build Coastguard Worker //    |                           | n3                     |
132*795d594fSAndroid Build Coastguard Worker //
133*795d594fSAndroid Build Coastguard Worker // The only candidate available for scheduling is `n2`. Schedule it before
134*795d594fSAndroid Build Coastguard Worker // (in program order) the previously scheduled nodes.
135*795d594fSAndroid Build Coastguard Worker //
136*795d594fSAndroid Build Coastguard Worker //    | (none)                    | n2                     |
137*795d594fSAndroid Build Coastguard Worker //    |                           | n1                     |
138*795d594fSAndroid Build Coastguard Worker //    |                           | n3                     |
139*795d594fSAndroid Build Coastguard Worker //    |---------------------------+------------------------|
140*795d594fSAndroid Build Coastguard Worker //
141*795d594fSAndroid Build Coastguard Worker // So finally the instructions will be executed in the order `i2`, `i1`, and `i3`.
142*795d594fSAndroid Build Coastguard Worker // In this trivial example, it does not matter which of `i1` and `i2` is
143*795d594fSAndroid Build Coastguard Worker // scheduled first since they are constants. However the same process would
144*795d594fSAndroid Build Coastguard Worker // apply if `i1` and `i2` were actual operations (for example `HMul` and `HDiv`).
145*795d594fSAndroid Build Coastguard Worker 
146*795d594fSAndroid Build Coastguard Worker // Set to true to have instruction scheduling dump scheduling graphs to the file
147*795d594fSAndroid Build Coastguard Worker // `scheduling_graphs.dot`. See `SchedulingGraph::DumpAsDotGraph()`.
148*795d594fSAndroid Build Coastguard Worker static constexpr bool kDumpDotSchedulingGraphs = false;
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker // Typically used as a default instruction latency.
151*795d594fSAndroid Build Coastguard Worker static constexpr uint32_t kGenericInstructionLatency = 1;
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker class HScheduler;
154*795d594fSAndroid Build Coastguard Worker 
155*795d594fSAndroid Build Coastguard Worker /**
156*795d594fSAndroid Build Coastguard Worker  * A node representing an `HInstruction` in the `SchedulingGraph`.
157*795d594fSAndroid Build Coastguard Worker  */
158*795d594fSAndroid Build Coastguard Worker class SchedulingNode : public DeletableArenaObject<kArenaAllocScheduler> {
159*795d594fSAndroid Build Coastguard Worker  public:
SchedulingNode(HInstruction * instr,ScopedArenaAllocator * allocator,bool is_scheduling_barrier)160*795d594fSAndroid Build Coastguard Worker   SchedulingNode(HInstruction* instr, ScopedArenaAllocator* allocator, bool is_scheduling_barrier)
161*795d594fSAndroid Build Coastguard Worker       : latency_(0),
162*795d594fSAndroid Build Coastguard Worker         internal_latency_(0),
163*795d594fSAndroid Build Coastguard Worker         critical_path_(0),
164*795d594fSAndroid Build Coastguard Worker         instruction_(instr),
165*795d594fSAndroid Build Coastguard Worker         is_scheduling_barrier_(is_scheduling_barrier),
166*795d594fSAndroid Build Coastguard Worker         data_predecessors_(allocator->Adapter(kArenaAllocScheduler)),
167*795d594fSAndroid Build Coastguard Worker         other_predecessors_(allocator->Adapter(kArenaAllocScheduler)),
168*795d594fSAndroid Build Coastguard Worker         num_unscheduled_successors_(0) {
169*795d594fSAndroid Build Coastguard Worker     data_predecessors_.reserve(kPreallocatedPredecessors);
170*795d594fSAndroid Build Coastguard Worker   }
171*795d594fSAndroid Build Coastguard Worker 
AddDataPredecessor(SchedulingNode * predecessor)172*795d594fSAndroid Build Coastguard Worker   void AddDataPredecessor(SchedulingNode* predecessor) {
173*795d594fSAndroid Build Coastguard Worker     // Check whether the predecessor has been added earlier.
174*795d594fSAndroid Build Coastguard Worker     if (HasDataDependency(predecessor)) {
175*795d594fSAndroid Build Coastguard Worker       return;
176*795d594fSAndroid Build Coastguard Worker     }
177*795d594fSAndroid Build Coastguard Worker     data_predecessors_.push_back(predecessor);
178*795d594fSAndroid Build Coastguard Worker     predecessor->num_unscheduled_successors_++;
179*795d594fSAndroid Build Coastguard Worker   }
180*795d594fSAndroid Build Coastguard Worker 
GetDataPredecessors()181*795d594fSAndroid Build Coastguard Worker   const ScopedArenaVector<SchedulingNode*>& GetDataPredecessors() const {
182*795d594fSAndroid Build Coastguard Worker     return data_predecessors_;
183*795d594fSAndroid Build Coastguard Worker   }
184*795d594fSAndroid Build Coastguard Worker 
AddOtherPredecessor(SchedulingNode * predecessor)185*795d594fSAndroid Build Coastguard Worker   void AddOtherPredecessor(SchedulingNode* predecessor) {
186*795d594fSAndroid Build Coastguard Worker     // Check whether the predecessor has been added earlier.
187*795d594fSAndroid Build Coastguard Worker     // As an optimization of the scheduling graph, we don't need to create another dependency if
188*795d594fSAndroid Build Coastguard Worker     // there is a data dependency between scheduling nodes.
189*795d594fSAndroid Build Coastguard Worker     if (HasOtherDependency(predecessor) || HasDataDependency(predecessor)) {
190*795d594fSAndroid Build Coastguard Worker       return;
191*795d594fSAndroid Build Coastguard Worker     }
192*795d594fSAndroid Build Coastguard Worker     other_predecessors_.push_back(predecessor);
193*795d594fSAndroid Build Coastguard Worker     predecessor->num_unscheduled_successors_++;
194*795d594fSAndroid Build Coastguard Worker   }
195*795d594fSAndroid Build Coastguard Worker 
GetOtherPredecessors()196*795d594fSAndroid Build Coastguard Worker   const ScopedArenaVector<SchedulingNode*>& GetOtherPredecessors() const {
197*795d594fSAndroid Build Coastguard Worker     return other_predecessors_;
198*795d594fSAndroid Build Coastguard Worker   }
199*795d594fSAndroid Build Coastguard Worker 
DecrementNumberOfUnscheduledSuccessors()200*795d594fSAndroid Build Coastguard Worker   void DecrementNumberOfUnscheduledSuccessors() {
201*795d594fSAndroid Build Coastguard Worker     num_unscheduled_successors_--;
202*795d594fSAndroid Build Coastguard Worker   }
203*795d594fSAndroid Build Coastguard Worker 
MaybeUpdateCriticalPath(uint32_t other_critical_path)204*795d594fSAndroid Build Coastguard Worker   void MaybeUpdateCriticalPath(uint32_t other_critical_path) {
205*795d594fSAndroid Build Coastguard Worker     critical_path_ = std::max(critical_path_, other_critical_path);
206*795d594fSAndroid Build Coastguard Worker   }
207*795d594fSAndroid Build Coastguard Worker 
HasUnscheduledSuccessors()208*795d594fSAndroid Build Coastguard Worker   bool HasUnscheduledSuccessors() const {
209*795d594fSAndroid Build Coastguard Worker     return num_unscheduled_successors_ != 0;
210*795d594fSAndroid Build Coastguard Worker   }
211*795d594fSAndroid Build Coastguard Worker 
GetInstruction()212*795d594fSAndroid Build Coastguard Worker   HInstruction* GetInstruction() const { return instruction_; }
GetLatency()213*795d594fSAndroid Build Coastguard Worker   uint32_t GetLatency() const { return latency_; }
SetLatency(uint32_t latency)214*795d594fSAndroid Build Coastguard Worker   void SetLatency(uint32_t latency) { latency_ = latency; }
GetInternalLatency()215*795d594fSAndroid Build Coastguard Worker   uint32_t GetInternalLatency() const { return internal_latency_; }
SetInternalLatency(uint32_t internal_latency)216*795d594fSAndroid Build Coastguard Worker   void SetInternalLatency(uint32_t internal_latency) { internal_latency_ = internal_latency; }
GetCriticalPath()217*795d594fSAndroid Build Coastguard Worker   uint32_t GetCriticalPath() const { return critical_path_; }
IsSchedulingBarrier()218*795d594fSAndroid Build Coastguard Worker   bool IsSchedulingBarrier() const { return is_scheduling_barrier_; }
219*795d594fSAndroid Build Coastguard Worker 
HasDataDependency(const SchedulingNode * node)220*795d594fSAndroid Build Coastguard Worker   bool HasDataDependency(const SchedulingNode* node) const {
221*795d594fSAndroid Build Coastguard Worker     return ContainsElement(data_predecessors_, node);
222*795d594fSAndroid Build Coastguard Worker   }
223*795d594fSAndroid Build Coastguard Worker 
HasOtherDependency(const SchedulingNode * node)224*795d594fSAndroid Build Coastguard Worker   bool HasOtherDependency(const SchedulingNode* node) const {
225*795d594fSAndroid Build Coastguard Worker     return ContainsElement(other_predecessors_, node);
226*795d594fSAndroid Build Coastguard Worker   }
227*795d594fSAndroid Build Coastguard Worker 
228*795d594fSAndroid Build Coastguard Worker  private:
229*795d594fSAndroid Build Coastguard Worker   // The latency of this node. It represents the latency between the moment the
230*795d594fSAndroid Build Coastguard Worker   // last instruction for this node has executed to the moment the result
231*795d594fSAndroid Build Coastguard Worker   // produced by this node is available to users.
232*795d594fSAndroid Build Coastguard Worker   uint32_t latency_;
233*795d594fSAndroid Build Coastguard Worker   // This represents the time spent *within* the generated code for this node.
234*795d594fSAndroid Build Coastguard Worker   // It should be zero for nodes that only generate a single instruction.
235*795d594fSAndroid Build Coastguard Worker   uint32_t internal_latency_;
236*795d594fSAndroid Build Coastguard Worker 
237*795d594fSAndroid Build Coastguard Worker   // The critical path from this instruction to the end of scheduling. It is
238*795d594fSAndroid Build Coastguard Worker   // used by the scheduling heuristics to measure the priority of this instruction.
239*795d594fSAndroid Build Coastguard Worker   // It is defined as
240*795d594fSAndroid Build Coastguard Worker   //     critical_path_ = latency_ + max((use.internal_latency_ + use.critical_path_) for all uses)
241*795d594fSAndroid Build Coastguard Worker   // (Note that here 'uses' is equivalent to 'data successors'. Also see comments in
242*795d594fSAndroid Build Coastguard Worker   // `HScheduler::Schedule(SchedulingNode* scheduling_node)`).
243*795d594fSAndroid Build Coastguard Worker   uint32_t critical_path_;
244*795d594fSAndroid Build Coastguard Worker 
245*795d594fSAndroid Build Coastguard Worker   // The instruction that this node represents.
246*795d594fSAndroid Build Coastguard Worker   HInstruction* const instruction_;
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker   // If a node is scheduling barrier, other nodes cannot be scheduled before it.
249*795d594fSAndroid Build Coastguard Worker   const bool is_scheduling_barrier_;
250*795d594fSAndroid Build Coastguard Worker 
251*795d594fSAndroid Build Coastguard Worker   // The lists of predecessors. They cannot be scheduled before this node. Once
252*795d594fSAndroid Build Coastguard Worker   // this node is scheduled, we check whether any of its predecessors has become a
253*795d594fSAndroid Build Coastguard Worker   // valid candidate for scheduling.
254*795d594fSAndroid Build Coastguard Worker   // Predecessors in `data_predecessors_` are data dependencies. Those in
255*795d594fSAndroid Build Coastguard Worker   // `other_predecessors_` contain side-effect dependencies, environment
256*795d594fSAndroid Build Coastguard Worker   // dependencies, and scheduling barrier dependencies.
257*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<SchedulingNode*> data_predecessors_;
258*795d594fSAndroid Build Coastguard Worker   ScopedArenaVector<SchedulingNode*> other_predecessors_;
259*795d594fSAndroid Build Coastguard Worker 
260*795d594fSAndroid Build Coastguard Worker   // The number of unscheduled successors for this node. This number is
261*795d594fSAndroid Build Coastguard Worker   // decremented as successors are scheduled. When it reaches zero this node
262*795d594fSAndroid Build Coastguard Worker   // becomes a valid candidate to schedule.
263*795d594fSAndroid Build Coastguard Worker   uint32_t num_unscheduled_successors_;
264*795d594fSAndroid Build Coastguard Worker 
265*795d594fSAndroid Build Coastguard Worker   static constexpr size_t kPreallocatedPredecessors = 4;
266*795d594fSAndroid Build Coastguard Worker };
267*795d594fSAndroid Build Coastguard Worker 
268*795d594fSAndroid Build Coastguard Worker /*
269*795d594fSAndroid Build Coastguard Worker  * Provide analysis of instruction dependencies (side effects) which are not in a form of explicit
270*795d594fSAndroid Build Coastguard Worker  * def-use data dependencies.
271*795d594fSAndroid Build Coastguard Worker  */
272*795d594fSAndroid Build Coastguard Worker class SideEffectDependencyAnalysis {
273*795d594fSAndroid Build Coastguard Worker  public:
SideEffectDependencyAnalysis(const HeapLocationCollector * heap_location_collector)274*795d594fSAndroid Build Coastguard Worker   explicit SideEffectDependencyAnalysis(const HeapLocationCollector* heap_location_collector)
275*795d594fSAndroid Build Coastguard Worker       : memory_dependency_analysis_(heap_location_collector) {}
276*795d594fSAndroid Build Coastguard Worker 
HasSideEffectDependency(HInstruction * instr1,HInstruction * instr2)277*795d594fSAndroid Build Coastguard Worker   bool HasSideEffectDependency(HInstruction* instr1, HInstruction* instr2) const {
278*795d594fSAndroid Build Coastguard Worker     if (memory_dependency_analysis_.HasMemoryDependency(instr1, instr2)) {
279*795d594fSAndroid Build Coastguard Worker       return true;
280*795d594fSAndroid Build Coastguard Worker     }
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker     // Even if above memory dependency check has passed, it is still necessary to
283*795d594fSAndroid Build Coastguard Worker     // check dependencies between instructions that can throw and instructions
284*795d594fSAndroid Build Coastguard Worker     // that write to memory.
285*795d594fSAndroid Build Coastguard Worker     if (HasExceptionDependency(instr1, instr2)) {
286*795d594fSAndroid Build Coastguard Worker       return true;
287*795d594fSAndroid Build Coastguard Worker     }
288*795d594fSAndroid Build Coastguard Worker 
289*795d594fSAndroid Build Coastguard Worker     return false;
290*795d594fSAndroid Build Coastguard Worker   }
291*795d594fSAndroid Build Coastguard Worker 
292*795d594fSAndroid Build Coastguard Worker  private:
293*795d594fSAndroid Build Coastguard Worker   static bool HasExceptionDependency(const HInstruction* instr1, const HInstruction* instr2);
294*795d594fSAndroid Build Coastguard Worker   static bool HasReorderingDependency(const HInstruction* instr1, const HInstruction* instr2);
295*795d594fSAndroid Build Coastguard Worker 
296*795d594fSAndroid Build Coastguard Worker   /*
297*795d594fSAndroid Build Coastguard Worker    * Memory dependency analysis of instructions based on their memory side effects
298*795d594fSAndroid Build Coastguard Worker    * and heap location information from the LCA pass if it is provided.
299*795d594fSAndroid Build Coastguard Worker    */
300*795d594fSAndroid Build Coastguard Worker   class MemoryDependencyAnalysis {
301*795d594fSAndroid Build Coastguard Worker    public:
MemoryDependencyAnalysis(const HeapLocationCollector * heap_location_collector)302*795d594fSAndroid Build Coastguard Worker     explicit MemoryDependencyAnalysis(const HeapLocationCollector* heap_location_collector)
303*795d594fSAndroid Build Coastguard Worker         : heap_location_collector_(heap_location_collector) {}
304*795d594fSAndroid Build Coastguard Worker 
305*795d594fSAndroid Build Coastguard Worker     bool HasMemoryDependency(HInstruction* instr1, HInstruction* instr2) const;
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker    private:
308*795d594fSAndroid Build Coastguard Worker     bool ArrayAccessMayAlias(HInstruction* instr1, HInstruction* instr2) const;
309*795d594fSAndroid Build Coastguard Worker     bool FieldAccessMayAlias(const HInstruction* instr1, const HInstruction* instr2) const;
310*795d594fSAndroid Build Coastguard Worker     size_t ArrayAccessHeapLocation(HInstruction* instruction) const;
311*795d594fSAndroid Build Coastguard Worker     size_t FieldAccessHeapLocation(const HInstruction* instruction) const;
312*795d594fSAndroid Build Coastguard Worker 
313*795d594fSAndroid Build Coastguard Worker     const HeapLocationCollector* const heap_location_collector_;
314*795d594fSAndroid Build Coastguard Worker   };
315*795d594fSAndroid Build Coastguard Worker 
316*795d594fSAndroid Build Coastguard Worker   MemoryDependencyAnalysis memory_dependency_analysis_;
317*795d594fSAndroid Build Coastguard Worker };
318*795d594fSAndroid Build Coastguard Worker 
319*795d594fSAndroid Build Coastguard Worker /*
320*795d594fSAndroid Build Coastguard Worker  * Directed acyclic graph for scheduling.
321*795d594fSAndroid Build Coastguard Worker  */
322*795d594fSAndroid Build Coastguard Worker class SchedulingGraph : public ValueObject {
323*795d594fSAndroid Build Coastguard Worker  public:
SchedulingGraph(ScopedArenaAllocator * allocator,const HeapLocationCollector * heap_location_collector)324*795d594fSAndroid Build Coastguard Worker   SchedulingGraph(ScopedArenaAllocator* allocator,
325*795d594fSAndroid Build Coastguard Worker                   const HeapLocationCollector* heap_location_collector)
326*795d594fSAndroid Build Coastguard Worker       : allocator_(allocator),
327*795d594fSAndroid Build Coastguard Worker         contains_scheduling_barrier_(false),
328*795d594fSAndroid Build Coastguard Worker         nodes_map_(allocator_->Adapter(kArenaAllocScheduler)),
329*795d594fSAndroid Build Coastguard Worker         side_effect_dependency_analysis_(heap_location_collector) {}
330*795d594fSAndroid Build Coastguard Worker 
331*795d594fSAndroid Build Coastguard Worker   SchedulingNode* AddNode(HInstruction* instr, bool is_scheduling_barrier = false) {
332*795d594fSAndroid Build Coastguard Worker     std::unique_ptr<SchedulingNode> node(
333*795d594fSAndroid Build Coastguard Worker         new (allocator_) SchedulingNode(instr, allocator_, is_scheduling_barrier));
334*795d594fSAndroid Build Coastguard Worker     SchedulingNode* result = node.get();
335*795d594fSAndroid Build Coastguard Worker     nodes_map_.insert(std::make_pair(instr, std::move(node)));
336*795d594fSAndroid Build Coastguard Worker     contains_scheduling_barrier_ |= is_scheduling_barrier;
337*795d594fSAndroid Build Coastguard Worker     AddDependencies(result, is_scheduling_barrier);
338*795d594fSAndroid Build Coastguard Worker     return result;
339*795d594fSAndroid Build Coastguard Worker   }
340*795d594fSAndroid Build Coastguard Worker 
GetNode(const HInstruction * instr)341*795d594fSAndroid Build Coastguard Worker   SchedulingNode* GetNode(const HInstruction* instr) const {
342*795d594fSAndroid Build Coastguard Worker     auto it = nodes_map_.find(instr);
343*795d594fSAndroid Build Coastguard Worker     if (it == nodes_map_.end()) {
344*795d594fSAndroid Build Coastguard Worker       return nullptr;
345*795d594fSAndroid Build Coastguard Worker     } else {
346*795d594fSAndroid Build Coastguard Worker       return it->second.get();
347*795d594fSAndroid Build Coastguard Worker     }
348*795d594fSAndroid Build Coastguard Worker   }
349*795d594fSAndroid Build Coastguard Worker 
Size()350*795d594fSAndroid Build Coastguard Worker   size_t Size() const {
351*795d594fSAndroid Build Coastguard Worker     return nodes_map_.size();
352*795d594fSAndroid Build Coastguard Worker   }
353*795d594fSAndroid Build Coastguard Worker 
354*795d594fSAndroid Build Coastguard Worker   // Dump the scheduling graph, in dot file format, appending it to the file
355*795d594fSAndroid Build Coastguard Worker   // `scheduling_graphs.dot`.
356*795d594fSAndroid Build Coastguard Worker   void DumpAsDotGraph(const std::string& description,
357*795d594fSAndroid Build Coastguard Worker                       const ScopedArenaVector<SchedulingNode*>& initial_candidates);
358*795d594fSAndroid Build Coastguard Worker 
359*795d594fSAndroid Build Coastguard Worker  protected:
360*795d594fSAndroid Build Coastguard Worker   void AddDependency(SchedulingNode* node, SchedulingNode* dependency, bool is_data_dependency);
AddDataDependency(SchedulingNode * node,SchedulingNode * dependency)361*795d594fSAndroid Build Coastguard Worker   void AddDataDependency(SchedulingNode* node, SchedulingNode* dependency) {
362*795d594fSAndroid Build Coastguard Worker     AddDependency(node, dependency, /*is_data_dependency*/true);
363*795d594fSAndroid Build Coastguard Worker   }
AddOtherDependency(SchedulingNode * node,SchedulingNode * dependency)364*795d594fSAndroid Build Coastguard Worker   void AddOtherDependency(SchedulingNode* node, SchedulingNode* dependency) {
365*795d594fSAndroid Build Coastguard Worker     AddDependency(node, dependency, /*is_data_dependency*/false);
366*795d594fSAndroid Build Coastguard Worker   }
367*795d594fSAndroid Build Coastguard Worker 
368*795d594fSAndroid Build Coastguard Worker   // Analyze whether the scheduling node has cross-iteration dependencies which mean it uses
369*795d594fSAndroid Build Coastguard Worker   // values defined on the previous iteration.
370*795d594fSAndroid Build Coastguard Worker   //
371*795d594fSAndroid Build Coastguard Worker   // Supported cases:
372*795d594fSAndroid Build Coastguard Worker   //
373*795d594fSAndroid Build Coastguard Worker   //   L:
374*795d594fSAndroid Build Coastguard Worker   //     v2 = loop_head_phi(v1)
375*795d594fSAndroid Build Coastguard Worker   //     instr1(v2)
376*795d594fSAndroid Build Coastguard Worker   //     v1 = instr2
377*795d594fSAndroid Build Coastguard Worker   //     goto L
378*795d594fSAndroid Build Coastguard Worker   //
379*795d594fSAndroid Build Coastguard Worker   // In such cases moving instr2 before instr1 creates intersecting live ranges
380*795d594fSAndroid Build Coastguard Worker   // of v1 and v2. As a result a separate register is needed to keep the value
381*795d594fSAndroid Build Coastguard Worker   // defined by instr2 which is only used on the next iteration.
382*795d594fSAndroid Build Coastguard Worker   // If instr2 is not moved, no additional register is needed. The register
383*795d594fSAndroid Build Coastguard Worker   // used by instr1 is reused.
384*795d594fSAndroid Build Coastguard Worker   // To prevent such a situation a "other" dependency between instr1 and instr2 must be set.
385*795d594fSAndroid Build Coastguard Worker   void AddCrossIterationDependencies(SchedulingNode* node);
386*795d594fSAndroid Build Coastguard Worker 
387*795d594fSAndroid Build Coastguard Worker   // Add dependencies nodes for the given `SchedulingNode`: inputs, environments, and side-effects.
388*795d594fSAndroid Build Coastguard Worker   void AddDependencies(SchedulingNode* node, bool is_scheduling_barrier = false);
389*795d594fSAndroid Build Coastguard Worker 
390*795d594fSAndroid Build Coastguard Worker   ScopedArenaAllocator* const allocator_;
391*795d594fSAndroid Build Coastguard Worker   bool contains_scheduling_barrier_;
392*795d594fSAndroid Build Coastguard Worker   ScopedArenaHashMap<const HInstruction*, std::unique_ptr<SchedulingNode>> nodes_map_;
393*795d594fSAndroid Build Coastguard Worker   SideEffectDependencyAnalysis side_effect_dependency_analysis_;
394*795d594fSAndroid Build Coastguard Worker };
395*795d594fSAndroid Build Coastguard Worker 
396*795d594fSAndroid Build Coastguard Worker /*
397*795d594fSAndroid Build Coastguard Worker  * The visitors derived from this base class are used by schedulers to evaluate
398*795d594fSAndroid Build Coastguard Worker  * the latencies of `HInstruction`s.
399*795d594fSAndroid Build Coastguard Worker  */
400*795d594fSAndroid Build Coastguard Worker class SchedulingLatencyVisitor : public HGraphDelegateVisitor {
401*795d594fSAndroid Build Coastguard Worker  public:
402*795d594fSAndroid Build Coastguard Worker   // This class and its sub-classes will never be used to drive a visit of an
403*795d594fSAndroid Build Coastguard Worker   // `HGraph` but only to visit `HInstructions` one at a time, so we do not need
404*795d594fSAndroid Build Coastguard Worker   // to pass a valid graph to `HGraphDelegateVisitor()`.
SchedulingLatencyVisitor()405*795d594fSAndroid Build Coastguard Worker   SchedulingLatencyVisitor()
406*795d594fSAndroid Build Coastguard Worker       : HGraphDelegateVisitor(nullptr),
407*795d594fSAndroid Build Coastguard Worker         last_visited_latency_(0),
408*795d594fSAndroid Build Coastguard Worker         last_visited_internal_latency_(0) {}
409*795d594fSAndroid Build Coastguard Worker 
VisitInstruction(HInstruction * instruction)410*795d594fSAndroid Build Coastguard Worker   void VisitInstruction(HInstruction* instruction) override {
411*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "Error visiting " << instruction->DebugName() << ". "
412*795d594fSAndroid Build Coastguard Worker         "Architecture-specific scheduling latency visitors must handle all instructions"
413*795d594fSAndroid Build Coastguard Worker         " (potentially by overriding the generic `VisitInstruction()`.";
414*795d594fSAndroid Build Coastguard Worker     UNREACHABLE();
415*795d594fSAndroid Build Coastguard Worker   }
416*795d594fSAndroid Build Coastguard Worker 
Visit(HInstruction * instruction)417*795d594fSAndroid Build Coastguard Worker   void Visit(HInstruction* instruction) {
418*795d594fSAndroid Build Coastguard Worker     instruction->Accept(this);
419*795d594fSAndroid Build Coastguard Worker   }
420*795d594fSAndroid Build Coastguard Worker 
CalculateLatency(SchedulingNode * node)421*795d594fSAndroid Build Coastguard Worker   void CalculateLatency(SchedulingNode* node) {
422*795d594fSAndroid Build Coastguard Worker     // By default nodes have no internal latency.
423*795d594fSAndroid Build Coastguard Worker     last_visited_internal_latency_ = 0;
424*795d594fSAndroid Build Coastguard Worker     Visit(node->GetInstruction());
425*795d594fSAndroid Build Coastguard Worker   }
426*795d594fSAndroid Build Coastguard Worker 
GetLastVisitedLatency()427*795d594fSAndroid Build Coastguard Worker   uint32_t GetLastVisitedLatency() const { return last_visited_latency_; }
GetLastVisitedInternalLatency()428*795d594fSAndroid Build Coastguard Worker   uint32_t GetLastVisitedInternalLatency() const { return last_visited_internal_latency_; }
429*795d594fSAndroid Build Coastguard Worker 
430*795d594fSAndroid Build Coastguard Worker  protected:
431*795d594fSAndroid Build Coastguard Worker   // The latency of the most recent visited SchedulingNode.
432*795d594fSAndroid Build Coastguard Worker   // This is for reporting the latency value to the user of this visitor.
433*795d594fSAndroid Build Coastguard Worker   uint32_t last_visited_latency_;
434*795d594fSAndroid Build Coastguard Worker   // This represents the time spent *within* the generated code for the most recent visited
435*795d594fSAndroid Build Coastguard Worker   // SchedulingNode. This is for reporting the internal latency value to the user of this visitor.
436*795d594fSAndroid Build Coastguard Worker   uint32_t last_visited_internal_latency_;
437*795d594fSAndroid Build Coastguard Worker };
438*795d594fSAndroid Build Coastguard Worker 
439*795d594fSAndroid Build Coastguard Worker class SchedulingNodeSelector : public ArenaObject<kArenaAllocScheduler> {
440*795d594fSAndroid Build Coastguard Worker  public:
Reset()441*795d594fSAndroid Build Coastguard Worker   virtual void Reset() {}
442*795d594fSAndroid Build Coastguard Worker   virtual SchedulingNode* PopHighestPriorityNode(ScopedArenaVector<SchedulingNode*>* nodes,
443*795d594fSAndroid Build Coastguard Worker                                                  const SchedulingGraph& graph) = 0;
~SchedulingNodeSelector()444*795d594fSAndroid Build Coastguard Worker   virtual ~SchedulingNodeSelector() {}
445*795d594fSAndroid Build Coastguard Worker  protected:
DeleteNodeAtIndex(ScopedArenaVector<SchedulingNode * > * nodes,size_t index)446*795d594fSAndroid Build Coastguard Worker   static void DeleteNodeAtIndex(ScopedArenaVector<SchedulingNode*>* nodes, size_t index) {
447*795d594fSAndroid Build Coastguard Worker     (*nodes)[index] = nodes->back();
448*795d594fSAndroid Build Coastguard Worker     nodes->pop_back();
449*795d594fSAndroid Build Coastguard Worker   }
450*795d594fSAndroid Build Coastguard Worker };
451*795d594fSAndroid Build Coastguard Worker 
452*795d594fSAndroid Build Coastguard Worker /*
453*795d594fSAndroid Build Coastguard Worker  * Select a `SchedulingNode` at random within the candidates.
454*795d594fSAndroid Build Coastguard Worker  */
455*795d594fSAndroid Build Coastguard Worker class RandomSchedulingNodeSelector : public SchedulingNodeSelector {
456*795d594fSAndroid Build Coastguard Worker  public:
RandomSchedulingNodeSelector()457*795d594fSAndroid Build Coastguard Worker   RandomSchedulingNodeSelector() : seed_(0) {
458*795d594fSAndroid Build Coastguard Worker     seed_  = static_cast<uint32_t>(NanoTime());
459*795d594fSAndroid Build Coastguard Worker     srand(seed_);
460*795d594fSAndroid Build Coastguard Worker   }
461*795d594fSAndroid Build Coastguard Worker 
PopHighestPriorityNode(ScopedArenaVector<SchedulingNode * > * nodes,const SchedulingGraph & graph)462*795d594fSAndroid Build Coastguard Worker   SchedulingNode* PopHighestPriorityNode(ScopedArenaVector<SchedulingNode*>* nodes,
463*795d594fSAndroid Build Coastguard Worker                                          const SchedulingGraph& graph) override {
464*795d594fSAndroid Build Coastguard Worker     UNUSED(graph);
465*795d594fSAndroid Build Coastguard Worker     DCHECK(!nodes->empty());
466*795d594fSAndroid Build Coastguard Worker     size_t select = rand_r(&seed_) % nodes->size();
467*795d594fSAndroid Build Coastguard Worker     SchedulingNode* select_node = (*nodes)[select];
468*795d594fSAndroid Build Coastguard Worker     DeleteNodeAtIndex(nodes, select);
469*795d594fSAndroid Build Coastguard Worker     return select_node;
470*795d594fSAndroid Build Coastguard Worker   }
471*795d594fSAndroid Build Coastguard Worker 
472*795d594fSAndroid Build Coastguard Worker   uint32_t seed_;
473*795d594fSAndroid Build Coastguard Worker };
474*795d594fSAndroid Build Coastguard Worker 
475*795d594fSAndroid Build Coastguard Worker /*
476*795d594fSAndroid Build Coastguard Worker  * Select a `SchedulingNode` according to critical path information,
477*795d594fSAndroid Build Coastguard Worker  * with heuristics to favor certain instruction patterns like materialized condition.
478*795d594fSAndroid Build Coastguard Worker  */
479*795d594fSAndroid Build Coastguard Worker class CriticalPathSchedulingNodeSelector : public SchedulingNodeSelector {
480*795d594fSAndroid Build Coastguard Worker  public:
CriticalPathSchedulingNodeSelector()481*795d594fSAndroid Build Coastguard Worker   CriticalPathSchedulingNodeSelector() : prev_select_(nullptr) {}
482*795d594fSAndroid Build Coastguard Worker 
Reset()483*795d594fSAndroid Build Coastguard Worker   void Reset() override { prev_select_ = nullptr; }
484*795d594fSAndroid Build Coastguard Worker   SchedulingNode* PopHighestPriorityNode(ScopedArenaVector<SchedulingNode*>* nodes,
485*795d594fSAndroid Build Coastguard Worker                                          const SchedulingGraph& graph) override;
486*795d594fSAndroid Build Coastguard Worker 
487*795d594fSAndroid Build Coastguard Worker  protected:
488*795d594fSAndroid Build Coastguard Worker   SchedulingNode* GetHigherPrioritySchedulingNode(SchedulingNode* candidate,
489*795d594fSAndroid Build Coastguard Worker                                                   SchedulingNode* check) const;
490*795d594fSAndroid Build Coastguard Worker 
491*795d594fSAndroid Build Coastguard Worker   SchedulingNode* SelectMaterializedCondition(ScopedArenaVector<SchedulingNode*>* nodes,
492*795d594fSAndroid Build Coastguard Worker                                               const SchedulingGraph& graph) const;
493*795d594fSAndroid Build Coastguard Worker 
494*795d594fSAndroid Build Coastguard Worker  private:
495*795d594fSAndroid Build Coastguard Worker   const SchedulingNode* prev_select_;
496*795d594fSAndroid Build Coastguard Worker };
497*795d594fSAndroid Build Coastguard Worker 
498*795d594fSAndroid Build Coastguard Worker class HScheduler {
499*795d594fSAndroid Build Coastguard Worker  public:
HScheduler(SchedulingNodeSelector * selector)500*795d594fSAndroid Build Coastguard Worker   explicit HScheduler(SchedulingNodeSelector* selector)
501*795d594fSAndroid Build Coastguard Worker       : selector_(selector),
502*795d594fSAndroid Build Coastguard Worker         only_optimize_loop_blocks_(true),
503*795d594fSAndroid Build Coastguard Worker         cursor_(nullptr) {}
~HScheduler()504*795d594fSAndroid Build Coastguard Worker   virtual ~HScheduler() {}
505*795d594fSAndroid Build Coastguard Worker 
506*795d594fSAndroid Build Coastguard Worker   void Schedule(HGraph* graph);
507*795d594fSAndroid Build Coastguard Worker 
SetOnlyOptimizeLoopBlocks(bool loop_only)508*795d594fSAndroid Build Coastguard Worker   void SetOnlyOptimizeLoopBlocks(bool loop_only) { only_optimize_loop_blocks_ = loop_only; }
509*795d594fSAndroid Build Coastguard Worker 
510*795d594fSAndroid Build Coastguard Worker   // Instructions can not be rescheduled across a scheduling barrier.
511*795d594fSAndroid Build Coastguard Worker   virtual bool IsSchedulingBarrier(const HInstruction* instruction) const;
512*795d594fSAndroid Build Coastguard Worker 
513*795d594fSAndroid Build Coastguard Worker  protected:
514*795d594fSAndroid Build Coastguard Worker   virtual std::pair<SchedulingGraph, ScopedArenaVector<SchedulingNode*>> BuildSchedulingGraph(
515*795d594fSAndroid Build Coastguard Worker       HBasicBlock* block,
516*795d594fSAndroid Build Coastguard Worker       ScopedArenaAllocator* allocator,
517*795d594fSAndroid Build Coastguard Worker       const HeapLocationCollector* heap_location_collector) = 0;
518*795d594fSAndroid Build Coastguard Worker 
519*795d594fSAndroid Build Coastguard Worker   template <typename LatencyVisitor>
BuildSchedulingGraph(HBasicBlock * block,ScopedArenaAllocator * allocator,const HeapLocationCollector * heap_location_collector,LatencyVisitor * latency_visitor)520*795d594fSAndroid Build Coastguard Worker   std::pair<SchedulingGraph, ScopedArenaVector<SchedulingNode*>> BuildSchedulingGraph(
521*795d594fSAndroid Build Coastguard Worker       HBasicBlock* block,
522*795d594fSAndroid Build Coastguard Worker       ScopedArenaAllocator* allocator,
523*795d594fSAndroid Build Coastguard Worker       const HeapLocationCollector* heap_location_collector,
524*795d594fSAndroid Build Coastguard Worker       LatencyVisitor* latency_visitor) ALWAYS_INLINE {
525*795d594fSAndroid Build Coastguard Worker     SchedulingGraph scheduling_graph(allocator, heap_location_collector);
526*795d594fSAndroid Build Coastguard Worker     ScopedArenaVector<SchedulingNode*> scheduling_nodes(allocator->Adapter(kArenaAllocScheduler));
527*795d594fSAndroid Build Coastguard Worker     for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
528*795d594fSAndroid Build Coastguard Worker       HInstruction* instruction = it.Current();
529*795d594fSAndroid Build Coastguard Worker       CHECK_EQ(instruction->GetBlock(), block)
530*795d594fSAndroid Build Coastguard Worker           << instruction->DebugName()
531*795d594fSAndroid Build Coastguard Worker           << " is in block " << instruction->GetBlock()->GetBlockId()
532*795d594fSAndroid Build Coastguard Worker           << ", and expected in block " << block->GetBlockId();
533*795d594fSAndroid Build Coastguard Worker       SchedulingNode* node =
534*795d594fSAndroid Build Coastguard Worker           scheduling_graph.AddNode(instruction, IsSchedulingBarrier(instruction));
535*795d594fSAndroid Build Coastguard Worker       latency_visitor->CalculateLatency(node);
536*795d594fSAndroid Build Coastguard Worker       node->SetLatency(latency_visitor->GetLastVisitedLatency());
537*795d594fSAndroid Build Coastguard Worker       node->SetInternalLatency(latency_visitor->GetLastVisitedInternalLatency());
538*795d594fSAndroid Build Coastguard Worker       scheduling_nodes.push_back(node);
539*795d594fSAndroid Build Coastguard Worker     }
540*795d594fSAndroid Build Coastguard Worker     return {std::move(scheduling_graph), std::move(scheduling_nodes)};
541*795d594fSAndroid Build Coastguard Worker   }
542*795d594fSAndroid Build Coastguard Worker 
543*795d594fSAndroid Build Coastguard Worker   void Schedule(HBasicBlock* block, const HeapLocationCollector* heap_location_collector);
544*795d594fSAndroid Build Coastguard Worker   void Schedule(SchedulingNode* scheduling_node,
545*795d594fSAndroid Build Coastguard Worker                 /*inout*/ ScopedArenaVector<SchedulingNode*>* candidates);
546*795d594fSAndroid Build Coastguard Worker   void Schedule(HInstruction* instruction);
547*795d594fSAndroid Build Coastguard Worker 
548*795d594fSAndroid Build Coastguard Worker   // Any instruction returning `false` via this method will prevent its
549*795d594fSAndroid Build Coastguard Worker   // containing basic block from being scheduled.
550*795d594fSAndroid Build Coastguard Worker   // This method is used to restrict scheduling to instructions that we know are
551*795d594fSAndroid Build Coastguard Worker   // safe to handle.
552*795d594fSAndroid Build Coastguard Worker   //
553*795d594fSAndroid Build Coastguard Worker   // For newly introduced instructions by default HScheduler::IsSchedulable returns false.
554*795d594fSAndroid Build Coastguard Worker   // HScheduler${ARCH}::IsSchedulable can be overridden to return true for an instruction (see
555*795d594fSAndroid Build Coastguard Worker   // scheduler_arm64.h for example) if it is safe to schedule it; in this case one *must* also
556*795d594fSAndroid Build Coastguard Worker   // look at/update HScheduler${ARCH}::IsSchedulingBarrier for this instruction.
557*795d594fSAndroid Build Coastguard Worker   virtual bool IsSchedulable(const HInstruction* instruction) const;
558*795d594fSAndroid Build Coastguard Worker   bool IsSchedulable(const HBasicBlock* block) const;
559*795d594fSAndroid Build Coastguard Worker 
560*795d594fSAndroid Build Coastguard Worker   SchedulingNodeSelector* const selector_;
561*795d594fSAndroid Build Coastguard Worker   bool only_optimize_loop_blocks_;
562*795d594fSAndroid Build Coastguard Worker 
563*795d594fSAndroid Build Coastguard Worker   // A pointer indicating where the next instruction to be scheduled will be inserted.
564*795d594fSAndroid Build Coastguard Worker   HInstruction* cursor_;
565*795d594fSAndroid Build Coastguard Worker 
566*795d594fSAndroid Build Coastguard Worker  private:
567*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(HScheduler);
568*795d594fSAndroid Build Coastguard Worker };
569*795d594fSAndroid Build Coastguard Worker 
570*795d594fSAndroid Build Coastguard Worker class HInstructionScheduling : public HOptimization {
571*795d594fSAndroid Build Coastguard Worker  public:
572*795d594fSAndroid Build Coastguard Worker   HInstructionScheduling(HGraph* graph,
573*795d594fSAndroid Build Coastguard Worker                          InstructionSet instruction_set,
574*795d594fSAndroid Build Coastguard Worker                          CodeGenerator* cg = nullptr,
575*795d594fSAndroid Build Coastguard Worker                          const char* name = kInstructionSchedulingPassName)
HOptimization(graph,name)576*795d594fSAndroid Build Coastguard Worker       : HOptimization(graph, name),
577*795d594fSAndroid Build Coastguard Worker         codegen_(cg),
578*795d594fSAndroid Build Coastguard Worker         instruction_set_(instruction_set) {}
579*795d594fSAndroid Build Coastguard Worker 
Run()580*795d594fSAndroid Build Coastguard Worker   bool Run() override {
581*795d594fSAndroid Build Coastguard Worker     return Run(/*only_optimize_loop_blocks*/ true, /*schedule_randomly*/ false);
582*795d594fSAndroid Build Coastguard Worker   }
583*795d594fSAndroid Build Coastguard Worker 
584*795d594fSAndroid Build Coastguard Worker   bool Run(bool only_optimize_loop_blocks, bool schedule_randomly);
585*795d594fSAndroid Build Coastguard Worker 
586*795d594fSAndroid Build Coastguard Worker   static constexpr const char* kInstructionSchedulingPassName = "scheduler";
587*795d594fSAndroid Build Coastguard Worker 
588*795d594fSAndroid Build Coastguard Worker  private:
589*795d594fSAndroid Build Coastguard Worker   CodeGenerator* const codegen_;
590*795d594fSAndroid Build Coastguard Worker   const InstructionSet instruction_set_;
591*795d594fSAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(HInstructionScheduling);
592*795d594fSAndroid Build Coastguard Worker };
593*795d594fSAndroid Build Coastguard Worker 
594*795d594fSAndroid Build Coastguard Worker }  // namespace art
595*795d594fSAndroid Build Coastguard Worker 
596*795d594fSAndroid Build Coastguard Worker #endif  // ART_COMPILER_OPTIMIZING_SCHEDULER_H_
597