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 14namespace v8 { 15namespace internal { 16namespace compiler { 17 18// Forward declarations. 19class BasicBlock; 20class BasicBlockInstrumentor; 21class Node; 22 23using BasicBlockVector = ZoneVector<BasicBlock*>; 24using 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. 29class 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 BasicBlock(const BasicBlock&) = delete; 60 BasicBlock& operator=(const BasicBlock&) = delete; 61 62 Id id() const { return id_; } 63#if DEBUG 64 void set_debug_info(AssemblerDebugInfo debug_info) { 65 debug_info_ = debug_info; 66 } 67 AssemblerDebugInfo debug_info() const { return debug_info_; } 68#endif // DEBUG 69 70 void Print(); 71 72 // Predecessors. 73 BasicBlockVector& predecessors() { return predecessors_; } 74 const BasicBlockVector& predecessors() const { return predecessors_; } 75 size_t PredecessorCount() const { return predecessors_.size(); } 76 BasicBlock* PredecessorAt(size_t index) { return predecessors_[index]; } 77 void ClearPredecessors() { predecessors_.clear(); } 78 void AddPredecessor(BasicBlock* predecessor); 79 void RemovePredecessor(size_t index); 80 81 // Successors. 82 BasicBlockVector& successors() { return successors_; } 83 const BasicBlockVector& successors() const { return successors_; } 84 size_t SuccessorCount() const { return successors_.size(); } 85 BasicBlock* SuccessorAt(size_t index) { return successors_[index]; } 86 void ClearSuccessors() { successors_.clear(); } 87 void AddSuccessor(BasicBlock* successor); 88 89 // Nodes in the basic block. 90 using value_type = Node*; 91 bool empty() const { return nodes_.empty(); } 92 size_t size() const { return nodes_.size(); } 93 Node* NodeAt(size_t index) { return nodes_[index]; } 94 size_t NodeCount() const { return nodes_.size(); } 95 96 value_type& front() { return nodes_.front(); } 97 value_type const& front() const { return nodes_.front(); } 98 99 using iterator = NodeVector::iterator; 100 iterator begin() { return nodes_.begin(); } 101 iterator end() { return nodes_.end(); } 102 103 void RemoveNode(iterator it) { nodes_.erase(it); } 104 105 using const_iterator = NodeVector::const_iterator; 106 const_iterator begin() const { return nodes_.begin(); } 107 const_iterator end() const { return nodes_.end(); } 108 109 using reverse_iterator = NodeVector::reverse_iterator; 110 reverse_iterator rbegin() { return nodes_.rbegin(); } 111 reverse_iterator rend() { return nodes_.rend(); } 112 113 void AddNode(Node* node); 114 template <class InputIterator> 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. 126 Control control() const { return control_; } 127 void set_control(Control control); 128 129 Node* control_input() const { return control_input_; } 130 void set_control_input(Node* control_input); 131 132 bool deferred() const { return deferred_; } 133 void set_deferred(bool deferred) { deferred_ = deferred; } 134 135 int32_t dominator_depth() const { return dominator_depth_; } 136 void set_dominator_depth(int32_t depth) { dominator_depth_ = depth; } 137 138 BasicBlock* dominator() const { return dominator_; } 139 void set_dominator(BasicBlock* dominator) { dominator_ = dominator; } 140 141 BasicBlock* rpo_next() const { return rpo_next_; } 142 void set_rpo_next(BasicBlock* rpo_next) { rpo_next_ = rpo_next; } 143 144 BasicBlock* loop_header() const { return loop_header_; } 145 void set_loop_header(BasicBlock* loop_header); 146 147 BasicBlock* loop_end() const { return loop_end_; } 148 void set_loop_end(BasicBlock* loop_end); 149 150 int32_t loop_depth() const { return loop_depth_; } 151 void set_loop_depth(int32_t loop_depth); 152 153 int32_t loop_number() const { return loop_number_; } 154 void set_loop_number(int32_t loop_number) { loop_number_ = loop_number; } 155 156 int32_t rpo_number() const { return rpo_number_; } 157 void set_rpo_number(int32_t rpo_number); 158 159 NodeVector* nodes() { return &nodes_; } 160 161 // Loop membership helpers. 162 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 194std::ostream& operator<<(std::ostream&, const BasicBlock&); 195std::ostream& operator<<(std::ostream&, const BasicBlock::Control&); 196std::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. 202class 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 215 size_t BasicBlockCount() const { return all_blocks_.size(); } 216 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. 267 void AddSuccessorForTesting(BasicBlock* block, BasicBlock* succ) { 268 return AddSuccessor(block, succ); 269 } 270 271 const BasicBlockVector* all_blocks() const { return &all_blocks_; } 272 BasicBlockVector* rpo_order() { return &rpo_order_; } 273 const BasicBlockVector* rpo_order() const { return &rpo_order_; } 274 275 BasicBlock* start() { return start_; } 276 BasicBlock* end() { return end_; } 277 278 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 314V8_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