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 <vector> 9 10 #include "src/v8.h" 11 12 #include "src/compiler/generic-algorithm.h" 13 #include "src/compiler/generic-graph.h" 14 #include "src/compiler/generic-node.h" 15 #include "src/compiler/generic-node-inl.h" 16 #include "src/compiler/node.h" 17 #include "src/compiler/opcodes.h" 18 #include "src/zone.h" 19 20 namespace v8 { 21 namespace internal { 22 namespace compiler { 23 24 class BasicBlock; 25 class Graph; 26 class ConstructScheduleData; 27 class CodeGenerator; // Because of a namespace bug in clang. 28 29 class BasicBlockData { 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 kBranch, // Branch if true to first successor, otherwise second. 36 kReturn, // Return a value from this method. 37 kThrow // Throw an exception. 38 }; 39 40 int32_t rpo_number_; // special RPO number of the block. 41 BasicBlock* dominator_; // Immediate dominator of the block. 42 BasicBlock* loop_header_; // Pointer to dominating loop header basic block, 43 // NULL if none. For loop headers, this points to 44 // enclosing loop header. 45 int32_t loop_depth_; // loop nesting, 0 is top-level 46 int32_t loop_end_; // end of the loop, if this block is a loop header. 47 int32_t code_start_; // start index of arch-specific code. 48 int32_t code_end_; // end index of arch-specific code. 49 bool deferred_; // {true} if this block is considered the slow 50 // path. 51 Control control_; // Control at the end of the block. 52 Node* control_input_; // Input value for control. 53 NodeVector nodes_; // nodes of this block in forward order. 54 BasicBlockData(Zone * zone)55 explicit BasicBlockData(Zone* zone) 56 : rpo_number_(-1), 57 dominator_(NULL), 58 loop_header_(NULL), 59 loop_depth_(0), 60 loop_end_(-1), 61 code_start_(-1), 62 code_end_(-1), 63 deferred_(false), 64 control_(kNone), 65 control_input_(NULL), 66 nodes_(zone) {} 67 IsLoopHeader()68 inline bool IsLoopHeader() const { return loop_end_ >= 0; } LoopContains(BasicBlockData * block)69 inline bool LoopContains(BasicBlockData* block) const { 70 // RPO numbers must be initialized. 71 DCHECK(rpo_number_ >= 0); 72 DCHECK(block->rpo_number_ >= 0); 73 if (loop_end_ < 0) return false; // This is not a loop. 74 return block->rpo_number_ >= rpo_number_ && block->rpo_number_ < loop_end_; 75 } first_instruction_index()76 int first_instruction_index() { 77 DCHECK(code_start_ >= 0); 78 DCHECK(code_end_ > 0); 79 DCHECK(code_end_ >= code_start_); 80 return code_start_; 81 } last_instruction_index()82 int last_instruction_index() { 83 DCHECK(code_start_ >= 0); 84 DCHECK(code_end_ > 0); 85 DCHECK(code_end_ >= code_start_); 86 return code_end_ - 1; 87 } 88 }; 89 90 OStream& operator<<(OStream& os, const BasicBlockData::Control& c); 91 92 // A basic block contains an ordered list of nodes and ends with a control 93 // node. Note that if a basic block has phis, then all phis must appear as the 94 // first nodes in the block. 95 class BasicBlock FINAL : public GenericNode<BasicBlockData, BasicBlock> { 96 public: BasicBlock(GenericGraphBase * graph,int input_count)97 BasicBlock(GenericGraphBase* graph, int input_count) 98 : GenericNode<BasicBlockData, BasicBlock>(graph, input_count) {} 99 100 typedef Uses Successors; 101 typedef Inputs Predecessors; 102 successors()103 Successors successors() { return static_cast<Successors>(uses()); } predecessors()104 Predecessors predecessors() { return static_cast<Predecessors>(inputs()); } 105 PredecessorCount()106 int PredecessorCount() { return InputCount(); } PredecessorAt(int index)107 BasicBlock* PredecessorAt(int index) { return InputAt(index); } 108 SuccessorCount()109 int SuccessorCount() { return UseCount(); } SuccessorAt(int index)110 BasicBlock* SuccessorAt(int index) { return UseAt(index); } 111 PredecessorIndexOf(BasicBlock * predecessor)112 int PredecessorIndexOf(BasicBlock* predecessor) { 113 BasicBlock::Predecessors predecessors = this->predecessors(); 114 for (BasicBlock::Predecessors::iterator i = predecessors.begin(); 115 i != predecessors.end(); ++i) { 116 if (*i == predecessor) return i.index(); 117 } 118 return -1; 119 } 120 loop_header()121 inline BasicBlock* loop_header() { 122 return static_cast<BasicBlock*>(loop_header_); 123 } ContainingLoop()124 inline BasicBlock* ContainingLoop() { 125 if (IsLoopHeader()) return this; 126 return static_cast<BasicBlock*>(loop_header_); 127 } 128 129 typedef NodeVector::iterator iterator; begin()130 iterator begin() { return nodes_.begin(); } end()131 iterator end() { return nodes_.end(); } 132 133 typedef NodeVector::const_iterator const_iterator; begin()134 const_iterator begin() const { return nodes_.begin(); } end()135 const_iterator end() const { return nodes_.end(); } 136 137 typedef NodeVector::reverse_iterator reverse_iterator; rbegin()138 reverse_iterator rbegin() { return nodes_.rbegin(); } rend()139 reverse_iterator rend() { return nodes_.rend(); } 140 141 private: 142 DISALLOW_COPY_AND_ASSIGN(BasicBlock); 143 }; 144 145 typedef GenericGraphVisit::NullNodeVisitor<BasicBlockData, BasicBlock> 146 NullBasicBlockVisitor; 147 148 typedef ZoneVector<BasicBlock*> BasicBlockVector; 149 typedef BasicBlockVector::iterator BasicBlockVectorIter; 150 typedef BasicBlockVector::reverse_iterator BasicBlockVectorRIter; 151 152 // A schedule represents the result of assigning nodes to basic blocks 153 // and ordering them within basic blocks. Prior to computing a schedule, 154 // a graph has no notion of control flow ordering other than that induced 155 // by the graph's dependencies. A schedule is required to generate code. 156 class Schedule : public GenericGraph<BasicBlock> { 157 public: Schedule(Zone * zone)158 explicit Schedule(Zone* zone) 159 : GenericGraph<BasicBlock>(zone), 160 zone_(zone), 161 all_blocks_(zone), 162 nodeid_to_block_(zone), 163 rpo_order_(zone) { 164 SetStart(NewBasicBlock()); // entry. 165 SetEnd(NewBasicBlock()); // exit. 166 } 167 168 // Return the block which contains {node}, if any. block(Node * node)169 BasicBlock* block(Node* node) const { 170 if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) { 171 return nodeid_to_block_[node->id()]; 172 } 173 return NULL; 174 } 175 IsScheduled(Node * node)176 bool IsScheduled(Node* node) { 177 int length = static_cast<int>(nodeid_to_block_.size()); 178 if (node->id() >= length) return false; 179 return nodeid_to_block_[node->id()] != NULL; 180 } 181 GetBlockById(int block_id)182 BasicBlock* GetBlockById(int block_id) { return all_blocks_[block_id]; } 183 BasicBlockCount()184 int BasicBlockCount() const { return NodeCount(); } RpoBlockCount()185 int RpoBlockCount() const { return static_cast<int>(rpo_order_.size()); } 186 187 typedef ContainerPointerWrapper<BasicBlockVector> BasicBlocks; 188 189 // Return a list of all the blocks in the schedule, in arbitrary order. all_blocks()190 BasicBlocks all_blocks() { return BasicBlocks(&all_blocks_); } 191 192 // Check if nodes {a} and {b} are in the same block. SameBasicBlock(Node * a,Node * b)193 inline bool SameBasicBlock(Node* a, Node* b) const { 194 BasicBlock* block = this->block(a); 195 return block != NULL && block == this->block(b); 196 } 197 198 // BasicBlock building: create a new block. NewBasicBlock()199 inline BasicBlock* NewBasicBlock() { 200 BasicBlock* block = 201 BasicBlock::New(this, 0, static_cast<BasicBlock**>(NULL)); 202 all_blocks_.push_back(block); 203 return block; 204 } 205 206 // BasicBlock building: records that a node will later be added to a block but 207 // doesn't actually add the node to the block. PlanNode(BasicBlock * block,Node * node)208 inline void PlanNode(BasicBlock* block, Node* node) { 209 if (FLAG_trace_turbo_scheduler) { 210 PrintF("Planning #%d:%s for future add to B%d\n", node->id(), 211 node->op()->mnemonic(), block->id()); 212 } 213 DCHECK(this->block(node) == NULL); 214 SetBlockForNode(block, node); 215 } 216 217 // BasicBlock building: add a node to the end of the block. AddNode(BasicBlock * block,Node * node)218 inline void AddNode(BasicBlock* block, Node* node) { 219 if (FLAG_trace_turbo_scheduler) { 220 PrintF("Adding #%d:%s to B%d\n", node->id(), node->op()->mnemonic(), 221 block->id()); 222 } 223 DCHECK(this->block(node) == NULL || this->block(node) == block); 224 block->nodes_.push_back(node); 225 SetBlockForNode(block, node); 226 } 227 228 // BasicBlock building: add a goto to the end of {block}. AddGoto(BasicBlock * block,BasicBlock * succ)229 void AddGoto(BasicBlock* block, BasicBlock* succ) { 230 DCHECK(block->control_ == BasicBlock::kNone); 231 block->control_ = BasicBlock::kGoto; 232 AddSuccessor(block, succ); 233 } 234 235 // BasicBlock building: add a branch at the end of {block}. AddBranch(BasicBlock * block,Node * branch,BasicBlock * tblock,BasicBlock * fblock)236 void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock, 237 BasicBlock* fblock) { 238 DCHECK(block->control_ == BasicBlock::kNone); 239 DCHECK(branch->opcode() == IrOpcode::kBranch); 240 block->control_ = BasicBlock::kBranch; 241 AddSuccessor(block, tblock); 242 AddSuccessor(block, fblock); 243 SetControlInput(block, branch); 244 if (branch->opcode() == IrOpcode::kBranch) { 245 // TODO(titzer): require a Branch node here. (sloppy tests). 246 SetBlockForNode(block, branch); 247 } 248 } 249 250 // BasicBlock building: add a return at the end of {block}. AddReturn(BasicBlock * block,Node * input)251 void AddReturn(BasicBlock* block, Node* input) { 252 DCHECK(block->control_ == BasicBlock::kNone); 253 block->control_ = BasicBlock::kReturn; 254 SetControlInput(block, input); 255 if (block != end()) AddSuccessor(block, end()); 256 if (input->opcode() == IrOpcode::kReturn) { 257 // TODO(titzer): require a Return node here. (sloppy tests). 258 SetBlockForNode(block, input); 259 } 260 } 261 262 // BasicBlock building: add a throw at the end of {block}. AddThrow(BasicBlock * block,Node * input)263 void AddThrow(BasicBlock* block, Node* input) { 264 DCHECK(block->control_ == BasicBlock::kNone); 265 block->control_ = BasicBlock::kThrow; 266 SetControlInput(block, input); 267 if (block != end()) AddSuccessor(block, end()); 268 } 269 270 friend class Scheduler; 271 friend class CodeGenerator; 272 AddSuccessor(BasicBlock * block,BasicBlock * succ)273 void AddSuccessor(BasicBlock* block, BasicBlock* succ) { 274 succ->AppendInput(zone_, block); 275 } 276 rpo_order()277 BasicBlockVector* rpo_order() { return &rpo_order_; } 278 279 private: 280 friend class ScheduleVisualizer; 281 SetControlInput(BasicBlock * block,Node * node)282 void SetControlInput(BasicBlock* block, Node* node) { 283 block->control_input_ = node; 284 SetBlockForNode(block, node); 285 } 286 SetBlockForNode(BasicBlock * block,Node * node)287 void SetBlockForNode(BasicBlock* block, Node* node) { 288 int length = static_cast<int>(nodeid_to_block_.size()); 289 if (node->id() >= length) { 290 nodeid_to_block_.resize(node->id() + 1); 291 } 292 nodeid_to_block_[node->id()] = block; 293 } 294 295 Zone* zone_; 296 BasicBlockVector all_blocks_; // All basic blocks in the schedule. 297 BasicBlockVector nodeid_to_block_; // Map from node to containing block. 298 BasicBlockVector rpo_order_; // Reverse-post-order block list. 299 }; 300 301 OStream& operator<<(OStream& os, const Schedule& s); 302 } 303 } 304 } // namespace v8::internal::compiler 305 306 #endif // V8_COMPILER_SCHEDULE_H_ 307