1// Copyright 2013 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/scheduler.h"
6
7#include <iomanip>
8
9#include "src/base/iterator.h"
10#include "src/builtins/profile-data-reader.h"
11#include "src/codegen/tick-counter.h"
12#include "src/compiler/common-operator.h"
13#include "src/compiler/control-equivalence.h"
14#include "src/compiler/graph.h"
15#include "src/compiler/node-marker.h"
16#include "src/compiler/node-properties.h"
17#include "src/compiler/node.h"
18#include "src/utils/bit-vector.h"
19#include "src/zone/zone-containers.h"
20
21namespace v8 {
22namespace internal {
23namespace compiler {
24
25#define TRACE(...)                                       \
26  do {                                                   \
27    if (FLAG_trace_turbo_scheduler) PrintF(__VA_ARGS__); \
28  } while (false)
29
30Scheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule, Flags flags,
31                     size_t node_count_hint, TickCounter* tick_counter,
32                     const ProfileDataFromFile* profile_data)
33    : zone_(zone),
34      graph_(graph),
35      schedule_(schedule),
36      flags_(flags),
37      scheduled_nodes_(zone),
38      schedule_root_nodes_(zone),
39      schedule_queue_(zone),
40      node_data_(zone),
41      tick_counter_(tick_counter),
42      profile_data_(profile_data),
43      common_dominator_cache_(zone) {
44  node_data_.reserve(node_count_hint);
45  node_data_.resize(graph->NodeCount(), DefaultSchedulerData());
46}
47
48Schedule* Scheduler::ComputeSchedule(Zone* zone, Graph* graph, Flags flags,
49                                     TickCounter* tick_counter,
50                                     const ProfileDataFromFile* profile_data) {
51  Zone* schedule_zone =
52      (flags & Scheduler::kTempSchedule) ? zone : graph->zone();
53
54  // Reserve 10% more space for nodes if node splitting is enabled to try to
55  // avoid resizing the vector since that would triple its zone memory usage.
56  float node_hint_multiplier = (flags & Scheduler::kSplitNodes) ? 1.1 : 1;
57  size_t node_count_hint = node_hint_multiplier * graph->NodeCount();
58
59  Schedule* schedule =
60      schedule_zone->New<Schedule>(schedule_zone, node_count_hint);
61  Scheduler scheduler(zone, graph, schedule, flags, node_count_hint,
62                      tick_counter, profile_data);
63
64  scheduler.BuildCFG();
65  scheduler.ComputeSpecialRPONumbering();
66  scheduler.GenerateDominatorTree();
67
68  scheduler.PrepareUses();
69  scheduler.ScheduleEarly();
70  scheduler.ScheduleLate();
71
72  scheduler.SealFinalSchedule();
73
74  return schedule;
75}
76
77Scheduler::SchedulerData Scheduler::DefaultSchedulerData() {
78  SchedulerData def = {schedule_->start(), 0, kUnknown};
79  return def;
80}
81
82
83Scheduler::SchedulerData* Scheduler::GetData(Node* node) {
84  return &node_data_[node->id()];
85}
86
87Scheduler::Placement Scheduler::InitializePlacement(Node* node) {
88  SchedulerData* data = GetData(node);
89  if (data->placement_ == kFixed) {
90    // Nothing to do for control nodes that have been already fixed in
91    // the schedule.
92    return data->placement_;
93  }
94  DCHECK_EQ(kUnknown, data->placement_);
95  switch (node->opcode()) {
96    case IrOpcode::kParameter:
97    case IrOpcode::kOsrValue:
98      // Parameters and OSR values are always fixed to the start block.
99      data->placement_ = kFixed;
100      break;
101    case IrOpcode::kPhi:
102    case IrOpcode::kEffectPhi: {
103      // Phis and effect phis are fixed if their control inputs are, whereas
104      // otherwise they are coupled to a floating control node.
105      Placement p = GetPlacement(NodeProperties::GetControlInput(node));
106      data->placement_ = (p == kFixed ? kFixed : kCoupled);
107      break;
108    }
109    default:
110      // Control nodes that were not control-reachable from end may float.
111      data->placement_ = kSchedulable;
112      break;
113  }
114  return data->placement_;
115}
116
117Scheduler::Placement Scheduler::GetPlacement(Node* node) {
118  return GetData(node)->placement_;
119}
120
121bool Scheduler::IsLive(Node* node) { return GetPlacement(node) != kUnknown; }
122
123void Scheduler::UpdatePlacement(Node* node, Placement placement) {
124  SchedulerData* data = GetData(node);
125  if (data->placement_ == kUnknown) {
126    // We only update control nodes from {kUnknown} to {kFixed}.  Ideally, we
127    // should check that {node} is a control node (including exceptional calls),
128    // but that is expensive.
129    DCHECK_EQ(Scheduler::kFixed, placement);
130    data->placement_ = placement;
131    return;
132  }
133
134  switch (node->opcode()) {
135    case IrOpcode::kParameter:
136      // Parameters are fixed once and for all.
137      UNREACHABLE();
138    case IrOpcode::kPhi:
139    case IrOpcode::kEffectPhi: {
140      // Phis and effect phis are coupled to their respective blocks.
141      DCHECK_EQ(Scheduler::kCoupled, data->placement_);
142      DCHECK_EQ(Scheduler::kFixed, placement);
143      Node* control = NodeProperties::GetControlInput(node);
144      BasicBlock* block = schedule_->block(control);
145      schedule_->AddNode(block, node);
146      break;
147    }
148#define DEFINE_CONTROL_CASE(V) case IrOpcode::k##V:
149      CONTROL_OP_LIST(DEFINE_CONTROL_CASE)
150#undef DEFINE_CONTROL_CASE
151      {
152        // Control nodes force coupled uses to be placed.
153        for (auto use : node->uses()) {
154          if (GetPlacement(use) == Scheduler::kCoupled) {
155            DCHECK_EQ(node, NodeProperties::GetControlInput(use));
156            UpdatePlacement(use, placement);
157          }
158      }
159      break;
160    }
161    default:
162      DCHECK_EQ(Scheduler::kSchedulable, data->placement_);
163      DCHECK_EQ(Scheduler::kScheduled, placement);
164      break;
165  }
166  // Reduce the use count of the node's inputs to potentially make them
167  // schedulable. If all the uses of a node have been scheduled, then the node
168  // itself can be scheduled.
169  base::Optional<int> coupled_control_edge = GetCoupledControlEdge(node);
170  for (Edge const edge : node->input_edges()) {
171    DCHECK_EQ(node, edge.from());
172    if (edge.index() != coupled_control_edge) {
173      DecrementUnscheduledUseCount(edge.to(), node);
174    }
175  }
176  data->placement_ = placement;
177}
178
179base::Optional<int> Scheduler::GetCoupledControlEdge(Node* node) {
180  if (GetPlacement(node) == kCoupled) {
181    return NodeProperties::FirstControlIndex(node);
182  }
183  return {};
184}
185
186void Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) {
187  // Tracking use counts for fixed nodes is useless.
188  if (GetPlacement(node) == kFixed) return;
189
190  // Use count for coupled nodes is summed up on their control.
191  if (GetPlacement(node) == kCoupled) {
192    node = NodeProperties::GetControlInput(node);
193    DCHECK_NE(GetPlacement(node), Placement::kFixed);
194    DCHECK_NE(GetPlacement(node), Placement::kCoupled);
195  }
196
197  ++(GetData(node)->unscheduled_count_);
198  if (FLAG_trace_turbo_scheduler) {
199    TRACE("  Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(),
200          node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
201          GetData(node)->unscheduled_count_);
202  }
203}
204
205void Scheduler::DecrementUnscheduledUseCount(Node* node, Node* from) {
206  // Tracking use counts for fixed nodes is useless.
207  if (GetPlacement(node) == kFixed) return;
208
209  // Use count for coupled nodes is summed up on their control.
210  if (GetPlacement(node) == kCoupled) {
211    node = NodeProperties::GetControlInput(node);
212    DCHECK_NE(GetPlacement(node), Placement::kFixed);
213    DCHECK_NE(GetPlacement(node), Placement::kCoupled);
214  }
215
216  DCHECK_LT(0, GetData(node)->unscheduled_count_);
217  --(GetData(node)->unscheduled_count_);
218  if (FLAG_trace_turbo_scheduler) {
219    TRACE("  Use count of #%d:%s (used by #%d:%s)-- = %d\n", node->id(),
220          node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
221          GetData(node)->unscheduled_count_);
222  }
223  if (GetData(node)->unscheduled_count_ == 0) {
224    TRACE("    newly eligible #%d:%s\n", node->id(), node->op()->mnemonic());
225    schedule_queue_.push(node);
226  }
227}
228
229// -----------------------------------------------------------------------------
230// Phase 1: Build control-flow graph.
231
232
233// Internal class to build a control flow graph (i.e the basic blocks and edges
234// between them within a Schedule) from the node graph. Visits control edges of
235// the graph backwards from an end node in order to find the connected control
236// subgraph, needed for scheduling.
237class CFGBuilder : public ZoneObject {
238 public:
239  CFGBuilder(Zone* zone, Scheduler* scheduler)
240      : zone_(zone),
241        scheduler_(scheduler),
242        schedule_(scheduler->schedule_),
243        queued_(scheduler->graph_, 2),
244        queue_(zone),
245        control_(zone),
246        component_entry_(nullptr),
247        component_start_(nullptr),
248        component_end_(nullptr) {}
249
250  // Run the control flow graph construction algorithm by walking the graph
251  // backwards from end through control edges, building and connecting the
252  // basic blocks for control nodes.
253  void Run() {
254    ResetDataStructures();
255    Queue(scheduler_->graph_->end());
256
257    while (!queue_.empty()) {  // Breadth-first backwards traversal.
258      scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
259      Node* node = queue_.front();
260      queue_.pop();
261      int max = NodeProperties::PastControlIndex(node);
262      for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
263        Queue(node->InputAt(i));
264      }
265    }
266
267    for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
268      ConnectBlocks(*i);  // Connect block to its predecessor/successors.
269    }
270  }
271
272  // Run the control flow graph construction for a minimal control-connected
273  // component ending in {exit} and merge that component into an existing
274  // control flow graph at the bottom of {block}.
275  void Run(BasicBlock* block, Node* exit) {
276    ResetDataStructures();
277    Queue(exit);
278
279    component_entry_ = nullptr;
280    component_start_ = block;
281    component_end_ = schedule_->block(exit);
282    scheduler_->equivalence_->Run(exit);
283    while (!queue_.empty()) {  // Breadth-first backwards traversal.
284      scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
285      Node* node = queue_.front();
286      queue_.pop();
287
288      // Use control dependence equivalence to find a canonical single-entry
289      // single-exit region that makes up a minimal component to be scheduled.
290      if (IsSingleEntrySingleExitRegion(node, exit)) {
291        TRACE("Found SESE at #%d:%s\n", node->id(), node->op()->mnemonic());
292        DCHECK(!component_entry_);
293        component_entry_ = node;
294        continue;
295      }
296
297      int max = NodeProperties::PastControlIndex(node);
298      for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
299        Queue(node->InputAt(i));
300      }
301    }
302    DCHECK(component_entry_);
303
304    for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
305      ConnectBlocks(*i);  // Connect block to its predecessor/successors.
306    }
307  }
308
309 private:
310  friend class ScheduleLateNodeVisitor;
311  friend class Scheduler;
312
313  void FixNode(BasicBlock* block, Node* node) {
314    schedule_->AddNode(block, node);
315    scheduler_->UpdatePlacement(node, Scheduler::kFixed);
316  }
317
318  void Queue(Node* node) {
319    // Mark the connected control nodes as they are queued.
320    if (!queued_.Get(node)) {
321      BuildBlocks(node);
322      queue_.push(node);
323      queued_.Set(node, true);
324      control_.push_back(node);
325    }
326  }
327
328  void BuildBlocks(Node* node) {
329    switch (node->opcode()) {
330      case IrOpcode::kEnd:
331        FixNode(schedule_->end(), node);
332        break;
333      case IrOpcode::kStart:
334        FixNode(schedule_->start(), node);
335        break;
336      case IrOpcode::kLoop:
337      case IrOpcode::kMerge:
338        BuildBlockForNode(node);
339        break;
340      case IrOpcode::kTerminate: {
341        // Put Terminate in the loop to which it refers.
342        Node* loop = NodeProperties::GetControlInput(node);
343        BasicBlock* block = BuildBlockForNode(loop);
344        FixNode(block, node);
345        break;
346      }
347      case IrOpcode::kBranch:
348      case IrOpcode::kSwitch:
349        BuildBlocksForSuccessors(node);
350        break;
351#define BUILD_BLOCK_JS_CASE(Name, ...) case IrOpcode::k##Name:
352        JS_OP_LIST(BUILD_BLOCK_JS_CASE)
353// JS opcodes are just like calls => fall through.
354#undef BUILD_BLOCK_JS_CASE
355      case IrOpcode::kCall:
356        if (NodeProperties::IsExceptionalCall(node)) {
357          BuildBlocksForSuccessors(node);
358        }
359        break;
360      default:
361        break;
362    }
363  }
364
365  void ConnectBlocks(Node* node) {
366    switch (node->opcode()) {
367      case IrOpcode::kLoop:
368      case IrOpcode::kMerge:
369        ConnectMerge(node);
370        break;
371      case IrOpcode::kBranch:
372        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
373        ConnectBranch(node);
374        break;
375      case IrOpcode::kSwitch:
376        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
377        ConnectSwitch(node);
378        break;
379      case IrOpcode::kDeoptimize:
380        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
381        ConnectDeoptimize(node);
382        break;
383      case IrOpcode::kTailCall:
384        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
385        ConnectTailCall(node);
386        break;
387      case IrOpcode::kReturn:
388        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
389        ConnectReturn(node);
390        break;
391      case IrOpcode::kThrow:
392        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
393        ConnectThrow(node);
394        break;
395#define CONNECT_BLOCK_JS_CASE(Name, ...) case IrOpcode::k##Name:
396        JS_OP_LIST(CONNECT_BLOCK_JS_CASE)
397// JS opcodes are just like calls => fall through.
398#undef CONNECT_BLOCK_JS_CASE
399      case IrOpcode::kCall:
400        if (NodeProperties::IsExceptionalCall(node)) {
401          scheduler_->UpdatePlacement(node, Scheduler::kFixed);
402          ConnectCall(node);
403        }
404        break;
405      default:
406        break;
407    }
408  }
409
410  BasicBlock* BuildBlockForNode(Node* node) {
411    BasicBlock* block = schedule_->block(node);
412    if (block == nullptr) {
413      block = schedule_->NewBasicBlock();
414      TRACE("Create block id:%d for #%d:%s\n", block->id().ToInt(), node->id(),
415            node->op()->mnemonic());
416      FixNode(block, node);
417    }
418    return block;
419  }
420
421  void BuildBlocksForSuccessors(Node* node) {
422    size_t const successor_cnt = node->op()->ControlOutputCount();
423    Node** successors = zone_->NewArray<Node*>(successor_cnt);
424    NodeProperties::CollectControlProjections(node, successors, successor_cnt);
425    for (size_t index = 0; index < successor_cnt; ++index) {
426      BuildBlockForNode(successors[index]);
427    }
428  }
429
430  void CollectSuccessorBlocks(Node* node, BasicBlock** successor_blocks,
431                              size_t successor_cnt) {
432    Node** successors = reinterpret_cast<Node**>(successor_blocks);
433    NodeProperties::CollectControlProjections(node, successors, successor_cnt);
434    for (size_t index = 0; index < successor_cnt; ++index) {
435      successor_blocks[index] = schedule_->block(successors[index]);
436    }
437  }
438
439  BasicBlock* FindPredecessorBlock(Node* node) {
440    BasicBlock* predecessor_block = nullptr;
441    while (true) {
442      predecessor_block = schedule_->block(node);
443      if (predecessor_block != nullptr) break;
444      node = NodeProperties::GetControlInput(node);
445    }
446    return predecessor_block;
447  }
448
449  void ConnectCall(Node* call) {
450    BasicBlock* successor_blocks[2];
451    CollectSuccessorBlocks(call, successor_blocks, arraysize(successor_blocks));
452
453    // Consider the exception continuation to be deferred.
454    successor_blocks[1]->set_deferred(true);
455
456    Node* call_control = NodeProperties::GetControlInput(call);
457    BasicBlock* call_block = FindPredecessorBlock(call_control);
458    TraceConnect(call, call_block, successor_blocks[0]);
459    TraceConnect(call, call_block, successor_blocks[1]);
460    schedule_->AddCall(call_block, call, successor_blocks[0],
461                       successor_blocks[1]);
462  }
463
464  void ConnectBranch(Node* branch) {
465    BasicBlock* successor_blocks[2];
466    CollectSuccessorBlocks(branch, successor_blocks,
467                           arraysize(successor_blocks));
468
469    BranchHint hint_from_profile = BranchHint::kNone;
470    if (const ProfileDataFromFile* profile_data = scheduler_->profile_data()) {
471      double block_zero_count =
472          profile_data->GetCounter(successor_blocks[0]->id().ToSize());
473      double block_one_count =
474          profile_data->GetCounter(successor_blocks[1]->id().ToSize());
475      // If a branch is visited a non-trivial number of times and substantially
476      // more often than its alternative, then mark it as likely.
477      constexpr double kMinimumCount = 100000;
478      constexpr double kThresholdRatio = 4000;
479      if (block_zero_count > kMinimumCount &&
480          block_zero_count / kThresholdRatio > block_one_count) {
481        hint_from_profile = BranchHint::kTrue;
482      } else if (block_one_count > kMinimumCount &&
483                 block_one_count / kThresholdRatio > block_zero_count) {
484        hint_from_profile = BranchHint::kFalse;
485      }
486    }
487
488    // Consider branch hints.
489    switch (hint_from_profile) {
490      case BranchHint::kNone:
491        switch (BranchHintOf(branch->op())) {
492          case BranchHint::kNone:
493            break;
494          case BranchHint::kTrue:
495            successor_blocks[1]->set_deferred(true);
496            break;
497          case BranchHint::kFalse:
498            successor_blocks[0]->set_deferred(true);
499            break;
500        }
501        break;
502      case BranchHint::kTrue:
503        successor_blocks[1]->set_deferred(true);
504        break;
505      case BranchHint::kFalse:
506        successor_blocks[0]->set_deferred(true);
507        break;
508    }
509
510    if (hint_from_profile != BranchHint::kNone &&
511        BranchHintOf(branch->op()) != BranchHint::kNone &&
512        hint_from_profile != BranchHintOf(branch->op())) {
513      PrintF("Warning: profiling data overrode manual branch hint.\n");
514    }
515
516    if (branch == component_entry_) {
517      TraceConnect(branch, component_start_, successor_blocks[0]);
518      TraceConnect(branch, component_start_, successor_blocks[1]);
519      schedule_->InsertBranch(component_start_, component_end_, branch,
520                              successor_blocks[0], successor_blocks[1]);
521    } else {
522      Node* branch_control = NodeProperties::GetControlInput(branch);
523      BasicBlock* branch_block = FindPredecessorBlock(branch_control);
524      TraceConnect(branch, branch_block, successor_blocks[0]);
525      TraceConnect(branch, branch_block, successor_blocks[1]);
526      schedule_->AddBranch(branch_block, branch, successor_blocks[0],
527                           successor_blocks[1]);
528    }
529  }
530
531  void ConnectSwitch(Node* sw) {
532    size_t const successor_count = sw->op()->ControlOutputCount();
533    BasicBlock** successor_blocks =
534        zone_->NewArray<BasicBlock*>(successor_count);
535    CollectSuccessorBlocks(sw, successor_blocks, successor_count);
536
537    if (sw == component_entry_) {
538      for (size_t index = 0; index < successor_count; ++index) {
539        TraceConnect(sw, component_start_, successor_blocks[index]);
540      }
541      schedule_->InsertSwitch(component_start_, component_end_, sw,
542                              successor_blocks, successor_count);
543    } else {
544      Node* switch_control = NodeProperties::GetControlInput(sw);
545      BasicBlock* switch_block = FindPredecessorBlock(switch_control);
546      for (size_t index = 0; index < successor_count; ++index) {
547        TraceConnect(sw, switch_block, successor_blocks[index]);
548      }
549      schedule_->AddSwitch(switch_block, sw, successor_blocks, successor_count);
550    }
551    for (size_t index = 0; index < successor_count; ++index) {
552      if (BranchHintOf(successor_blocks[index]->front()->op()) ==
553          BranchHint::kFalse) {
554        successor_blocks[index]->set_deferred(true);
555      }
556    }
557  }
558
559  void ConnectMerge(Node* merge) {
560    // Don't connect the special merge at the end to its predecessors.
561    if (IsFinalMerge(merge)) return;
562
563    BasicBlock* block = schedule_->block(merge);
564    DCHECK_NOT_NULL(block);
565    // For all of the merge's control inputs, add a goto at the end to the
566    // merge's basic block.
567    for (Node* const input : merge->inputs()) {
568      BasicBlock* predecessor_block = FindPredecessorBlock(input);
569      TraceConnect(merge, predecessor_block, block);
570      schedule_->AddGoto(predecessor_block, block);
571    }
572  }
573
574  void ConnectTailCall(Node* call) {
575    Node* call_control = NodeProperties::GetControlInput(call);
576    BasicBlock* call_block = FindPredecessorBlock(call_control);
577    TraceConnect(call, call_block, nullptr);
578    schedule_->AddTailCall(call_block, call);
579  }
580
581  void ConnectReturn(Node* ret) {
582    Node* return_control = NodeProperties::GetControlInput(ret);
583    BasicBlock* return_block = FindPredecessorBlock(return_control);
584    TraceConnect(ret, return_block, nullptr);
585    schedule_->AddReturn(return_block, ret);
586  }
587
588  void ConnectDeoptimize(Node* deopt) {
589    Node* deoptimize_control = NodeProperties::GetControlInput(deopt);
590    BasicBlock* deoptimize_block = FindPredecessorBlock(deoptimize_control);
591    TraceConnect(deopt, deoptimize_block, nullptr);
592    schedule_->AddDeoptimize(deoptimize_block, deopt);
593  }
594
595  void ConnectThrow(Node* thr) {
596    Node* throw_control = NodeProperties::GetControlInput(thr);
597    BasicBlock* throw_block = FindPredecessorBlock(throw_control);
598    TraceConnect(thr, throw_block, nullptr);
599    schedule_->AddThrow(throw_block, thr);
600  }
601
602  void TraceConnect(Node* node, BasicBlock* block, BasicBlock* succ) {
603    DCHECK_NOT_NULL(block);
604    if (succ == nullptr) {
605      TRACE("Connect #%d:%s, id:%d -> end\n", node->id(),
606            node->op()->mnemonic(), block->id().ToInt());
607    } else {
608      TRACE("Connect #%d:%s, id:%d -> id:%d\n", node->id(),
609            node->op()->mnemonic(), block->id().ToInt(), succ->id().ToInt());
610    }
611  }
612
613  bool IsFinalMerge(Node* node) {
614    return (node->opcode() == IrOpcode::kMerge &&
615            node == scheduler_->graph_->end()->InputAt(0));
616  }
617
618  bool IsSingleEntrySingleExitRegion(Node* entry, Node* exit) const {
619    size_t entry_class = scheduler_->equivalence_->ClassOf(entry);
620    size_t exit_class = scheduler_->equivalence_->ClassOf(exit);
621    return entry != exit && entry_class == exit_class;
622  }
623
624  void ResetDataStructures() {
625    control_.clear();
626    DCHECK(queue_.empty());
627    DCHECK(control_.empty());
628  }
629
630  Zone* zone_;
631  Scheduler* scheduler_;
632  Schedule* schedule_;
633  NodeMarker<bool> queued_;      // Mark indicating whether node is queued.
634  ZoneQueue<Node*> queue_;       // Queue used for breadth-first traversal.
635  NodeVector control_;           // List of encountered control nodes.
636  Node* component_entry_;        // Component single-entry node.
637  BasicBlock* component_start_;  // Component single-entry block.
638  BasicBlock* component_end_;    // Component single-exit block.
639};
640
641
642void Scheduler::BuildCFG() {
643  TRACE("--- CREATING CFG -------------------------------------------\n");
644
645  // Instantiate a new control equivalence algorithm for the graph.
646  equivalence_ = zone_->New<ControlEquivalence>(zone_, graph_);
647
648  // Build a control-flow graph for the main control-connected component that
649  // is being spanned by the graph's start and end nodes.
650  control_flow_builder_ = zone_->New<CFGBuilder>(zone_, this);
651  control_flow_builder_->Run();
652
653  // Initialize per-block data.
654  // Reserve an extra 10% to avoid resizing vector when fusing floating control.
655  scheduled_nodes_.reserve(schedule_->BasicBlockCount() * 1.1);
656  scheduled_nodes_.resize(schedule_->BasicBlockCount());
657}
658
659
660// -----------------------------------------------------------------------------
661// Phase 2: Compute special RPO and dominator tree.
662
663
664// Compute the special reverse-post-order block ordering, which is essentially
665// a RPO of the graph where loop bodies are contiguous. Properties:
666// 1. If block A is a predecessor of B, then A appears before B in the order,
667//    unless B is a loop header and A is in the loop headed at B
668//    (i.e. A -> B is a backedge).
669// => If block A dominates block B, then A appears before B in the order.
670// => If block A is a loop header, A appears before all blocks in the loop
671//    headed at A.
672// 2. All loops are contiguous in the order (i.e. no intervening blocks that
673//    do not belong to the loop.)
674// Note a simple RPO traversal satisfies (1) but not (2).
675class SpecialRPONumberer : public ZoneObject {
676 public:
677  SpecialRPONumberer(Zone* zone, Schedule* schedule)
678      : zone_(zone),
679        schedule_(schedule),
680        order_(nullptr),
681        beyond_end_(nullptr),
682        loops_(zone),
683        backedges_(zone),
684        stack_(zone),
685        previous_block_count_(0),
686        empty_(0, zone) {}
687
688  // Computes the special reverse-post-order for the main control flow graph,
689  // that is for the graph spanned between the schedule's start and end blocks.
690  void ComputeSpecialRPO() {
691    DCHECK_EQ(0, schedule_->end()->SuccessorCount());
692    DCHECK(!order_);  // Main order does not exist yet.
693    ComputeAndInsertSpecialRPO(schedule_->start(), schedule_->end());
694  }
695
696  // Computes the special reverse-post-order for a partial control flow graph,
697  // that is for the graph spanned between the given {entry} and {end} blocks,
698  // then updates the existing ordering with this new information.
699  void UpdateSpecialRPO(BasicBlock* entry, BasicBlock* end) {
700    DCHECK(order_);  // Main order to be updated is present.
701    ComputeAndInsertSpecialRPO(entry, end);
702  }
703
704  // Serialize the previously computed order as a special reverse-post-order
705  // numbering for basic blocks into the final schedule.
706  void SerializeRPOIntoSchedule() {
707    int32_t number = 0;
708    for (BasicBlock* b = order_; b != nullptr; b = b->rpo_next()) {
709      b->set_rpo_number(number++);
710      schedule_->rpo_order()->push_back(b);
711    }
712    BeyondEndSentinel()->set_rpo_number(number);
713  }
714
715  // Print and verify the special reverse-post-order.
716  void PrintAndVerifySpecialRPO() {
717#if DEBUG
718    if (FLAG_trace_turbo_scheduler) PrintRPO();
719    VerifySpecialRPO();
720#endif
721  }
722
723  const ZoneVector<BasicBlock*>& GetOutgoingBlocks(BasicBlock* block) {
724    if (HasLoopNumber(block)) {
725      LoopInfo const& loop = loops_[GetLoopNumber(block)];
726      if (loop.outgoing) return *loop.outgoing;
727    }
728    return empty_;
729  }
730
731  bool HasLoopBlocks() const { return loops_.size() != 0; }
732
733 private:
734  using Backedge = std::pair<BasicBlock*, size_t>;
735
736  // Numbering for BasicBlock::rpo_number for this block traversal:
737  static const int kBlockOnStack = -2;
738  static const int kBlockVisited1 = -3;
739  static const int kBlockVisited2 = -4;
740  static const int kBlockUnvisited1 = -1;
741  static const int kBlockUnvisited2 = kBlockVisited1;
742
743  struct SpecialRPOStackFrame {
744    BasicBlock* block;
745    size_t index;
746  };
747
748  struct LoopInfo {
749    BasicBlock* header;
750    ZoneVector<BasicBlock*>* outgoing;
751    BitVector* members;
752    LoopInfo* prev;
753    BasicBlock* end;
754    BasicBlock* start;
755
756    void AddOutgoing(Zone* zone, BasicBlock* block) {
757      if (outgoing == nullptr) {
758        outgoing = zone->New<ZoneVector<BasicBlock*>>(zone);
759      }
760      outgoing->push_back(block);
761    }
762  };
763
764  int Push(int depth, BasicBlock* child, int unvisited) {
765    if (child->rpo_number() == unvisited) {
766      stack_[depth].block = child;
767      stack_[depth].index = 0;
768      child->set_rpo_number(kBlockOnStack);
769      return depth + 1;
770    }
771    return depth;
772  }
773
774  BasicBlock* PushFront(BasicBlock* head, BasicBlock* block) {
775    block->set_rpo_next(head);
776    return block;
777  }
778
779  static int GetLoopNumber(BasicBlock* block) { return block->loop_number(); }
780  static void SetLoopNumber(BasicBlock* block, int loop_number) {
781    return block->set_loop_number(loop_number);
782  }
783  static bool HasLoopNumber(BasicBlock* block) {
784    return block->loop_number() >= 0;
785  }
786
787  // We only need this special sentinel because some tests use the schedule's
788  // end block in actual control flow (e.g. with end having successors).
789  BasicBlock* BeyondEndSentinel() {
790    if (beyond_end_ == nullptr) {
791      BasicBlock::Id id = BasicBlock::Id::FromInt(-1);
792      beyond_end_ = schedule_->zone()->New<BasicBlock>(schedule_->zone(), id);
793    }
794    return beyond_end_;
795  }
796
797  // Compute special RPO for the control flow graph between {entry} and {end},
798  // mutating any existing order so that the result is still valid.
799  void ComputeAndInsertSpecialRPO(BasicBlock* entry, BasicBlock* end) {
800    // RPO should not have been serialized for this schedule yet.
801    CHECK_EQ(kBlockUnvisited1, schedule_->start()->loop_number());
802    CHECK_EQ(kBlockUnvisited1, schedule_->start()->rpo_number());
803    CHECK_EQ(0, static_cast<int>(schedule_->rpo_order()->size()));
804
805    // Find correct insertion point within existing order.
806    BasicBlock* insertion_point = entry->rpo_next();
807    BasicBlock* order = insertion_point;
808
809    // Perform an iterative RPO traversal using an explicit stack,
810    // recording backedges that form cycles. O(|B|).
811    DCHECK_LT(previous_block_count_, schedule_->BasicBlockCount());
812    stack_.resize(schedule_->BasicBlockCount() - previous_block_count_);
813    previous_block_count_ = schedule_->BasicBlockCount();
814    int stack_depth = Push(0, entry, kBlockUnvisited1);
815    int num_loops = static_cast<int>(loops_.size());
816
817    while (stack_depth > 0) {
818      int current = stack_depth - 1;
819      SpecialRPOStackFrame* frame = &stack_[current];
820
821      if (frame->block != end &&
822          frame->index < frame->block->SuccessorCount()) {
823        // Process the next successor.
824        BasicBlock* succ = frame->block->SuccessorAt(frame->index++);
825        if (succ->rpo_number() == kBlockVisited1) continue;
826        if (succ->rpo_number() == kBlockOnStack) {
827          // The successor is on the stack, so this is a backedge (cycle).
828          backedges_.push_back(Backedge(frame->block, frame->index - 1));
829          if (!HasLoopNumber(succ)) {
830            // Assign a new loop number to the header if it doesn't have one.
831            SetLoopNumber(succ, num_loops++);
832          }
833        } else {
834          // Push the successor onto the stack.
835          DCHECK_EQ(kBlockUnvisited1, succ->rpo_number());
836          stack_depth = Push(stack_depth, succ, kBlockUnvisited1);
837        }
838      } else {
839        // Finished with all successors; pop the stack and add the block.
840        order = PushFront(order, frame->block);
841        frame->block->set_rpo_number(kBlockVisited1);
842        stack_depth--;
843      }
844    }
845
846    // If no loops were encountered, then the order we computed was correct.
847    if (num_loops > static_cast<int>(loops_.size())) {
848      // Otherwise, compute the loop information from the backedges in order
849      // to perform a traversal that groups loop bodies together.
850      ComputeLoopInfo(&stack_, num_loops, &backedges_);
851
852      // Initialize the "loop stack". Note the entry could be a loop header.
853      LoopInfo* loop =
854          HasLoopNumber(entry) ? &loops_[GetLoopNumber(entry)] : nullptr;
855      order = insertion_point;
856
857      // Perform an iterative post-order traversal, visiting loop bodies before
858      // edges that lead out of loops. Visits each block once, but linking loop
859      // sections together is linear in the loop size, so overall is
860      // O(|B| + max(loop_depth) * max(|loop|))
861      stack_depth = Push(0, entry, kBlockUnvisited2);
862      while (stack_depth > 0) {
863        SpecialRPOStackFrame* frame = &stack_[stack_depth - 1];
864        BasicBlock* block = frame->block;
865        BasicBlock* succ = nullptr;
866
867        if (block != end && frame->index < block->SuccessorCount()) {
868          // Process the next normal successor.
869          succ = block->SuccessorAt(frame->index++);
870        } else if (HasLoopNumber(block)) {
871          // Process additional outgoing edges from the loop header.
872          if (block->rpo_number() == kBlockOnStack) {
873            // Finish the loop body the first time the header is left on the
874            // stack.
875            DCHECK(loop != nullptr && loop->header == block);
876            loop->start = PushFront(order, block);
877            order = loop->end;
878            block->set_rpo_number(kBlockVisited2);
879            // Pop the loop stack and continue visiting outgoing edges within
880            // the context of the outer loop, if any.
881            loop = loop->prev;
882            // We leave the loop header on the stack; the rest of this iteration
883            // and later iterations will go through its outgoing edges list.
884          }
885
886          // Use the next outgoing edge if there are any.
887          size_t outgoing_index = frame->index - block->SuccessorCount();
888          LoopInfo* info = &loops_[GetLoopNumber(block)];
889          DCHECK(loop != info);
890          if (block != entry && info->outgoing != nullptr &&
891              outgoing_index < info->outgoing->size()) {
892            succ = info->outgoing->at(outgoing_index);
893            frame->index++;
894          }
895        }
896
897        if (succ != nullptr) {
898          // Process the next successor.
899          if (succ->rpo_number() == kBlockOnStack) continue;
900          if (succ->rpo_number() == kBlockVisited2) continue;
901          DCHECK_EQ(kBlockUnvisited2, succ->rpo_number());
902          if (loop != nullptr && !loop->members->Contains(succ->id().ToInt())) {
903            // The successor is not in the current loop or any nested loop.
904            // Add it to the outgoing edges of this loop and visit it later.
905            loop->AddOutgoing(zone_, succ);
906          } else {
907            // Push the successor onto the stack.
908            stack_depth = Push(stack_depth, succ, kBlockUnvisited2);
909            if (HasLoopNumber(succ)) {
910              // Push the inner loop onto the loop stack.
911              DCHECK(GetLoopNumber(succ) < num_loops);
912              LoopInfo* next = &loops_[GetLoopNumber(succ)];
913              next->end = order;
914              next->prev = loop;
915              loop = next;
916            }
917          }
918        } else {
919          // Finished with all successors of the current block.
920          if (HasLoopNumber(block)) {
921            // If we are going to pop a loop header, then add its entire body.
922            LoopInfo* info = &loops_[GetLoopNumber(block)];
923            for (BasicBlock* b = info->start; true; b = b->rpo_next()) {
924              if (b->rpo_next() == info->end) {
925                b->set_rpo_next(order);
926                info->end = order;
927                break;
928              }
929            }
930            order = info->start;
931          } else {
932            // Pop a single node off the stack and add it to the order.
933            order = PushFront(order, block);
934            block->set_rpo_number(kBlockVisited2);
935          }
936          stack_depth--;
937        }
938      }
939    }
940
941    // Publish new order the first time.
942    if (order_ == nullptr) order_ = order;
943
944    // Compute the correct loop headers and set the correct loop ends.
945    LoopInfo* current_loop = nullptr;
946    BasicBlock* current_header = entry->loop_header();
947    int32_t loop_depth = entry->loop_depth();
948    if (entry->IsLoopHeader()) --loop_depth;  // Entry might be a loop header.
949    for (BasicBlock* b = order; b != insertion_point; b = b->rpo_next()) {
950      BasicBlock* current = b;
951
952      // Reset BasicBlock::rpo_number again.
953      current->set_rpo_number(kBlockUnvisited1);
954
955      // Finish the previous loop(s) if we just exited them.
956      while (current_header != nullptr &&
957             current == current_header->loop_end()) {
958        DCHECK(current_header->IsLoopHeader());
959        DCHECK_NOT_NULL(current_loop);
960        current_loop = current_loop->prev;
961        current_header =
962            current_loop == nullptr ? nullptr : current_loop->header;
963        --loop_depth;
964      }
965      current->set_loop_header(current_header);
966
967      // Push a new loop onto the stack if this loop is a loop header.
968      if (HasLoopNumber(current)) {
969        ++loop_depth;
970        current_loop = &loops_[GetLoopNumber(current)];
971        BasicBlock* loop_end = current_loop->end;
972        current->set_loop_end(loop_end == nullptr ? BeyondEndSentinel()
973                                                  : loop_end);
974        current_header = current_loop->header;
975        TRACE("id:%d is a loop header, increment loop depth to %d\n",
976              current->id().ToInt(), loop_depth);
977      }
978
979      current->set_loop_depth(loop_depth);
980
981      if (current->loop_header() == nullptr) {
982        TRACE("id:%d is not in a loop (depth == %d)\n", current->id().ToInt(),
983              current->loop_depth());
984      } else {
985        TRACE("id:%d has loop header id:%d, (depth == %d)\n",
986              current->id().ToInt(), current->loop_header()->id().ToInt(),
987              current->loop_depth());
988      }
989    }
990  }
991
992  // Computes loop membership from the backedges of the control flow graph.
993  void ComputeLoopInfo(ZoneVector<SpecialRPOStackFrame>* queue,
994                       size_t num_loops, ZoneVector<Backedge>* backedges) {
995    // Extend existing loop membership vectors.
996    for (LoopInfo& loop : loops_) {
997      loop.members->Resize(static_cast<int>(schedule_->BasicBlockCount()),
998                           zone_);
999    }
1000
1001    // Extend loop information vector.
1002    loops_.resize(num_loops, LoopInfo());
1003
1004    // Compute loop membership starting from backedges.
1005    // O(max(loop_depth) * max(|loop|)
1006    for (size_t i = 0; i < backedges->size(); i++) {
1007      BasicBlock* member = backedges->at(i).first;
1008      BasicBlock* header = member->SuccessorAt(backedges->at(i).second);
1009      size_t loop_num = GetLoopNumber(header);
1010      if (loops_[loop_num].header == nullptr) {
1011        loops_[loop_num].header = header;
1012        loops_[loop_num].members = zone_->New<BitVector>(
1013            static_cast<int>(schedule_->BasicBlockCount()), zone_);
1014      }
1015
1016      int queue_length = 0;
1017      if (member != header) {
1018        // As long as the header doesn't have a backedge to itself,
1019        // Push the member onto the queue and process its predecessors.
1020        if (!loops_[loop_num].members->Contains(member->id().ToInt())) {
1021          loops_[loop_num].members->Add(member->id().ToInt());
1022        }
1023        (*queue)[queue_length++].block = member;
1024      }
1025
1026      // Propagate loop membership backwards. All predecessors of M up to the
1027      // loop header H are members of the loop too. O(|blocks between M and H|).
1028      while (queue_length > 0) {
1029        BasicBlock* block = (*queue)[--queue_length].block;
1030        for (size_t j = 0; j < block->PredecessorCount(); j++) {
1031          BasicBlock* pred = block->PredecessorAt(j);
1032          if (pred != header) {
1033            if (!loops_[loop_num].members->Contains(pred->id().ToInt())) {
1034              loops_[loop_num].members->Add(pred->id().ToInt());
1035              (*queue)[queue_length++].block = pred;
1036            }
1037          }
1038        }
1039      }
1040    }
1041  }
1042
1043#if DEBUG
1044  void PrintRPO() {
1045    StdoutStream os;
1046    os << "RPO with " << loops_.size() << " loops";
1047    if (loops_.size() > 0) {
1048      os << " (";
1049      for (size_t i = 0; i < loops_.size(); i++) {
1050        if (i > 0) os << " ";
1051        os << "id:" << loops_[i].header->id();
1052      }
1053      os << ")";
1054    }
1055    os << ":\n";
1056
1057    for (BasicBlock* block = order_; block != nullptr;
1058         block = block->rpo_next()) {
1059      os << std::setw(5) << "B" << block->rpo_number() << ":";
1060      for (size_t i = 0; i < loops_.size(); i++) {
1061        bool range = loops_[i].header->LoopContains(block);
1062        bool membership = loops_[i].header != block && range;
1063        os << (membership ? " |" : "  ");
1064        os << (range ? "x" : " ");
1065      }
1066      os << "  id:" << block->id() << ": ";
1067      if (block->loop_end() != nullptr) {
1068        os << " range: [B" << block->rpo_number() << ", B"
1069           << block->loop_end()->rpo_number() << ")";
1070      }
1071      if (block->loop_header() != nullptr) {
1072        os << " header: id:" << block->loop_header()->id();
1073      }
1074      if (block->loop_depth() > 0) {
1075        os << " depth: " << block->loop_depth();
1076      }
1077      os << "\n";
1078    }
1079  }
1080
1081  void VerifySpecialRPO() {
1082    BasicBlockVector* order = schedule_->rpo_order();
1083    DCHECK_LT(0, order->size());
1084    DCHECK_EQ(0, (*order)[0]->id().ToInt());  // entry should be first.
1085
1086    for (size_t i = 0; i < loops_.size(); i++) {
1087      LoopInfo* loop = &loops_[i];
1088      BasicBlock* header = loop->header;
1089      BasicBlock* end = header->loop_end();
1090
1091      DCHECK_NOT_NULL(header);
1092      DCHECK_LE(0, header->rpo_number());
1093      DCHECK_LT(header->rpo_number(), order->size());
1094      DCHECK_NOT_NULL(end);
1095      DCHECK_LE(end->rpo_number(), order->size());
1096      DCHECK_GT(end->rpo_number(), header->rpo_number());
1097      DCHECK_NE(header->loop_header(), header);
1098
1099      // Verify the start ... end list relationship.
1100      int links = 0;
1101      BasicBlock* block = loop->start;
1102      DCHECK_EQ(header, block);
1103      bool end_found;
1104      while (true) {
1105        if (block == nullptr || block == loop->end) {
1106          end_found = (loop->end == block);
1107          break;
1108        }
1109        // The list should be in same order as the final result.
1110        DCHECK(block->rpo_number() == links + header->rpo_number());
1111        links++;
1112        block = block->rpo_next();
1113        DCHECK_LT(links, static_cast<int>(2 * order->size()));  // cycle?
1114      }
1115      DCHECK_LT(0, links);
1116      DCHECK_EQ(links, end->rpo_number() - header->rpo_number());
1117      DCHECK(end_found);
1118
1119      // Check loop depth of the header.
1120      int loop_depth = 0;
1121      for (LoopInfo* outer = loop; outer != nullptr; outer = outer->prev) {
1122        loop_depth++;
1123      }
1124      DCHECK_EQ(loop_depth, header->loop_depth());
1125
1126      // Check the contiguousness of loops.
1127      int count = 0;
1128      for (int j = 0; j < static_cast<int>(order->size()); j++) {
1129        block = order->at(j);
1130        DCHECK_EQ(block->rpo_number(), j);
1131        if (j < header->rpo_number() || j >= end->rpo_number()) {
1132          DCHECK(!header->LoopContains(block));
1133        } else {
1134          DCHECK(header->LoopContains(block));
1135          DCHECK_GE(block->loop_depth(), loop_depth);
1136          count++;
1137        }
1138      }
1139      DCHECK_EQ(links, count);
1140    }
1141  }
1142#endif  // DEBUG
1143
1144  Zone* zone_;
1145  Schedule* schedule_;
1146  BasicBlock* order_;
1147  BasicBlock* beyond_end_;
1148  ZoneVector<LoopInfo> loops_;
1149  ZoneVector<Backedge> backedges_;
1150  ZoneVector<SpecialRPOStackFrame> stack_;
1151  size_t previous_block_count_;
1152  ZoneVector<BasicBlock*> const empty_;
1153};
1154
1155
1156BasicBlockVector* Scheduler::ComputeSpecialRPO(Zone* zone, Schedule* schedule) {
1157  SpecialRPONumberer numberer(zone, schedule);
1158  numberer.ComputeSpecialRPO();
1159  numberer.SerializeRPOIntoSchedule();
1160  numberer.PrintAndVerifySpecialRPO();
1161  return schedule->rpo_order();
1162}
1163
1164
1165void Scheduler::ComputeSpecialRPONumbering() {
1166  TRACE("--- COMPUTING SPECIAL RPO ----------------------------------\n");
1167
1168  // Compute the special reverse-post-order for basic blocks.
1169  special_rpo_ = zone_->New<SpecialRPONumberer>(zone_, schedule_);
1170  special_rpo_->ComputeSpecialRPO();
1171}
1172
1173BasicBlock* Scheduler::GetCommonDominatorIfCached(BasicBlock* b1,
1174                                                  BasicBlock* b2) {
1175  auto entry1 = common_dominator_cache_.find(b1->id().ToInt());
1176  if (entry1 == common_dominator_cache_.end()) return nullptr;
1177  auto entry2 = entry1->second->find(b2->id().ToInt());
1178  if (entry2 == entry1->second->end()) return nullptr;
1179  return entry2->second;
1180}
1181
1182BasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
1183  // A very common fast case:
1184  if (b1 == b2) return b1;
1185  // Try to find the common dominator by walking, if there is a chance of
1186  // finding it quickly.
1187  constexpr int kCacheGranularity = 63;
1188  STATIC_ASSERT((kCacheGranularity & (kCacheGranularity + 1)) == 0);
1189  int depth_difference = b1->dominator_depth() - b2->dominator_depth();
1190  if (depth_difference > -kCacheGranularity &&
1191      depth_difference < kCacheGranularity) {
1192    for (int i = 0; i < kCacheGranularity; i++) {
1193      if (b1->dominator_depth() < b2->dominator_depth()) {
1194        b2 = b2->dominator();
1195      } else {
1196        b1 = b1->dominator();
1197      }
1198      if (b1 == b2) return b1;
1199    }
1200    // We might fall out of the loop here if the dominator tree has several
1201    // deep "parallel" subtrees.
1202  }
1203  // If it'd be a long walk, take the bus instead (i.e. use the cache).
1204  // To keep memory consumption low, there'll be a bus stop every 64 blocks.
1205  // First, walk to the nearest bus stop.
1206  if (b1->dominator_depth() < b2->dominator_depth()) std::swap(b1, b2);
1207  while ((b1->dominator_depth() & kCacheGranularity) != 0) {
1208    if (V8_LIKELY(b1->dominator_depth() > b2->dominator_depth())) {
1209      b1 = b1->dominator();
1210    } else {
1211      b2 = b2->dominator();
1212    }
1213    if (b1 == b2) return b1;
1214  }
1215  // Then, walk from bus stop to bus stop until we either find a bus (i.e. an
1216  // existing cache entry) or the result. Make a list of any empty bus stops
1217  // we'd like to populate for next time.
1218  constexpr int kMaxNewCacheEntries = 2 * 50;  // Must be even.
1219  // This array stores a flattened list of pairs, e.g. if after finding the
1220  // {result}, we want to cache [(B11, B12) -> result, (B21, B22) -> result],
1221  // then we store [11, 12, 21, 22] here.
1222  int new_cache_entries[kMaxNewCacheEntries];
1223  // Next free slot in {new_cache_entries}.
1224  int new_cache_entries_cursor = 0;
1225  while (b1 != b2) {
1226    if ((b1->dominator_depth() & kCacheGranularity) == 0) {
1227      BasicBlock* maybe_cache_hit = GetCommonDominatorIfCached(b1, b2);
1228      if (maybe_cache_hit != nullptr) {
1229        b1 = b2 = maybe_cache_hit;
1230        break;
1231      } else if (new_cache_entries_cursor < kMaxNewCacheEntries) {
1232        new_cache_entries[new_cache_entries_cursor++] = b1->id().ToInt();
1233        new_cache_entries[new_cache_entries_cursor++] = b2->id().ToInt();
1234      }
1235    }
1236    if (V8_LIKELY(b1->dominator_depth() > b2->dominator_depth())) {
1237      b1 = b1->dominator();
1238    } else {
1239      b2 = b2->dominator();
1240    }
1241  }
1242  // Lastly, create new cache entries we noted down earlier.
1243  BasicBlock* result = b1;
1244  for (int i = 0; i < new_cache_entries_cursor;) {
1245    int id1 = new_cache_entries[i++];
1246    int id2 = new_cache_entries[i++];
1247    ZoneMap<int, BasicBlock*>* mapping;
1248    auto entry = common_dominator_cache_.find(id1);
1249    if (entry == common_dominator_cache_.end()) {
1250      mapping = zone_->New<ZoneMap<int, BasicBlock*>>(zone_);
1251      common_dominator_cache_[id1] = mapping;
1252    } else {
1253      mapping = entry->second;
1254    }
1255    // If there was an existing entry, we would have found it earlier.
1256    DCHECK_EQ(mapping->find(id2), mapping->end());
1257    mapping->insert({id2, result});
1258  }
1259  return result;
1260}
1261
1262void Scheduler::PropagateImmediateDominators(BasicBlock* block) {
1263  for (/*nop*/; block != nullptr; block = block->rpo_next()) {
1264    auto pred = block->predecessors().begin();
1265    auto end = block->predecessors().end();
1266    DCHECK(pred != end);  // All blocks except start have predecessors.
1267    BasicBlock* dominator = *pred;
1268    bool deferred = dominator->deferred();
1269    // For multiple predecessors, walk up the dominator tree until a common
1270    // dominator is found. Visitation order guarantees that all predecessors
1271    // except for backwards edges have been visited.
1272    // We use a one-element cache for previously-seen dominators. This gets
1273    // hit a lot for functions that have long chains of diamonds, and in
1274    // those cases turns quadratic into linear complexity.
1275    BasicBlock* cache = nullptr;
1276    for (++pred; pred != end; ++pred) {
1277      // Don't examine backwards edges.
1278      if ((*pred)->dominator_depth() < 0) continue;
1279      if ((*pred)->dominator_depth() > 3 &&
1280          ((*pred)->dominator()->dominator() == cache ||
1281           (*pred)->dominator()->dominator()->dominator() == cache)) {
1282        // Nothing to do, the last iteration covered this case.
1283        DCHECK_EQ(dominator, BasicBlock::GetCommonDominator(dominator, *pred));
1284      } else {
1285        dominator = BasicBlock::GetCommonDominator(dominator, *pred);
1286      }
1287      cache = (*pred)->dominator();
1288      deferred = deferred & (*pred)->deferred();
1289    }
1290    block->set_dominator(dominator);
1291    block->set_dominator_depth(dominator->dominator_depth() + 1);
1292    block->set_deferred(deferred | block->deferred());
1293    TRACE("Block id:%d's idom is id:%d, depth = %d\n", block->id().ToInt(),
1294          dominator->id().ToInt(), block->dominator_depth());
1295  }
1296}
1297
1298void Scheduler::GenerateDominatorTree(Schedule* schedule) {
1299  // Seed start block to be the first dominator.
1300  schedule->start()->set_dominator_depth(0);
1301
1302  // Build the block dominator tree resulting from the above seed.
1303  PropagateImmediateDominators(schedule->start()->rpo_next());
1304}
1305
1306void Scheduler::GenerateDominatorTree() {
1307  TRACE("--- IMMEDIATE BLOCK DOMINATORS -----------------------------\n");
1308  GenerateDominatorTree(schedule_);
1309}
1310
1311// -----------------------------------------------------------------------------
1312// Phase 3: Prepare use counts for nodes.
1313
1314
1315class PrepareUsesVisitor {
1316 public:
1317  explicit PrepareUsesVisitor(Scheduler* scheduler, Graph* graph, Zone* zone)
1318      : scheduler_(scheduler),
1319        schedule_(scheduler->schedule_),
1320        graph_(graph),
1321        visited_(graph_->NodeCount(), false, zone),
1322        stack_(zone) {}
1323
1324  void Run() {
1325    InitializePlacement(graph_->end());
1326    while (!stack_.empty()) {
1327      Node* node = stack_.top();
1328      stack_.pop();
1329      VisitInputs(node);
1330    }
1331  }
1332
1333 private:
1334  void InitializePlacement(Node* node) {
1335    TRACE("Pre #%d:%s\n", node->id(), node->op()->mnemonic());
1336    DCHECK(!Visited(node));
1337    if (scheduler_->InitializePlacement(node) == Scheduler::kFixed) {
1338      // Fixed nodes are always roots for schedule late.
1339      scheduler_->schedule_root_nodes_.push_back(node);
1340      if (!schedule_->IsScheduled(node)) {
1341        // Make sure root nodes are scheduled in their respective blocks.
1342        TRACE("Scheduling fixed position node #%d:%s\n", node->id(),
1343              node->op()->mnemonic());
1344        IrOpcode::Value opcode = node->opcode();
1345        BasicBlock* block =
1346            opcode == IrOpcode::kParameter
1347                ? schedule_->start()
1348                : schedule_->block(NodeProperties::GetControlInput(node));
1349        DCHECK_NOT_NULL(block);
1350        schedule_->AddNode(block, node);
1351      }
1352    }
1353    stack_.push(node);
1354    visited_[node->id()] = true;
1355  }
1356
1357  void VisitInputs(Node* node) {
1358    DCHECK_NE(scheduler_->GetPlacement(node), Scheduler::kUnknown);
1359    bool is_scheduled = schedule_->IsScheduled(node);
1360    base::Optional<int> coupled_control_edge =
1361        scheduler_->GetCoupledControlEdge(node);
1362    for (auto edge : node->input_edges()) {
1363      Node* to = edge.to();
1364      DCHECK_EQ(node, edge.from());
1365      if (!Visited(to)) {
1366        InitializePlacement(to);
1367      }
1368      TRACE("PostEdge #%d:%s->#%d:%s\n", node->id(), node->op()->mnemonic(),
1369            to->id(), to->op()->mnemonic());
1370      DCHECK_NE(scheduler_->GetPlacement(to), Scheduler::kUnknown);
1371      if (!is_scheduled && edge.index() != coupled_control_edge) {
1372        scheduler_->IncrementUnscheduledUseCount(to, node);
1373      }
1374    }
1375  }
1376
1377  bool Visited(Node* node) { return visited_[node->id()]; }
1378
1379  Scheduler* scheduler_;
1380  Schedule* schedule_;
1381  Graph* graph_;
1382  BoolVector visited_;
1383  ZoneStack<Node*> stack_;
1384};
1385
1386
1387void Scheduler::PrepareUses() {
1388  TRACE("--- PREPARE USES -------------------------------------------\n");
1389
1390  // Count the uses of every node, which is used to ensure that all of a
1391  // node's uses are scheduled before the node itself.
1392  PrepareUsesVisitor prepare_uses(this, graph_, zone_);
1393  prepare_uses.Run();
1394}
1395
1396
1397// -----------------------------------------------------------------------------
1398// Phase 4: Schedule nodes early.
1399
1400
1401class ScheduleEarlyNodeVisitor {
1402 public:
1403  ScheduleEarlyNodeVisitor(Zone* zone, Scheduler* scheduler)
1404      : scheduler_(scheduler), schedule_(scheduler->schedule_), queue_(zone) {}
1405
1406  // Run the schedule early algorithm on a set of fixed root nodes.
1407  void Run(NodeVector* roots) {
1408    for (Node* const root : *roots) {
1409      queue_.push(root);
1410    }
1411
1412    while (!queue_.empty()) {
1413      scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
1414      VisitNode(queue_.front());
1415      queue_.pop();
1416    }
1417  }
1418
1419 private:
1420  // Visits one node from the queue and propagates its current schedule early
1421  // position to all uses. This in turn might push more nodes onto the queue.
1422  void VisitNode(Node* node) {
1423    Scheduler::SchedulerData* data = scheduler_->GetData(node);
1424
1425    // Fixed nodes already know their schedule early position.
1426    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
1427      data->minimum_block_ = schedule_->block(node);
1428      TRACE("Fixing #%d:%s minimum_block = id:%d, dominator_depth = %d\n",
1429            node->id(), node->op()->mnemonic(),
1430            data->minimum_block_->id().ToInt(),
1431            data->minimum_block_->dominator_depth());
1432    }
1433
1434    // No need to propagate unconstrained schedule early positions.
1435    if (data->minimum_block_ == schedule_->start()) return;
1436
1437    // Propagate schedule early position.
1438    DCHECK_NOT_NULL(data->minimum_block_);
1439    for (auto use : node->uses()) {
1440      if (scheduler_->IsLive(use)) {
1441        PropagateMinimumPositionToNode(data->minimum_block_, use);
1442      }
1443    }
1444  }
1445
1446  // Propagates {block} as another minimum position into the given {node}. This
1447  // has the net effect of computing the minimum dominator block of {node} that
1448  // still post-dominates all inputs to {node} when the queue is processed.
1449  void PropagateMinimumPositionToNode(BasicBlock* block, Node* node) {
1450    Scheduler::SchedulerData* data = scheduler_->GetData(node);
1451
1452    // No need to propagate to fixed node, it's guaranteed to be a root.
1453    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) return;
1454
1455    // Coupled nodes influence schedule early position of their control.
1456    if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
1457      Node* control = NodeProperties::GetControlInput(node);
1458      PropagateMinimumPositionToNode(block, control);
1459    }
1460
1461    // Propagate new position if it is deeper down the dominator tree than the
1462    // current. Note that all inputs need to have minimum block position inside
1463    // the dominator chain of {node}'s minimum block position.
1464    DCHECK(InsideSameDominatorChain(block, data->minimum_block_));
1465    if (block->dominator_depth() > data->minimum_block_->dominator_depth()) {
1466      data->minimum_block_ = block;
1467      queue_.push(node);
1468      TRACE("Propagating #%d:%s minimum_block = id:%d, dominator_depth = %d\n",
1469            node->id(), node->op()->mnemonic(),
1470            data->minimum_block_->id().ToInt(),
1471            data->minimum_block_->dominator_depth());
1472    }
1473  }
1474
1475#if DEBUG
1476  bool InsideSameDominatorChain(BasicBlock* b1, BasicBlock* b2) {
1477    BasicBlock* dominator = BasicBlock::GetCommonDominator(b1, b2);
1478    return dominator == b1 || dominator == b2;
1479  }
1480#endif
1481
1482  Scheduler* scheduler_;
1483  Schedule* schedule_;
1484  ZoneQueue<Node*> queue_;
1485};
1486
1487
1488void Scheduler::ScheduleEarly() {
1489  if (!special_rpo_->HasLoopBlocks()) {
1490    TRACE("--- NO LOOPS SO SKIPPING SCHEDULE EARLY --------------------\n");
1491    return;
1492  }
1493
1494  TRACE("--- SCHEDULE EARLY -----------------------------------------\n");
1495  if (FLAG_trace_turbo_scheduler) {
1496    TRACE("roots: ");
1497    for (Node* node : schedule_root_nodes_) {
1498      TRACE("#%d:%s ", node->id(), node->op()->mnemonic());
1499    }
1500    TRACE("\n");
1501  }
1502
1503  // Compute the minimum block for each node thereby determining the earliest
1504  // position each node could be placed within a valid schedule.
1505  ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this);
1506  schedule_early_visitor.Run(&schedule_root_nodes_);
1507}
1508
1509
1510// -----------------------------------------------------------------------------
1511// Phase 5: Schedule nodes late.
1512
1513
1514class ScheduleLateNodeVisitor {
1515 public:
1516  ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler)
1517      : zone_(zone),
1518        scheduler_(scheduler),
1519        schedule_(scheduler_->schedule_),
1520        marked_(scheduler->zone_),
1521        marking_queue_(scheduler->zone_) {}
1522
1523  // Run the schedule late algorithm on a set of fixed root nodes.
1524  void Run(NodeVector* roots) {
1525    for (Node* const root : *roots) {
1526      ProcessQueue(root);
1527    }
1528  }
1529
1530 private:
1531  void ProcessQueue(Node* root) {
1532    ZoneQueue<Node*>* queue = &(scheduler_->schedule_queue_);
1533    for (Node* node : root->inputs()) {
1534      // Don't schedule coupled nodes on their own.
1535      if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
1536        node = NodeProperties::GetControlInput(node);
1537      }
1538
1539      // Test schedulability condition by looking at unscheduled use count.
1540      if (scheduler_->GetData(node)->unscheduled_count_ != 0) continue;
1541
1542      queue->push(node);
1543      do {
1544        scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
1545        Node* const n = queue->front();
1546        queue->pop();
1547        VisitNode(n);
1548      } while (!queue->empty());
1549    }
1550  }
1551
1552  // Visits one node from the queue of schedulable nodes and determines its
1553  // schedule late position. Also hoists nodes out of loops to find a more
1554  // optimal scheduling position.
1555  void VisitNode(Node* node) {
1556    DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_);
1557
1558    // Don't schedule nodes that are already scheduled.
1559    if (schedule_->IsScheduled(node)) return;
1560    DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node));
1561
1562    // Determine the dominating block for all of the uses of this node. It is
1563    // the latest block that this node can be scheduled in.
1564    TRACE("Scheduling #%d:%s\n", node->id(), node->op()->mnemonic());
1565    BasicBlock* block = GetCommonDominatorOfUses(node);
1566    DCHECK_NOT_NULL(block);
1567
1568    // The schedule early block dominates the schedule late block.
1569    BasicBlock* min_block = scheduler_->GetData(node)->minimum_block_;
1570    DCHECK_EQ(min_block, BasicBlock::GetCommonDominator(block, min_block));
1571
1572    TRACE(
1573        "Schedule late of #%d:%s is id:%d at loop depth %d, minimum = id:%d\n",
1574        node->id(), node->op()->mnemonic(), block->id().ToInt(),
1575        block->loop_depth(), min_block->id().ToInt());
1576
1577    // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively
1578    // into enclosing loop pre-headers until they would precede their schedule
1579    // early position.
1580    BasicBlock* hoist_block = GetHoistBlock(block);
1581    if (hoist_block &&
1582        hoist_block->dominator_depth() >= min_block->dominator_depth()) {
1583      DCHECK(scheduler_->special_rpo_->HasLoopBlocks());
1584      do {
1585        TRACE("  hoisting #%d:%s to block id:%d\n", node->id(),
1586              node->op()->mnemonic(), hoist_block->id().ToInt());
1587        DCHECK_LT(hoist_block->loop_depth(), block->loop_depth());
1588        block = hoist_block;
1589        hoist_block = GetHoistBlock(hoist_block);
1590      } while (hoist_block &&
1591               hoist_block->dominator_depth() >= min_block->dominator_depth());
1592    } else if (scheduler_->flags_ & Scheduler::kSplitNodes) {
1593      // Split the {node} if beneficial and return the new {block} for it.
1594      block = SplitNode(block, node);
1595    }
1596
1597    // Schedule the node or a floating control structure.
1598    if (IrOpcode::IsMergeOpcode(node->opcode())) {
1599      ScheduleFloatingControl(block, node);
1600    } else if (node->opcode() == IrOpcode::kFinishRegion) {
1601      ScheduleRegion(block, node);
1602    } else {
1603      ScheduleNode(block, node);
1604    }
1605  }
1606
1607  bool IsMarked(BasicBlock* block) const {
1608    DCHECK_LT(block->id().ToSize(), marked_.size());
1609    return marked_[block->id().ToSize()];
1610  }
1611
1612  void Mark(BasicBlock* block) { marked_[block->id().ToSize()] = true; }
1613
1614  // Mark {block} and push its non-marked predecessor on the marking queue.
1615  void MarkBlock(BasicBlock* block) {
1616    DCHECK_LT(block->id().ToSize(), marked_.size());
1617    Mark(block);
1618    for (BasicBlock* pred_block : block->predecessors()) {
1619      if (IsMarked(pred_block)) continue;
1620      marking_queue_.push_back(pred_block);
1621    }
1622  }
1623
1624  BasicBlock* SplitNode(BasicBlock* block, Node* node) {
1625    // For now, we limit splitting to pure nodes.
1626    if (!node->op()->HasProperty(Operator::kPure)) return block;
1627    // TODO(titzer): fix the special case of splitting of projections.
1628    if (node->opcode() == IrOpcode::kProjection) return block;
1629
1630    // The {block} is common dominator of all uses of {node}, so we cannot
1631    // split anything unless the {block} has at least two successors.
1632    DCHECK_EQ(block, GetCommonDominatorOfUses(node));
1633    if (block->SuccessorCount() < 2) return block;
1634
1635    // Clear marking bits.
1636    DCHECK(marking_queue_.empty());
1637    std::fill(marked_.begin(), marked_.end(), false);
1638    marked_.resize(schedule_->BasicBlockCount() + 1, false);
1639
1640    // Check if the {node} has uses in {block}.
1641    for (Edge edge : node->use_edges()) {
1642      if (!scheduler_->IsLive(edge.from())) continue;
1643      BasicBlock* use_block = GetBlockForUse(edge);
1644      if (use_block == nullptr || IsMarked(use_block)) continue;
1645      if (use_block == block) {
1646        TRACE("  not splitting #%d:%s, it is used in id:%d\n", node->id(),
1647              node->op()->mnemonic(), block->id().ToInt());
1648        marking_queue_.clear();
1649        return block;
1650      }
1651      MarkBlock(use_block);
1652    }
1653
1654    // Compute transitive marking closure; a block is marked if all its
1655    // successors are marked.
1656    do {
1657      BasicBlock* top_block = marking_queue_.front();
1658      marking_queue_.pop_front();
1659      if (IsMarked(top_block)) continue;
1660      bool marked = true;
1661      for (BasicBlock* successor : top_block->successors()) {
1662        if (!IsMarked(successor)) {
1663          marked = false;
1664          break;
1665        }
1666      }
1667      if (marked) MarkBlock(top_block);
1668    } while (!marking_queue_.empty());
1669
1670    // If the (common dominator) {block} is marked, we know that all paths from
1671    // {block} to the end contain at least one use of {node}, and hence there's
1672    // no point in splitting the {node} in this case.
1673    if (IsMarked(block)) {
1674      TRACE("  not splitting #%d:%s, its common dominator id:%d is perfect\n",
1675            node->id(), node->op()->mnemonic(), block->id().ToInt());
1676      return block;
1677    }
1678
1679    // Split {node} for uses according to the previously computed marking
1680    // closure. Every marking partition has a unique dominator, which get's a
1681    // copy of the {node} with the exception of the first partition, which get's
1682    // the {node} itself.
1683    ZoneMap<BasicBlock*, Node*> dominators(scheduler_->zone_);
1684    for (Edge edge : node->use_edges()) {
1685      if (!scheduler_->IsLive(edge.from())) continue;
1686      BasicBlock* use_block = GetBlockForUse(edge);
1687      if (use_block == nullptr) continue;
1688      while (IsMarked(use_block->dominator())) {
1689        use_block = use_block->dominator();
1690      }
1691      auto& use_node = dominators[use_block];
1692      if (use_node == nullptr) {
1693        if (dominators.size() == 1u) {
1694          // Place the {node} at {use_block}.
1695          block = use_block;
1696          use_node = node;
1697          TRACE("  pushing #%d:%s down to id:%d\n", node->id(),
1698                node->op()->mnemonic(), block->id().ToInt());
1699        } else {
1700          // Place a copy of {node} at {use_block}.
1701          use_node = CloneNode(node);
1702          TRACE("  cloning #%d:%s for id:%d\n", use_node->id(),
1703                use_node->op()->mnemonic(), use_block->id().ToInt());
1704          scheduler_->schedule_queue_.push(use_node);
1705        }
1706      }
1707      edge.UpdateTo(use_node);
1708    }
1709    return block;
1710  }
1711
1712  BasicBlock* GetHoistBlock(BasicBlock* block) {
1713    if (!scheduler_->special_rpo_->HasLoopBlocks()) return nullptr;
1714    if (block->IsLoopHeader()) return block->dominator();
1715    // We have to check to make sure that the {block} dominates all
1716    // of the outgoing blocks.  If it doesn't, then there is a path
1717    // out of the loop which does not execute this {block}, so we
1718    // can't hoist operations from this {block} out of the loop, as
1719    // that would introduce additional computations.
1720    if (BasicBlock* header_block = block->loop_header()) {
1721      for (BasicBlock* outgoing_block :
1722           scheduler_->special_rpo_->GetOutgoingBlocks(header_block)) {
1723        if (scheduler_->GetCommonDominator(block, outgoing_block) != block) {
1724          return nullptr;
1725        }
1726      }
1727      return header_block->dominator();
1728    }
1729    return nullptr;
1730  }
1731
1732  BasicBlock* GetCommonDominatorOfUses(Node* node) {
1733    BasicBlock* block = nullptr;
1734    for (Edge edge : node->use_edges()) {
1735      if (!scheduler_->IsLive(edge.from())) continue;
1736      BasicBlock* use_block = GetBlockForUse(edge);
1737      block = block == nullptr
1738                  ? use_block
1739                  : use_block == nullptr
1740                        ? block
1741                        : scheduler_->GetCommonDominator(block, use_block);
1742    }
1743    return block;
1744  }
1745
1746  BasicBlock* FindPredecessorBlock(Node* node) {
1747    return scheduler_->control_flow_builder_->FindPredecessorBlock(node);
1748  }
1749
1750  BasicBlock* GetBlockForUse(Edge edge) {
1751    // TODO(titzer): ignore uses from dead nodes (not visited in PrepareUses()).
1752    // Dead uses only occur if the graph is not trimmed before scheduling.
1753    Node* use = edge.from();
1754    if (IrOpcode::IsPhiOpcode(use->opcode())) {
1755      // If the use is from a coupled (i.e. floating) phi, compute the common
1756      // dominator of its uses. This will not recurse more than one level.
1757      if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) {
1758        TRACE("  inspecting uses of coupled #%d:%s\n", use->id(),
1759              use->op()->mnemonic());
1760        // TODO(titzer): reenable once above TODO is addressed.
1761        //        DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use));
1762        return GetCommonDominatorOfUses(use);
1763      }
1764      // If the use is from a fixed (i.e. non-floating) phi, we use the
1765      // predecessor block of the corresponding control input to the merge.
1766      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
1767        TRACE("  input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(),
1768              use->op()->mnemonic());
1769        Node* merge = NodeProperties::GetControlInput(use, 0);
1770        DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
1771        Node* input = NodeProperties::GetControlInput(merge, edge.index());
1772        return FindPredecessorBlock(input);
1773      }
1774    } else if (IrOpcode::IsMergeOpcode(use->opcode())) {
1775      // If the use is from a fixed (i.e. non-floating) merge, we use the
1776      // predecessor block of the current input to the merge.
1777      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
1778        TRACE("  input@%d into a fixed merge #%d:%s\n", edge.index(), use->id(),
1779              use->op()->mnemonic());
1780        return FindPredecessorBlock(edge.to());
1781      }
1782    }
1783    BasicBlock* result = schedule_->block(use);
1784    if (result == nullptr) return nullptr;
1785    TRACE("  must dominate use #%d:%s in id:%d\n", use->id(),
1786          use->op()->mnemonic(), result->id().ToInt());
1787    return result;
1788  }
1789
1790  void ScheduleFloatingControl(BasicBlock* block, Node* node) {
1791    scheduler_->FuseFloatingControl(block, node);
1792  }
1793
1794  void ScheduleRegion(BasicBlock* block, Node* region_end) {
1795    // We only allow regions of instructions connected into a linear
1796    // effect chain. The only value allowed to be produced by a node
1797    // in the chain must be the value consumed by the FinishRegion node.
1798
1799    // We schedule back to front; we first schedule FinishRegion.
1800    CHECK_EQ(IrOpcode::kFinishRegion, region_end->opcode());
1801    ScheduleNode(block, region_end);
1802
1803    // Schedule the chain.
1804    Node* node = NodeProperties::GetEffectInput(region_end);
1805    while (node->opcode() != IrOpcode::kBeginRegion) {
1806      DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_);
1807      DCHECK_EQ(1, node->op()->EffectInputCount());
1808      DCHECK_EQ(1, node->op()->EffectOutputCount());
1809      DCHECK_EQ(0, node->op()->ControlOutputCount());
1810      // The value output (if there is any) must be consumed
1811      // by the EndRegion node.
1812      DCHECK(node->op()->ValueOutputCount() == 0 ||
1813             node == region_end->InputAt(0));
1814      ScheduleNode(block, node);
1815      node = NodeProperties::GetEffectInput(node);
1816    }
1817    // Schedule the BeginRegion node.
1818    DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_);
1819    ScheduleNode(block, node);
1820  }
1821
1822  void ScheduleNode(BasicBlock* block, Node* node) {
1823    schedule_->PlanNode(block, node);
1824    size_t block_id = block->id().ToSize();
1825    if (!scheduler_->scheduled_nodes_[block_id]) {
1826      scheduler_->scheduled_nodes_[block_id] = zone_->New<NodeVector>(zone_);
1827    }
1828    scheduler_->scheduled_nodes_[block_id]->push_back(node);
1829    scheduler_->UpdatePlacement(node, Scheduler::kScheduled);
1830  }
1831
1832  Node* CloneNode(Node* node) {
1833    int const input_count = node->InputCount();
1834    base::Optional<int> coupled_control_edge =
1835        scheduler_->GetCoupledControlEdge(node);
1836    for (int index = 0; index < input_count; ++index) {
1837      if (index != coupled_control_edge) {
1838        Node* const input = node->InputAt(index);
1839        scheduler_->IncrementUnscheduledUseCount(input, node);
1840      }
1841    }
1842    Node* const copy = scheduler_->graph_->CloneNode(node);
1843    TRACE(("clone #%d:%s -> #%d\n"), node->id(), node->op()->mnemonic(),
1844          copy->id());
1845    scheduler_->node_data_.resize(copy->id() + 1,
1846                                  scheduler_->DefaultSchedulerData());
1847    scheduler_->node_data_[copy->id()] = scheduler_->node_data_[node->id()];
1848    return copy;
1849  }
1850
1851  Zone* zone_;
1852  Scheduler* scheduler_;
1853  Schedule* schedule_;
1854  BoolVector marked_;
1855  ZoneDeque<BasicBlock*> marking_queue_;
1856};
1857
1858
1859void Scheduler::ScheduleLate() {
1860  TRACE("--- SCHEDULE LATE ------------------------------------------\n");
1861  if (FLAG_trace_turbo_scheduler) {
1862    TRACE("roots: ");
1863    for (Node* node : schedule_root_nodes_) {
1864      TRACE("#%d:%s ", node->id(), node->op()->mnemonic());
1865    }
1866    TRACE("\n");
1867  }
1868
1869  // Schedule: Places nodes in dominator block of all their uses.
1870  ScheduleLateNodeVisitor schedule_late_visitor(zone_, this);
1871  schedule_late_visitor.Run(&schedule_root_nodes_);
1872}
1873
1874
1875// -----------------------------------------------------------------------------
1876// Phase 6: Seal the final schedule.
1877
1878
1879void Scheduler::SealFinalSchedule() {
1880  TRACE("--- SEAL FINAL SCHEDULE ------------------------------------\n");
1881
1882  // Serialize the assembly order and reverse-post-order numbering.
1883  special_rpo_->SerializeRPOIntoSchedule();
1884  special_rpo_->PrintAndVerifySpecialRPO();
1885
1886  // Add collected nodes for basic blocks to their blocks in the right order.
1887  int block_num = 0;
1888  for (NodeVector* nodes : scheduled_nodes_) {
1889    BasicBlock::Id id = BasicBlock::Id::FromInt(block_num++);
1890    BasicBlock* block = schedule_->GetBlockById(id);
1891    if (nodes) {
1892      for (Node* node : base::Reversed(*nodes)) {
1893        schedule_->AddNode(block, node);
1894      }
1895    }
1896  }
1897}
1898
1899
1900// -----------------------------------------------------------------------------
1901
1902
1903void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
1904  TRACE("--- FUSE FLOATING CONTROL ----------------------------------\n");
1905  if (FLAG_trace_turbo_scheduler) {
1906    StdoutStream{} << "Schedule before control flow fusion:\n" << *schedule_;
1907  }
1908
1909  // Iterate on phase 1: Build control-flow graph.
1910  control_flow_builder_->Run(block, node);
1911
1912  // Iterate on phase 2: Compute special RPO and dominator tree.
1913  special_rpo_->UpdateSpecialRPO(block, schedule_->block(node));
1914  // TODO(turbofan): Currently "iterate on" means "re-run". Fix that.
1915  for (BasicBlock* b = block->rpo_next(); b != nullptr; b = b->rpo_next()) {
1916    b->set_dominator_depth(-1);
1917    b->set_dominator(nullptr);
1918  }
1919  PropagateImmediateDominators(block->rpo_next());
1920
1921  // Iterate on phase 4: Schedule nodes early.
1922  // TODO(turbofan): The following loop gathering the propagation roots is a
1923  // temporary solution and should be merged into the rest of the scheduler as
1924  // soon as the approach settled for all floating loops.
1925  NodeVector propagation_roots(control_flow_builder_->control_);
1926  for (Node* control : control_flow_builder_->control_) {
1927    for (Node* use : control->uses()) {
1928      if (NodeProperties::IsPhi(use) && IsLive(use)) {
1929        propagation_roots.push_back(use);
1930      }
1931    }
1932  }
1933  if (FLAG_trace_turbo_scheduler) {
1934    TRACE("propagation roots: ");
1935    for (Node* r : propagation_roots) {
1936      TRACE("#%d:%s ", r->id(), r->op()->mnemonic());
1937    }
1938    TRACE("\n");
1939  }
1940  ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this);
1941  schedule_early_visitor.Run(&propagation_roots);
1942
1943  // Move previously planned nodes.
1944  // TODO(turbofan): Improve that by supporting bulk moves.
1945  scheduled_nodes_.resize(schedule_->BasicBlockCount());
1946  MovePlannedNodes(block, schedule_->block(node));
1947
1948  if (FLAG_trace_turbo_scheduler) {
1949    StdoutStream{} << "Schedule after control flow fusion:\n" << *schedule_;
1950  }
1951}
1952
1953
1954void Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) {
1955  TRACE("Move planned nodes from id:%d to id:%d\n", from->id().ToInt(),
1956        to->id().ToInt());
1957  NodeVector* from_nodes = scheduled_nodes_[from->id().ToSize()];
1958  NodeVector* to_nodes = scheduled_nodes_[to->id().ToSize()];
1959  if (!from_nodes) return;
1960
1961  for (Node* const node : *from_nodes) {
1962    schedule_->SetBlockForNode(to, node);
1963  }
1964  if (to_nodes) {
1965    to_nodes->insert(to_nodes->end(), from_nodes->begin(), from_nodes->end());
1966    from_nodes->clear();
1967  } else {
1968    std::swap(scheduled_nodes_[from->id().ToSize()],
1969              scheduled_nodes_[to->id().ToSize()]);
1970  }
1971}
1972
1973#undef TRACE
1974
1975}  // namespace compiler
1976}  // namespace internal
1977}  // namespace v8
1978