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