Home | History | Annotate | Download | only in compiler
      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 <deque>
      6 #include <queue>
      7 
      8 #include "src/compiler/scheduler.h"
      9 
     10 #include "src/compiler/graph.h"
     11 #include "src/compiler/graph-inl.h"
     12 #include "src/compiler/node.h"
     13 #include "src/compiler/node-properties.h"
     14 #include "src/compiler/node-properties-inl.h"
     15 #include "src/data-flow.h"
     16 
     17 namespace v8 {
     18 namespace internal {
     19 namespace compiler {
     20 
     21 static inline void Trace(const char* msg, ...) {
     22   if (FLAG_trace_turbo_scheduler) {
     23     va_list arguments;
     24     va_start(arguments, msg);
     25     base::OS::VPrint(msg, arguments);
     26     va_end(arguments);
     27   }
     28 }
     29 
     30 
     31 // Internal class to build a control flow graph (i.e the basic blocks and edges
     32 // between them within a Schedule) from the node graph.
     33 // Visits the control edges of the graph backwards from end in order to find
     34 // the connected control subgraph, needed for scheduling.
     35 class CFGBuilder {
     36  public:
     37   Scheduler* scheduler_;
     38   Schedule* schedule_;
     39   ZoneQueue<Node*> queue_;
     40   NodeVector control_;
     41 
     42   CFGBuilder(Zone* zone, Scheduler* scheduler)
     43       : scheduler_(scheduler),
     44         schedule_(scheduler->schedule_),
     45         queue_(zone),
     46         control_(zone) {}
     47 
     48   // Run the control flow graph construction algorithm by walking the graph
     49   // backwards from end through control edges, building and connecting the
     50   // basic blocks for control nodes.
     51   void Run() {
     52     Graph* graph = scheduler_->graph_;
     53     FixNode(schedule_->start(), graph->start());
     54     Queue(graph->end());
     55 
     56     while (!queue_.empty()) {  // Breadth-first backwards traversal.
     57       Node* node = queue_.front();
     58       queue_.pop();
     59       int max = NodeProperties::PastControlIndex(node);
     60       for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
     61         Queue(node->InputAt(i));
     62       }
     63     }
     64 
     65     for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
     66       ConnectBlocks(*i);  // Connect block to its predecessor/successors.
     67     }
     68 
     69     FixNode(schedule_->end(), graph->end());
     70   }
     71 
     72   void FixNode(BasicBlock* block, Node* node) {
     73     schedule_->AddNode(block, node);
     74     scheduler_->GetData(node)->is_connected_control_ = true;
     75     scheduler_->GetData(node)->placement_ = Scheduler::kFixed;
     76   }
     77 
     78   void Queue(Node* node) {
     79     // Mark the connected control nodes as they queued.
     80     Scheduler::SchedulerData* data = scheduler_->GetData(node);
     81     if (!data->is_connected_control_) {
     82       BuildBlocks(node);
     83       queue_.push(node);
     84       control_.push_back(node);
     85       data->is_connected_control_ = true;
     86     }
     87   }
     88 
     89   void BuildBlocks(Node* node) {
     90     switch (node->opcode()) {
     91       case IrOpcode::kLoop:
     92       case IrOpcode::kMerge:
     93         BuildBlockForNode(node);
     94         break;
     95       case IrOpcode::kBranch:
     96         BuildBlocksForSuccessors(node, IrOpcode::kIfTrue, IrOpcode::kIfFalse);
     97         break;
     98       default:
     99         break;
    100     }
    101   }
    102 
    103   void ConnectBlocks(Node* node) {
    104     switch (node->opcode()) {
    105       case IrOpcode::kLoop:
    106       case IrOpcode::kMerge:
    107         ConnectMerge(node);
    108         break;
    109       case IrOpcode::kBranch:
    110         scheduler_->schedule_root_nodes_.push_back(node);
    111         ConnectBranch(node);
    112         break;
    113       case IrOpcode::kReturn:
    114         scheduler_->schedule_root_nodes_.push_back(node);
    115         ConnectReturn(node);
    116         break;
    117       default:
    118         break;
    119     }
    120   }
    121 
    122   void BuildBlockForNode(Node* node) {
    123     if (schedule_->block(node) == NULL) {
    124       BasicBlock* block = schedule_->NewBasicBlock();
    125       Trace("Create block B%d for #%d:%s\n", block->id(), node->id(),
    126             node->op()->mnemonic());
    127       FixNode(block, node);
    128     }
    129   }
    130 
    131   void BuildBlocksForSuccessors(Node* node, IrOpcode::Value a,
    132                                 IrOpcode::Value b) {
    133     Node* successors[2];
    134     CollectSuccessorProjections(node, successors, a, b);
    135     BuildBlockForNode(successors[0]);
    136     BuildBlockForNode(successors[1]);
    137   }
    138 
    139   // Collect the branch-related projections from a node, such as IfTrue,
    140   // IfFalse.
    141   // TODO(titzer): consider moving this to node.h
    142   void CollectSuccessorProjections(Node* node, Node** buffer,
    143                                    IrOpcode::Value true_opcode,
    144                                    IrOpcode::Value false_opcode) {
    145     buffer[0] = NULL;
    146     buffer[1] = NULL;
    147     for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
    148       if ((*i)->opcode() == true_opcode) {
    149         DCHECK_EQ(NULL, buffer[0]);
    150         buffer[0] = *i;
    151       }
    152       if ((*i)->opcode() == false_opcode) {
    153         DCHECK_EQ(NULL, buffer[1]);
    154         buffer[1] = *i;
    155       }
    156     }
    157     DCHECK_NE(NULL, buffer[0]);
    158     DCHECK_NE(NULL, buffer[1]);
    159   }
    160 
    161   void CollectSuccessorBlocks(Node* node, BasicBlock** buffer,
    162                               IrOpcode::Value true_opcode,
    163                               IrOpcode::Value false_opcode) {
    164     Node* successors[2];
    165     CollectSuccessorProjections(node, successors, true_opcode, false_opcode);
    166     buffer[0] = schedule_->block(successors[0]);
    167     buffer[1] = schedule_->block(successors[1]);
    168   }
    169 
    170   void ConnectBranch(Node* branch) {
    171     Node* branch_block_node = NodeProperties::GetControlInput(branch);
    172     BasicBlock* branch_block = schedule_->block(branch_block_node);
    173     DCHECK(branch_block != NULL);
    174 
    175     BasicBlock* successor_blocks[2];
    176     CollectSuccessorBlocks(branch, successor_blocks, IrOpcode::kIfTrue,
    177                            IrOpcode::kIfFalse);
    178 
    179     TraceConnect(branch, branch_block, successor_blocks[0]);
    180     TraceConnect(branch, branch_block, successor_blocks[1]);
    181 
    182     schedule_->AddBranch(branch_block, branch, successor_blocks[0],
    183                          successor_blocks[1]);
    184   }
    185 
    186   void ConnectMerge(Node* merge) {
    187     BasicBlock* block = schedule_->block(merge);
    188     DCHECK(block != NULL);
    189     // For all of the merge's control inputs, add a goto at the end to the
    190     // merge's basic block.
    191     for (InputIter j = merge->inputs().begin(); j != merge->inputs().end();
    192          ++j) {
    193       BasicBlock* predecessor_block = schedule_->block(*j);
    194       if ((*j)->opcode() != IrOpcode::kReturn) {
    195         TraceConnect(merge, predecessor_block, block);
    196         schedule_->AddGoto(predecessor_block, block);
    197       }
    198     }
    199   }
    200 
    201   void ConnectReturn(Node* ret) {
    202     Node* return_block_node = NodeProperties::GetControlInput(ret);
    203     BasicBlock* return_block = schedule_->block(return_block_node);
    204     TraceConnect(ret, return_block, NULL);
    205     schedule_->AddReturn(return_block, ret);
    206   }
    207 
    208   void TraceConnect(Node* node, BasicBlock* block, BasicBlock* succ) {
    209     DCHECK_NE(NULL, block);
    210     if (succ == NULL) {
    211       Trace("Connect #%d:%s, B%d -> end\n", node->id(), node->op()->mnemonic(),
    212             block->id());
    213     } else {
    214       Trace("Connect #%d:%s, B%d -> B%d\n", node->id(), node->op()->mnemonic(),
    215             block->id(), succ->id());
    216     }
    217   }
    218 };
    219 
    220 
    221 Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
    222   SchedulerData def = {0, 0, false, false, kUnknown};
    223   return def;
    224 }
    225 
    226 
    227 Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule)
    228     : zone_(zone),
    229       graph_(graph),
    230       schedule_(schedule),
    231       scheduled_nodes_(zone),
    232       schedule_root_nodes_(zone),
    233       node_data_(graph_->NodeCount(), DefaultSchedulerData(), zone),
    234       has_floating_control_(false) {}
    235 
    236 
    237 Schedule* Scheduler::ComputeSchedule(Graph* graph) {
    238   Schedule* schedule;
    239   bool had_floating_control = false;
    240   do {
    241     Zone tmp_zone(graph->zone()->isolate());
    242     schedule = new (graph->zone()) Schedule(graph->zone());
    243     Scheduler scheduler(&tmp_zone, graph, schedule);
    244 
    245     scheduler.BuildCFG();
    246 
    247     Scheduler::ComputeSpecialRPO(schedule);
    248     scheduler.GenerateImmediateDominatorTree();
    249 
    250     scheduler.PrepareUses();
    251     scheduler.ScheduleEarly();
    252     scheduler.ScheduleLate();
    253 
    254     had_floating_control = scheduler.ConnectFloatingControl();
    255   } while (had_floating_control);
    256 
    257   return schedule;
    258 }
    259 
    260 
    261 Scheduler::Placement Scheduler::GetPlacement(Node* node) {
    262   SchedulerData* data = GetData(node);
    263   if (data->placement_ == kUnknown) {  // Compute placement, once, on demand.
    264     switch (node->opcode()) {
    265       case IrOpcode::kParameter:
    266         // Parameters are always fixed to the start node.
    267         data->placement_ = kFixed;
    268         break;
    269       case IrOpcode::kPhi:
    270       case IrOpcode::kEffectPhi: {
    271         // Phis and effect phis are fixed if their control inputs are.
    272         data->placement_ = GetPlacement(NodeProperties::GetControlInput(node));
    273         break;
    274       }
    275 #define DEFINE_FLOATING_CONTROL_CASE(V) case IrOpcode::k##V:
    276         CONTROL_OP_LIST(DEFINE_FLOATING_CONTROL_CASE)
    277 #undef DEFINE_FLOATING_CONTROL_CASE
    278         {
    279           // Control nodes that were not control-reachable from end may float.
    280           data->placement_ = kSchedulable;
    281           if (!data->is_connected_control_) {
    282             data->is_floating_control_ = true;
    283             has_floating_control_ = true;
    284             Trace("Floating control found: #%d:%s\n", node->id(),
    285                   node->op()->mnemonic());
    286           }
    287           break;
    288         }
    289       default:
    290         data->placement_ = kSchedulable;
    291         break;
    292     }
    293   }
    294   return data->placement_;
    295 }
    296 
    297 
    298 void Scheduler::BuildCFG() {
    299   Trace("---------------- CREATING CFG ------------------\n");
    300   CFGBuilder cfg_builder(zone_, this);
    301   cfg_builder.Run();
    302   // Initialize per-block data.
    303   scheduled_nodes_.resize(schedule_->BasicBlockCount(), NodeVector(zone_));
    304 }
    305 
    306 
    307 BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
    308   while (b1 != b2) {
    309     int b1_rpo = GetRPONumber(b1);
    310     int b2_rpo = GetRPONumber(b2);
    311     DCHECK(b1_rpo != b2_rpo);
    312     if (b1_rpo < b2_rpo) {
    313       b2 = b2->dominator_;
    314     } else {
    315       b1 = b1->dominator_;
    316     }
    317   }
    318   return b1;
    319 }
    320 
    321 
    322 void Scheduler::GenerateImmediateDominatorTree() {
    323   // Build the dominator graph.  TODO(danno): consider using Lengauer & Tarjan's
    324   // if this becomes really slow.
    325   Trace("------------ IMMEDIATE BLOCK DOMINATORS -----------\n");
    326   for (size_t i = 0; i < schedule_->rpo_order_.size(); i++) {
    327     BasicBlock* current_rpo = schedule_->rpo_order_[i];
    328     if (current_rpo != schedule_->start()) {
    329       BasicBlock::Predecessors::iterator current_pred =
    330           current_rpo->predecessors().begin();
    331       BasicBlock::Predecessors::iterator end =
    332           current_rpo->predecessors().end();
    333       DCHECK(current_pred != end);
    334       BasicBlock* dominator = *current_pred;
    335       ++current_pred;
    336       // For multiple predecessors, walk up the rpo ordering until a common
    337       // dominator is found.
    338       int current_rpo_pos = GetRPONumber(current_rpo);
    339       while (current_pred != end) {
    340         // Don't examine backwards edges
    341         BasicBlock* pred = *current_pred;
    342         if (GetRPONumber(pred) < current_rpo_pos) {
    343           dominator = GetCommonDominator(dominator, *current_pred);
    344         }
    345         ++current_pred;
    346       }
    347       current_rpo->dominator_ = dominator;
    348       Trace("Block %d's idom is %d\n", current_rpo->id(), dominator->id());
    349     }
    350   }
    351 }
    352 
    353 
    354 class ScheduleEarlyNodeVisitor : public NullNodeVisitor {
    355  public:
    356   explicit ScheduleEarlyNodeVisitor(Scheduler* scheduler)
    357       : has_changed_rpo_constraints_(true),
    358         scheduler_(scheduler),
    359         schedule_(scheduler->schedule_) {}
    360 
    361   GenericGraphVisit::Control Pre(Node* node) {
    362     int max_rpo = 0;
    363     // Fixed nodes already know their schedule early position.
    364     if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
    365       BasicBlock* block = schedule_->block(node);
    366       DCHECK(block != NULL);
    367       max_rpo = block->rpo_number_;
    368       if (scheduler_->GetData(node)->minimum_rpo_ != max_rpo) {
    369         has_changed_rpo_constraints_ = true;
    370       }
    371       scheduler_->GetData(node)->minimum_rpo_ = max_rpo;
    372       Trace("Preschedule #%d:%s minimum_rpo = %d\n", node->id(),
    373             node->op()->mnemonic(), max_rpo);
    374     }
    375     return GenericGraphVisit::CONTINUE;
    376   }
    377 
    378   GenericGraphVisit::Control Post(Node* node) {
    379     int max_rpo = 0;
    380     // Otherwise, the minimum rpo for the node is the max of all of the inputs.
    381     if (scheduler_->GetPlacement(node) != Scheduler::kFixed) {
    382       for (InputIter i = node->inputs().begin(); i != node->inputs().end();
    383            ++i) {
    384         int control_rpo = scheduler_->GetData(*i)->minimum_rpo_;
    385         if (control_rpo > max_rpo) {
    386           max_rpo = control_rpo;
    387         }
    388       }
    389       if (scheduler_->GetData(node)->minimum_rpo_ != max_rpo) {
    390         has_changed_rpo_constraints_ = true;
    391       }
    392       scheduler_->GetData(node)->minimum_rpo_ = max_rpo;
    393       Trace("Postschedule #%d:%s minimum_rpo = %d\n", node->id(),
    394             node->op()->mnemonic(), max_rpo);
    395     }
    396     return GenericGraphVisit::CONTINUE;
    397   }
    398 
    399   // TODO(mstarzinger): Dirty hack to unblock others, schedule early should be
    400   // rewritten to use a pre-order traversal from the start instead.
    401   bool has_changed_rpo_constraints_;
    402 
    403  private:
    404   Scheduler* scheduler_;
    405   Schedule* schedule_;
    406 };
    407 
    408 
    409 void Scheduler::ScheduleEarly() {
    410   Trace("------------------- SCHEDULE EARLY ----------------\n");
    411 
    412   int fixpoint_count = 0;
    413   ScheduleEarlyNodeVisitor visitor(this);
    414   while (visitor.has_changed_rpo_constraints_) {
    415     visitor.has_changed_rpo_constraints_ = false;
    416     graph_->VisitNodeInputsFromEnd(&visitor);
    417     fixpoint_count++;
    418   }
    419 
    420   Trace("It took %d iterations to determine fixpoint\n", fixpoint_count);
    421 }
    422 
    423 
    424 class PrepareUsesVisitor : public NullNodeVisitor {
    425  public:
    426   explicit PrepareUsesVisitor(Scheduler* scheduler)
    427       : scheduler_(scheduler), schedule_(scheduler->schedule_) {}
    428 
    429   GenericGraphVisit::Control Pre(Node* node) {
    430     if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
    431       // Fixed nodes are always roots for schedule late.
    432       scheduler_->schedule_root_nodes_.push_back(node);
    433       if (!schedule_->IsScheduled(node)) {
    434         // Make sure root nodes are scheduled in their respective blocks.
    435         Trace("  Scheduling fixed position node #%d:%s\n", node->id(),
    436               node->op()->mnemonic());
    437         IrOpcode::Value opcode = node->opcode();
    438         BasicBlock* block =
    439             opcode == IrOpcode::kParameter
    440                 ? schedule_->start()
    441                 : schedule_->block(NodeProperties::GetControlInput(node));
    442         DCHECK(block != NULL);
    443         schedule_->AddNode(block, node);
    444       }
    445     }
    446 
    447     return GenericGraphVisit::CONTINUE;
    448   }
    449 
    450   void PostEdge(Node* from, int index, Node* to) {
    451     // If the edge is from an unscheduled node, then tally it in the use count
    452     // for all of its inputs. The same criterion will be used in ScheduleLate
    453     // for decrementing use counts.
    454     if (!schedule_->IsScheduled(from)) {
    455       DCHECK_NE(Scheduler::kFixed, scheduler_->GetPlacement(from));
    456       ++(scheduler_->GetData(to)->unscheduled_count_);
    457       Trace("  Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
    458             to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
    459             scheduler_->GetData(to)->unscheduled_count_);
    460     }
    461   }
    462 
    463  private:
    464   Scheduler* scheduler_;
    465   Schedule* schedule_;
    466 };
    467 
    468 
    469 void Scheduler::PrepareUses() {
    470   Trace("------------------- PREPARE USES ------------------\n");
    471   // Count the uses of every node, it will be used to ensure that all of a
    472   // node's uses are scheduled before the node itself.
    473   PrepareUsesVisitor prepare_uses(this);
    474   graph_->VisitNodeInputsFromEnd(&prepare_uses);
    475 }
    476 
    477 
    478 class ScheduleLateNodeVisitor : public NullNodeVisitor {
    479  public:
    480   explicit ScheduleLateNodeVisitor(Scheduler* scheduler)
    481       : scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
    482 
    483   GenericGraphVisit::Control Pre(Node* node) {
    484     // Don't schedule nodes that are already scheduled.
    485     if (schedule_->IsScheduled(node)) {
    486       return GenericGraphVisit::CONTINUE;
    487     }
    488     Scheduler::SchedulerData* data = scheduler_->GetData(node);
    489     DCHECK_EQ(Scheduler::kSchedulable, data->placement_);
    490 
    491     // If all the uses of a node have been scheduled, then the node itself can
    492     // be scheduled.
    493     bool eligible = data->unscheduled_count_ == 0;
    494     Trace("Testing for schedule eligibility for #%d:%s = %s\n", node->id(),
    495           node->op()->mnemonic(), eligible ? "true" : "false");
    496     if (!eligible) return GenericGraphVisit::DEFER;
    497 
    498     // Determine the dominating block for all of the uses of this node. It is
    499     // the latest block that this node can be scheduled in.
    500     BasicBlock* block = NULL;
    501     for (Node::Uses::iterator i = node->uses().begin(); i != node->uses().end();
    502          ++i) {
    503       BasicBlock* use_block = GetBlockForUse(i.edge());
    504       block = block == NULL ? use_block : use_block == NULL
    505                                               ? block
    506                                               : scheduler_->GetCommonDominator(
    507                                                     block, use_block);
    508     }
    509     DCHECK(block != NULL);
    510 
    511     int min_rpo = data->minimum_rpo_;
    512     Trace(
    513         "Schedule late conservative for #%d:%s is B%d at loop depth %d, "
    514         "minimum_rpo = %d\n",
    515         node->id(), node->op()->mnemonic(), block->id(), block->loop_depth_,
    516         min_rpo);
    517     // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively
    518     // into enclosing loop pre-headers until they would preceed their
    519     // ScheduleEarly position.
    520     BasicBlock* hoist_block = block;
    521     while (hoist_block != NULL && hoist_block->rpo_number_ >= min_rpo) {
    522       if (hoist_block->loop_depth_ < block->loop_depth_) {
    523         block = hoist_block;
    524         Trace("  hoisting #%d:%s to block %d\n", node->id(),
    525               node->op()->mnemonic(), block->id());
    526       }
    527       // Try to hoist to the pre-header of the loop header.
    528       hoist_block = hoist_block->loop_header();
    529       if (hoist_block != NULL) {
    530         BasicBlock* pre_header = hoist_block->dominator_;
    531         DCHECK(pre_header == NULL ||
    532                *hoist_block->predecessors().begin() == pre_header);
    533         Trace(
    534             "  hoist to pre-header B%d of loop header B%d, depth would be %d\n",
    535             pre_header->id(), hoist_block->id(), pre_header->loop_depth_);
    536         hoist_block = pre_header;
    537       }
    538     }
    539 
    540     ScheduleNode(block, node);
    541 
    542     return GenericGraphVisit::CONTINUE;
    543   }
    544 
    545  private:
    546   BasicBlock* GetBlockForUse(Node::Edge edge) {
    547     Node* use = edge.from();
    548     IrOpcode::Value opcode = use->opcode();
    549     if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
    550       // If the use is from a fixed (i.e. non-floating) phi, use the block
    551       // of the corresponding control input to the merge.
    552       int index = edge.index();
    553       if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
    554         Trace("  input@%d into a fixed phi #%d:%s\n", index, use->id(),
    555               use->op()->mnemonic());
    556         Node* merge = NodeProperties::GetControlInput(use, 0);
    557         opcode = merge->opcode();
    558         DCHECK(opcode == IrOpcode::kMerge || opcode == IrOpcode::kLoop);
    559         use = NodeProperties::GetControlInput(merge, index);
    560       }
    561     }
    562     BasicBlock* result = schedule_->block(use);
    563     if (result == NULL) return NULL;
    564     Trace("  must dominate use #%d:%s in B%d\n", use->id(),
    565           use->op()->mnemonic(), result->id());
    566     return result;
    567   }
    568 
    569   void ScheduleNode(BasicBlock* block, Node* node) {
    570     schedule_->PlanNode(block, node);
    571     scheduler_->scheduled_nodes_[block->id()].push_back(node);
    572 
    573     // Reduce the use count of the node's inputs to potentially make them
    574     // schedulable.
    575     for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
    576       Scheduler::SchedulerData* data = scheduler_->GetData(*i);
    577       DCHECK(data->unscheduled_count_ > 0);
    578       --data->unscheduled_count_;
    579       if (FLAG_trace_turbo_scheduler) {
    580         Trace("  Use count for #%d:%s (used by #%d:%s)-- = %d\n", (*i)->id(),
    581               (*i)->op()->mnemonic(), i.edge().from()->id(),
    582               i.edge().from()->op()->mnemonic(), data->unscheduled_count_);
    583         if (data->unscheduled_count_ == 0) {
    584           Trace("  newly eligible #%d:%s\n", (*i)->id(),
    585                 (*i)->op()->mnemonic());
    586         }
    587       }
    588     }
    589   }
    590 
    591   Scheduler* scheduler_;
    592   Schedule* schedule_;
    593 };
    594 
    595 
    596 void Scheduler::ScheduleLate() {
    597   Trace("------------------- SCHEDULE LATE -----------------\n");
    598   if (FLAG_trace_turbo_scheduler) {
    599     Trace("roots: ");
    600     for (NodeVectorIter i = schedule_root_nodes_.begin();
    601          i != schedule_root_nodes_.end(); ++i) {
    602       Trace("#%d:%s ", (*i)->id(), (*i)->op()->mnemonic());
    603     }
    604     Trace("\n");
    605   }
    606 
    607   // Schedule: Places nodes in dominator block of all their uses.
    608   ScheduleLateNodeVisitor schedule_late_visitor(this);
    609 
    610   {
    611     Zone zone(zone_->isolate());
    612     GenericGraphVisit::Visit<ScheduleLateNodeVisitor,
    613                              NodeInputIterationTraits<Node> >(
    614         graph_, &zone, schedule_root_nodes_.begin(), schedule_root_nodes_.end(),
    615         &schedule_late_visitor);
    616   }
    617 
    618   // Add collected nodes for basic blocks to their blocks in the right order.
    619   int block_num = 0;
    620   for (NodeVectorVectorIter i = scheduled_nodes_.begin();
    621        i != scheduled_nodes_.end(); ++i) {
    622     for (NodeVectorRIter j = i->rbegin(); j != i->rend(); ++j) {
    623       schedule_->AddNode(schedule_->all_blocks_.at(block_num), *j);
    624     }
    625     block_num++;
    626   }
    627 }
    628 
    629 
    630 bool Scheduler::ConnectFloatingControl() {
    631   if (!has_floating_control_) return false;
    632 
    633   Trace("Connecting floating control...\n");
    634 
    635   // Process blocks and instructions backwards to find and connect floating
    636   // control nodes into the control graph according to the block they were
    637   // scheduled into.
    638   int max = static_cast<int>(schedule_->rpo_order()->size());
    639   for (int i = max - 1; i >= 0; i--) {
    640     BasicBlock* block = schedule_->rpo_order()->at(i);
    641     // TODO(titzer): we place at most one floating control structure per
    642     // basic block because scheduling currently can interleave phis from
    643     // one subgraph with the merges from another subgraph.
    644     bool one_placed = false;
    645     for (int j = static_cast<int>(block->nodes_.size()) - 1; j >= 0; j--) {
    646       Node* node = block->nodes_[j];
    647       SchedulerData* data = GetData(node);
    648       if (data->is_floating_control_ && !data->is_connected_control_ &&
    649           !one_placed) {
    650         Trace("  Floating control #%d:%s was scheduled in B%d\n", node->id(),
    651               node->op()->mnemonic(), block->id());
    652         ConnectFloatingControlSubgraph(block, node);
    653         one_placed = true;
    654       }
    655     }
    656   }
    657 
    658   return true;
    659 }
    660 
    661 
    662 void Scheduler::ConnectFloatingControlSubgraph(BasicBlock* block, Node* end) {
    663   Node* block_start = block->nodes_[0];
    664   DCHECK(IrOpcode::IsControlOpcode(block_start->opcode()));
    665   // Find the current "control successor" of the node that starts the block
    666   // by searching the control uses for a control input edge from a connected
    667   // control node.
    668   Node* control_succ = NULL;
    669   for (UseIter i = block_start->uses().begin(); i != block_start->uses().end();
    670        ++i) {
    671     Node::Edge edge = i.edge();
    672     if (NodeProperties::IsControlEdge(edge) &&
    673         GetData(edge.from())->is_connected_control_) {
    674       DCHECK_EQ(NULL, control_succ);
    675       control_succ = edge.from();
    676       control_succ->ReplaceInput(edge.index(), end);
    677     }
    678   }
    679   DCHECK_NE(NULL, control_succ);
    680   Trace("  Inserting floating control end %d:%s between %d:%s -> %d:%s\n",
    681         end->id(), end->op()->mnemonic(), control_succ->id(),
    682         control_succ->op()->mnemonic(), block_start->id(),
    683         block_start->op()->mnemonic());
    684 
    685   // Find the "start" node of the control subgraph, which should be the
    686   // unique node that is itself floating control but has a control input that
    687   // is not floating.
    688   Node* start = NULL;
    689   ZoneQueue<Node*> queue(zone_);
    690   queue.push(end);
    691   GetData(end)->is_connected_control_ = true;
    692   while (!queue.empty()) {
    693     Node* node = queue.front();
    694     queue.pop();
    695     Trace("  Search #%d:%s for control subgraph start\n", node->id(),
    696           node->op()->mnemonic());
    697     int max = NodeProperties::PastControlIndex(node);
    698     for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
    699       Node* input = node->InputAt(i);
    700       SchedulerData* data = GetData(input);
    701       if (data->is_floating_control_) {
    702         // {input} is floating control.
    703         if (!data->is_connected_control_) {
    704           // First time seeing {input} during this traversal, queue it.
    705           queue.push(input);
    706           data->is_connected_control_ = true;
    707         }
    708       } else {
    709         // Otherwise, {node} is the start node, because it is floating control
    710         // but is connected to {input} that is not floating control.
    711         DCHECK_EQ(NULL, start);  // There can be only one.
    712         start = node;
    713       }
    714     }
    715   }
    716 
    717   DCHECK_NE(NULL, start);
    718   start->ReplaceInput(NodeProperties::FirstControlIndex(start), block_start);
    719 
    720   Trace("  Connecting floating control start %d:%s to %d:%s\n", start->id(),
    721         start->op()->mnemonic(), block_start->id(),
    722         block_start->op()->mnemonic());
    723 }
    724 
    725 
    726 // Numbering for BasicBlockData.rpo_number_ for this block traversal:
    727 static const int kBlockOnStack = -2;
    728 static const int kBlockVisited1 = -3;
    729 static const int kBlockVisited2 = -4;
    730 static const int kBlockUnvisited1 = -1;
    731 static const int kBlockUnvisited2 = kBlockVisited1;
    732 
    733 struct SpecialRPOStackFrame {
    734   BasicBlock* block;
    735   int index;
    736 };
    737 
    738 struct BlockList {
    739   BasicBlock* block;
    740   BlockList* next;
    741 
    742   BlockList* Add(Zone* zone, BasicBlock* b) {
    743     BlockList* list = static_cast<BlockList*>(zone->New(sizeof(BlockList)));
    744     list->block = b;
    745     list->next = this;
    746     return list;
    747   }
    748 
    749   void Serialize(BasicBlockVector* final_order) {
    750     for (BlockList* l = this; l != NULL; l = l->next) {
    751       l->block->rpo_number_ = static_cast<int>(final_order->size());
    752       final_order->push_back(l->block);
    753     }
    754   }
    755 };
    756 
    757 struct LoopInfo {
    758   BasicBlock* header;
    759   ZoneList<BasicBlock*>* outgoing;
    760   BitVector* members;
    761   LoopInfo* prev;
    762   BlockList* end;
    763   BlockList* start;
    764 
    765   void AddOutgoing(Zone* zone, BasicBlock* block) {
    766     if (outgoing == NULL) outgoing = new (zone) ZoneList<BasicBlock*>(2, zone);
    767     outgoing->Add(block, zone);
    768   }
    769 };
    770 
    771 
    772 static int Push(SpecialRPOStackFrame* stack, int depth, BasicBlock* child,
    773                 int unvisited) {
    774   if (child->rpo_number_ == unvisited) {
    775     stack[depth].block = child;
    776     stack[depth].index = 0;
    777     child->rpo_number_ = kBlockOnStack;
    778     return depth + 1;
    779   }
    780   return depth;
    781 }
    782 
    783 
    784 // Computes loop membership from the backedges of the control flow graph.
    785 static LoopInfo* ComputeLoopInfo(
    786     Zone* zone, SpecialRPOStackFrame* queue, int num_loops, int num_blocks,
    787     ZoneList<std::pair<BasicBlock*, int> >* backedges) {
    788   LoopInfo* loops = zone->NewArray<LoopInfo>(num_loops);
    789   memset(loops, 0, num_loops * sizeof(LoopInfo));
    790 
    791   // Compute loop membership starting from backedges.
    792   // O(max(loop_depth) * max(|loop|)
    793   for (int i = 0; i < backedges->length(); i++) {
    794     BasicBlock* member = backedges->at(i).first;
    795     BasicBlock* header = member->SuccessorAt(backedges->at(i).second);
    796     int loop_num = header->loop_end_;
    797     if (loops[loop_num].header == NULL) {
    798       loops[loop_num].header = header;
    799       loops[loop_num].members = new (zone) BitVector(num_blocks, zone);
    800     }
    801 
    802     int queue_length = 0;
    803     if (member != header) {
    804       // As long as the header doesn't have a backedge to itself,
    805       // Push the member onto the queue and process its predecessors.
    806       if (!loops[loop_num].members->Contains(member->id())) {
    807         loops[loop_num].members->Add(member->id());
    808       }
    809       queue[queue_length++].block = member;
    810     }
    811 
    812     // Propagate loop membership backwards. All predecessors of M up to the
    813     // loop header H are members of the loop too. O(|blocks between M and H|).
    814     while (queue_length > 0) {
    815       BasicBlock* block = queue[--queue_length].block;
    816       for (int i = 0; i < block->PredecessorCount(); i++) {
    817         BasicBlock* pred = block->PredecessorAt(i);
    818         if (pred != header) {
    819           if (!loops[loop_num].members->Contains(pred->id())) {
    820             loops[loop_num].members->Add(pred->id());
    821             queue[queue_length++].block = pred;
    822           }
    823         }
    824       }
    825     }
    826   }
    827   return loops;
    828 }
    829 
    830 
    831 #if DEBUG
    832 static void PrintRPO(int num_loops, LoopInfo* loops, BasicBlockVector* order) {
    833   PrintF("-- RPO with %d loops ", num_loops);
    834   if (num_loops > 0) {
    835     PrintF("(");
    836     for (int i = 0; i < num_loops; i++) {
    837       if (i > 0) PrintF(" ");
    838       PrintF("B%d", loops[i].header->id());
    839     }
    840     PrintF(") ");
    841   }
    842   PrintF("-- \n");
    843 
    844   for (int i = 0; i < static_cast<int>(order->size()); i++) {
    845     BasicBlock* block = (*order)[i];
    846     int bid = block->id();
    847     PrintF("%5d:", i);
    848     for (int i = 0; i < num_loops; i++) {
    849       bool membership = loops[i].members->Contains(bid);
    850       bool range = loops[i].header->LoopContains(block);
    851       PrintF(membership ? " |" : "  ");
    852       PrintF(range ? "x" : " ");
    853     }
    854     PrintF("  B%d: ", bid);
    855     if (block->loop_end_ >= 0) {
    856       PrintF(" range: [%d, %d)", block->rpo_number_, block->loop_end_);
    857     }
    858     PrintF("\n");
    859   }
    860 }
    861 
    862 
    863 static void VerifySpecialRPO(int num_loops, LoopInfo* loops,
    864                              BasicBlockVector* order) {
    865   DCHECK(order->size() > 0);
    866   DCHECK((*order)[0]->id() == 0);  // entry should be first.
    867 
    868   for (int i = 0; i < num_loops; i++) {
    869     LoopInfo* loop = &loops[i];
    870     BasicBlock* header = loop->header;
    871 
    872     DCHECK(header != NULL);
    873     DCHECK(header->rpo_number_ >= 0);
    874     DCHECK(header->rpo_number_ < static_cast<int>(order->size()));
    875     DCHECK(header->loop_end_ >= 0);
    876     DCHECK(header->loop_end_ <= static_cast<int>(order->size()));
    877     DCHECK(header->loop_end_ > header->rpo_number_);
    878 
    879     // Verify the start ... end list relationship.
    880     int links = 0;
    881     BlockList* l = loop->start;
    882     DCHECK(l != NULL && l->block == header);
    883     bool end_found;
    884     while (true) {
    885       if (l == NULL || l == loop->end) {
    886         end_found = (loop->end == l);
    887         break;
    888       }
    889       // The list should be in same order as the final result.
    890       DCHECK(l->block->rpo_number_ == links + loop->header->rpo_number_);
    891       links++;
    892       l = l->next;
    893       DCHECK(links < static_cast<int>(2 * order->size()));  // cycle?
    894     }
    895     DCHECK(links > 0);
    896     DCHECK(links == (header->loop_end_ - header->rpo_number_));
    897     DCHECK(end_found);
    898 
    899     // Check the contiguousness of loops.
    900     int count = 0;
    901     for (int j = 0; j < static_cast<int>(order->size()); j++) {
    902       BasicBlock* block = order->at(j);
    903       DCHECK(block->rpo_number_ == j);
    904       if (j < header->rpo_number_ || j >= header->loop_end_) {
    905         DCHECK(!loop->members->Contains(block->id()));
    906       } else {
    907         if (block == header) {
    908           DCHECK(!loop->members->Contains(block->id()));
    909         } else {
    910           DCHECK(loop->members->Contains(block->id()));
    911         }
    912         count++;
    913       }
    914     }
    915     DCHECK(links == count);
    916   }
    917 }
    918 #endif  // DEBUG
    919 
    920 
    921 // Compute the special reverse-post-order block ordering, which is essentially
    922 // a RPO of the graph where loop bodies are contiguous. Properties:
    923 // 1. If block A is a predecessor of B, then A appears before B in the order,
    924 //    unless B is a loop header and A is in the loop headed at B
    925 //    (i.e. A -> B is a backedge).
    926 // => If block A dominates block B, then A appears before B in the order.
    927 // => If block A is a loop header, A appears before all blocks in the loop
    928 //    headed at A.
    929 // 2. All loops are contiguous in the order (i.e. no intervening blocks that
    930 //    do not belong to the loop.)
    931 // Note a simple RPO traversal satisfies (1) but not (3).
    932 BasicBlockVector* Scheduler::ComputeSpecialRPO(Schedule* schedule) {
    933   Zone tmp_zone(schedule->zone()->isolate());
    934   Zone* zone = &tmp_zone;
    935   Trace("------------- COMPUTING SPECIAL RPO ---------------\n");
    936   // RPO should not have been computed for this schedule yet.
    937   CHECK_EQ(kBlockUnvisited1, schedule->start()->rpo_number_);
    938   CHECK_EQ(0, static_cast<int>(schedule->rpo_order_.size()));
    939 
    940   // Perform an iterative RPO traversal using an explicit stack,
    941   // recording backedges that form cycles. O(|B|).
    942   ZoneList<std::pair<BasicBlock*, int> > backedges(1, zone);
    943   SpecialRPOStackFrame* stack =
    944       zone->NewArray<SpecialRPOStackFrame>(schedule->BasicBlockCount());
    945   BasicBlock* entry = schedule->start();
    946   BlockList* order = NULL;
    947   int stack_depth = Push(stack, 0, entry, kBlockUnvisited1);
    948   int num_loops = 0;
    949 
    950   while (stack_depth > 0) {
    951     int current = stack_depth - 1;
    952     SpecialRPOStackFrame* frame = stack + current;
    953 
    954     if (frame->index < frame->block->SuccessorCount()) {
    955       // Process the next successor.
    956       BasicBlock* succ = frame->block->SuccessorAt(frame->index++);
    957       if (succ->rpo_number_ == kBlockVisited1) continue;
    958       if (succ->rpo_number_ == kBlockOnStack) {
    959         // The successor is on the stack, so this is a backedge (cycle).
    960         backedges.Add(
    961             std::pair<BasicBlock*, int>(frame->block, frame->index - 1), zone);
    962         if (succ->loop_end_ < 0) {
    963           // Assign a new loop number to the header if it doesn't have one.
    964           succ->loop_end_ = num_loops++;
    965         }
    966       } else {
    967         // Push the successor onto the stack.
    968         DCHECK(succ->rpo_number_ == kBlockUnvisited1);
    969         stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited1);
    970       }
    971     } else {
    972       // Finished with all successors; pop the stack and add the block.
    973       order = order->Add(zone, frame->block);
    974       frame->block->rpo_number_ = kBlockVisited1;
    975       stack_depth--;
    976     }
    977   }
    978 
    979   // If no loops were encountered, then the order we computed was correct.
    980   LoopInfo* loops = NULL;
    981   if (num_loops != 0) {
    982     // Otherwise, compute the loop information from the backedges in order
    983     // to perform a traversal that groups loop bodies together.
    984     loops = ComputeLoopInfo(zone, stack, num_loops, schedule->BasicBlockCount(),
    985                             &backedges);
    986 
    987     // Initialize the "loop stack". Note the entry could be a loop header.
    988     LoopInfo* loop = entry->IsLoopHeader() ? &loops[entry->loop_end_] : NULL;
    989     order = NULL;
    990 
    991     // Perform an iterative post-order traversal, visiting loop bodies before
    992     // edges that lead out of loops. Visits each block once, but linking loop
    993     // sections together is linear in the loop size, so overall is
    994     // O(|B| + max(loop_depth) * max(|loop|))
    995     stack_depth = Push(stack, 0, entry, kBlockUnvisited2);
    996     while (stack_depth > 0) {
    997       SpecialRPOStackFrame* frame = stack + (stack_depth - 1);
    998       BasicBlock* block = frame->block;
    999       BasicBlock* succ = NULL;
   1000 
   1001       if (frame->index < block->SuccessorCount()) {
   1002         // Process the next normal successor.
   1003         succ = block->SuccessorAt(frame->index++);
   1004       } else if (block->IsLoopHeader()) {
   1005         // Process additional outgoing edges from the loop header.
   1006         if (block->rpo_number_ == kBlockOnStack) {
   1007           // Finish the loop body the first time the header is left on the
   1008           // stack.
   1009           DCHECK(loop != NULL && loop->header == block);
   1010           loop->start = order->Add(zone, block);
   1011           order = loop->end;
   1012           block->rpo_number_ = kBlockVisited2;
   1013           // Pop the loop stack and continue visiting outgoing edges within the
   1014           // the context of the outer loop, if any.
   1015           loop = loop->prev;
   1016           // We leave the loop header on the stack; the rest of this iteration
   1017           // and later iterations will go through its outgoing edges list.
   1018         }
   1019 
   1020         // Use the next outgoing edge if there are any.
   1021         int outgoing_index = frame->index - block->SuccessorCount();
   1022         LoopInfo* info = &loops[block->loop_end_];
   1023         DCHECK(loop != info);
   1024         if (info->outgoing != NULL &&
   1025             outgoing_index < info->outgoing->length()) {
   1026           succ = info->outgoing->at(outgoing_index);
   1027           frame->index++;
   1028         }
   1029       }
   1030 
   1031       if (succ != NULL) {
   1032         // Process the next successor.
   1033         if (succ->rpo_number_ == kBlockOnStack) continue;
   1034         if (succ->rpo_number_ == kBlockVisited2) continue;
   1035         DCHECK(succ->rpo_number_ == kBlockUnvisited2);
   1036         if (loop != NULL && !loop->members->Contains(succ->id())) {
   1037           // The successor is not in the current loop or any nested loop.
   1038           // Add it to the outgoing edges of this loop and visit it later.
   1039           loop->AddOutgoing(zone, succ);
   1040         } else {
   1041           // Push the successor onto the stack.
   1042           stack_depth = Push(stack, stack_depth, succ, kBlockUnvisited2);
   1043           if (succ->IsLoopHeader()) {
   1044             // Push the inner loop onto the loop stack.
   1045             DCHECK(succ->loop_end_ >= 0 && succ->loop_end_ < num_loops);
   1046             LoopInfo* next = &loops[succ->loop_end_];
   1047             next->end = order;
   1048             next->prev = loop;
   1049             loop = next;
   1050           }
   1051         }
   1052       } else {
   1053         // Finished with all successors of the current block.
   1054         if (block->IsLoopHeader()) {
   1055           // If we are going to pop a loop header, then add its entire body.
   1056           LoopInfo* info = &loops[block->loop_end_];
   1057           for (BlockList* l = info->start; true; l = l->next) {
   1058             if (l->next == info->end) {
   1059               l->next = order;
   1060               info->end = order;
   1061               break;
   1062             }
   1063           }
   1064           order = info->start;
   1065         } else {
   1066           // Pop a single node off the stack and add it to the order.
   1067           order = order->Add(zone, block);
   1068           block->rpo_number_ = kBlockVisited2;
   1069         }
   1070         stack_depth--;
   1071       }
   1072     }
   1073   }
   1074 
   1075   // Construct the final order from the list.
   1076   BasicBlockVector* final_order = &schedule->rpo_order_;
   1077   order->Serialize(final_order);
   1078 
   1079   // Compute the correct loop header for every block and set the correct loop
   1080   // ends.
   1081   LoopInfo* current_loop = NULL;
   1082   BasicBlock* current_header = NULL;
   1083   int loop_depth = 0;
   1084   for (BasicBlockVectorIter i = final_order->begin(); i != final_order->end();
   1085        ++i) {
   1086     BasicBlock* current = *i;
   1087     current->loop_header_ = current_header;
   1088     if (current->IsLoopHeader()) {
   1089       loop_depth++;
   1090       current_loop = &loops[current->loop_end_];
   1091       BlockList* end = current_loop->end;
   1092       current->loop_end_ = end == NULL ? static_cast<int>(final_order->size())
   1093                                        : end->block->rpo_number_;
   1094       current_header = current_loop->header;
   1095       Trace("B%d is a loop header, increment loop depth to %d\n", current->id(),
   1096             loop_depth);
   1097     } else {
   1098       while (current_header != NULL &&
   1099              current->rpo_number_ >= current_header->loop_end_) {
   1100         DCHECK(current_header->IsLoopHeader());
   1101         DCHECK(current_loop != NULL);
   1102         current_loop = current_loop->prev;
   1103         current_header = current_loop == NULL ? NULL : current_loop->header;
   1104         --loop_depth;
   1105       }
   1106     }
   1107     current->loop_depth_ = loop_depth;
   1108     if (current->loop_header_ == NULL) {
   1109       Trace("B%d is not in a loop (depth == %d)\n", current->id(),
   1110             current->loop_depth_);
   1111     } else {
   1112       Trace("B%d has loop header B%d, (depth == %d)\n", current->id(),
   1113             current->loop_header_->id(), current->loop_depth_);
   1114     }
   1115   }
   1116 
   1117 #if DEBUG
   1118   if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order);
   1119   VerifySpecialRPO(num_loops, loops, final_order);
   1120 #endif
   1121   return final_order;
   1122 }
   1123 }
   1124 }
   1125 }  // namespace v8::internal::compiler
   1126