1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_COMPILER_SCHEDULE_H_ 6 #define V8_COMPILER_SCHEDULE_H_ 7 8 #include <iosfwd> 9 10 #include "src/zone-containers.h" 11 12 namespace v8 { 13 namespace internal { 14 namespace compiler { 15 16 // Forward declarations. 17 class BasicBlock; 18 class BasicBlockInstrumentor; 19 class Node; 20 21 22 typedef ZoneVector<BasicBlock*> BasicBlockVector; 23 typedef ZoneVector<Node*> NodeVector; 24 25 26 // A basic block contains an ordered list of nodes and ends with a control 27 // node. Note that if a basic block has phis, then all phis must appear as the 28 // first nodes in the block. 29 class BasicBlock final : public ZoneObject { 30 public: 31 // Possible control nodes that can end a block. 32 enum Control { 33 kNone, // Control not initialized yet. 34 kGoto, // Goto a single successor block. 35 kCall, // Call with continuation as first successor, exception 36 // second. 37 kBranch, // Branch if true to first successor, otherwise second. 38 kSwitch, // Table dispatch to one of the successor blocks. 39 kDeoptimize, // Return a value from this method. 40 kTailCall, // Tail call another method from this method. 41 kReturn, // Return a value from this method. 42 kThrow // Throw an exception. 43 }; 44 45 class Id { 46 public: ToInt()47 int ToInt() const { return static_cast<int>(index_); } ToSize()48 size_t ToSize() const { return index_; } FromSize(size_t index)49 static Id FromSize(size_t index) { return Id(index); } FromInt(int index)50 static Id FromInt(int index) { return Id(static_cast<size_t>(index)); } 51 52 private: Id(size_t index)53 explicit Id(size_t index) : index_(index) {} 54 size_t index_; 55 }; 56 57 BasicBlock(Zone* zone, Id id); 58 id()59 Id id() const { return id_; } 60 61 // Predecessors. predecessors()62 BasicBlockVector& predecessors() { return predecessors_; } predecessors()63 const BasicBlockVector& predecessors() const { return predecessors_; } PredecessorCount()64 size_t PredecessorCount() const { return predecessors_.size(); } PredecessorAt(size_t index)65 BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; } ClearPredecessors()66 void ClearPredecessors() { predecessors_.clear(); } 67 void AddPredecessor(BasicBlock* predecessor); 68 69 // Successors. successors()70 BasicBlockVector& successors() { return successors_; } successors()71 const BasicBlockVector& successors() const { return successors_; } SuccessorCount()72 size_t SuccessorCount() const { return successors_.size(); } SuccessorAt(size_t index)73 BasicBlock* SuccessorAt(size_t index) { return successors_[index]; } ClearSuccessors()74 void ClearSuccessors() { successors_.clear(); } 75 void AddSuccessor(BasicBlock* successor); 76 77 // Nodes in the basic block. 78 typedef Node* value_type; empty()79 bool empty() const { return nodes_.empty(); } size()80 size_t size() const { return nodes_.size(); } NodeAt(size_t index)81 Node* NodeAt(size_t index) { return nodes_[index]; } NodeCount()82 size_t NodeCount() const { return nodes_.size(); } 83 front()84 value_type& front() { return nodes_.front(); } front()85 value_type const& front() const { return nodes_.front(); } 86 87 typedef NodeVector::iterator iterator; begin()88 iterator begin() { return nodes_.begin(); } end()89 iterator end() { return nodes_.end(); } 90 91 typedef NodeVector::const_iterator const_iterator; begin()92 const_iterator begin() const { return nodes_.begin(); } end()93 const_iterator end() const { return nodes_.end(); } 94 95 typedef NodeVector::reverse_iterator reverse_iterator; rbegin()96 reverse_iterator rbegin() { return nodes_.rbegin(); } rend()97 reverse_iterator rend() { return nodes_.rend(); } 98 99 void AddNode(Node* node); 100 template <class InputIterator> InsertNodes(iterator insertion_point,InputIterator insertion_start,InputIterator insertion_end)101 void InsertNodes(iterator insertion_point, InputIterator insertion_start, 102 InputIterator insertion_end) { 103 nodes_.insert(insertion_point, insertion_start, insertion_end); 104 } 105 106 // Accessors. control()107 Control control() const { return control_; } 108 void set_control(Control control); 109 control_input()110 Node* control_input() const { return control_input_; } 111 void set_control_input(Node* control_input); 112 deferred()113 bool deferred() const { return deferred_; } set_deferred(bool deferred)114 void set_deferred(bool deferred) { deferred_ = deferred; } 115 dominator_depth()116 int32_t dominator_depth() const { return dominator_depth_; } set_dominator_depth(int32_t depth)117 void set_dominator_depth(int32_t depth) { dominator_depth_ = depth; } 118 dominator()119 BasicBlock* dominator() const { return dominator_; } set_dominator(BasicBlock * dominator)120 void set_dominator(BasicBlock* dominator) { dominator_ = dominator; } 121 rpo_next()122 BasicBlock* rpo_next() const { return rpo_next_; } set_rpo_next(BasicBlock * rpo_next)123 void set_rpo_next(BasicBlock* rpo_next) { rpo_next_ = rpo_next; } 124 loop_header()125 BasicBlock* loop_header() const { return loop_header_; } 126 void set_loop_header(BasicBlock* loop_header); 127 loop_end()128 BasicBlock* loop_end() const { return loop_end_; } 129 void set_loop_end(BasicBlock* loop_end); 130 loop_depth()131 int32_t loop_depth() const { return loop_depth_; } 132 void set_loop_depth(int32_t loop_depth); 133 loop_number()134 int32_t loop_number() const { return loop_number_; } set_loop_number(int32_t loop_number)135 void set_loop_number(int32_t loop_number) { loop_number_ = loop_number; } 136 rpo_number()137 int32_t rpo_number() const { return rpo_number_; } 138 void set_rpo_number(int32_t rpo_number); 139 140 // Loop membership helpers. IsLoopHeader()141 inline bool IsLoopHeader() const { return loop_end_ != nullptr; } 142 bool LoopContains(BasicBlock* block) const; 143 144 // Computes the immediate common dominator of {b1} and {b2}. The worst time 145 // complexity is O(N) where N is the height of the dominator tree. 146 static BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2); 147 148 private: 149 int32_t loop_number_; // loop number of the block. 150 int32_t rpo_number_; // special RPO number of the block. 151 bool deferred_; // true if the block contains deferred code. 152 int32_t dominator_depth_; // Depth within the dominator tree. 153 BasicBlock* dominator_; // Immediate dominator of the block. 154 BasicBlock* rpo_next_; // Link to next block in special RPO order. 155 BasicBlock* loop_header_; // Pointer to dominating loop header basic block, 156 // nullptr if none. For loop headers, this points to 157 // enclosing loop header. 158 BasicBlock* loop_end_; // end of the loop, if this block is a loop header. 159 int32_t loop_depth_; // loop nesting, 0 is top-level 160 161 Control control_; // Control at the end of the block. 162 Node* control_input_; // Input value for control. 163 NodeVector nodes_; // nodes of this block in forward order. 164 165 BasicBlockVector successors_; 166 BasicBlockVector predecessors_; 167 Id id_; 168 169 DISALLOW_COPY_AND_ASSIGN(BasicBlock); 170 }; 171 172 std::ostream& operator<<(std::ostream&, const BasicBlock::Control&); 173 std::ostream& operator<<(std::ostream&, const BasicBlock::Id&); 174 175 176 // A schedule represents the result of assigning nodes to basic blocks 177 // and ordering them within basic blocks. Prior to computing a schedule, 178 // a graph has no notion of control flow ordering other than that induced 179 // by the graph's dependencies. A schedule is required to generate code. 180 class Schedule final : public ZoneObject { 181 public: 182 explicit Schedule(Zone* zone, size_t node_count_hint = 0); 183 184 // Return the block which contains {node}, if any. 185 BasicBlock* block(Node* node) const; 186 187 bool IsScheduled(Node* node); 188 BasicBlock* GetBlockById(BasicBlock::Id block_id); 189 BasicBlockCount()190 size_t BasicBlockCount() const { return all_blocks_.size(); } RpoBlockCount()191 size_t RpoBlockCount() const { return rpo_order_.size(); } 192 193 // Check if nodes {a} and {b} are in the same block. 194 bool SameBasicBlock(Node* a, Node* b) const; 195 196 // BasicBlock building: create a new block. 197 BasicBlock* NewBasicBlock(); 198 199 // BasicBlock building: records that a node will later be added to a block but 200 // doesn't actually add the node to the block. 201 void PlanNode(BasicBlock* block, Node* node); 202 203 // BasicBlock building: add a node to the end of the block. 204 void AddNode(BasicBlock* block, Node* node); 205 206 // BasicBlock building: add a goto to the end of {block}. 207 void AddGoto(BasicBlock* block, BasicBlock* succ); 208 209 // BasicBlock building: add a call at the end of {block}. 210 void AddCall(BasicBlock* block, Node* call, BasicBlock* success_block, 211 BasicBlock* exception_block); 212 213 // BasicBlock building: add a branch at the end of {block}. 214 void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock, 215 BasicBlock* fblock); 216 217 // BasicBlock building: add a switch at the end of {block}. 218 void AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks, 219 size_t succ_count); 220 221 // BasicBlock building: add a deoptimize at the end of {block}. 222 void AddDeoptimize(BasicBlock* block, Node* input); 223 224 // BasicBlock building: add a tailcall at the end of {block}. 225 void AddTailCall(BasicBlock* block, Node* input); 226 227 // BasicBlock building: add a return at the end of {block}. 228 void AddReturn(BasicBlock* block, Node* input); 229 230 // BasicBlock building: add a throw at the end of {block}. 231 void AddThrow(BasicBlock* block, Node* input); 232 233 // BasicBlock mutation: insert a branch into the end of {block}. 234 void InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch, 235 BasicBlock* tblock, BasicBlock* fblock); 236 237 // BasicBlock mutation: insert a switch into the end of {block}. 238 void InsertSwitch(BasicBlock* block, BasicBlock* end, Node* sw, 239 BasicBlock** succ_blocks, size_t succ_count); 240 241 // Exposed publicly for testing only. AddSuccessorForTesting(BasicBlock * block,BasicBlock * succ)242 void AddSuccessorForTesting(BasicBlock* block, BasicBlock* succ) { 243 return AddSuccessor(block, succ); 244 } 245 rpo_order()246 BasicBlockVector* rpo_order() { return &rpo_order_; } rpo_order()247 const BasicBlockVector* rpo_order() const { return &rpo_order_; } 248 start()249 BasicBlock* start() { return start_; } end()250 BasicBlock* end() { return end_; } 251 zone()252 Zone* zone() const { return zone_; } 253 254 private: 255 friend class Scheduler; 256 friend class BasicBlockInstrumentor; 257 258 void AddSuccessor(BasicBlock* block, BasicBlock* succ); 259 void MoveSuccessors(BasicBlock* from, BasicBlock* to); 260 261 void SetControlInput(BasicBlock* block, Node* node); 262 void SetBlockForNode(BasicBlock* block, Node* node); 263 264 Zone* zone_; 265 BasicBlockVector all_blocks_; // All basic blocks in the schedule. 266 BasicBlockVector nodeid_to_block_; // Map from node to containing block. 267 BasicBlockVector rpo_order_; // Reverse-post-order block list. 268 BasicBlock* start_; 269 BasicBlock* end_; 270 271 DISALLOW_COPY_AND_ASSIGN(Schedule); 272 }; 273 274 std::ostream& operator<<(std::ostream&, const Schedule&); 275 276 } // namespace compiler 277 } // namespace internal 278 } // namespace v8 279 280 #endif // V8_COMPILER_SCHEDULE_H_ 281