| Index: src/compiler/scheduler.cc
|
| diff --git a/src/compiler/scheduler.cc b/src/compiler/scheduler.cc
|
| index 2e12dd36af6a3bf25d2af21634efd7808ff86d94..555625691723db9b9e754931896c28fd51120915 100644
|
| --- a/src/compiler/scheduler.cc
|
| +++ b/src/compiler/scheduler.cc
|
| @@ -218,7 +218,8 @@ void Scheduler::DecrementUnscheduledUseCount(Node* node, int index,
|
| class CFGBuilder : public ZoneObject {
|
| public:
|
| CFGBuilder(Zone* zone, Scheduler* scheduler)
|
| - : scheduler_(scheduler),
|
| + : zone_(zone),
|
| + scheduler_(scheduler),
|
| schedule_(scheduler->schedule_),
|
| queued_(scheduler->graph_, 2),
|
| queue_(zone),
|
| @@ -316,7 +317,8 @@ class CFGBuilder : public ZoneObject {
|
| BuildBlockForNode(node);
|
| break;
|
| case IrOpcode::kBranch:
|
| - BuildBlocksForSuccessors(node, IrOpcode::kIfTrue, IrOpcode::kIfFalse);
|
| + case IrOpcode::kSwitch:
|
| + BuildBlocksForSuccessors(node);
|
| break;
|
| default:
|
| break;
|
| @@ -333,6 +335,10 @@ class CFGBuilder : public ZoneObject {
|
| scheduler_->UpdatePlacement(node, Scheduler::kFixed);
|
| ConnectBranch(node);
|
| break;
|
| + case IrOpcode::kSwitch:
|
| + scheduler_->UpdatePlacement(node, Scheduler::kFixed);
|
| + ConnectSwitch(node);
|
| + break;
|
| case IrOpcode::kReturn:
|
| scheduler_->UpdatePlacement(node, Scheduler::kFixed);
|
| ConnectReturn(node);
|
| @@ -357,49 +363,67 @@ class CFGBuilder : public ZoneObject {
|
| return block;
|
| }
|
|
|
| - void BuildBlocksForSuccessors(Node* node, IrOpcode::Value a,
|
| - IrOpcode::Value b) {
|
| - Node* successors[2];
|
| - CollectSuccessorProjections(node, successors, a, b);
|
| - BuildBlockForNode(successors[0]);
|
| - BuildBlockForNode(successors[1]);
|
| + void BuildBlocksForSuccessors(Node* node) {
|
| + size_t const successor_count = node->op()->ControlOutputCount();
|
| + Node** successors =
|
| + zone_->NewArray<Node*>(static_cast<int>(successor_count));
|
| + CollectSuccessorProjections(node, successors, successor_count);
|
| + for (size_t index = 0; index < successor_count; ++index) {
|
| + BuildBlockForNode(successors[index]);
|
| + }
|
| }
|
|
|
| // Collect the branch-related projections from a node, such as IfTrue,
|
| - // IfFalse.
|
| - // TODO(titzer): consider moving this to node.h
|
| - void CollectSuccessorProjections(Node* node, Node** buffer,
|
| - IrOpcode::Value true_opcode,
|
| - IrOpcode::Value false_opcode) {
|
| - buffer[0] = NULL;
|
| - buffer[1] = NULL;
|
| - for (Node* use : node->uses()) {
|
| - if (use->opcode() == true_opcode) {
|
| - DCHECK(!buffer[0]);
|
| - buffer[0] = use;
|
| - }
|
| - if (use->opcode() == false_opcode) {
|
| - DCHECK(!buffer[1]);
|
| - buffer[1] = use;
|
| + // IfFalse, and Case.
|
| + void CollectSuccessorProjections(Node* node, Node** successors,
|
| + size_t successor_count) {
|
| +#ifdef DEBUG
|
| + DCHECK_EQ(static_cast<int>(successor_count), node->UseCount());
|
| + std::memset(successors, 0, sizeof(*successors) * successor_count);
|
| +#endif
|
| + for (Node* const use : node->uses()) {
|
| + size_t index;
|
| + switch (use->opcode()) {
|
| + default:
|
| + UNREACHABLE();
|
| + // Fall through.
|
| + case IrOpcode::kIfTrue:
|
| + DCHECK_EQ(IrOpcode::kBranch, node->opcode());
|
| + index = 0;
|
| + break;
|
| + case IrOpcode::kIfFalse:
|
| + DCHECK_EQ(IrOpcode::kBranch, node->opcode());
|
| + index = 1;
|
| + break;
|
| + case IrOpcode::kCase:
|
| + DCHECK_EQ(IrOpcode::kSwitch, node->opcode());
|
| + index = CaseIndexOf(use->op());
|
| + break;
|
| }
|
| + DCHECK_LT(index, successor_count);
|
| + DCHECK(successors[index] == nullptr);
|
| + successors[index] = use;
|
| + }
|
| +#ifdef DEBUG
|
| + for (size_t index = 0; index < successor_count; ++index) {
|
| + DCHECK_NOT_NULL(successors[index]);
|
| }
|
| - DCHECK(buffer[0]);
|
| - DCHECK(buffer[1]);
|
| +#endif
|
| }
|
|
|
| - void CollectSuccessorBlocks(Node* node, BasicBlock** buffer,
|
| - IrOpcode::Value true_opcode,
|
| - IrOpcode::Value false_opcode) {
|
| - Node* successors[2];
|
| - CollectSuccessorProjections(node, successors, true_opcode, false_opcode);
|
| - buffer[0] = schedule_->block(successors[0]);
|
| - buffer[1] = schedule_->block(successors[1]);
|
| + void CollectSuccessorBlocks(Node* node, BasicBlock** successor_blocks,
|
| + size_t successor_count) {
|
| + Node** successors = reinterpret_cast<Node**>(successor_blocks);
|
| + CollectSuccessorProjections(node, successors, successor_count);
|
| + for (size_t index = 0; index < successor_count; ++index) {
|
| + successor_blocks[index] = schedule_->block(successors[index]);
|
| + }
|
| }
|
|
|
| void ConnectBranch(Node* branch) {
|
| BasicBlock* successor_blocks[2];
|
| - CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue,
|
| - IrOpcode::kIfFalse);
|
| + CollectSuccessorBlocks(branch, successor_blocks,
|
| + arraysize(successor_blocks));
|
|
|
| // Consider branch hints.
|
| switch (BranchHintOf(branch->op())) {
|
| @@ -421,7 +445,7 @@ class CFGBuilder : public ZoneObject {
|
| } else {
|
| Node* branch_block_node = NodeProperties::GetControlInput(branch);
|
| BasicBlock* branch_block = schedule_->block(branch_block_node);
|
| - DCHECK(branch_block != NULL);
|
| + DCHECK_NOT_NULL(branch_block);
|
|
|
| TraceConnect(branch, branch_block, successor_blocks[0]);
|
| TraceConnect(branch, branch_block, successor_blocks[1]);
|
| @@ -430,12 +454,36 @@ class CFGBuilder : public ZoneObject {
|
| }
|
| }
|
|
|
| + void ConnectSwitch(Node* sw) {
|
| + size_t const successor_count = sw->op()->ControlOutputCount();
|
| + BasicBlock** successor_blocks =
|
| + zone_->NewArray<BasicBlock*>(static_cast<int>(successor_count));
|
| + CollectSuccessorBlocks(sw, successor_blocks, successor_count);
|
| +
|
| + if (sw == component_entry_) {
|
| + for (size_t index = 0; index < successor_count; ++index) {
|
| + TraceConnect(sw, component_start_, successor_blocks[index]);
|
| + }
|
| + schedule_->InsertSwitch(component_start_, component_end_, sw,
|
| + successor_blocks, successor_count);
|
| + } else {
|
| + Node* sw_block_node = NodeProperties::GetControlInput(sw);
|
| + BasicBlock* sw_block = schedule_->block(sw_block_node);
|
| + DCHECK_NOT_NULL(sw_block);
|
| +
|
| + for (size_t index = 0; index < successor_count; ++index) {
|
| + TraceConnect(sw, sw_block, successor_blocks[index]);
|
| + }
|
| + schedule_->AddSwitch(sw_block, sw, successor_blocks, successor_count);
|
| + }
|
| + }
|
| +
|
| void ConnectMerge(Node* merge) {
|
| // Don't connect the special merge at the end to its predecessors.
|
| if (IsFinalMerge(merge)) return;
|
|
|
| BasicBlock* block = schedule_->block(merge);
|
| - DCHECK(block != NULL);
|
| + DCHECK_NOT_NULL(block);
|
| // For all of the merge's control inputs, add a goto at the end to the
|
| // merge's basic block.
|
| for (Node* const input : merge->inputs()) {
|
| @@ -460,7 +508,7 @@ class CFGBuilder : public ZoneObject {
|
| }
|
|
|
| void TraceConnect(Node* node, BasicBlock* block, BasicBlock* succ) {
|
| - DCHECK(block);
|
| + DCHECK_NOT_NULL(block);
|
| if (succ == NULL) {
|
| Trace("Connect #%d:%s, B%d -> end\n", node->id(), node->op()->mnemonic(),
|
| block->id().ToInt());
|
| @@ -487,6 +535,7 @@ class CFGBuilder : public ZoneObject {
|
| DCHECK(control_.empty());
|
| }
|
|
|
| + Zone* zone_;
|
| Scheduler* scheduler_;
|
| Schedule* schedule_;
|
| NodeMarker<bool> queued_; // Mark indicating whether node is queued.
|
|
|