blob: 6bd1a17be0603476585442eaea760ce2b1ad3eb4 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/compiler/schedule.h"
6
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/compiler/node.h"
8#include "src/compiler/node-properties.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/ostreams.h"
10
11namespace v8 {
12namespace internal {
13namespace compiler {
14
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015BasicBlock::BasicBlock(Zone* zone, Id id)
16 : loop_number_(-1),
17 rpo_number_(-1),
18 deferred_(false),
19 dominator_depth_(-1),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020 dominator_(nullptr),
21 rpo_next_(nullptr),
22 loop_header_(nullptr),
23 loop_end_(nullptr),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040024 loop_depth_(0),
25 control_(kNone),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000026 control_input_(nullptr),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040027 nodes_(zone),
28 successors_(zone),
29 predecessors_(zone),
30 id_(id) {}
31
32
33bool BasicBlock::LoopContains(BasicBlock* block) const {
34 // RPO numbers must be initialized.
35 DCHECK(rpo_number_ >= 0);
36 DCHECK(block->rpo_number_ >= 0);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 if (loop_end_ == nullptr) return false; // This is not a loop.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040038 return block->rpo_number_ >= rpo_number_ &&
39 block->rpo_number_ < loop_end_->rpo_number_;
40}
41
42
43void BasicBlock::AddSuccessor(BasicBlock* successor) {
44 successors_.push_back(successor);
45}
46
47
48void BasicBlock::AddPredecessor(BasicBlock* predecessor) {
49 predecessors_.push_back(predecessor);
50}
51
52
53void BasicBlock::AddNode(Node* node) { nodes_.push_back(node); }
54
55
56void BasicBlock::set_control(Control control) {
57 control_ = control;
58}
59
60
61void BasicBlock::set_control_input(Node* control_input) {
62 control_input_ = control_input;
63}
64
65
66void BasicBlock::set_loop_depth(int32_t loop_depth) {
67 loop_depth_ = loop_depth;
68}
69
70
71void BasicBlock::set_rpo_number(int32_t rpo_number) {
72 rpo_number_ = rpo_number;
73}
74
75
76void BasicBlock::set_loop_end(BasicBlock* loop_end) { loop_end_ = loop_end; }
77
78
79void BasicBlock::set_loop_header(BasicBlock* loop_header) {
80 loop_header_ = loop_header;
81}
82
83
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000084// static
85BasicBlock* 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -040097std::ostream& operator<<(std::ostream& os, const BasicBlock::Control& c) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098 switch (c) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040099 case BasicBlock::kNone:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 return os << "none";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400101 case BasicBlock::kGoto:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000102 return os << "goto";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103 case BasicBlock::kCall:
104 return os << "call";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400105 case BasicBlock::kBranch:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000106 return os << "branch";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 case BasicBlock::kSwitch:
108 return os << "switch";
109 case BasicBlock::kDeoptimize:
110 return os << "deoptimize";
111 case BasicBlock::kTailCall:
112 return os << "tailcall";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400113 case BasicBlock::kReturn:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000114 return os << "return";
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400115 case BasicBlock::kThrow:
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000116 return os << "throw";
117 }
118 UNREACHABLE();
119 return os;
120}
121
122
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400123std::ostream& operator<<(std::ostream& os, const BasicBlock::Id& id) {
124 return os << id.ToSize();
125}
126
127
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400128Schedule::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
139BasicBlock* Schedule::block(Node* node) const {
140 if (node->id() < static_cast<NodeId>(nodeid_to_block_.size())) {
141 return nodeid_to_block_[node->id()];
142 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000143 return nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400144}
145
146
147bool Schedule::IsScheduled(Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 if (node->id() >= nodeid_to_block_.size()) return false;
149 return nodeid_to_block_[node->id()] != nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150}
151
152
153BasicBlock* Schedule::GetBlockById(BasicBlock::Id block_id) {
154 DCHECK(block_id.ToSize() < all_blocks_.size());
155 return all_blocks_[block_id.ToSize()];
156}
157
158
159bool Schedule::SameBasicBlock(Node* a, Node* b) const {
160 BasicBlock* block = this->block(a);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161 return block != nullptr && block == this->block(b);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400162}
163
164
165BasicBlock* 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
173void 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 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 DCHECK(this->block(node) == nullptr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400180 SetBlockForNode(block, node);
181}
182
183
184void 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 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000190 DCHECK(this->block(node) == nullptr || this->block(node) == block);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400191 block->AddNode(node);
192 SetBlockForNode(block, node);
193}
194
195
196void Schedule::AddGoto(BasicBlock* block, BasicBlock* succ) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 DCHECK_EQ(BasicBlock::kNone, block->control());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400198 block->set_control(BasicBlock::kGoto);
199 AddSuccessor(block, succ);
200}
201
Ben Murdochc5610432016-08-08 18:44:38 +0100202#if DEBUG
203namespace {
204
205bool IsPotentiallyThrowingCall(IrOpcode::Value opcode) {
206 switch (opcode) {
207#define BUILD_BLOCK_JS_CASE(Name) case IrOpcode::k##Name:
208 JS_OP_LIST(BUILD_BLOCK_JS_CASE)
209#undef BUILD_BLOCK_JS_CASE
210 case IrOpcode::kCall:
211 return true;
212 default:
213 return false;
214 }
215}
216
217} // namespace
218#endif // DEBUG
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400219
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220void Schedule::AddCall(BasicBlock* block, Node* call, BasicBlock* success_block,
221 BasicBlock* exception_block) {
222 DCHECK_EQ(BasicBlock::kNone, block->control());
Ben Murdochc5610432016-08-08 18:44:38 +0100223 DCHECK(IsPotentiallyThrowingCall(call->opcode()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 block->set_control(BasicBlock::kCall);
225 AddSuccessor(block, success_block);
226 AddSuccessor(block, exception_block);
227 SetControlInput(block, call);
228}
229
230
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231void Schedule::AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
232 BasicBlock* fblock) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000233 DCHECK_EQ(BasicBlock::kNone, block->control());
234 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400235 block->set_control(BasicBlock::kBranch);
236 AddSuccessor(block, tblock);
237 AddSuccessor(block, fblock);
238 SetControlInput(block, branch);
239}
240
241
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242void Schedule::AddSwitch(BasicBlock* block, Node* sw, BasicBlock** succ_blocks,
243 size_t succ_count) {
244 DCHECK_EQ(BasicBlock::kNone, block->control());
245 DCHECK_EQ(IrOpcode::kSwitch, sw->opcode());
246 block->set_control(BasicBlock::kSwitch);
247 for (size_t index = 0; index < succ_count; ++index) {
248 AddSuccessor(block, succ_blocks[index]);
249 }
250 SetControlInput(block, sw);
251}
252
253
254void Schedule::AddTailCall(BasicBlock* block, Node* input) {
255 DCHECK_EQ(BasicBlock::kNone, block->control());
256 block->set_control(BasicBlock::kTailCall);
257 SetControlInput(block, input);
258 if (block != end()) AddSuccessor(block, end());
259}
260
261
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400262void Schedule::AddReturn(BasicBlock* block, Node* input) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 DCHECK_EQ(BasicBlock::kNone, block->control());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 block->set_control(BasicBlock::kReturn);
265 SetControlInput(block, input);
266 if (block != end()) AddSuccessor(block, end());
267}
268
269
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270void Schedule::AddDeoptimize(BasicBlock* block, Node* input) {
271 DCHECK_EQ(BasicBlock::kNone, block->control());
272 block->set_control(BasicBlock::kDeoptimize);
273 SetControlInput(block, input);
274 if (block != end()) AddSuccessor(block, end());
275}
276
277
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400278void Schedule::AddThrow(BasicBlock* block, Node* input) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279 DCHECK_EQ(BasicBlock::kNone, block->control());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400280 block->set_control(BasicBlock::kThrow);
281 SetControlInput(block, input);
282 if (block != end()) AddSuccessor(block, end());
283}
284
285
286void Schedule::InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
287 BasicBlock* tblock, BasicBlock* fblock) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288 DCHECK_NE(BasicBlock::kNone, block->control());
289 DCHECK_EQ(BasicBlock::kNone, end->control());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400290 end->set_control(block->control());
291 block->set_control(BasicBlock::kBranch);
292 MoveSuccessors(block, end);
293 AddSuccessor(block, tblock);
294 AddSuccessor(block, fblock);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 if (block->control_input() != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400296 SetControlInput(end, block->control_input());
297 }
298 SetControlInput(block, branch);
299}
300
301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302void Schedule::InsertSwitch(BasicBlock* block, BasicBlock* end, Node* sw,
303 BasicBlock** succ_blocks, size_t succ_count) {
304 DCHECK_NE(BasicBlock::kNone, block->control());
305 DCHECK_EQ(BasicBlock::kNone, end->control());
306 end->set_control(block->control());
307 block->set_control(BasicBlock::kSwitch);
308 MoveSuccessors(block, end);
309 for (size_t index = 0; index < succ_count; ++index) {
310 AddSuccessor(block, succ_blocks[index]);
311 }
312 if (block->control_input() != nullptr) {
313 SetControlInput(end, block->control_input());
314 }
315 SetControlInput(block, sw);
316}
317
Ben Murdochc5610432016-08-08 18:44:38 +0100318void Schedule::EnsureCFGWellFormedness() {
Ben Murdochda12d292016-06-02 14:46:10 +0100319 // Make a copy of all the blocks for the iteration, since adding the split
320 // edges will allocate new blocks.
321 BasicBlockVector all_blocks_copy(all_blocks_);
322
323 // Insert missing split edge blocks.
324 for (auto block : all_blocks_copy) {
Ben Murdochc5610432016-08-08 18:44:38 +0100325 if (block->PredecessorCount() > 1) {
326 if (block != end_) {
327 EnsureSplitEdgeForm(block);
328 }
329 if (block->deferred()) {
330 EnsureDeferredCodeSingleEntryPoint(block);
331 }
332 }
333 }
334}
335
336void Schedule::EnsureSplitEdgeForm(BasicBlock* block) {
337 DCHECK(block->PredecessorCount() > 1 && block != end_);
338 for (auto current_pred = block->predecessors().begin();
339 current_pred != block->predecessors().end(); ++current_pred) {
340 BasicBlock* pred = *current_pred;
341 if (pred->SuccessorCount() > 1) {
342 // Found a predecessor block with multiple successors.
343 BasicBlock* split_edge_block = NewBasicBlock();
344 split_edge_block->set_control(BasicBlock::kGoto);
345 split_edge_block->successors().push_back(block);
346 split_edge_block->predecessors().push_back(pred);
347 split_edge_block->set_deferred(pred->deferred());
348 *current_pred = split_edge_block;
349 // Find a corresponding successor in the previous block, replace it
350 // with the split edge block... but only do it once, since we only
351 // replace the previous blocks in the current block one at a time.
352 for (auto successor = pred->successors().begin();
353 successor != pred->successors().end(); ++successor) {
354 if (*successor == block) {
355 *successor = split_edge_block;
356 break;
Ben Murdochda12d292016-06-02 14:46:10 +0100357 }
358 }
359 }
360 }
361}
362
Ben Murdochc5610432016-08-08 18:44:38 +0100363void Schedule::EnsureDeferredCodeSingleEntryPoint(BasicBlock* block) {
364 // If a deferred block has multiple predecessors, they have to
365 // all be deferred. Otherwise, we can run into a situation where a range
366 // that spills only in deferred blocks inserts its spill in the block, but
367 // other ranges need moves inserted by ResolveControlFlow in the predecessors,
368 // which may clobber the register of this range.
369 // To ensure that, when a deferred block has multiple predecessors, and some
370 // are not deferred, we add a non-deferred block to collect all such edges.
371
372 DCHECK(block->deferred() && block->PredecessorCount() > 1);
373 bool all_deferred = true;
374 for (auto current_pred = block->predecessors().begin();
375 current_pred != block->predecessors().end(); ++current_pred) {
376 BasicBlock* pred = *current_pred;
377 if (!pred->deferred()) {
378 all_deferred = false;
379 break;
380 }
381 }
382
383 if (all_deferred) return;
384 BasicBlock* merger = NewBasicBlock();
385 merger->set_control(BasicBlock::kGoto);
386 merger->successors().push_back(block);
387 for (auto current_pred = block->predecessors().begin();
388 current_pred != block->predecessors().end(); ++current_pred) {
389 BasicBlock* pred = *current_pred;
390 merger->predecessors().push_back(pred);
391 pred->successors().clear();
392 pred->successors().push_back(merger);
393 }
394 merger->set_deferred(false);
395 block->predecessors().clear();
396 block->predecessors().push_back(merger);
397}
398
Ben Murdochda12d292016-06-02 14:46:10 +0100399void Schedule::PropagateDeferredMark() {
400 // Push forward the deferred block marks through newly inserted blocks and
401 // other improperly marked blocks until a fixed point is reached.
402 // TODO(danno): optimize the propagation
403 bool done = false;
404 while (!done) {
405 done = true;
406 for (auto block : all_blocks_) {
407 if (!block->deferred()) {
408 bool deferred = block->PredecessorCount() > 0;
409 for (auto pred : block->predecessors()) {
410 if (!pred->deferred()) {
411 deferred = false;
412 }
413 }
414 if (deferred) {
415 block->set_deferred(true);
416 done = false;
417 }
418 }
419 }
420 }
421}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000422
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400423void Schedule::AddSuccessor(BasicBlock* block, BasicBlock* succ) {
424 block->AddSuccessor(succ);
425 succ->AddPredecessor(block);
426}
427
428
429void Schedule::MoveSuccessors(BasicBlock* from, BasicBlock* to) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000430 for (BasicBlock* const successor : from->successors()) {
431 to->AddSuccessor(successor);
432 for (BasicBlock*& predecessor : successor->predecessors()) {
433 if (predecessor == from) predecessor = to;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400434 }
435 }
436 from->ClearSuccessors();
437}
438
439
440void Schedule::SetControlInput(BasicBlock* block, Node* node) {
441 block->set_control_input(node);
442 SetBlockForNode(block, node);
443}
444
445
446void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447 if (node->id() >= nodeid_to_block_.size()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400448 nodeid_to_block_.resize(node->id() + 1);
449 }
450 nodeid_to_block_[node->id()] = block;
451}
452
453
454std::ostream& operator<<(std::ostream& os, const Schedule& s) {
Ben Murdochda12d292016-06-02 14:46:10 +0100455 for (BasicBlock* block :
456 ((s.RpoBlockCount() == 0) ? *s.all_blocks() : *s.rpo_order())) {
457 if (block->rpo_number() == -1) {
458 os << "--- BLOCK id:" << block->id().ToInt();
459 } else {
460 os << "--- BLOCK B" << block->rpo_number();
461 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400462 if (block->deferred()) os << " (deferred)";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 if (block->PredecessorCount() != 0) os << " <- ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 bool comma = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000465 for (BasicBlock const* predecessor : block->predecessors()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466 if (comma) os << ", ";
467 comma = true;
Ben Murdochda12d292016-06-02 14:46:10 +0100468 if (predecessor->rpo_number() == -1) {
469 os << "id:" << predecessor->id().ToInt();
470 } else {
471 os << "B" << predecessor->rpo_number();
472 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000473 }
474 os << " ---\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 for (Node* node : *block) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000476 os << " " << *node;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400477 if (NodeProperties::IsTyped(node)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478 Type* type = NodeProperties::GetType(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000479 os << " : ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000480 type->PrintTo(os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 }
482 os << "\n";
483 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400484 BasicBlock::Control control = block->control();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000485 if (control != BasicBlock::kNone) {
486 os << " ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000487 if (block->control_input() != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400488 os << *block->control_input();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000489 } else {
490 os << "Goto";
491 }
492 os << " -> ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000493 comma = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 for (BasicBlock const* successor : block->successors()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000495 if (comma) os << ", ";
496 comma = true;
Ben Murdochda12d292016-06-02 14:46:10 +0100497 if (successor->rpo_number() == -1) {
498 os << "id:" << successor->id().ToInt();
499 } else {
500 os << "B" << successor->rpo_number();
501 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000502 }
503 os << "\n";
504 }
505 }
506 return os;
507}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400508
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509} // namespace compiler
510} // namespace internal
511} // namespace v8