| // Copyright 2013 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_COMPILER_SCHEDULER_H_ |
| #define V8_COMPILER_SCHEDULER_H_ |
| |
| #include "src/base/flags.h" |
| #include "src/compiler/node.h" |
| #include "src/compiler/opcodes.h" |
| #include "src/compiler/schedule.h" |
| #include "src/compiler/zone-stats.h" |
| #include "src/globals.h" |
| #include "src/zone/zone-containers.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| // Forward declarations. |
| class CFGBuilder; |
| class ControlEquivalence; |
| class Graph; |
| class SpecialRPONumberer; |
| |
| |
| // Computes a schedule from a graph, placing nodes into basic blocks and |
| // ordering the basic blocks in the special RPO order. |
| class V8_EXPORT_PRIVATE Scheduler { |
| public: |
| // Flags that control the mode of operation. |
| enum Flag { kNoFlags = 0u, kSplitNodes = 1u << 1, kTempSchedule = 1u << 2 }; |
| typedef base::Flags<Flag> Flags; |
| |
| // The complete scheduling algorithm. Creates a new schedule and places all |
| // nodes from the graph into it. |
| static Schedule* ComputeSchedule(Zone* temp_zone, Graph* graph, Flags flags); |
| |
| // Compute the RPO of blocks in an existing schedule. |
| static BasicBlockVector* ComputeSpecialRPO(Zone* zone, Schedule* schedule); |
| |
| private: |
| // Placement of a node changes during scheduling. The placement state |
| // transitions over time while the scheduler is choosing a position: |
| // |
| // +---------------------+-----+----> kFixed |
| // / / / |
| // kUnknown ----+------> kCoupled ----+ / |
| // \ / |
| // +----> kSchedulable ----+--------> kScheduled |
| // |
| // 1) InitializePlacement(): kUnknown -> kCoupled|kSchedulable|kFixed |
| // 2) UpdatePlacement(): kCoupled|kSchedulable -> kFixed|kScheduled |
| // |
| // We maintain the invariant that all nodes that are not reachable |
| // from the end have kUnknown placement. After the PrepareUses phase runs, |
| // also the opposite is true - all nodes with kUnknown placement are not |
| // reachable from the end. |
| enum Placement { kUnknown, kSchedulable, kFixed, kCoupled, kScheduled }; |
| |
| // Per-node data tracked during scheduling. |
| struct SchedulerData { |
| BasicBlock* minimum_block_; // Minimum legal RPO placement. |
| int unscheduled_count_; // Number of unscheduled uses of this node. |
| Placement placement_; // Whether the node is fixed, schedulable, |
| // coupled to another node, or not yet known. |
| }; |
| |
| Zone* zone_; |
| Graph* graph_; |
| Schedule* schedule_; |
| Flags flags_; |
| ZoneVector<NodeVector*> |
| scheduled_nodes_; // Per-block list of nodes in reverse. |
| NodeVector schedule_root_nodes_; // Fixed root nodes seed the worklist. |
| ZoneQueue<Node*> schedule_queue_; // Worklist of schedulable nodes. |
| ZoneVector<SchedulerData> node_data_; // Per-node data for all nodes. |
| CFGBuilder* control_flow_builder_; // Builds basic blocks for controls. |
| SpecialRPONumberer* special_rpo_; // Special RPO numbering of blocks. |
| ControlEquivalence* equivalence_; // Control dependence equivalence. |
| |
| Scheduler(Zone* zone, Graph* graph, Schedule* schedule, Flags flags, |
| size_t node_count_hint_); |
| |
| inline SchedulerData DefaultSchedulerData(); |
| inline SchedulerData* GetData(Node* node); |
| |
| Placement GetPlacement(Node* node); |
| Placement InitializePlacement(Node* node); |
| void UpdatePlacement(Node* node, Placement placement); |
| bool IsLive(Node* node); |
| |
| inline bool IsCoupledControlEdge(Node* node, int index); |
| void IncrementUnscheduledUseCount(Node* node, int index, Node* from); |
| void DecrementUnscheduledUseCount(Node* node, int index, Node* from); |
| |
| void PropagateImmediateDominators(BasicBlock* block); |
| |
| // Phase 1: Build control-flow graph. |
| friend class CFGBuilder; |
| void BuildCFG(); |
| |
| // Phase 2: Compute special RPO and dominator tree. |
| friend class SpecialRPONumberer; |
| void ComputeSpecialRPONumbering(); |
| void GenerateImmediateDominatorTree(); |
| |
| // Phase 3: Prepare use counts for nodes. |
| friend class PrepareUsesVisitor; |
| void PrepareUses(); |
| |
| // Phase 4: Schedule nodes early. |
| friend class ScheduleEarlyNodeVisitor; |
| void ScheduleEarly(); |
| |
| // Phase 5: Schedule nodes late. |
| friend class ScheduleLateNodeVisitor; |
| void ScheduleLate(); |
| |
| // Phase 6: Seal the final schedule. |
| void SealFinalSchedule(); |
| |
| void FuseFloatingControl(BasicBlock* block, Node* node); |
| void MovePlannedNodes(BasicBlock* from, BasicBlock* to); |
| }; |
| |
| |
| DEFINE_OPERATORS_FOR_FLAGS(Scheduler::Flags) |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_COMPILER_SCHEDULER_H_ |