blob: 4ac65e5ae4055b665c9409c878f0c0a18d9310c0 [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
202
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000203void 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400214void Schedule::AddBranch(BasicBlock* block, Node* branch, BasicBlock* tblock,
215 BasicBlock* fblock) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 DCHECK_EQ(BasicBlock::kNone, block->control());
217 DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400218 block->set_control(BasicBlock::kBranch);
219 AddSuccessor(block, tblock);
220 AddSuccessor(block, fblock);
221 SetControlInput(block, branch);
222}
223
224
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225void 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
237void 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400245void Schedule::AddReturn(BasicBlock* block, Node* input) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000246 DCHECK_EQ(BasicBlock::kNone, block->control());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400247 block->set_control(BasicBlock::kReturn);
248 SetControlInput(block, input);
249 if (block != end()) AddSuccessor(block, end());
250}
251
252
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253void 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400261void Schedule::AddThrow(BasicBlock* block, Node* input) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000262 DCHECK_EQ(BasicBlock::kNone, block->control());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400263 block->set_control(BasicBlock::kThrow);
264 SetControlInput(block, input);
265 if (block != end()) AddSuccessor(block, end());
266}
267
268
269void Schedule::InsertBranch(BasicBlock* block, BasicBlock* end, Node* branch,
270 BasicBlock* tblock, BasicBlock* fblock) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000271 DCHECK_NE(BasicBlock::kNone, block->control());
272 DCHECK_EQ(BasicBlock::kNone, end->control());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400273 end->set_control(block->control());
274 block->set_control(BasicBlock::kBranch);
275 MoveSuccessors(block, end);
276 AddSuccessor(block, tblock);
277 AddSuccessor(block, fblock);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000278 if (block->control_input() != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400279 SetControlInput(end, block->control_input());
280 }
281 SetControlInput(block, branch);
282}
283
284
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000285void 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
Ben Murdochda12d292016-06-02 14:46:10 +0100301void Schedule::EnsureSplitEdgeForm() {
302 // Make a copy of all the blocks for the iteration, since adding the split
303 // edges will allocate new blocks.
304 BasicBlockVector all_blocks_copy(all_blocks_);
305
306 // Insert missing split edge blocks.
307 for (auto block : all_blocks_copy) {
308 if (block->PredecessorCount() > 1 && block != end_) {
309 for (auto current_pred = block->predecessors().begin();
310 current_pred != block->predecessors().end(); ++current_pred) {
311 BasicBlock* pred = *current_pred;
312 if (pred->SuccessorCount() > 1) {
313 // Found a predecessor block with multiple successors.
314 BasicBlock* split_edge_block = NewBasicBlock();
315 split_edge_block->set_control(BasicBlock::kGoto);
316 split_edge_block->successors().push_back(block);
317 split_edge_block->predecessors().push_back(pred);
318 split_edge_block->set_deferred(pred->deferred());
319 *current_pred = split_edge_block;
320 // Find a corresponding successor in the previous block, replace it
321 // with the split edge block... but only do it once, since we only
322 // replace the previous blocks in the current block one at a time.
323 for (auto successor = pred->successors().begin();
324 successor != pred->successors().end(); ++successor) {
325 if (*successor == block) {
326 *successor = split_edge_block;
327 break;
328 }
329 }
330 }
331 }
332 }
333 }
334}
335
336void Schedule::PropagateDeferredMark() {
337 // Push forward the deferred block marks through newly inserted blocks and
338 // other improperly marked blocks until a fixed point is reached.
339 // TODO(danno): optimize the propagation
340 bool done = false;
341 while (!done) {
342 done = true;
343 for (auto block : all_blocks_) {
344 if (!block->deferred()) {
345 bool deferred = block->PredecessorCount() > 0;
346 for (auto pred : block->predecessors()) {
347 if (!pred->deferred()) {
348 deferred = false;
349 }
350 }
351 if (deferred) {
352 block->set_deferred(true);
353 done = false;
354 }
355 }
356 }
357 }
358}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400360void Schedule::AddSuccessor(BasicBlock* block, BasicBlock* succ) {
361 block->AddSuccessor(succ);
362 succ->AddPredecessor(block);
363}
364
365
366void Schedule::MoveSuccessors(BasicBlock* from, BasicBlock* to) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000367 for (BasicBlock* const successor : from->successors()) {
368 to->AddSuccessor(successor);
369 for (BasicBlock*& predecessor : successor->predecessors()) {
370 if (predecessor == from) predecessor = to;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400371 }
372 }
373 from->ClearSuccessors();
374}
375
376
377void Schedule::SetControlInput(BasicBlock* block, Node* node) {
378 block->set_control_input(node);
379 SetBlockForNode(block, node);
380}
381
382
383void Schedule::SetBlockForNode(BasicBlock* block, Node* node) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384 if (node->id() >= nodeid_to_block_.size()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400385 nodeid_to_block_.resize(node->id() + 1);
386 }
387 nodeid_to_block_[node->id()] = block;
388}
389
390
391std::ostream& operator<<(std::ostream& os, const Schedule& s) {
Ben Murdochda12d292016-06-02 14:46:10 +0100392 for (BasicBlock* block :
393 ((s.RpoBlockCount() == 0) ? *s.all_blocks() : *s.rpo_order())) {
394 if (block->rpo_number() == -1) {
395 os << "--- BLOCK id:" << block->id().ToInt();
396 } else {
397 os << "--- BLOCK B" << block->rpo_number();
398 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400399 if (block->deferred()) os << " (deferred)";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000400 if (block->PredecessorCount() != 0) os << " <- ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000401 bool comma = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000402 for (BasicBlock const* predecessor : block->predecessors()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000403 if (comma) os << ", ";
404 comma = true;
Ben Murdochda12d292016-06-02 14:46:10 +0100405 if (predecessor->rpo_number() == -1) {
406 os << "id:" << predecessor->id().ToInt();
407 } else {
408 os << "B" << predecessor->rpo_number();
409 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000410 }
411 os << " ---\n";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412 for (Node* node : *block) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000413 os << " " << *node;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400414 if (NodeProperties::IsTyped(node)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 Type* type = NodeProperties::GetType(node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000416 os << " : ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000417 type->PrintTo(os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000418 }
419 os << "\n";
420 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400421 BasicBlock::Control control = block->control();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000422 if (control != BasicBlock::kNone) {
423 os << " ";
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000424 if (block->control_input() != nullptr) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400425 os << *block->control_input();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000426 } else {
427 os << "Goto";
428 }
429 os << " -> ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430 comma = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431 for (BasicBlock const* successor : block->successors()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000432 if (comma) os << ", ";
433 comma = true;
Ben Murdochda12d292016-06-02 14:46:10 +0100434 if (successor->rpo_number() == -1) {
435 os << "id:" << successor->id().ToInt();
436 } else {
437 os << "B" << successor->rpo_number();
438 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000439 }
440 os << "\n";
441 }
442 }
443 return os;
444}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400445
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446} // namespace compiler
447} // namespace internal
448} // namespace v8