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