• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
NON_EXPORTED_BASE(ZoneObject)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.
NON_EXPORTED_BASE(ZoneObject)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