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/common/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 using BasicBlockVector = ZoneVector<BasicBlock*>; 24 using NodeVector = ZoneVector<Node*>; 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: ToInt() const48 int ToInt() const { return static_cast<int>(index_); } ToSize() const49 size_t ToSize() const { return index_; } FromSize(size_t index)50 static Id FromSize(size_t index) { return Id(index); } FromInt(int index)51 static Id FromInt(int index) { return Id(static_cast<size_t>(index)); } 52 53 private: Id(size_t index)54 explicit Id(size_t index) : index_(index) {} 55 size_t index_; 56 }; 57 58 BasicBlock(Zone* zone, Id id); 59 BasicBlock(const BasicBlock&) = delete; 60 BasicBlock& operator=(const BasicBlock&) = delete; 61 id() const62 Id id() const { return id_; } 63 #if DEBUG set_debug_info(AssemblerDebugInfo debug_info)64 void set_debug_info(AssemblerDebugInfo debug_info) { 65 debug_info_ = debug_info; 66 } debug_info() const67 AssemblerDebugInfo debug_info() const { return debug_info_; } 68 #endif // DEBUG 69 70 void Print(); 71 72 // Predecessors. predecessors()73 BasicBlockVector& predecessors() { return predecessors_; } predecessors() const74 const BasicBlockVector& predecessors() const { return predecessors_; } PredecessorCount() const75 size_t PredecessorCount() const { return predecessors_.size(); } PredecessorAt(size_t index)76 BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; } ClearPredecessors()77 void ClearPredecessors() { predecessors_.clear(); } 78 void AddPredecessor(BasicBlock* predecessor); 79 void RemovePredecessor(size_t index); 80 81 // Successors. successors()82 BasicBlockVector& successors() { return successors_; } successors() const83 const BasicBlockVector& successors() const { return successors_; } SuccessorCount() const84 size_t SuccessorCount() const { return successors_.size(); } SuccessorAt(size_t index)85 BasicBlock* SuccessorAt(size_t index) { return successors_[index]; } ClearSuccessors()86 void ClearSuccessors() { successors_.clear(); } 87 void AddSuccessor(BasicBlock* successor); 88 89 // Nodes in the basic block. 90 using value_type = Node*; empty() const91 bool empty() const { return nodes_.empty(); } size() const92 size_t size() const { return nodes_.size(); } NodeAt(size_t index)93 Node* NodeAt(size_t index) { return nodes_[index]; } NodeCount() const94 size_t NodeCount() const { return nodes_.size(); } 95 front()96 value_type& front() { return nodes_.front(); } front() const97 value_type const& front() const { return nodes_.front(); } 98 99 using iterator = NodeVector::iterator; begin()100 iterator begin() { return nodes_.begin(); } end()101 iterator end() { return nodes_.end(); } 102 RemoveNode(iterator it)103 void RemoveNode(iterator it) { nodes_.erase(it); } 104 105 using const_iterator = NodeVector::const_iterator; begin() const106 const_iterator begin() const { return nodes_.begin(); } end() const107 const_iterator end() const { return nodes_.end(); } 108 109 using reverse_iterator = NodeVector::reverse_iterator; rbegin()110 reverse_iterator rbegin() { return nodes_.rbegin(); } rend()111 reverse_iterator rend() { return nodes_.rend(); } 112 113 void AddNode(Node* node); 114 template <class InputIterator> InsertNodes(iterator insertion_point, InputIterator insertion_start, InputIterator insertion_end)115 void InsertNodes(iterator insertion_point, InputIterator insertion_start, 116 InputIterator insertion_end) { 117 nodes_.insert(insertion_point, insertion_start, insertion_end); 118 } 119 120 // Trim basic block to end at {new_end}. 121 void TrimNodes(iterator new_end); 122 123 void ResetRPOInfo(); 124 125 // Accessors. control() const126 Control control() const { return control_; } 127 void set_control(Control control); 128 control_input() const129 Node* control_input() const { return control_input_; } 130 void set_control_input(Node* control_input); 131 deferred() const132 bool deferred() const { return deferred_; } set_deferred(bool deferred)133 void set_deferred(bool deferred) { deferred_ = deferred; } 134 dominator_depth() const135 int32_t dominator_depth() const { return dominator_depth_; } set_dominator_depth(int32_t depth)136 void set_dominator_depth(int32_t depth) { dominator_depth_ = depth; } 137 dominator() const138 BasicBlock* dominator() const { return dominator_; } set_dominator(BasicBlock* dominator)139 void set_dominator(BasicBlock* dominator) { dominator_ = dominator; } 140 rpo_next() const141 BasicBlock* rpo_next() const { return rpo_next_; } set_rpo_next(BasicBlock* rpo_next)142 void set_rpo_next(BasicBlock* rpo_next) { rpo_next_ = rpo_next; } 143 loop_header() const144 BasicBlock* loop_header() const { return loop_header_; } 145 void set_loop_header(BasicBlock* loop_header); 146 loop_end() const147 BasicBlock* loop_end() const { return loop_end_; } 148 void set_loop_end(BasicBlock* loop_end); 149 loop_depth() const150 int32_t loop_depth() const { return loop_depth_; } 151 void set_loop_depth(int32_t loop_depth); 152 loop_number() const153 int32_t loop_number() const { return loop_number_; } set_loop_number(int32_t loop_number)154 void set_loop_number(int32_t loop_number) { loop_number_ = loop_number; } 155 rpo_number() const156 int32_t rpo_number() const { return rpo_number_; } 157 void set_rpo_number(int32_t rpo_number); 158 nodes()159 NodeVector* nodes() { return &nodes_; } 160 161 // Loop membership helpers. IsLoopHeader() const162 inline bool IsLoopHeader() const { return loop_end_ != nullptr; } 163 bool LoopContains(BasicBlock* block) const; 164 165 // Computes the immediate common dominator of {b1} and {b2}. The worst time 166 // complexity is O(N) where N is the height of the dominator tree. 167 static BasicBlock* GetCommonDominator(BasicBlock* b1, BasicBlock* b2); 168 169 private: 170 int32_t loop_number_; // loop number of the block. 171 int32_t rpo_number_; // special RPO number of the block. 172 bool deferred_; // true if the block contains deferred code. 173 int32_t dominator_depth_; // Depth within the dominator tree. 174 BasicBlock* dominator_; // Immediate dominator of the block. 175 BasicBlock* rpo_next_; // Link to next block in special RPO order. 176 BasicBlock* loop_header_; // Pointer to dominating loop header basic block, 177 // nullptr if none. For loop headers, this points to 178 // enclosing loop header. 179 BasicBlock* loop_end_; // end of the loop, if this block is a loop header. 180 int32_t loop_depth_; // loop nesting, 0 is top-level 181 182 Control control_; // Control at the end of the block. 183 Node* control_input_; // Input value for control. 184 NodeVector nodes_; // nodes of this block in forward order. 185 186 BasicBlockVector successors_; 187 BasicBlockVector predecessors_; 188 #if DEBUG 189 AssemblerDebugInfo debug_info_; 190 #endif 191 Id id_; 192 }; 193 194 std::ostream& operator<<(std::ostream&, const BasicBlock&); 195 std::ostream& operator<<(std::ostream&, const BasicBlock::Control&); 196 std::ostream& operator<<(std::ostream&, const BasicBlock::Id&); 197 198 // A schedule represents the result of assigning nodes to basic blocks 199 // and ordering them within basic blocks. Prior to computing a schedule, 200 // a graph has no notion of control flow ordering other than that induced 201 // by the graph's dependencies. A schedule is required to generate code. 202 class V8_EXPORT_PRIVATE Schedule final : public NON_EXPORTED_BASE(ZoneObject) { 203 public: 204 explicit Schedule(Zone* zone, size_t node_count_hint = 0); 205 Schedule(const Schedule&) = delete; 206 Schedule& operator=(const Schedule&) = delete; 207 208 // Return the block which contains {node}, if any. 209 BasicBlock* block(Node* node) const; 210 211 bool IsScheduled(Node* node); 212 BasicBlock* GetBlockById(BasicBlock::Id block_id); 213 void ClearBlockById(BasicBlock::Id block_id); 214 BasicBlockCount() const215 size_t BasicBlockCount() const { return all_blocks_.size(); } RpoBlockCount() const216 size_t RpoBlockCount() const { return rpo_order_.size(); } 217 218 // Check if nodes {a} and {b} are in the same block. 219 bool SameBasicBlock(Node* a, Node* b) const; 220 221 // BasicBlock building: create a new block. 222 BasicBlock* NewBasicBlock(); 223 224 // BasicBlock building: records that a node will later be added to a block but 225 // doesn't actually add the node to the block. 226 void PlanNode(BasicBlock* block, Node* node); 227 228 // BasicBlock building: add a node to the end of the block. 229 void AddNode(BasicBlock* block, Node* node); 230 231 // BasicBlock building: add a goto to the end of {block}. 232 void AddGoto(BasicBlock* block, BasicBlock* succ); 233 234 // BasicBlock building: add a call at the end of {block}. 235 void AddCall(BasicBlock* block, Node* call, BasicBlock* success_block, 236 BasicBlock* exception_block); 237 238 // BasicBlock building: add a branch at the end of {block}. 239 void AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock, 240 BasicBlock* fblock); 241 242 // BasicBlock building: add a switch at the end of {block}. 243 void AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks, 244 size_t succ_count); 245 246 // BasicBlock building: add a deoptimize at the end of {block}. 247 void AddDeoptimize(BasicBlock* block, Node* input); 248 249 // BasicBlock building: add a tailcall at the end of {block}. 250 void AddTailCall(BasicBlock* block, Node* input); 251 252 // BasicBlock building: add a return at the end of {block}. 253 void AddReturn(BasicBlock* block, Node* input); 254 255 // BasicBlock building: add a throw at the end of {block}. 256 void AddThrow(BasicBlock* block, Node* input); 257 258 // BasicBlock mutation: insert a branch into the end of {block}. 259 void InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch, 260 BasicBlock* tblock, BasicBlock* fblock); 261 262 // BasicBlock mutation: insert a switch into the end of {block}. 263 void InsertSwitch(BasicBlock* block, BasicBlock* end, Node* sw, 264 BasicBlock** succ_blocks, size_t succ_count); 265 266 // Exposed publicly for testing only. AddSuccessorForTesting(BasicBlock* block, BasicBlock* succ)267 void AddSuccessorForTesting(BasicBlock* block, BasicBlock* succ) { 268 return AddSuccessor(block, succ); 269 } 270 all_blocks() const271 const BasicBlockVector* all_blocks() const { return &all_blocks_; } rpo_order()272 BasicBlockVector* rpo_order() { return &rpo_order_; } rpo_order() const273 const BasicBlockVector* rpo_order() const { return &rpo_order_; } 274 start()275 BasicBlock* start() { return start_; } end()276 BasicBlock* end() { return end_; } 277 zone() const278 Zone* zone() const { return zone_; } 279 280 private: 281 friend class GraphAssembler; 282 friend class Scheduler; 283 friend class BasicBlockInstrumentor; 284 friend class RawMachineAssembler; 285 286 // For CSA/Torque: Ensure properties of the CFG assumed by further stages. 287 void EnsureCFGWellFormedness(); 288 // For CSA/Torque: Eliminates unnecessary phi nodes, including phis with a 289 // single input. The latter is necessary to ensure the property required for 290 // SSA deconstruction that the target block of a control flow split has no 291 // phis. 292 void EliminateRedundantPhiNodes(); 293 // Ensure split-edge form for a hand-assembled schedule. 294 void EnsureSplitEdgeForm(BasicBlock* block); 295 // Move Phi operands to newly created merger blocks 296 void MovePhis(BasicBlock* from, BasicBlock* to); 297 // Copy deferred block markers down as far as possible 298 void PropagateDeferredMark(); 299 300 void AddSuccessor(BasicBlock* block, BasicBlock* succ); 301 void MoveSuccessors(BasicBlock* from, BasicBlock* to); 302 303 void SetControlInput(BasicBlock* block, Node* node); 304 void SetBlockForNode(BasicBlock* block, Node* node); 305 306 Zone* zone_; 307 BasicBlockVector all_blocks_; // All basic blocks in the schedule. 308 BasicBlockVector nodeid_to_block_; // Map from node to containing block. 309 BasicBlockVector rpo_order_; // Reverse-post-order block list. 310 BasicBlock* start_; 311 BasicBlock* end_; 312 }; 313 314 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream&, const Schedule&); 315 316 } // namespace compiler 317 } // namespace internal 318 } // namespace v8 319 320 #endif // V8_COMPILER_SCHEDULE_H_ 321