• 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 <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