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 #include "src/compiler/schedule.h"
6 
7 #include "src/compiler/node.h"
8 #include "src/compiler/node-properties.h"
9 #include "src/ostreams.h"
10 
11 namespace v8 {
12 namespace internal {
13 namespace compiler {
14 
BasicBlock(Zone * zone,Id id)15 BasicBlock::BasicBlock(Zone* zone, Id id)
16     : loop_number_(-1),
17       rpo_number_(-1),
18       deferred_(false),
19       dominator_depth_(-1),
20       dominator_(nullptr),
21       rpo_next_(nullptr),
22       loop_header_(nullptr),
23       loop_end_(nullptr),
24       loop_depth_(0),
25       control_(kNone),
26       control_input_(nullptr),
27       nodes_(zone),
28       successors_(zone),
29       predecessors_(zone),
30       id_(id) {}
31 
32 
LoopContains(BasicBlock * block) const33 bool BasicBlock::LoopContains(BasicBlock* block) const {
34   // RPO numbers must be initialized.
35   DCHECK(rpo_number_ >= 0);
36   DCHECK(block->rpo_number_ >= 0);
37   if (loop_end_ == nullptr) return false;  // This is not a loop.
38   return block->rpo_number_ >= rpo_number_ &&
39          block->rpo_number_ < loop_end_->rpo_number_;
40 }
41 
42 
AddSuccessor(BasicBlock * successor)43 void BasicBlock::AddSuccessor(BasicBlock* successor) {
44   successors_.push_back(successor);
45 }
46 
47 
AddPredecessor(BasicBlock * predecessor)48 void BasicBlock::AddPredecessor(BasicBlock* predecessor) {
49   predecessors_.push_back(predecessor);
50 }
51 
52 
AddNode(Node * node)53 void BasicBlock::AddNode(Node* node) { nodes_.push_back(node); }
54 
55 
set_control(Control control)56 void BasicBlock::set_control(Control control) {
57   control_ = control;
58 }
59 
60 
set_control_input(Node * control_input)61 void BasicBlock::set_control_input(Node* control_input) {
62   control_input_ = control_input;
63 }
64 
65 
set_loop_depth(int32_t loop_depth)66 void BasicBlock::set_loop_depth(int32_t loop_depth) {
67   loop_depth_ = loop_depth;
68 }
69 
70 
set_rpo_number(int32_t rpo_number)71 void BasicBlock::set_rpo_number(int32_t rpo_number) {
72   rpo_number_ = rpo_number;
73 }
74 
75 
set_loop_end(BasicBlock * loop_end)76 void BasicBlock::set_loop_end(BasicBlock* loop_end) { loop_end_ = loop_end; }
77 
78 
set_loop_header(BasicBlock * loop_header)79 void BasicBlock::set_loop_header(BasicBlock* loop_header) {
80   loop_header_ = loop_header;
81 }
82 
83 
84 // static
GetCommonDominator(BasicBlock * b1,BasicBlock * b2)85 BasicBlock* BasicBlock::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
86   while (b1 != b2) {
87     if (b1->dominator_depth() < b2->dominator_depth()) {
88       b2 = b2->dominator();
89     } else {
90       b1 = b1->dominator();
91     }
92   }
93   return b1;
94 }
95 
96 
operator <<(std::ostream & os,const BasicBlock::Control & c)97 std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c) {
98   switch (c) {
99     case BasicBlock::kNone:
100       return os << "none";
101     case BasicBlock::kGoto:
102       return os << "goto";
103     case BasicBlock::kCall:
104       return os << "call";
105     case BasicBlock::kBranch:
106       return os << "branch";
107     case BasicBlock::kSwitch:
108       return os << "switch";
109     case BasicBlock::kDeoptimize:
110       return os << "deoptimize";
111     case BasicBlock::kTailCall:
112       return os << "tailcall";
113     case BasicBlock::kReturn:
114       return os << "return";
115     case BasicBlock::kThrow:
116       return os << "throw";
117   }
118   UNREACHABLE();
119   return os;
120 }
121 
122 
operator <<(std::ostream & os,const BasicBlock::Id & id)123 std::ostream& operator<<(std::ostream& os, const BasicBlock::Id& id) {
124   return os << id.ToSize();
125 }
126 
127 
Schedule(Zone * zone,size_t node_count_hint)128 Schedule::Schedule(Zone* zone, size_t node_count_hint)
129     : zone_(zone),
130       all_blocks_(zone),
131       nodeid_to_block_(zone),
132       rpo_order_(zone),
133       start_(NewBasicBlock()),
134       end_(NewBasicBlock()) {
135   nodeid_to_block_.reserve(node_count_hint);
136 }
137 
138 
block(Node * node) const139 BasicBlock* Schedule::block(Node* node) const {
140   if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) {
141     return nodeid_to_block_[node->id()];
142   }
143   return nullptr;
144 }
145 
146 
IsScheduled(Node * node)147 bool Schedule::IsScheduled(Node* node) {
148   if (node->id() >= nodeid_to_block_.size()) return false;
149   return nodeid_to_block_[node->id()] != nullptr;
150 }
151 
152 
GetBlockById(BasicBlock::Id block_id)153 BasicBlock* Schedule::GetBlockById(BasicBlock::Id block_id) {
154   DCHECK(block_id.ToSize() < all_blocks_.size());
155   return all_blocks_[block_id.ToSize()];
156 }
157 
158 
SameBasicBlock(Node * a,Node * b) const159 bool Schedule::SameBasicBlock(Node* a, Node* b) const {
160   BasicBlock* block = this->block(a);
161   return block != nullptr && block == this->block(b);
162 }
163 
164 
NewBasicBlock()165 BasicBlock* Schedule::NewBasicBlock() {
166   BasicBlock* block = new (zone_)
167       BasicBlock(zone_, BasicBlock::Id::FromSize(all_blocks_.size()));
168   all_blocks_.push_back(block);
169   return block;
170 }
171 
172 
PlanNode(BasicBlock * block,Node * node)173 void Schedule::PlanNode(BasicBlock* block, Node* node) {
174   if (FLAG_trace_turbo_scheduler) {
175     OFStream os(stdout);
176     os << "Planning #" << node->id() << ":" << node->op()->mnemonic()
177        << " for future add to B" << block->id() << "\n";
178   }
179   DCHECK(this->block(node) == nullptr);
180   SetBlockForNode(block, node);
181 }
182 
183 
AddNode(BasicBlock * block,Node * node)184 void Schedule::AddNode(BasicBlock* block, Node* node) {
185   if (FLAG_trace_turbo_scheduler) {
186     OFStream os(stdout);
187     os << "Adding #" << node->id() << ":" << node->op()->mnemonic() << " to B"
188        << block->id() << "\n";
189   }
190   DCHECK(this->block(node) == nullptr || this->block(node) == block);
191   block->AddNode(node);
192   SetBlockForNode(block, node);
193 }
194 
195 
AddGoto(BasicBlock * block,BasicBlock * succ)196 void Schedule::AddGoto(BasicBlock* block, BasicBlock* succ) {
197   DCHECK_EQ(BasicBlock::kNone, block->control());
198   block->set_control(BasicBlock::kGoto);
199   AddSuccessor(block, succ);
200 }
201 
202 
AddCall(BasicBlock * block,Node * call,BasicBlock * success_block,BasicBlock * exception_block)203 void Schedule::AddCall(BasicBlock* block, Node* call, BasicBlock* success_block,
204                        BasicBlock* exception_block) {
205   DCHECK_EQ(BasicBlock::kNone, block->control());
206   DCHECK_EQ(IrOpcode::kCall, call->opcode());
207   block->set_control(BasicBlock::kCall);
208   AddSuccessor(block, success_block);
209   AddSuccessor(block, exception_block);
210   SetControlInput(block, call);
211 }
212 
213 
AddBranch(BasicBlock * block,Node * branch,BasicBlock * tblock,BasicBlock * fblock)214 void Schedule::AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
215                          BasicBlock* fblock) {
216   DCHECK_EQ(BasicBlock::kNone, block->control());
217   DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
218   block->set_control(BasicBlock::kBranch);
219   AddSuccessor(block, tblock);
220   AddSuccessor(block, fblock);
221   SetControlInput(block, branch);
222 }
223 
224 
AddSwitch(BasicBlock * block,Node * sw,BasicBlock ** succ_blocks,size_t succ_count)225 void Schedule::AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks,
226                          size_t succ_count) {
227   DCHECK_EQ(BasicBlock::kNone, block->control());
228   DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
229   block->set_control(BasicBlock::kSwitch);
230   for (size_t index = 0; index < succ_count; ++index) {
231     AddSuccessor(block, succ_blocks[index]);
232   }
233   SetControlInput(block, sw);
234 }
235 
236 
AddTailCall(BasicBlock * block,Node * input)237 void Schedule::AddTailCall(BasicBlock* block, Node* input) {
238   DCHECK_EQ(BasicBlock::kNone, block->control());
239   block->set_control(BasicBlock::kTailCall);
240   SetControlInput(block, input);
241   if (block != end()) AddSuccessor(block, end());
242 }
243 
244 
AddReturn(BasicBlock * block,Node * input)245 void Schedule::AddReturn(BasicBlock* block, Node* input) {
246   DCHECK_EQ(BasicBlock::kNone, block->control());
247   block->set_control(BasicBlock::kReturn);
248   SetControlInput(block, input);
249   if (block != end()) AddSuccessor(block, end());
250 }
251 
252 
AddDeoptimize(BasicBlock * block,Node * input)253 void Schedule::AddDeoptimize(BasicBlock* block, Node* input) {
254   DCHECK_EQ(BasicBlock::kNone, block->control());
255   block->set_control(BasicBlock::kDeoptimize);
256   SetControlInput(block, input);
257   if (block != end()) AddSuccessor(block, end());
258 }
259 
260 
AddThrow(BasicBlock * block,Node * input)261 void Schedule::AddThrow(BasicBlock* block, Node* input) {
262   DCHECK_EQ(BasicBlock::kNone, block->control());
263   block->set_control(BasicBlock::kThrow);
264   SetControlInput(block, input);
265   if (block != end()) AddSuccessor(block, end());
266 }
267 
268 
InsertBranch(BasicBlock * block,BasicBlock * end,Node * branch,BasicBlock * tblock,BasicBlock * fblock)269 void Schedule::InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
270                             BasicBlock* tblock, BasicBlock* fblock) {
271   DCHECK_NE(BasicBlock::kNone, block->control());
272   DCHECK_EQ(BasicBlock::kNone, end->control());
273   end->set_control(block->control());
274   block->set_control(BasicBlock::kBranch);
275   MoveSuccessors(block, end);
276   AddSuccessor(block, tblock);
277   AddSuccessor(block, fblock);
278   if (block->control_input() != nullptr) {
279     SetControlInput(end, block->control_input());
280   }
281   SetControlInput(block, branch);
282 }
283 
284 
InsertSwitch(BasicBlock * block,BasicBlock * end,Node * sw,BasicBlock ** succ_blocks,size_t succ_count)285 void Schedule::InsertSwitch(BasicBlock* block, BasicBlock* end, Node* sw,
286                             BasicBlock** succ_blocks, size_t succ_count) {
287   DCHECK_NE(BasicBlock::kNone, block->control());
288   DCHECK_EQ(BasicBlock::kNone, end->control());
289   end->set_control(block->control());
290   block->set_control(BasicBlock::kSwitch);
291   MoveSuccessors(block, end);
292   for (size_t index = 0; index < succ_count; ++index) {
293     AddSuccessor(block, succ_blocks[index]);
294   }
295   if (block->control_input() != nullptr) {
296     SetControlInput(end, block->control_input());
297   }
298   SetControlInput(block, sw);
299 }
300 
301 
AddSuccessor(BasicBlock * block,BasicBlock * succ)302 void Schedule::AddSuccessor(BasicBlock* block, BasicBlock* succ) {
303   block->AddSuccessor(succ);
304   succ->AddPredecessor(block);
305 }
306 
307 
MoveSuccessors(BasicBlock * from,BasicBlock * to)308 void Schedule::MoveSuccessors(BasicBlock* from, BasicBlock* to) {
309   for (BasicBlock* const successor : from->successors()) {
310     to->AddSuccessor(successor);
311     for (BasicBlock*& predecessor : successor->predecessors()) {
312       if (predecessor == from) predecessor = to;
313     }
314   }
315   from->ClearSuccessors();
316 }
317 
318 
SetControlInput(BasicBlock * block,Node * node)319 void Schedule::SetControlInput(BasicBlock* block, Node* node) {
320   block->set_control_input(node);
321   SetBlockForNode(block, node);
322 }
323 
324 
SetBlockForNode(BasicBlock * block,Node * node)325 void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
326   if (node->id() >= nodeid_to_block_.size()) {
327     nodeid_to_block_.resize(node->id() + 1);
328   }
329   nodeid_to_block_[node->id()] = block;
330 }
331 
332 
operator <<(std::ostream & os,const Schedule & s)333 std::ostream& operator<<(std::ostream& os, const Schedule& s) {
334   for (BasicBlock* block : *s.rpo_order()) {
335     os << "--- BLOCK B" << block->rpo_number();
336     if (block->deferred()) os << " (deferred)";
337     if (block->PredecessorCount() != 0) os << " <- ";
338     bool comma = false;
339     for (BasicBlock const* predecessor : block->predecessors()) {
340       if (comma) os << ", ";
341       comma = true;
342       os << "B" << predecessor->rpo_number();
343     }
344     os << " ---\n";
345     for (Node* node : *block) {
346       os << "  " << *node;
347       if (NodeProperties::IsTyped(node)) {
348         Type* type = NodeProperties::GetType(node);
349         os << " : ";
350         type->PrintTo(os);
351       }
352       os << "\n";
353     }
354     BasicBlock::Control control = block->control();
355     if (control != BasicBlock::kNone) {
356       os << "  ";
357       if (block->control_input() != nullptr) {
358         os << *block->control_input();
359       } else {
360         os << "Goto";
361       }
362       os << " -> ";
363       comma = false;
364       for (BasicBlock const* successor : block->successors()) {
365         if (comma) os << ", ";
366         comma = true;
367         os << "B" << successor->rpo_number();
368       }
369       os << "\n";
370     }
371   }
372   return os;
373 }
374 
375 }  // namespace compiler
376 }  // namespace internal
377 }  // namespace v8
378