11cb0ef41Sopenharmony_ci// Copyright 2013 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/compiler/scheduler.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <iomanip>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "src/base/iterator.h"
101cb0ef41Sopenharmony_ci#include "src/builtins/profile-data-reader.h"
111cb0ef41Sopenharmony_ci#include "src/codegen/tick-counter.h"
121cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h"
131cb0ef41Sopenharmony_ci#include "src/compiler/control-equivalence.h"
141cb0ef41Sopenharmony_ci#include "src/compiler/graph.h"
151cb0ef41Sopenharmony_ci#include "src/compiler/node-marker.h"
161cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h"
171cb0ef41Sopenharmony_ci#include "src/compiler/node.h"
181cb0ef41Sopenharmony_ci#include "src/utils/bit-vector.h"
191cb0ef41Sopenharmony_ci#include "src/zone/zone-containers.h"
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_cinamespace v8 {
221cb0ef41Sopenharmony_cinamespace internal {
231cb0ef41Sopenharmony_cinamespace compiler {
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci#define TRACE(...)                                       \
261cb0ef41Sopenharmony_ci  do {                                                   \
271cb0ef41Sopenharmony_ci    if (FLAG_trace_turbo_scheduler) PrintF(__VA_ARGS__); \
281cb0ef41Sopenharmony_ci  } while (false)
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ciScheduler::Scheduler(Zone* zone, Graph* graph, Schedule* schedule, Flags flags,
311cb0ef41Sopenharmony_ci                     size_t node_count_hint, TickCounter* tick_counter,
321cb0ef41Sopenharmony_ci                     const ProfileDataFromFile* profile_data)
331cb0ef41Sopenharmony_ci    : zone_(zone),
341cb0ef41Sopenharmony_ci      graph_(graph),
351cb0ef41Sopenharmony_ci      schedule_(schedule),
361cb0ef41Sopenharmony_ci      flags_(flags),
371cb0ef41Sopenharmony_ci      scheduled_nodes_(zone),
381cb0ef41Sopenharmony_ci      schedule_root_nodes_(zone),
391cb0ef41Sopenharmony_ci      schedule_queue_(zone),
401cb0ef41Sopenharmony_ci      node_data_(zone),
411cb0ef41Sopenharmony_ci      tick_counter_(tick_counter),
421cb0ef41Sopenharmony_ci      profile_data_(profile_data),
431cb0ef41Sopenharmony_ci      common_dominator_cache_(zone) {
441cb0ef41Sopenharmony_ci  node_data_.reserve(node_count_hint);
451cb0ef41Sopenharmony_ci  node_data_.resize(graph->NodeCount(), DefaultSchedulerData());
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ciSchedule* Scheduler::ComputeSchedule(Zone* zone, Graph* graph, Flags flags,
491cb0ef41Sopenharmony_ci                                     TickCounter* tick_counter,
501cb0ef41Sopenharmony_ci                                     const ProfileDataFromFile* profile_data) {
511cb0ef41Sopenharmony_ci  Zone* schedule_zone =
521cb0ef41Sopenharmony_ci      (flags & Scheduler::kTempSchedule) ? zone : graph->zone();
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  // Reserve 10% more space for nodes if node splitting is enabled to try to
551cb0ef41Sopenharmony_ci  // avoid resizing the vector since that would triple its zone memory usage.
561cb0ef41Sopenharmony_ci  float node_hint_multiplier = (flags & Scheduler::kSplitNodes) ? 1.1 : 1;
571cb0ef41Sopenharmony_ci  size_t node_count_hint = node_hint_multiplier * graph->NodeCount();
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci  Schedule* schedule =
601cb0ef41Sopenharmony_ci      schedule_zone->New<Schedule>(schedule_zone, node_count_hint);
611cb0ef41Sopenharmony_ci  Scheduler scheduler(zone, graph, schedule, flags, node_count_hint,
621cb0ef41Sopenharmony_ci                      tick_counter, profile_data);
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  scheduler.BuildCFG();
651cb0ef41Sopenharmony_ci  scheduler.ComputeSpecialRPONumbering();
661cb0ef41Sopenharmony_ci  scheduler.GenerateDominatorTree();
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci  scheduler.PrepareUses();
691cb0ef41Sopenharmony_ci  scheduler.ScheduleEarly();
701cb0ef41Sopenharmony_ci  scheduler.ScheduleLate();
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  scheduler.SealFinalSchedule();
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  return schedule;
751cb0ef41Sopenharmony_ci}
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ciScheduler::SchedulerData Scheduler::DefaultSchedulerData() {
781cb0ef41Sopenharmony_ci  SchedulerData def = {schedule_->start(), 0, kUnknown};
791cb0ef41Sopenharmony_ci  return def;
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ciScheduler::SchedulerData* Scheduler::GetData(Node* node) {
841cb0ef41Sopenharmony_ci  return &node_data_[node->id()];
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ciScheduler::Placement Scheduler::InitializePlacement(Node* node) {
881cb0ef41Sopenharmony_ci  SchedulerData* data = GetData(node);
891cb0ef41Sopenharmony_ci  if (data->placement_ == kFixed) {
901cb0ef41Sopenharmony_ci    // Nothing to do for control nodes that have been already fixed in
911cb0ef41Sopenharmony_ci    // the schedule.
921cb0ef41Sopenharmony_ci    return data->placement_;
931cb0ef41Sopenharmony_ci  }
941cb0ef41Sopenharmony_ci  DCHECK_EQ(kUnknown, data->placement_);
951cb0ef41Sopenharmony_ci  switch (node->opcode()) {
961cb0ef41Sopenharmony_ci    case IrOpcode::kParameter:
971cb0ef41Sopenharmony_ci    case IrOpcode::kOsrValue:
981cb0ef41Sopenharmony_ci      // Parameters and OSR values are always fixed to the start block.
991cb0ef41Sopenharmony_ci      data->placement_ = kFixed;
1001cb0ef41Sopenharmony_ci      break;
1011cb0ef41Sopenharmony_ci    case IrOpcode::kPhi:
1021cb0ef41Sopenharmony_ci    case IrOpcode::kEffectPhi: {
1031cb0ef41Sopenharmony_ci      // Phis and effect phis are fixed if their control inputs are, whereas
1041cb0ef41Sopenharmony_ci      // otherwise they are coupled to a floating control node.
1051cb0ef41Sopenharmony_ci      Placement p = GetPlacement(NodeProperties::GetControlInput(node));
1061cb0ef41Sopenharmony_ci      data->placement_ = (p == kFixed ? kFixed : kCoupled);
1071cb0ef41Sopenharmony_ci      break;
1081cb0ef41Sopenharmony_ci    }
1091cb0ef41Sopenharmony_ci    default:
1101cb0ef41Sopenharmony_ci      // Control nodes that were not control-reachable from end may float.
1111cb0ef41Sopenharmony_ci      data->placement_ = kSchedulable;
1121cb0ef41Sopenharmony_ci      break;
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci  return data->placement_;
1151cb0ef41Sopenharmony_ci}
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ciScheduler::Placement Scheduler::GetPlacement(Node* node) {
1181cb0ef41Sopenharmony_ci  return GetData(node)->placement_;
1191cb0ef41Sopenharmony_ci}
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_cibool Scheduler::IsLive(Node* node) { return GetPlacement(node) != kUnknown; }
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_civoid Scheduler::UpdatePlacement(Node* node, Placement placement) {
1241cb0ef41Sopenharmony_ci  SchedulerData* data = GetData(node);
1251cb0ef41Sopenharmony_ci  if (data->placement_ == kUnknown) {
1261cb0ef41Sopenharmony_ci    // We only update control nodes from {kUnknown} to {kFixed}.  Ideally, we
1271cb0ef41Sopenharmony_ci    // should check that {node} is a control node (including exceptional calls),
1281cb0ef41Sopenharmony_ci    // but that is expensive.
1291cb0ef41Sopenharmony_ci    DCHECK_EQ(Scheduler::kFixed, placement);
1301cb0ef41Sopenharmony_ci    data->placement_ = placement;
1311cb0ef41Sopenharmony_ci    return;
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  switch (node->opcode()) {
1351cb0ef41Sopenharmony_ci    case IrOpcode::kParameter:
1361cb0ef41Sopenharmony_ci      // Parameters are fixed once and for all.
1371cb0ef41Sopenharmony_ci      UNREACHABLE();
1381cb0ef41Sopenharmony_ci    case IrOpcode::kPhi:
1391cb0ef41Sopenharmony_ci    case IrOpcode::kEffectPhi: {
1401cb0ef41Sopenharmony_ci      // Phis and effect phis are coupled to their respective blocks.
1411cb0ef41Sopenharmony_ci      DCHECK_EQ(Scheduler::kCoupled, data->placement_);
1421cb0ef41Sopenharmony_ci      DCHECK_EQ(Scheduler::kFixed, placement);
1431cb0ef41Sopenharmony_ci      Node* control = NodeProperties::GetControlInput(node);
1441cb0ef41Sopenharmony_ci      BasicBlock* block = schedule_->block(control);
1451cb0ef41Sopenharmony_ci      schedule_->AddNode(block, node);
1461cb0ef41Sopenharmony_ci      break;
1471cb0ef41Sopenharmony_ci    }
1481cb0ef41Sopenharmony_ci#define DEFINE_CONTROL_CASE(V) case IrOpcode::k##V:
1491cb0ef41Sopenharmony_ci      CONTROL_OP_LIST(DEFINE_CONTROL_CASE)
1501cb0ef41Sopenharmony_ci#undef DEFINE_CONTROL_CASE
1511cb0ef41Sopenharmony_ci      {
1521cb0ef41Sopenharmony_ci        // Control nodes force coupled uses to be placed.
1531cb0ef41Sopenharmony_ci        for (auto use : node->uses()) {
1541cb0ef41Sopenharmony_ci          if (GetPlacement(use) == Scheduler::kCoupled) {
1551cb0ef41Sopenharmony_ci            DCHECK_EQ(node, NodeProperties::GetControlInput(use));
1561cb0ef41Sopenharmony_ci            UpdatePlacement(use, placement);
1571cb0ef41Sopenharmony_ci          }
1581cb0ef41Sopenharmony_ci      }
1591cb0ef41Sopenharmony_ci      break;
1601cb0ef41Sopenharmony_ci    }
1611cb0ef41Sopenharmony_ci    default:
1621cb0ef41Sopenharmony_ci      DCHECK_EQ(Scheduler::kSchedulable, data->placement_);
1631cb0ef41Sopenharmony_ci      DCHECK_EQ(Scheduler::kScheduled, placement);
1641cb0ef41Sopenharmony_ci      break;
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci  // Reduce the use count of the node's inputs to potentially make them
1671cb0ef41Sopenharmony_ci  // schedulable. If all the uses of a node have been scheduled, then the node
1681cb0ef41Sopenharmony_ci  // itself can be scheduled.
1691cb0ef41Sopenharmony_ci  base::Optional<int> coupled_control_edge = GetCoupledControlEdge(node);
1701cb0ef41Sopenharmony_ci  for (Edge const edge : node->input_edges()) {
1711cb0ef41Sopenharmony_ci    DCHECK_EQ(node, edge.from());
1721cb0ef41Sopenharmony_ci    if (edge.index() != coupled_control_edge) {
1731cb0ef41Sopenharmony_ci      DecrementUnscheduledUseCount(edge.to(), node);
1741cb0ef41Sopenharmony_ci    }
1751cb0ef41Sopenharmony_ci  }
1761cb0ef41Sopenharmony_ci  data->placement_ = placement;
1771cb0ef41Sopenharmony_ci}
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_cibase::Optional<int> Scheduler::GetCoupledControlEdge(Node* node) {
1801cb0ef41Sopenharmony_ci  if (GetPlacement(node) == kCoupled) {
1811cb0ef41Sopenharmony_ci    return NodeProperties::FirstControlIndex(node);
1821cb0ef41Sopenharmony_ci  }
1831cb0ef41Sopenharmony_ci  return {};
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_civoid Scheduler::IncrementUnscheduledUseCount(Node* node, Node* from) {
1871cb0ef41Sopenharmony_ci  // Tracking use counts for fixed nodes is useless.
1881cb0ef41Sopenharmony_ci  if (GetPlacement(node) == kFixed) return;
1891cb0ef41Sopenharmony_ci
1901cb0ef41Sopenharmony_ci  // Use count for coupled nodes is summed up on their control.
1911cb0ef41Sopenharmony_ci  if (GetPlacement(node) == kCoupled) {
1921cb0ef41Sopenharmony_ci    node = NodeProperties::GetControlInput(node);
1931cb0ef41Sopenharmony_ci    DCHECK_NE(GetPlacement(node), Placement::kFixed);
1941cb0ef41Sopenharmony_ci    DCHECK_NE(GetPlacement(node), Placement::kCoupled);
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  ++(GetData(node)->unscheduled_count_);
1981cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
1991cb0ef41Sopenharmony_ci    TRACE("  Use count of #%d:%s (used by #%d:%s)++ = %d\n", node->id(),
2001cb0ef41Sopenharmony_ci          node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
2011cb0ef41Sopenharmony_ci          GetData(node)->unscheduled_count_);
2021cb0ef41Sopenharmony_ci  }
2031cb0ef41Sopenharmony_ci}
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_civoid Scheduler::DecrementUnscheduledUseCount(Node* node, Node* from) {
2061cb0ef41Sopenharmony_ci  // Tracking use counts for fixed nodes is useless.
2071cb0ef41Sopenharmony_ci  if (GetPlacement(node) == kFixed) return;
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci  // Use count for coupled nodes is summed up on their control.
2101cb0ef41Sopenharmony_ci  if (GetPlacement(node) == kCoupled) {
2111cb0ef41Sopenharmony_ci    node = NodeProperties::GetControlInput(node);
2121cb0ef41Sopenharmony_ci    DCHECK_NE(GetPlacement(node), Placement::kFixed);
2131cb0ef41Sopenharmony_ci    DCHECK_NE(GetPlacement(node), Placement::kCoupled);
2141cb0ef41Sopenharmony_ci  }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  DCHECK_LT(0, GetData(node)->unscheduled_count_);
2171cb0ef41Sopenharmony_ci  --(GetData(node)->unscheduled_count_);
2181cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
2191cb0ef41Sopenharmony_ci    TRACE("  Use count of #%d:%s (used by #%d:%s)-- = %d\n", node->id(),
2201cb0ef41Sopenharmony_ci          node->op()->mnemonic(), from->id(), from->op()->mnemonic(),
2211cb0ef41Sopenharmony_ci          GetData(node)->unscheduled_count_);
2221cb0ef41Sopenharmony_ci  }
2231cb0ef41Sopenharmony_ci  if (GetData(node)->unscheduled_count_ == 0) {
2241cb0ef41Sopenharmony_ci    TRACE("    newly eligible #%d:%s\n", node->id(), node->op()->mnemonic());
2251cb0ef41Sopenharmony_ci    schedule_queue_.push(node);
2261cb0ef41Sopenharmony_ci  }
2271cb0ef41Sopenharmony_ci}
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
2301cb0ef41Sopenharmony_ci// Phase 1: Build control-flow graph.
2311cb0ef41Sopenharmony_ci
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci// Internal class to build a control flow graph (i.e the basic blocks and edges
2341cb0ef41Sopenharmony_ci// between them within a Schedule) from the node graph. Visits control edges of
2351cb0ef41Sopenharmony_ci// the graph backwards from an end node in order to find the connected control
2361cb0ef41Sopenharmony_ci// subgraph, needed for scheduling.
2371cb0ef41Sopenharmony_ciclass CFGBuilder : public ZoneObject {
2381cb0ef41Sopenharmony_ci public:
2391cb0ef41Sopenharmony_ci  CFGBuilder(Zone* zone, Scheduler* scheduler)
2401cb0ef41Sopenharmony_ci      : zone_(zone),
2411cb0ef41Sopenharmony_ci        scheduler_(scheduler),
2421cb0ef41Sopenharmony_ci        schedule_(scheduler->schedule_),
2431cb0ef41Sopenharmony_ci        queued_(scheduler->graph_, 2),
2441cb0ef41Sopenharmony_ci        queue_(zone),
2451cb0ef41Sopenharmony_ci        control_(zone),
2461cb0ef41Sopenharmony_ci        component_entry_(nullptr),
2471cb0ef41Sopenharmony_ci        component_start_(nullptr),
2481cb0ef41Sopenharmony_ci        component_end_(nullptr) {}
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci  // Run the control flow graph construction algorithm by walking the graph
2511cb0ef41Sopenharmony_ci  // backwards from end through control edges, building and connecting the
2521cb0ef41Sopenharmony_ci  // basic blocks for control nodes.
2531cb0ef41Sopenharmony_ci  void Run() {
2541cb0ef41Sopenharmony_ci    ResetDataStructures();
2551cb0ef41Sopenharmony_ci    Queue(scheduler_->graph_->end());
2561cb0ef41Sopenharmony_ci
2571cb0ef41Sopenharmony_ci    while (!queue_.empty()) {  // Breadth-first backwards traversal.
2581cb0ef41Sopenharmony_ci      scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
2591cb0ef41Sopenharmony_ci      Node* node = queue_.front();
2601cb0ef41Sopenharmony_ci      queue_.pop();
2611cb0ef41Sopenharmony_ci      int max = NodeProperties::PastControlIndex(node);
2621cb0ef41Sopenharmony_ci      for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
2631cb0ef41Sopenharmony_ci        Queue(node->InputAt(i));
2641cb0ef41Sopenharmony_ci      }
2651cb0ef41Sopenharmony_ci    }
2661cb0ef41Sopenharmony_ci
2671cb0ef41Sopenharmony_ci    for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
2681cb0ef41Sopenharmony_ci      ConnectBlocks(*i);  // Connect block to its predecessor/successors.
2691cb0ef41Sopenharmony_ci    }
2701cb0ef41Sopenharmony_ci  }
2711cb0ef41Sopenharmony_ci
2721cb0ef41Sopenharmony_ci  // Run the control flow graph construction for a minimal control-connected
2731cb0ef41Sopenharmony_ci  // component ending in {exit} and merge that component into an existing
2741cb0ef41Sopenharmony_ci  // control flow graph at the bottom of {block}.
2751cb0ef41Sopenharmony_ci  void Run(BasicBlock* block, Node* exit) {
2761cb0ef41Sopenharmony_ci    ResetDataStructures();
2771cb0ef41Sopenharmony_ci    Queue(exit);
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_ci    component_entry_ = nullptr;
2801cb0ef41Sopenharmony_ci    component_start_ = block;
2811cb0ef41Sopenharmony_ci    component_end_ = schedule_->block(exit);
2821cb0ef41Sopenharmony_ci    scheduler_->equivalence_->Run(exit);
2831cb0ef41Sopenharmony_ci    while (!queue_.empty()) {  // Breadth-first backwards traversal.
2841cb0ef41Sopenharmony_ci      scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
2851cb0ef41Sopenharmony_ci      Node* node = queue_.front();
2861cb0ef41Sopenharmony_ci      queue_.pop();
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ci      // Use control dependence equivalence to find a canonical single-entry
2891cb0ef41Sopenharmony_ci      // single-exit region that makes up a minimal component to be scheduled.
2901cb0ef41Sopenharmony_ci      if (IsSingleEntrySingleExitRegion(node, exit)) {
2911cb0ef41Sopenharmony_ci        TRACE("Found SESE at #%d:%s\n", node->id(), node->op()->mnemonic());
2921cb0ef41Sopenharmony_ci        DCHECK(!component_entry_);
2931cb0ef41Sopenharmony_ci        component_entry_ = node;
2941cb0ef41Sopenharmony_ci        continue;
2951cb0ef41Sopenharmony_ci      }
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci      int max = NodeProperties::PastControlIndex(node);
2981cb0ef41Sopenharmony_ci      for (int i = NodeProperties::FirstControlIndex(node); i < max; i++) {
2991cb0ef41Sopenharmony_ci        Queue(node->InputAt(i));
3001cb0ef41Sopenharmony_ci      }
3011cb0ef41Sopenharmony_ci    }
3021cb0ef41Sopenharmony_ci    DCHECK(component_entry_);
3031cb0ef41Sopenharmony_ci
3041cb0ef41Sopenharmony_ci    for (NodeVector::iterator i = control_.begin(); i != control_.end(); ++i) {
3051cb0ef41Sopenharmony_ci      ConnectBlocks(*i);  // Connect block to its predecessor/successors.
3061cb0ef41Sopenharmony_ci    }
3071cb0ef41Sopenharmony_ci  }
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ci private:
3101cb0ef41Sopenharmony_ci  friend class ScheduleLateNodeVisitor;
3111cb0ef41Sopenharmony_ci  friend class Scheduler;
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci  void FixNode(BasicBlock* block, Node* node) {
3141cb0ef41Sopenharmony_ci    schedule_->AddNode(block, node);
3151cb0ef41Sopenharmony_ci    scheduler_->UpdatePlacement(node, Scheduler::kFixed);
3161cb0ef41Sopenharmony_ci  }
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci  void Queue(Node* node) {
3191cb0ef41Sopenharmony_ci    // Mark the connected control nodes as they are queued.
3201cb0ef41Sopenharmony_ci    if (!queued_.Get(node)) {
3211cb0ef41Sopenharmony_ci      BuildBlocks(node);
3221cb0ef41Sopenharmony_ci      queue_.push(node);
3231cb0ef41Sopenharmony_ci      queued_.Set(node, true);
3241cb0ef41Sopenharmony_ci      control_.push_back(node);
3251cb0ef41Sopenharmony_ci    }
3261cb0ef41Sopenharmony_ci  }
3271cb0ef41Sopenharmony_ci
3281cb0ef41Sopenharmony_ci  void BuildBlocks(Node* node) {
3291cb0ef41Sopenharmony_ci    switch (node->opcode()) {
3301cb0ef41Sopenharmony_ci      case IrOpcode::kEnd:
3311cb0ef41Sopenharmony_ci        FixNode(schedule_->end(), node);
3321cb0ef41Sopenharmony_ci        break;
3331cb0ef41Sopenharmony_ci      case IrOpcode::kStart:
3341cb0ef41Sopenharmony_ci        FixNode(schedule_->start(), node);
3351cb0ef41Sopenharmony_ci        break;
3361cb0ef41Sopenharmony_ci      case IrOpcode::kLoop:
3371cb0ef41Sopenharmony_ci      case IrOpcode::kMerge:
3381cb0ef41Sopenharmony_ci        BuildBlockForNode(node);
3391cb0ef41Sopenharmony_ci        break;
3401cb0ef41Sopenharmony_ci      case IrOpcode::kTerminate: {
3411cb0ef41Sopenharmony_ci        // Put Terminate in the loop to which it refers.
3421cb0ef41Sopenharmony_ci        Node* loop = NodeProperties::GetControlInput(node);
3431cb0ef41Sopenharmony_ci        BasicBlock* block = BuildBlockForNode(loop);
3441cb0ef41Sopenharmony_ci        FixNode(block, node);
3451cb0ef41Sopenharmony_ci        break;
3461cb0ef41Sopenharmony_ci      }
3471cb0ef41Sopenharmony_ci      case IrOpcode::kBranch:
3481cb0ef41Sopenharmony_ci      case IrOpcode::kSwitch:
3491cb0ef41Sopenharmony_ci        BuildBlocksForSuccessors(node);
3501cb0ef41Sopenharmony_ci        break;
3511cb0ef41Sopenharmony_ci#define BUILD_BLOCK_JS_CASE(Name, ...) case IrOpcode::k##Name:
3521cb0ef41Sopenharmony_ci        JS_OP_LIST(BUILD_BLOCK_JS_CASE)
3531cb0ef41Sopenharmony_ci// JS opcodes are just like calls => fall through.
3541cb0ef41Sopenharmony_ci#undef BUILD_BLOCK_JS_CASE
3551cb0ef41Sopenharmony_ci      case IrOpcode::kCall:
3561cb0ef41Sopenharmony_ci        if (NodeProperties::IsExceptionalCall(node)) {
3571cb0ef41Sopenharmony_ci          BuildBlocksForSuccessors(node);
3581cb0ef41Sopenharmony_ci        }
3591cb0ef41Sopenharmony_ci        break;
3601cb0ef41Sopenharmony_ci      default:
3611cb0ef41Sopenharmony_ci        break;
3621cb0ef41Sopenharmony_ci    }
3631cb0ef41Sopenharmony_ci  }
3641cb0ef41Sopenharmony_ci
3651cb0ef41Sopenharmony_ci  void ConnectBlocks(Node* node) {
3661cb0ef41Sopenharmony_ci    switch (node->opcode()) {
3671cb0ef41Sopenharmony_ci      case IrOpcode::kLoop:
3681cb0ef41Sopenharmony_ci      case IrOpcode::kMerge:
3691cb0ef41Sopenharmony_ci        ConnectMerge(node);
3701cb0ef41Sopenharmony_ci        break;
3711cb0ef41Sopenharmony_ci      case IrOpcode::kBranch:
3721cb0ef41Sopenharmony_ci        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
3731cb0ef41Sopenharmony_ci        ConnectBranch(node);
3741cb0ef41Sopenharmony_ci        break;
3751cb0ef41Sopenharmony_ci      case IrOpcode::kSwitch:
3761cb0ef41Sopenharmony_ci        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
3771cb0ef41Sopenharmony_ci        ConnectSwitch(node);
3781cb0ef41Sopenharmony_ci        break;
3791cb0ef41Sopenharmony_ci      case IrOpcode::kDeoptimize:
3801cb0ef41Sopenharmony_ci        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
3811cb0ef41Sopenharmony_ci        ConnectDeoptimize(node);
3821cb0ef41Sopenharmony_ci        break;
3831cb0ef41Sopenharmony_ci      case IrOpcode::kTailCall:
3841cb0ef41Sopenharmony_ci        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
3851cb0ef41Sopenharmony_ci        ConnectTailCall(node);
3861cb0ef41Sopenharmony_ci        break;
3871cb0ef41Sopenharmony_ci      case IrOpcode::kReturn:
3881cb0ef41Sopenharmony_ci        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
3891cb0ef41Sopenharmony_ci        ConnectReturn(node);
3901cb0ef41Sopenharmony_ci        break;
3911cb0ef41Sopenharmony_ci      case IrOpcode::kThrow:
3921cb0ef41Sopenharmony_ci        scheduler_->UpdatePlacement(node, Scheduler::kFixed);
3931cb0ef41Sopenharmony_ci        ConnectThrow(node);
3941cb0ef41Sopenharmony_ci        break;
3951cb0ef41Sopenharmony_ci#define CONNECT_BLOCK_JS_CASE(Name, ...) case IrOpcode::k##Name:
3961cb0ef41Sopenharmony_ci        JS_OP_LIST(CONNECT_BLOCK_JS_CASE)
3971cb0ef41Sopenharmony_ci// JS opcodes are just like calls => fall through.
3981cb0ef41Sopenharmony_ci#undef CONNECT_BLOCK_JS_CASE
3991cb0ef41Sopenharmony_ci      case IrOpcode::kCall:
4001cb0ef41Sopenharmony_ci        if (NodeProperties::IsExceptionalCall(node)) {
4011cb0ef41Sopenharmony_ci          scheduler_->UpdatePlacement(node, Scheduler::kFixed);
4021cb0ef41Sopenharmony_ci          ConnectCall(node);
4031cb0ef41Sopenharmony_ci        }
4041cb0ef41Sopenharmony_ci        break;
4051cb0ef41Sopenharmony_ci      default:
4061cb0ef41Sopenharmony_ci        break;
4071cb0ef41Sopenharmony_ci    }
4081cb0ef41Sopenharmony_ci  }
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ci  BasicBlock* BuildBlockForNode(Node* node) {
4111cb0ef41Sopenharmony_ci    BasicBlock* block = schedule_->block(node);
4121cb0ef41Sopenharmony_ci    if (block == nullptr) {
4131cb0ef41Sopenharmony_ci      block = schedule_->NewBasicBlock();
4141cb0ef41Sopenharmony_ci      TRACE("Create block id:%d for #%d:%s\n", block->id().ToInt(), node->id(),
4151cb0ef41Sopenharmony_ci            node->op()->mnemonic());
4161cb0ef41Sopenharmony_ci      FixNode(block, node);
4171cb0ef41Sopenharmony_ci    }
4181cb0ef41Sopenharmony_ci    return block;
4191cb0ef41Sopenharmony_ci  }
4201cb0ef41Sopenharmony_ci
4211cb0ef41Sopenharmony_ci  void BuildBlocksForSuccessors(Node* node) {
4221cb0ef41Sopenharmony_ci    size_t const successor_cnt = node->op()->ControlOutputCount();
4231cb0ef41Sopenharmony_ci    Node** successors = zone_->NewArray<Node*>(successor_cnt);
4241cb0ef41Sopenharmony_ci    NodeProperties::CollectControlProjections(node, successors, successor_cnt);
4251cb0ef41Sopenharmony_ci    for (size_t index = 0; index < successor_cnt; ++index) {
4261cb0ef41Sopenharmony_ci      BuildBlockForNode(successors[index]);
4271cb0ef41Sopenharmony_ci    }
4281cb0ef41Sopenharmony_ci  }
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci  void CollectSuccessorBlocks(Node* node, BasicBlock** successor_blocks,
4311cb0ef41Sopenharmony_ci                              size_t successor_cnt) {
4321cb0ef41Sopenharmony_ci    Node** successors = reinterpret_cast<Node**>(successor_blocks);
4331cb0ef41Sopenharmony_ci    NodeProperties::CollectControlProjections(node, successors, successor_cnt);
4341cb0ef41Sopenharmony_ci    for (size_t index = 0; index < successor_cnt; ++index) {
4351cb0ef41Sopenharmony_ci      successor_blocks[index] = schedule_->block(successors[index]);
4361cb0ef41Sopenharmony_ci    }
4371cb0ef41Sopenharmony_ci  }
4381cb0ef41Sopenharmony_ci
4391cb0ef41Sopenharmony_ci  BasicBlock* FindPredecessorBlock(Node* node) {
4401cb0ef41Sopenharmony_ci    BasicBlock* predecessor_block = nullptr;
4411cb0ef41Sopenharmony_ci    while (true) {
4421cb0ef41Sopenharmony_ci      predecessor_block = schedule_->block(node);
4431cb0ef41Sopenharmony_ci      if (predecessor_block != nullptr) break;
4441cb0ef41Sopenharmony_ci      node = NodeProperties::GetControlInput(node);
4451cb0ef41Sopenharmony_ci    }
4461cb0ef41Sopenharmony_ci    return predecessor_block;
4471cb0ef41Sopenharmony_ci  }
4481cb0ef41Sopenharmony_ci
4491cb0ef41Sopenharmony_ci  void ConnectCall(Node* call) {
4501cb0ef41Sopenharmony_ci    BasicBlock* successor_blocks[2];
4511cb0ef41Sopenharmony_ci    CollectSuccessorBlocks(call, successor_blocks, arraysize(successor_blocks));
4521cb0ef41Sopenharmony_ci
4531cb0ef41Sopenharmony_ci    // Consider the exception continuation to be deferred.
4541cb0ef41Sopenharmony_ci    successor_blocks[1]->set_deferred(true);
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci    Node* call_control = NodeProperties::GetControlInput(call);
4571cb0ef41Sopenharmony_ci    BasicBlock* call_block = FindPredecessorBlock(call_control);
4581cb0ef41Sopenharmony_ci    TraceConnect(call, call_block, successor_blocks[0]);
4591cb0ef41Sopenharmony_ci    TraceConnect(call, call_block, successor_blocks[1]);
4601cb0ef41Sopenharmony_ci    schedule_->AddCall(call_block, call, successor_blocks[0],
4611cb0ef41Sopenharmony_ci                       successor_blocks[1]);
4621cb0ef41Sopenharmony_ci  }
4631cb0ef41Sopenharmony_ci
4641cb0ef41Sopenharmony_ci  void ConnectBranch(Node* branch) {
4651cb0ef41Sopenharmony_ci    BasicBlock* successor_blocks[2];
4661cb0ef41Sopenharmony_ci    CollectSuccessorBlocks(branch, successor_blocks,
4671cb0ef41Sopenharmony_ci                           arraysize(successor_blocks));
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci    BranchHint hint_from_profile = BranchHint::kNone;
4701cb0ef41Sopenharmony_ci    if (const ProfileDataFromFile* profile_data = scheduler_->profile_data()) {
4711cb0ef41Sopenharmony_ci      double block_zero_count =
4721cb0ef41Sopenharmony_ci          profile_data->GetCounter(successor_blocks[0]->id().ToSize());
4731cb0ef41Sopenharmony_ci      double block_one_count =
4741cb0ef41Sopenharmony_ci          profile_data->GetCounter(successor_blocks[1]->id().ToSize());
4751cb0ef41Sopenharmony_ci      // If a branch is visited a non-trivial number of times and substantially
4761cb0ef41Sopenharmony_ci      // more often than its alternative, then mark it as likely.
4771cb0ef41Sopenharmony_ci      constexpr double kMinimumCount = 100000;
4781cb0ef41Sopenharmony_ci      constexpr double kThresholdRatio = 4000;
4791cb0ef41Sopenharmony_ci      if (block_zero_count > kMinimumCount &&
4801cb0ef41Sopenharmony_ci          block_zero_count / kThresholdRatio > block_one_count) {
4811cb0ef41Sopenharmony_ci        hint_from_profile = BranchHint::kTrue;
4821cb0ef41Sopenharmony_ci      } else if (block_one_count > kMinimumCount &&
4831cb0ef41Sopenharmony_ci                 block_one_count / kThresholdRatio > block_zero_count) {
4841cb0ef41Sopenharmony_ci        hint_from_profile = BranchHint::kFalse;
4851cb0ef41Sopenharmony_ci      }
4861cb0ef41Sopenharmony_ci    }
4871cb0ef41Sopenharmony_ci
4881cb0ef41Sopenharmony_ci    // Consider branch hints.
4891cb0ef41Sopenharmony_ci    switch (hint_from_profile) {
4901cb0ef41Sopenharmony_ci      case BranchHint::kNone:
4911cb0ef41Sopenharmony_ci        switch (BranchHintOf(branch->op())) {
4921cb0ef41Sopenharmony_ci          case BranchHint::kNone:
4931cb0ef41Sopenharmony_ci            break;
4941cb0ef41Sopenharmony_ci          case BranchHint::kTrue:
4951cb0ef41Sopenharmony_ci            successor_blocks[1]->set_deferred(true);
4961cb0ef41Sopenharmony_ci            break;
4971cb0ef41Sopenharmony_ci          case BranchHint::kFalse:
4981cb0ef41Sopenharmony_ci            successor_blocks[0]->set_deferred(true);
4991cb0ef41Sopenharmony_ci            break;
5001cb0ef41Sopenharmony_ci        }
5011cb0ef41Sopenharmony_ci        break;
5021cb0ef41Sopenharmony_ci      case BranchHint::kTrue:
5031cb0ef41Sopenharmony_ci        successor_blocks[1]->set_deferred(true);
5041cb0ef41Sopenharmony_ci        break;
5051cb0ef41Sopenharmony_ci      case BranchHint::kFalse:
5061cb0ef41Sopenharmony_ci        successor_blocks[0]->set_deferred(true);
5071cb0ef41Sopenharmony_ci        break;
5081cb0ef41Sopenharmony_ci    }
5091cb0ef41Sopenharmony_ci
5101cb0ef41Sopenharmony_ci    if (hint_from_profile != BranchHint::kNone &&
5111cb0ef41Sopenharmony_ci        BranchHintOf(branch->op()) != BranchHint::kNone &&
5121cb0ef41Sopenharmony_ci        hint_from_profile != BranchHintOf(branch->op())) {
5131cb0ef41Sopenharmony_ci      PrintF("Warning: profiling data overrode manual branch hint.\n");
5141cb0ef41Sopenharmony_ci    }
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci    if (branch == component_entry_) {
5171cb0ef41Sopenharmony_ci      TraceConnect(branch, component_start_, successor_blocks[0]);
5181cb0ef41Sopenharmony_ci      TraceConnect(branch, component_start_, successor_blocks[1]);
5191cb0ef41Sopenharmony_ci      schedule_->InsertBranch(component_start_, component_end_, branch,
5201cb0ef41Sopenharmony_ci                              successor_blocks[0], successor_blocks[1]);
5211cb0ef41Sopenharmony_ci    } else {
5221cb0ef41Sopenharmony_ci      Node* branch_control = NodeProperties::GetControlInput(branch);
5231cb0ef41Sopenharmony_ci      BasicBlock* branch_block = FindPredecessorBlock(branch_control);
5241cb0ef41Sopenharmony_ci      TraceConnect(branch, branch_block, successor_blocks[0]);
5251cb0ef41Sopenharmony_ci      TraceConnect(branch, branch_block, successor_blocks[1]);
5261cb0ef41Sopenharmony_ci      schedule_->AddBranch(branch_block, branch, successor_blocks[0],
5271cb0ef41Sopenharmony_ci                           successor_blocks[1]);
5281cb0ef41Sopenharmony_ci    }
5291cb0ef41Sopenharmony_ci  }
5301cb0ef41Sopenharmony_ci
5311cb0ef41Sopenharmony_ci  void ConnectSwitch(Node* sw) {
5321cb0ef41Sopenharmony_ci    size_t const successor_count = sw->op()->ControlOutputCount();
5331cb0ef41Sopenharmony_ci    BasicBlock** successor_blocks =
5341cb0ef41Sopenharmony_ci        zone_->NewArray<BasicBlock*>(successor_count);
5351cb0ef41Sopenharmony_ci    CollectSuccessorBlocks(sw, successor_blocks, successor_count);
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_ci    if (sw == component_entry_) {
5381cb0ef41Sopenharmony_ci      for (size_t index = 0; index < successor_count; ++index) {
5391cb0ef41Sopenharmony_ci        TraceConnect(sw, component_start_, successor_blocks[index]);
5401cb0ef41Sopenharmony_ci      }
5411cb0ef41Sopenharmony_ci      schedule_->InsertSwitch(component_start_, component_end_, sw,
5421cb0ef41Sopenharmony_ci                              successor_blocks, successor_count);
5431cb0ef41Sopenharmony_ci    } else {
5441cb0ef41Sopenharmony_ci      Node* switch_control = NodeProperties::GetControlInput(sw);
5451cb0ef41Sopenharmony_ci      BasicBlock* switch_block = FindPredecessorBlock(switch_control);
5461cb0ef41Sopenharmony_ci      for (size_t index = 0; index < successor_count; ++index) {
5471cb0ef41Sopenharmony_ci        TraceConnect(sw, switch_block, successor_blocks[index]);
5481cb0ef41Sopenharmony_ci      }
5491cb0ef41Sopenharmony_ci      schedule_->AddSwitch(switch_block, sw, successor_blocks, successor_count);
5501cb0ef41Sopenharmony_ci    }
5511cb0ef41Sopenharmony_ci    for (size_t index = 0; index < successor_count; ++index) {
5521cb0ef41Sopenharmony_ci      if (BranchHintOf(successor_blocks[index]->front()->op()) ==
5531cb0ef41Sopenharmony_ci          BranchHint::kFalse) {
5541cb0ef41Sopenharmony_ci        successor_blocks[index]->set_deferred(true);
5551cb0ef41Sopenharmony_ci      }
5561cb0ef41Sopenharmony_ci    }
5571cb0ef41Sopenharmony_ci  }
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_ci  void ConnectMerge(Node* merge) {
5601cb0ef41Sopenharmony_ci    // Don't connect the special merge at the end to its predecessors.
5611cb0ef41Sopenharmony_ci    if (IsFinalMerge(merge)) return;
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci    BasicBlock* block = schedule_->block(merge);
5641cb0ef41Sopenharmony_ci    DCHECK_NOT_NULL(block);
5651cb0ef41Sopenharmony_ci    // For all of the merge's control inputs, add a goto at the end to the
5661cb0ef41Sopenharmony_ci    // merge's basic block.
5671cb0ef41Sopenharmony_ci    for (Node* const input : merge->inputs()) {
5681cb0ef41Sopenharmony_ci      BasicBlock* predecessor_block = FindPredecessorBlock(input);
5691cb0ef41Sopenharmony_ci      TraceConnect(merge, predecessor_block, block);
5701cb0ef41Sopenharmony_ci      schedule_->AddGoto(predecessor_block, block);
5711cb0ef41Sopenharmony_ci    }
5721cb0ef41Sopenharmony_ci  }
5731cb0ef41Sopenharmony_ci
5741cb0ef41Sopenharmony_ci  void ConnectTailCall(Node* call) {
5751cb0ef41Sopenharmony_ci    Node* call_control = NodeProperties::GetControlInput(call);
5761cb0ef41Sopenharmony_ci    BasicBlock* call_block = FindPredecessorBlock(call_control);
5771cb0ef41Sopenharmony_ci    TraceConnect(call, call_block, nullptr);
5781cb0ef41Sopenharmony_ci    schedule_->AddTailCall(call_block, call);
5791cb0ef41Sopenharmony_ci  }
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_ci  void ConnectReturn(Node* ret) {
5821cb0ef41Sopenharmony_ci    Node* return_control = NodeProperties::GetControlInput(ret);
5831cb0ef41Sopenharmony_ci    BasicBlock* return_block = FindPredecessorBlock(return_control);
5841cb0ef41Sopenharmony_ci    TraceConnect(ret, return_block, nullptr);
5851cb0ef41Sopenharmony_ci    schedule_->AddReturn(return_block, ret);
5861cb0ef41Sopenharmony_ci  }
5871cb0ef41Sopenharmony_ci
5881cb0ef41Sopenharmony_ci  void ConnectDeoptimize(Node* deopt) {
5891cb0ef41Sopenharmony_ci    Node* deoptimize_control = NodeProperties::GetControlInput(deopt);
5901cb0ef41Sopenharmony_ci    BasicBlock* deoptimize_block = FindPredecessorBlock(deoptimize_control);
5911cb0ef41Sopenharmony_ci    TraceConnect(deopt, deoptimize_block, nullptr);
5921cb0ef41Sopenharmony_ci    schedule_->AddDeoptimize(deoptimize_block, deopt);
5931cb0ef41Sopenharmony_ci  }
5941cb0ef41Sopenharmony_ci
5951cb0ef41Sopenharmony_ci  void ConnectThrow(Node* thr) {
5961cb0ef41Sopenharmony_ci    Node* throw_control = NodeProperties::GetControlInput(thr);
5971cb0ef41Sopenharmony_ci    BasicBlock* throw_block = FindPredecessorBlock(throw_control);
5981cb0ef41Sopenharmony_ci    TraceConnect(thr, throw_block, nullptr);
5991cb0ef41Sopenharmony_ci    schedule_->AddThrow(throw_block, thr);
6001cb0ef41Sopenharmony_ci  }
6011cb0ef41Sopenharmony_ci
6021cb0ef41Sopenharmony_ci  void TraceConnect(Node* node, BasicBlock* block, BasicBlock* succ) {
6031cb0ef41Sopenharmony_ci    DCHECK_NOT_NULL(block);
6041cb0ef41Sopenharmony_ci    if (succ == nullptr) {
6051cb0ef41Sopenharmony_ci      TRACE("Connect #%d:%s, id:%d -> end\n", node->id(),
6061cb0ef41Sopenharmony_ci            node->op()->mnemonic(), block->id().ToInt());
6071cb0ef41Sopenharmony_ci    } else {
6081cb0ef41Sopenharmony_ci      TRACE("Connect #%d:%s, id:%d -> id:%d\n", node->id(),
6091cb0ef41Sopenharmony_ci            node->op()->mnemonic(), block->id().ToInt(), succ->id().ToInt());
6101cb0ef41Sopenharmony_ci    }
6111cb0ef41Sopenharmony_ci  }
6121cb0ef41Sopenharmony_ci
6131cb0ef41Sopenharmony_ci  bool IsFinalMerge(Node* node) {
6141cb0ef41Sopenharmony_ci    return (node->opcode() == IrOpcode::kMerge &&
6151cb0ef41Sopenharmony_ci            node == scheduler_->graph_->end()->InputAt(0));
6161cb0ef41Sopenharmony_ci  }
6171cb0ef41Sopenharmony_ci
6181cb0ef41Sopenharmony_ci  bool IsSingleEntrySingleExitRegion(Node* entry, Node* exit) const {
6191cb0ef41Sopenharmony_ci    size_t entry_class = scheduler_->equivalence_->ClassOf(entry);
6201cb0ef41Sopenharmony_ci    size_t exit_class = scheduler_->equivalence_->ClassOf(exit);
6211cb0ef41Sopenharmony_ci    return entry != exit && entry_class == exit_class;
6221cb0ef41Sopenharmony_ci  }
6231cb0ef41Sopenharmony_ci
6241cb0ef41Sopenharmony_ci  void ResetDataStructures() {
6251cb0ef41Sopenharmony_ci    control_.clear();
6261cb0ef41Sopenharmony_ci    DCHECK(queue_.empty());
6271cb0ef41Sopenharmony_ci    DCHECK(control_.empty());
6281cb0ef41Sopenharmony_ci  }
6291cb0ef41Sopenharmony_ci
6301cb0ef41Sopenharmony_ci  Zone* zone_;
6311cb0ef41Sopenharmony_ci  Scheduler* scheduler_;
6321cb0ef41Sopenharmony_ci  Schedule* schedule_;
6331cb0ef41Sopenharmony_ci  NodeMarker<bool> queued_;      // Mark indicating whether node is queued.
6341cb0ef41Sopenharmony_ci  ZoneQueue<Node*> queue_;       // Queue used for breadth-first traversal.
6351cb0ef41Sopenharmony_ci  NodeVector control_;           // List of encountered control nodes.
6361cb0ef41Sopenharmony_ci  Node* component_entry_;        // Component single-entry node.
6371cb0ef41Sopenharmony_ci  BasicBlock* component_start_;  // Component single-entry block.
6381cb0ef41Sopenharmony_ci  BasicBlock* component_end_;    // Component single-exit block.
6391cb0ef41Sopenharmony_ci};
6401cb0ef41Sopenharmony_ci
6411cb0ef41Sopenharmony_ci
6421cb0ef41Sopenharmony_civoid Scheduler::BuildCFG() {
6431cb0ef41Sopenharmony_ci  TRACE("--- CREATING CFG -------------------------------------------\n");
6441cb0ef41Sopenharmony_ci
6451cb0ef41Sopenharmony_ci  // Instantiate a new control equivalence algorithm for the graph.
6461cb0ef41Sopenharmony_ci  equivalence_ = zone_->New<ControlEquivalence>(zone_, graph_);
6471cb0ef41Sopenharmony_ci
6481cb0ef41Sopenharmony_ci  // Build a control-flow graph for the main control-connected component that
6491cb0ef41Sopenharmony_ci  // is being spanned by the graph's start and end nodes.
6501cb0ef41Sopenharmony_ci  control_flow_builder_ = zone_->New<CFGBuilder>(zone_, this);
6511cb0ef41Sopenharmony_ci  control_flow_builder_->Run();
6521cb0ef41Sopenharmony_ci
6531cb0ef41Sopenharmony_ci  // Initialize per-block data.
6541cb0ef41Sopenharmony_ci  // Reserve an extra 10% to avoid resizing vector when fusing floating control.
6551cb0ef41Sopenharmony_ci  scheduled_nodes_.reserve(schedule_->BasicBlockCount() * 1.1);
6561cb0ef41Sopenharmony_ci  scheduled_nodes_.resize(schedule_->BasicBlockCount());
6571cb0ef41Sopenharmony_ci}
6581cb0ef41Sopenharmony_ci
6591cb0ef41Sopenharmony_ci
6601cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
6611cb0ef41Sopenharmony_ci// Phase 2: Compute special RPO and dominator tree.
6621cb0ef41Sopenharmony_ci
6631cb0ef41Sopenharmony_ci
6641cb0ef41Sopenharmony_ci// Compute the special reverse-post-order block ordering, which is essentially
6651cb0ef41Sopenharmony_ci// a RPO of the graph where loop bodies are contiguous. Properties:
6661cb0ef41Sopenharmony_ci// 1. If block A is a predecessor of B, then A appears before B in the order,
6671cb0ef41Sopenharmony_ci//    unless B is a loop header and A is in the loop headed at B
6681cb0ef41Sopenharmony_ci//    (i.e. A -> B is a backedge).
6691cb0ef41Sopenharmony_ci// => If block A dominates block B, then A appears before B in the order.
6701cb0ef41Sopenharmony_ci// => If block A is a loop header, A appears before all blocks in the loop
6711cb0ef41Sopenharmony_ci//    headed at A.
6721cb0ef41Sopenharmony_ci// 2. All loops are contiguous in the order (i.e. no intervening blocks that
6731cb0ef41Sopenharmony_ci//    do not belong to the loop.)
6741cb0ef41Sopenharmony_ci// Note a simple RPO traversal satisfies (1) but not (2).
6751cb0ef41Sopenharmony_ciclass SpecialRPONumberer : public ZoneObject {
6761cb0ef41Sopenharmony_ci public:
6771cb0ef41Sopenharmony_ci  SpecialRPONumberer(Zone* zone, Schedule* schedule)
6781cb0ef41Sopenharmony_ci      : zone_(zone),
6791cb0ef41Sopenharmony_ci        schedule_(schedule),
6801cb0ef41Sopenharmony_ci        order_(nullptr),
6811cb0ef41Sopenharmony_ci        beyond_end_(nullptr),
6821cb0ef41Sopenharmony_ci        loops_(zone),
6831cb0ef41Sopenharmony_ci        backedges_(zone),
6841cb0ef41Sopenharmony_ci        stack_(zone),
6851cb0ef41Sopenharmony_ci        previous_block_count_(0),
6861cb0ef41Sopenharmony_ci        empty_(0, zone) {}
6871cb0ef41Sopenharmony_ci
6881cb0ef41Sopenharmony_ci  // Computes the special reverse-post-order for the main control flow graph,
6891cb0ef41Sopenharmony_ci  // that is for the graph spanned between the schedule's start and end blocks.
6901cb0ef41Sopenharmony_ci  void ComputeSpecialRPO() {
6911cb0ef41Sopenharmony_ci    DCHECK_EQ(0, schedule_->end()->SuccessorCount());
6921cb0ef41Sopenharmony_ci    DCHECK(!order_);  // Main order does not exist yet.
6931cb0ef41Sopenharmony_ci    ComputeAndInsertSpecialRPO(schedule_->start(), schedule_->end());
6941cb0ef41Sopenharmony_ci  }
6951cb0ef41Sopenharmony_ci
6961cb0ef41Sopenharmony_ci  // Computes the special reverse-post-order for a partial control flow graph,
6971cb0ef41Sopenharmony_ci  // that is for the graph spanned between the given {entry} and {end} blocks,
6981cb0ef41Sopenharmony_ci  // then updates the existing ordering with this new information.
6991cb0ef41Sopenharmony_ci  void UpdateSpecialRPO(BasicBlock* entry, BasicBlock* end) {
7001cb0ef41Sopenharmony_ci    DCHECK(order_);  // Main order to be updated is present.
7011cb0ef41Sopenharmony_ci    ComputeAndInsertSpecialRPO(entry, end);
7021cb0ef41Sopenharmony_ci  }
7031cb0ef41Sopenharmony_ci
7041cb0ef41Sopenharmony_ci  // Serialize the previously computed order as a special reverse-post-order
7051cb0ef41Sopenharmony_ci  // numbering for basic blocks into the final schedule.
7061cb0ef41Sopenharmony_ci  void SerializeRPOIntoSchedule() {
7071cb0ef41Sopenharmony_ci    int32_t number = 0;
7081cb0ef41Sopenharmony_ci    for (BasicBlock* b = order_; b != nullptr; b = b->rpo_next()) {
7091cb0ef41Sopenharmony_ci      b->set_rpo_number(number++);
7101cb0ef41Sopenharmony_ci      schedule_->rpo_order()->push_back(b);
7111cb0ef41Sopenharmony_ci    }
7121cb0ef41Sopenharmony_ci    BeyondEndSentinel()->set_rpo_number(number);
7131cb0ef41Sopenharmony_ci  }
7141cb0ef41Sopenharmony_ci
7151cb0ef41Sopenharmony_ci  // Print and verify the special reverse-post-order.
7161cb0ef41Sopenharmony_ci  void PrintAndVerifySpecialRPO() {
7171cb0ef41Sopenharmony_ci#if DEBUG
7181cb0ef41Sopenharmony_ci    if (FLAG_trace_turbo_scheduler) PrintRPO();
7191cb0ef41Sopenharmony_ci    VerifySpecialRPO();
7201cb0ef41Sopenharmony_ci#endif
7211cb0ef41Sopenharmony_ci  }
7221cb0ef41Sopenharmony_ci
7231cb0ef41Sopenharmony_ci  const ZoneVector<BasicBlock*>& GetOutgoingBlocks(BasicBlock* block) {
7241cb0ef41Sopenharmony_ci    if (HasLoopNumber(block)) {
7251cb0ef41Sopenharmony_ci      LoopInfo const& loop = loops_[GetLoopNumber(block)];
7261cb0ef41Sopenharmony_ci      if (loop.outgoing) return *loop.outgoing;
7271cb0ef41Sopenharmony_ci    }
7281cb0ef41Sopenharmony_ci    return empty_;
7291cb0ef41Sopenharmony_ci  }
7301cb0ef41Sopenharmony_ci
7311cb0ef41Sopenharmony_ci  bool HasLoopBlocks() const { return loops_.size() != 0; }
7321cb0ef41Sopenharmony_ci
7331cb0ef41Sopenharmony_ci private:
7341cb0ef41Sopenharmony_ci  using Backedge = std::pair<BasicBlock*, size_t>;
7351cb0ef41Sopenharmony_ci
7361cb0ef41Sopenharmony_ci  // Numbering for BasicBlock::rpo_number for this block traversal:
7371cb0ef41Sopenharmony_ci  static const int kBlockOnStack = -2;
7381cb0ef41Sopenharmony_ci  static const int kBlockVisited1 = -3;
7391cb0ef41Sopenharmony_ci  static const int kBlockVisited2 = -4;
7401cb0ef41Sopenharmony_ci  static const int kBlockUnvisited1 = -1;
7411cb0ef41Sopenharmony_ci  static const int kBlockUnvisited2 = kBlockVisited1;
7421cb0ef41Sopenharmony_ci
7431cb0ef41Sopenharmony_ci  struct SpecialRPOStackFrame {
7441cb0ef41Sopenharmony_ci    BasicBlock* block;
7451cb0ef41Sopenharmony_ci    size_t index;
7461cb0ef41Sopenharmony_ci  };
7471cb0ef41Sopenharmony_ci
7481cb0ef41Sopenharmony_ci  struct LoopInfo {
7491cb0ef41Sopenharmony_ci    BasicBlock* header;
7501cb0ef41Sopenharmony_ci    ZoneVector<BasicBlock*>* outgoing;
7511cb0ef41Sopenharmony_ci    BitVector* members;
7521cb0ef41Sopenharmony_ci    LoopInfo* prev;
7531cb0ef41Sopenharmony_ci    BasicBlock* end;
7541cb0ef41Sopenharmony_ci    BasicBlock* start;
7551cb0ef41Sopenharmony_ci
7561cb0ef41Sopenharmony_ci    void AddOutgoing(Zone* zone, BasicBlock* block) {
7571cb0ef41Sopenharmony_ci      if (outgoing == nullptr) {
7581cb0ef41Sopenharmony_ci        outgoing = zone->New<ZoneVector<BasicBlock*>>(zone);
7591cb0ef41Sopenharmony_ci      }
7601cb0ef41Sopenharmony_ci      outgoing->push_back(block);
7611cb0ef41Sopenharmony_ci    }
7621cb0ef41Sopenharmony_ci  };
7631cb0ef41Sopenharmony_ci
7641cb0ef41Sopenharmony_ci  int Push(int depth, BasicBlock* child, int unvisited) {
7651cb0ef41Sopenharmony_ci    if (child->rpo_number() == unvisited) {
7661cb0ef41Sopenharmony_ci      stack_[depth].block = child;
7671cb0ef41Sopenharmony_ci      stack_[depth].index = 0;
7681cb0ef41Sopenharmony_ci      child->set_rpo_number(kBlockOnStack);
7691cb0ef41Sopenharmony_ci      return depth + 1;
7701cb0ef41Sopenharmony_ci    }
7711cb0ef41Sopenharmony_ci    return depth;
7721cb0ef41Sopenharmony_ci  }
7731cb0ef41Sopenharmony_ci
7741cb0ef41Sopenharmony_ci  BasicBlock* PushFront(BasicBlock* head, BasicBlock* block) {
7751cb0ef41Sopenharmony_ci    block->set_rpo_next(head);
7761cb0ef41Sopenharmony_ci    return block;
7771cb0ef41Sopenharmony_ci  }
7781cb0ef41Sopenharmony_ci
7791cb0ef41Sopenharmony_ci  static int GetLoopNumber(BasicBlock* block) { return block->loop_number(); }
7801cb0ef41Sopenharmony_ci  static void SetLoopNumber(BasicBlock* block, int loop_number) {
7811cb0ef41Sopenharmony_ci    return block->set_loop_number(loop_number);
7821cb0ef41Sopenharmony_ci  }
7831cb0ef41Sopenharmony_ci  static bool HasLoopNumber(BasicBlock* block) {
7841cb0ef41Sopenharmony_ci    return block->loop_number() >= 0;
7851cb0ef41Sopenharmony_ci  }
7861cb0ef41Sopenharmony_ci
7871cb0ef41Sopenharmony_ci  // We only need this special sentinel because some tests use the schedule's
7881cb0ef41Sopenharmony_ci  // end block in actual control flow (e.g. with end having successors).
7891cb0ef41Sopenharmony_ci  BasicBlock* BeyondEndSentinel() {
7901cb0ef41Sopenharmony_ci    if (beyond_end_ == nullptr) {
7911cb0ef41Sopenharmony_ci      BasicBlock::Id id = BasicBlock::Id::FromInt(-1);
7921cb0ef41Sopenharmony_ci      beyond_end_ = schedule_->zone()->New<BasicBlock>(schedule_->zone(), id);
7931cb0ef41Sopenharmony_ci    }
7941cb0ef41Sopenharmony_ci    return beyond_end_;
7951cb0ef41Sopenharmony_ci  }
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_ci  // Compute special RPO for the control flow graph between {entry} and {end},
7981cb0ef41Sopenharmony_ci  // mutating any existing order so that the result is still valid.
7991cb0ef41Sopenharmony_ci  void ComputeAndInsertSpecialRPO(BasicBlock* entry, BasicBlock* end) {
8001cb0ef41Sopenharmony_ci    // RPO should not have been serialized for this schedule yet.
8011cb0ef41Sopenharmony_ci    CHECK_EQ(kBlockUnvisited1, schedule_->start()->loop_number());
8021cb0ef41Sopenharmony_ci    CHECK_EQ(kBlockUnvisited1, schedule_->start()->rpo_number());
8031cb0ef41Sopenharmony_ci    CHECK_EQ(0, static_cast<int>(schedule_->rpo_order()->size()));
8041cb0ef41Sopenharmony_ci
8051cb0ef41Sopenharmony_ci    // Find correct insertion point within existing order.
8061cb0ef41Sopenharmony_ci    BasicBlock* insertion_point = entry->rpo_next();
8071cb0ef41Sopenharmony_ci    BasicBlock* order = insertion_point;
8081cb0ef41Sopenharmony_ci
8091cb0ef41Sopenharmony_ci    // Perform an iterative RPO traversal using an explicit stack,
8101cb0ef41Sopenharmony_ci    // recording backedges that form cycles. O(|B|).
8111cb0ef41Sopenharmony_ci    DCHECK_LT(previous_block_count_, schedule_->BasicBlockCount());
8121cb0ef41Sopenharmony_ci    stack_.resize(schedule_->BasicBlockCount() - previous_block_count_);
8131cb0ef41Sopenharmony_ci    previous_block_count_ = schedule_->BasicBlockCount();
8141cb0ef41Sopenharmony_ci    int stack_depth = Push(0, entry, kBlockUnvisited1);
8151cb0ef41Sopenharmony_ci    int num_loops = static_cast<int>(loops_.size());
8161cb0ef41Sopenharmony_ci
8171cb0ef41Sopenharmony_ci    while (stack_depth > 0) {
8181cb0ef41Sopenharmony_ci      int current = stack_depth - 1;
8191cb0ef41Sopenharmony_ci      SpecialRPOStackFrame* frame = &stack_[current];
8201cb0ef41Sopenharmony_ci
8211cb0ef41Sopenharmony_ci      if (frame->block != end &&
8221cb0ef41Sopenharmony_ci          frame->index < frame->block->SuccessorCount()) {
8231cb0ef41Sopenharmony_ci        // Process the next successor.
8241cb0ef41Sopenharmony_ci        BasicBlock* succ = frame->block->SuccessorAt(frame->index++);
8251cb0ef41Sopenharmony_ci        if (succ->rpo_number() == kBlockVisited1) continue;
8261cb0ef41Sopenharmony_ci        if (succ->rpo_number() == kBlockOnStack) {
8271cb0ef41Sopenharmony_ci          // The successor is on the stack, so this is a backedge (cycle).
8281cb0ef41Sopenharmony_ci          backedges_.push_back(Backedge(frame->block, frame->index - 1));
8291cb0ef41Sopenharmony_ci          if (!HasLoopNumber(succ)) {
8301cb0ef41Sopenharmony_ci            // Assign a new loop number to the header if it doesn't have one.
8311cb0ef41Sopenharmony_ci            SetLoopNumber(succ, num_loops++);
8321cb0ef41Sopenharmony_ci          }
8331cb0ef41Sopenharmony_ci        } else {
8341cb0ef41Sopenharmony_ci          // Push the successor onto the stack.
8351cb0ef41Sopenharmony_ci          DCHECK_EQ(kBlockUnvisited1, succ->rpo_number());
8361cb0ef41Sopenharmony_ci          stack_depth = Push(stack_depth, succ, kBlockUnvisited1);
8371cb0ef41Sopenharmony_ci        }
8381cb0ef41Sopenharmony_ci      } else {
8391cb0ef41Sopenharmony_ci        // Finished with all successors; pop the stack and add the block.
8401cb0ef41Sopenharmony_ci        order = PushFront(order, frame->block);
8411cb0ef41Sopenharmony_ci        frame->block->set_rpo_number(kBlockVisited1);
8421cb0ef41Sopenharmony_ci        stack_depth--;
8431cb0ef41Sopenharmony_ci      }
8441cb0ef41Sopenharmony_ci    }
8451cb0ef41Sopenharmony_ci
8461cb0ef41Sopenharmony_ci    // If no loops were encountered, then the order we computed was correct.
8471cb0ef41Sopenharmony_ci    if (num_loops > static_cast<int>(loops_.size())) {
8481cb0ef41Sopenharmony_ci      // Otherwise, compute the loop information from the backedges in order
8491cb0ef41Sopenharmony_ci      // to perform a traversal that groups loop bodies together.
8501cb0ef41Sopenharmony_ci      ComputeLoopInfo(&stack_, num_loops, &backedges_);
8511cb0ef41Sopenharmony_ci
8521cb0ef41Sopenharmony_ci      // Initialize the "loop stack". Note the entry could be a loop header.
8531cb0ef41Sopenharmony_ci      LoopInfo* loop =
8541cb0ef41Sopenharmony_ci          HasLoopNumber(entry) ? &loops_[GetLoopNumber(entry)] : nullptr;
8551cb0ef41Sopenharmony_ci      order = insertion_point;
8561cb0ef41Sopenharmony_ci
8571cb0ef41Sopenharmony_ci      // Perform an iterative post-order traversal, visiting loop bodies before
8581cb0ef41Sopenharmony_ci      // edges that lead out of loops. Visits each block once, but linking loop
8591cb0ef41Sopenharmony_ci      // sections together is linear in the loop size, so overall is
8601cb0ef41Sopenharmony_ci      // O(|B| + max(loop_depth) * max(|loop|))
8611cb0ef41Sopenharmony_ci      stack_depth = Push(0, entry, kBlockUnvisited2);
8621cb0ef41Sopenharmony_ci      while (stack_depth > 0) {
8631cb0ef41Sopenharmony_ci        SpecialRPOStackFrame* frame = &stack_[stack_depth - 1];
8641cb0ef41Sopenharmony_ci        BasicBlock* block = frame->block;
8651cb0ef41Sopenharmony_ci        BasicBlock* succ = nullptr;
8661cb0ef41Sopenharmony_ci
8671cb0ef41Sopenharmony_ci        if (block != end && frame->index < block->SuccessorCount()) {
8681cb0ef41Sopenharmony_ci          // Process the next normal successor.
8691cb0ef41Sopenharmony_ci          succ = block->SuccessorAt(frame->index++);
8701cb0ef41Sopenharmony_ci        } else if (HasLoopNumber(block)) {
8711cb0ef41Sopenharmony_ci          // Process additional outgoing edges from the loop header.
8721cb0ef41Sopenharmony_ci          if (block->rpo_number() == kBlockOnStack) {
8731cb0ef41Sopenharmony_ci            // Finish the loop body the first time the header is left on the
8741cb0ef41Sopenharmony_ci            // stack.
8751cb0ef41Sopenharmony_ci            DCHECK(loop != nullptr && loop->header == block);
8761cb0ef41Sopenharmony_ci            loop->start = PushFront(order, block);
8771cb0ef41Sopenharmony_ci            order = loop->end;
8781cb0ef41Sopenharmony_ci            block->set_rpo_number(kBlockVisited2);
8791cb0ef41Sopenharmony_ci            // Pop the loop stack and continue visiting outgoing edges within
8801cb0ef41Sopenharmony_ci            // the context of the outer loop, if any.
8811cb0ef41Sopenharmony_ci            loop = loop->prev;
8821cb0ef41Sopenharmony_ci            // We leave the loop header on the stack; the rest of this iteration
8831cb0ef41Sopenharmony_ci            // and later iterations will go through its outgoing edges list.
8841cb0ef41Sopenharmony_ci          }
8851cb0ef41Sopenharmony_ci
8861cb0ef41Sopenharmony_ci          // Use the next outgoing edge if there are any.
8871cb0ef41Sopenharmony_ci          size_t outgoing_index = frame->index - block->SuccessorCount();
8881cb0ef41Sopenharmony_ci          LoopInfo* info = &loops_[GetLoopNumber(block)];
8891cb0ef41Sopenharmony_ci          DCHECK(loop != info);
8901cb0ef41Sopenharmony_ci          if (block != entry && info->outgoing != nullptr &&
8911cb0ef41Sopenharmony_ci              outgoing_index < info->outgoing->size()) {
8921cb0ef41Sopenharmony_ci            succ = info->outgoing->at(outgoing_index);
8931cb0ef41Sopenharmony_ci            frame->index++;
8941cb0ef41Sopenharmony_ci          }
8951cb0ef41Sopenharmony_ci        }
8961cb0ef41Sopenharmony_ci
8971cb0ef41Sopenharmony_ci        if (succ != nullptr) {
8981cb0ef41Sopenharmony_ci          // Process the next successor.
8991cb0ef41Sopenharmony_ci          if (succ->rpo_number() == kBlockOnStack) continue;
9001cb0ef41Sopenharmony_ci          if (succ->rpo_number() == kBlockVisited2) continue;
9011cb0ef41Sopenharmony_ci          DCHECK_EQ(kBlockUnvisited2, succ->rpo_number());
9021cb0ef41Sopenharmony_ci          if (loop != nullptr && !loop->members->Contains(succ->id().ToInt())) {
9031cb0ef41Sopenharmony_ci            // The successor is not in the current loop or any nested loop.
9041cb0ef41Sopenharmony_ci            // Add it to the outgoing edges of this loop and visit it later.
9051cb0ef41Sopenharmony_ci            loop->AddOutgoing(zone_, succ);
9061cb0ef41Sopenharmony_ci          } else {
9071cb0ef41Sopenharmony_ci            // Push the successor onto the stack.
9081cb0ef41Sopenharmony_ci            stack_depth = Push(stack_depth, succ, kBlockUnvisited2);
9091cb0ef41Sopenharmony_ci            if (HasLoopNumber(succ)) {
9101cb0ef41Sopenharmony_ci              // Push the inner loop onto the loop stack.
9111cb0ef41Sopenharmony_ci              DCHECK(GetLoopNumber(succ) < num_loops);
9121cb0ef41Sopenharmony_ci              LoopInfo* next = &loops_[GetLoopNumber(succ)];
9131cb0ef41Sopenharmony_ci              next->end = order;
9141cb0ef41Sopenharmony_ci              next->prev = loop;
9151cb0ef41Sopenharmony_ci              loop = next;
9161cb0ef41Sopenharmony_ci            }
9171cb0ef41Sopenharmony_ci          }
9181cb0ef41Sopenharmony_ci        } else {
9191cb0ef41Sopenharmony_ci          // Finished with all successors of the current block.
9201cb0ef41Sopenharmony_ci          if (HasLoopNumber(block)) {
9211cb0ef41Sopenharmony_ci            // If we are going to pop a loop header, then add its entire body.
9221cb0ef41Sopenharmony_ci            LoopInfo* info = &loops_[GetLoopNumber(block)];
9231cb0ef41Sopenharmony_ci            for (BasicBlock* b = info->start; true; b = b->rpo_next()) {
9241cb0ef41Sopenharmony_ci              if (b->rpo_next() == info->end) {
9251cb0ef41Sopenharmony_ci                b->set_rpo_next(order);
9261cb0ef41Sopenharmony_ci                info->end = order;
9271cb0ef41Sopenharmony_ci                break;
9281cb0ef41Sopenharmony_ci              }
9291cb0ef41Sopenharmony_ci            }
9301cb0ef41Sopenharmony_ci            order = info->start;
9311cb0ef41Sopenharmony_ci          } else {
9321cb0ef41Sopenharmony_ci            // Pop a single node off the stack and add it to the order.
9331cb0ef41Sopenharmony_ci            order = PushFront(order, block);
9341cb0ef41Sopenharmony_ci            block->set_rpo_number(kBlockVisited2);
9351cb0ef41Sopenharmony_ci          }
9361cb0ef41Sopenharmony_ci          stack_depth--;
9371cb0ef41Sopenharmony_ci        }
9381cb0ef41Sopenharmony_ci      }
9391cb0ef41Sopenharmony_ci    }
9401cb0ef41Sopenharmony_ci
9411cb0ef41Sopenharmony_ci    // Publish new order the first time.
9421cb0ef41Sopenharmony_ci    if (order_ == nullptr) order_ = order;
9431cb0ef41Sopenharmony_ci
9441cb0ef41Sopenharmony_ci    // Compute the correct loop headers and set the correct loop ends.
9451cb0ef41Sopenharmony_ci    LoopInfo* current_loop = nullptr;
9461cb0ef41Sopenharmony_ci    BasicBlock* current_header = entry->loop_header();
9471cb0ef41Sopenharmony_ci    int32_t loop_depth = entry->loop_depth();
9481cb0ef41Sopenharmony_ci    if (entry->IsLoopHeader()) --loop_depth;  // Entry might be a loop header.
9491cb0ef41Sopenharmony_ci    for (BasicBlock* b = order; b != insertion_point; b = b->rpo_next()) {
9501cb0ef41Sopenharmony_ci      BasicBlock* current = b;
9511cb0ef41Sopenharmony_ci
9521cb0ef41Sopenharmony_ci      // Reset BasicBlock::rpo_number again.
9531cb0ef41Sopenharmony_ci      current->set_rpo_number(kBlockUnvisited1);
9541cb0ef41Sopenharmony_ci
9551cb0ef41Sopenharmony_ci      // Finish the previous loop(s) if we just exited them.
9561cb0ef41Sopenharmony_ci      while (current_header != nullptr &&
9571cb0ef41Sopenharmony_ci             current == current_header->loop_end()) {
9581cb0ef41Sopenharmony_ci        DCHECK(current_header->IsLoopHeader());
9591cb0ef41Sopenharmony_ci        DCHECK_NOT_NULL(current_loop);
9601cb0ef41Sopenharmony_ci        current_loop = current_loop->prev;
9611cb0ef41Sopenharmony_ci        current_header =
9621cb0ef41Sopenharmony_ci            current_loop == nullptr ? nullptr : current_loop->header;
9631cb0ef41Sopenharmony_ci        --loop_depth;
9641cb0ef41Sopenharmony_ci      }
9651cb0ef41Sopenharmony_ci      current->set_loop_header(current_header);
9661cb0ef41Sopenharmony_ci
9671cb0ef41Sopenharmony_ci      // Push a new loop onto the stack if this loop is a loop header.
9681cb0ef41Sopenharmony_ci      if (HasLoopNumber(current)) {
9691cb0ef41Sopenharmony_ci        ++loop_depth;
9701cb0ef41Sopenharmony_ci        current_loop = &loops_[GetLoopNumber(current)];
9711cb0ef41Sopenharmony_ci        BasicBlock* loop_end = current_loop->end;
9721cb0ef41Sopenharmony_ci        current->set_loop_end(loop_end == nullptr ? BeyondEndSentinel()
9731cb0ef41Sopenharmony_ci                                                  : loop_end);
9741cb0ef41Sopenharmony_ci        current_header = current_loop->header;
9751cb0ef41Sopenharmony_ci        TRACE("id:%d is a loop header, increment loop depth to %d\n",
9761cb0ef41Sopenharmony_ci              current->id().ToInt(), loop_depth);
9771cb0ef41Sopenharmony_ci      }
9781cb0ef41Sopenharmony_ci
9791cb0ef41Sopenharmony_ci      current->set_loop_depth(loop_depth);
9801cb0ef41Sopenharmony_ci
9811cb0ef41Sopenharmony_ci      if (current->loop_header() == nullptr) {
9821cb0ef41Sopenharmony_ci        TRACE("id:%d is not in a loop (depth == %d)\n", current->id().ToInt(),
9831cb0ef41Sopenharmony_ci              current->loop_depth());
9841cb0ef41Sopenharmony_ci      } else {
9851cb0ef41Sopenharmony_ci        TRACE("id:%d has loop header id:%d, (depth == %d)\n",
9861cb0ef41Sopenharmony_ci              current->id().ToInt(), current->loop_header()->id().ToInt(),
9871cb0ef41Sopenharmony_ci              current->loop_depth());
9881cb0ef41Sopenharmony_ci      }
9891cb0ef41Sopenharmony_ci    }
9901cb0ef41Sopenharmony_ci  }
9911cb0ef41Sopenharmony_ci
9921cb0ef41Sopenharmony_ci  // Computes loop membership from the backedges of the control flow graph.
9931cb0ef41Sopenharmony_ci  void ComputeLoopInfo(ZoneVector<SpecialRPOStackFrame>* queue,
9941cb0ef41Sopenharmony_ci                       size_t num_loops, ZoneVector<Backedge>* backedges) {
9951cb0ef41Sopenharmony_ci    // Extend existing loop membership vectors.
9961cb0ef41Sopenharmony_ci    for (LoopInfo& loop : loops_) {
9971cb0ef41Sopenharmony_ci      loop.members->Resize(static_cast<int>(schedule_->BasicBlockCount()),
9981cb0ef41Sopenharmony_ci                           zone_);
9991cb0ef41Sopenharmony_ci    }
10001cb0ef41Sopenharmony_ci
10011cb0ef41Sopenharmony_ci    // Extend loop information vector.
10021cb0ef41Sopenharmony_ci    loops_.resize(num_loops, LoopInfo());
10031cb0ef41Sopenharmony_ci
10041cb0ef41Sopenharmony_ci    // Compute loop membership starting from backedges.
10051cb0ef41Sopenharmony_ci    // O(max(loop_depth) * max(|loop|)
10061cb0ef41Sopenharmony_ci    for (size_t i = 0; i < backedges->size(); i++) {
10071cb0ef41Sopenharmony_ci      BasicBlock* member = backedges->at(i).first;
10081cb0ef41Sopenharmony_ci      BasicBlock* header = member->SuccessorAt(backedges->at(i).second);
10091cb0ef41Sopenharmony_ci      size_t loop_num = GetLoopNumber(header);
10101cb0ef41Sopenharmony_ci      if (loops_[loop_num].header == nullptr) {
10111cb0ef41Sopenharmony_ci        loops_[loop_num].header = header;
10121cb0ef41Sopenharmony_ci        loops_[loop_num].members = zone_->New<BitVector>(
10131cb0ef41Sopenharmony_ci            static_cast<int>(schedule_->BasicBlockCount()), zone_);
10141cb0ef41Sopenharmony_ci      }
10151cb0ef41Sopenharmony_ci
10161cb0ef41Sopenharmony_ci      int queue_length = 0;
10171cb0ef41Sopenharmony_ci      if (member != header) {
10181cb0ef41Sopenharmony_ci        // As long as the header doesn't have a backedge to itself,
10191cb0ef41Sopenharmony_ci        // Push the member onto the queue and process its predecessors.
10201cb0ef41Sopenharmony_ci        if (!loops_[loop_num].members->Contains(member->id().ToInt())) {
10211cb0ef41Sopenharmony_ci          loops_[loop_num].members->Add(member->id().ToInt());
10221cb0ef41Sopenharmony_ci        }
10231cb0ef41Sopenharmony_ci        (*queue)[queue_length++].block = member;
10241cb0ef41Sopenharmony_ci      }
10251cb0ef41Sopenharmony_ci
10261cb0ef41Sopenharmony_ci      // Propagate loop membership backwards. All predecessors of M up to the
10271cb0ef41Sopenharmony_ci      // loop header H are members of the loop too. O(|blocks between M and H|).
10281cb0ef41Sopenharmony_ci      while (queue_length > 0) {
10291cb0ef41Sopenharmony_ci        BasicBlock* block = (*queue)[--queue_length].block;
10301cb0ef41Sopenharmony_ci        for (size_t j = 0; j < block->PredecessorCount(); j++) {
10311cb0ef41Sopenharmony_ci          BasicBlock* pred = block->PredecessorAt(j);
10321cb0ef41Sopenharmony_ci          if (pred != header) {
10331cb0ef41Sopenharmony_ci            if (!loops_[loop_num].members->Contains(pred->id().ToInt())) {
10341cb0ef41Sopenharmony_ci              loops_[loop_num].members->Add(pred->id().ToInt());
10351cb0ef41Sopenharmony_ci              (*queue)[queue_length++].block = pred;
10361cb0ef41Sopenharmony_ci            }
10371cb0ef41Sopenharmony_ci          }
10381cb0ef41Sopenharmony_ci        }
10391cb0ef41Sopenharmony_ci      }
10401cb0ef41Sopenharmony_ci    }
10411cb0ef41Sopenharmony_ci  }
10421cb0ef41Sopenharmony_ci
10431cb0ef41Sopenharmony_ci#if DEBUG
10441cb0ef41Sopenharmony_ci  void PrintRPO() {
10451cb0ef41Sopenharmony_ci    StdoutStream os;
10461cb0ef41Sopenharmony_ci    os << "RPO with " << loops_.size() << " loops";
10471cb0ef41Sopenharmony_ci    if (loops_.size() > 0) {
10481cb0ef41Sopenharmony_ci      os << " (";
10491cb0ef41Sopenharmony_ci      for (size_t i = 0; i < loops_.size(); i++) {
10501cb0ef41Sopenharmony_ci        if (i > 0) os << " ";
10511cb0ef41Sopenharmony_ci        os << "id:" << loops_[i].header->id();
10521cb0ef41Sopenharmony_ci      }
10531cb0ef41Sopenharmony_ci      os << ")";
10541cb0ef41Sopenharmony_ci    }
10551cb0ef41Sopenharmony_ci    os << ":\n";
10561cb0ef41Sopenharmony_ci
10571cb0ef41Sopenharmony_ci    for (BasicBlock* block = order_; block != nullptr;
10581cb0ef41Sopenharmony_ci         block = block->rpo_next()) {
10591cb0ef41Sopenharmony_ci      os << std::setw(5) << "B" << block->rpo_number() << ":";
10601cb0ef41Sopenharmony_ci      for (size_t i = 0; i < loops_.size(); i++) {
10611cb0ef41Sopenharmony_ci        bool range = loops_[i].header->LoopContains(block);
10621cb0ef41Sopenharmony_ci        bool membership = loops_[i].header != block && range;
10631cb0ef41Sopenharmony_ci        os << (membership ? " |" : "  ");
10641cb0ef41Sopenharmony_ci        os << (range ? "x" : " ");
10651cb0ef41Sopenharmony_ci      }
10661cb0ef41Sopenharmony_ci      os << "  id:" << block->id() << ": ";
10671cb0ef41Sopenharmony_ci      if (block->loop_end() != nullptr) {
10681cb0ef41Sopenharmony_ci        os << " range: [B" << block->rpo_number() << ", B"
10691cb0ef41Sopenharmony_ci           << block->loop_end()->rpo_number() << ")";
10701cb0ef41Sopenharmony_ci      }
10711cb0ef41Sopenharmony_ci      if (block->loop_header() != nullptr) {
10721cb0ef41Sopenharmony_ci        os << " header: id:" << block->loop_header()->id();
10731cb0ef41Sopenharmony_ci      }
10741cb0ef41Sopenharmony_ci      if (block->loop_depth() > 0) {
10751cb0ef41Sopenharmony_ci        os << " depth: " << block->loop_depth();
10761cb0ef41Sopenharmony_ci      }
10771cb0ef41Sopenharmony_ci      os << "\n";
10781cb0ef41Sopenharmony_ci    }
10791cb0ef41Sopenharmony_ci  }
10801cb0ef41Sopenharmony_ci
10811cb0ef41Sopenharmony_ci  void VerifySpecialRPO() {
10821cb0ef41Sopenharmony_ci    BasicBlockVector* order = schedule_->rpo_order();
10831cb0ef41Sopenharmony_ci    DCHECK_LT(0, order->size());
10841cb0ef41Sopenharmony_ci    DCHECK_EQ(0, (*order)[0]->id().ToInt());  // entry should be first.
10851cb0ef41Sopenharmony_ci
10861cb0ef41Sopenharmony_ci    for (size_t i = 0; i < loops_.size(); i++) {
10871cb0ef41Sopenharmony_ci      LoopInfo* loop = &loops_[i];
10881cb0ef41Sopenharmony_ci      BasicBlock* header = loop->header;
10891cb0ef41Sopenharmony_ci      BasicBlock* end = header->loop_end();
10901cb0ef41Sopenharmony_ci
10911cb0ef41Sopenharmony_ci      DCHECK_NOT_NULL(header);
10921cb0ef41Sopenharmony_ci      DCHECK_LE(0, header->rpo_number());
10931cb0ef41Sopenharmony_ci      DCHECK_LT(header->rpo_number(), order->size());
10941cb0ef41Sopenharmony_ci      DCHECK_NOT_NULL(end);
10951cb0ef41Sopenharmony_ci      DCHECK_LE(end->rpo_number(), order->size());
10961cb0ef41Sopenharmony_ci      DCHECK_GT(end->rpo_number(), header->rpo_number());
10971cb0ef41Sopenharmony_ci      DCHECK_NE(header->loop_header(), header);
10981cb0ef41Sopenharmony_ci
10991cb0ef41Sopenharmony_ci      // Verify the start ... end list relationship.
11001cb0ef41Sopenharmony_ci      int links = 0;
11011cb0ef41Sopenharmony_ci      BasicBlock* block = loop->start;
11021cb0ef41Sopenharmony_ci      DCHECK_EQ(header, block);
11031cb0ef41Sopenharmony_ci      bool end_found;
11041cb0ef41Sopenharmony_ci      while (true) {
11051cb0ef41Sopenharmony_ci        if (block == nullptr || block == loop->end) {
11061cb0ef41Sopenharmony_ci          end_found = (loop->end == block);
11071cb0ef41Sopenharmony_ci          break;
11081cb0ef41Sopenharmony_ci        }
11091cb0ef41Sopenharmony_ci        // The list should be in same order as the final result.
11101cb0ef41Sopenharmony_ci        DCHECK(block->rpo_number() == links + header->rpo_number());
11111cb0ef41Sopenharmony_ci        links++;
11121cb0ef41Sopenharmony_ci        block = block->rpo_next();
11131cb0ef41Sopenharmony_ci        DCHECK_LT(links, static_cast<int>(2 * order->size()));  // cycle?
11141cb0ef41Sopenharmony_ci      }
11151cb0ef41Sopenharmony_ci      DCHECK_LT(0, links);
11161cb0ef41Sopenharmony_ci      DCHECK_EQ(links, end->rpo_number() - header->rpo_number());
11171cb0ef41Sopenharmony_ci      DCHECK(end_found);
11181cb0ef41Sopenharmony_ci
11191cb0ef41Sopenharmony_ci      // Check loop depth of the header.
11201cb0ef41Sopenharmony_ci      int loop_depth = 0;
11211cb0ef41Sopenharmony_ci      for (LoopInfo* outer = loop; outer != nullptr; outer = outer->prev) {
11221cb0ef41Sopenharmony_ci        loop_depth++;
11231cb0ef41Sopenharmony_ci      }
11241cb0ef41Sopenharmony_ci      DCHECK_EQ(loop_depth, header->loop_depth());
11251cb0ef41Sopenharmony_ci
11261cb0ef41Sopenharmony_ci      // Check the contiguousness of loops.
11271cb0ef41Sopenharmony_ci      int count = 0;
11281cb0ef41Sopenharmony_ci      for (int j = 0; j < static_cast<int>(order->size()); j++) {
11291cb0ef41Sopenharmony_ci        block = order->at(j);
11301cb0ef41Sopenharmony_ci        DCHECK_EQ(block->rpo_number(), j);
11311cb0ef41Sopenharmony_ci        if (j < header->rpo_number() || j >= end->rpo_number()) {
11321cb0ef41Sopenharmony_ci          DCHECK(!header->LoopContains(block));
11331cb0ef41Sopenharmony_ci        } else {
11341cb0ef41Sopenharmony_ci          DCHECK(header->LoopContains(block));
11351cb0ef41Sopenharmony_ci          DCHECK_GE(block->loop_depth(), loop_depth);
11361cb0ef41Sopenharmony_ci          count++;
11371cb0ef41Sopenharmony_ci        }
11381cb0ef41Sopenharmony_ci      }
11391cb0ef41Sopenharmony_ci      DCHECK_EQ(links, count);
11401cb0ef41Sopenharmony_ci    }
11411cb0ef41Sopenharmony_ci  }
11421cb0ef41Sopenharmony_ci#endif  // DEBUG
11431cb0ef41Sopenharmony_ci
11441cb0ef41Sopenharmony_ci  Zone* zone_;
11451cb0ef41Sopenharmony_ci  Schedule* schedule_;
11461cb0ef41Sopenharmony_ci  BasicBlock* order_;
11471cb0ef41Sopenharmony_ci  BasicBlock* beyond_end_;
11481cb0ef41Sopenharmony_ci  ZoneVector<LoopInfo> loops_;
11491cb0ef41Sopenharmony_ci  ZoneVector<Backedge> backedges_;
11501cb0ef41Sopenharmony_ci  ZoneVector<SpecialRPOStackFrame> stack_;
11511cb0ef41Sopenharmony_ci  size_t previous_block_count_;
11521cb0ef41Sopenharmony_ci  ZoneVector<BasicBlock*> const empty_;
11531cb0ef41Sopenharmony_ci};
11541cb0ef41Sopenharmony_ci
11551cb0ef41Sopenharmony_ci
11561cb0ef41Sopenharmony_ciBasicBlockVector* Scheduler::ComputeSpecialRPO(Zone* zone, Schedule* schedule) {
11571cb0ef41Sopenharmony_ci  SpecialRPONumberer numberer(zone, schedule);
11581cb0ef41Sopenharmony_ci  numberer.ComputeSpecialRPO();
11591cb0ef41Sopenharmony_ci  numberer.SerializeRPOIntoSchedule();
11601cb0ef41Sopenharmony_ci  numberer.PrintAndVerifySpecialRPO();
11611cb0ef41Sopenharmony_ci  return schedule->rpo_order();
11621cb0ef41Sopenharmony_ci}
11631cb0ef41Sopenharmony_ci
11641cb0ef41Sopenharmony_ci
11651cb0ef41Sopenharmony_civoid Scheduler::ComputeSpecialRPONumbering() {
11661cb0ef41Sopenharmony_ci  TRACE("--- COMPUTING SPECIAL RPO ----------------------------------\n");
11671cb0ef41Sopenharmony_ci
11681cb0ef41Sopenharmony_ci  // Compute the special reverse-post-order for basic blocks.
11691cb0ef41Sopenharmony_ci  special_rpo_ = zone_->New<SpecialRPONumberer>(zone_, schedule_);
11701cb0ef41Sopenharmony_ci  special_rpo_->ComputeSpecialRPO();
11711cb0ef41Sopenharmony_ci}
11721cb0ef41Sopenharmony_ci
11731cb0ef41Sopenharmony_ciBasicBlock* Scheduler::GetCommonDominatorIfCached(BasicBlock* b1,
11741cb0ef41Sopenharmony_ci                                                  BasicBlock* b2) {
11751cb0ef41Sopenharmony_ci  auto entry1 = common_dominator_cache_.find(b1->id().ToInt());
11761cb0ef41Sopenharmony_ci  if (entry1 == common_dominator_cache_.end()) return nullptr;
11771cb0ef41Sopenharmony_ci  auto entry2 = entry1->second->find(b2->id().ToInt());
11781cb0ef41Sopenharmony_ci  if (entry2 == entry1->second->end()) return nullptr;
11791cb0ef41Sopenharmony_ci  return entry2->second;
11801cb0ef41Sopenharmony_ci}
11811cb0ef41Sopenharmony_ci
11821cb0ef41Sopenharmony_ciBasicBlock* Scheduler::GetCommonDominator(BasicBlock* b1, BasicBlock* b2) {
11831cb0ef41Sopenharmony_ci  // A very common fast case:
11841cb0ef41Sopenharmony_ci  if (b1 == b2) return b1;
11851cb0ef41Sopenharmony_ci  // Try to find the common dominator by walking, if there is a chance of
11861cb0ef41Sopenharmony_ci  // finding it quickly.
11871cb0ef41Sopenharmony_ci  constexpr int kCacheGranularity = 63;
11881cb0ef41Sopenharmony_ci  STATIC_ASSERT((kCacheGranularity & (kCacheGranularity + 1)) == 0);
11891cb0ef41Sopenharmony_ci  int depth_difference = b1->dominator_depth() - b2->dominator_depth();
11901cb0ef41Sopenharmony_ci  if (depth_difference > -kCacheGranularity &&
11911cb0ef41Sopenharmony_ci      depth_difference < kCacheGranularity) {
11921cb0ef41Sopenharmony_ci    for (int i = 0; i < kCacheGranularity; i++) {
11931cb0ef41Sopenharmony_ci      if (b1->dominator_depth() < b2->dominator_depth()) {
11941cb0ef41Sopenharmony_ci        b2 = b2->dominator();
11951cb0ef41Sopenharmony_ci      } else {
11961cb0ef41Sopenharmony_ci        b1 = b1->dominator();
11971cb0ef41Sopenharmony_ci      }
11981cb0ef41Sopenharmony_ci      if (b1 == b2) return b1;
11991cb0ef41Sopenharmony_ci    }
12001cb0ef41Sopenharmony_ci    // We might fall out of the loop here if the dominator tree has several
12011cb0ef41Sopenharmony_ci    // deep "parallel" subtrees.
12021cb0ef41Sopenharmony_ci  }
12031cb0ef41Sopenharmony_ci  // If it'd be a long walk, take the bus instead (i.e. use the cache).
12041cb0ef41Sopenharmony_ci  // To keep memory consumption low, there'll be a bus stop every 64 blocks.
12051cb0ef41Sopenharmony_ci  // First, walk to the nearest bus stop.
12061cb0ef41Sopenharmony_ci  if (b1->dominator_depth() < b2->dominator_depth()) std::swap(b1, b2);
12071cb0ef41Sopenharmony_ci  while ((b1->dominator_depth() & kCacheGranularity) != 0) {
12081cb0ef41Sopenharmony_ci    if (V8_LIKELY(b1->dominator_depth() > b2->dominator_depth())) {
12091cb0ef41Sopenharmony_ci      b1 = b1->dominator();
12101cb0ef41Sopenharmony_ci    } else {
12111cb0ef41Sopenharmony_ci      b2 = b2->dominator();
12121cb0ef41Sopenharmony_ci    }
12131cb0ef41Sopenharmony_ci    if (b1 == b2) return b1;
12141cb0ef41Sopenharmony_ci  }
12151cb0ef41Sopenharmony_ci  // Then, walk from bus stop to bus stop until we either find a bus (i.e. an
12161cb0ef41Sopenharmony_ci  // existing cache entry) or the result. Make a list of any empty bus stops
12171cb0ef41Sopenharmony_ci  // we'd like to populate for next time.
12181cb0ef41Sopenharmony_ci  constexpr int kMaxNewCacheEntries = 2 * 50;  // Must be even.
12191cb0ef41Sopenharmony_ci  // This array stores a flattened list of pairs, e.g. if after finding the
12201cb0ef41Sopenharmony_ci  // {result}, we want to cache [(B11, B12) -> result, (B21, B22) -> result],
12211cb0ef41Sopenharmony_ci  // then we store [11, 12, 21, 22] here.
12221cb0ef41Sopenharmony_ci  int new_cache_entries[kMaxNewCacheEntries];
12231cb0ef41Sopenharmony_ci  // Next free slot in {new_cache_entries}.
12241cb0ef41Sopenharmony_ci  int new_cache_entries_cursor = 0;
12251cb0ef41Sopenharmony_ci  while (b1 != b2) {
12261cb0ef41Sopenharmony_ci    if ((b1->dominator_depth() & kCacheGranularity) == 0) {
12271cb0ef41Sopenharmony_ci      BasicBlock* maybe_cache_hit = GetCommonDominatorIfCached(b1, b2);
12281cb0ef41Sopenharmony_ci      if (maybe_cache_hit != nullptr) {
12291cb0ef41Sopenharmony_ci        b1 = b2 = maybe_cache_hit;
12301cb0ef41Sopenharmony_ci        break;
12311cb0ef41Sopenharmony_ci      } else if (new_cache_entries_cursor < kMaxNewCacheEntries) {
12321cb0ef41Sopenharmony_ci        new_cache_entries[new_cache_entries_cursor++] = b1->id().ToInt();
12331cb0ef41Sopenharmony_ci        new_cache_entries[new_cache_entries_cursor++] = b2->id().ToInt();
12341cb0ef41Sopenharmony_ci      }
12351cb0ef41Sopenharmony_ci    }
12361cb0ef41Sopenharmony_ci    if (V8_LIKELY(b1->dominator_depth() > b2->dominator_depth())) {
12371cb0ef41Sopenharmony_ci      b1 = b1->dominator();
12381cb0ef41Sopenharmony_ci    } else {
12391cb0ef41Sopenharmony_ci      b2 = b2->dominator();
12401cb0ef41Sopenharmony_ci    }
12411cb0ef41Sopenharmony_ci  }
12421cb0ef41Sopenharmony_ci  // Lastly, create new cache entries we noted down earlier.
12431cb0ef41Sopenharmony_ci  BasicBlock* result = b1;
12441cb0ef41Sopenharmony_ci  for (int i = 0; i < new_cache_entries_cursor;) {
12451cb0ef41Sopenharmony_ci    int id1 = new_cache_entries[i++];
12461cb0ef41Sopenharmony_ci    int id2 = new_cache_entries[i++];
12471cb0ef41Sopenharmony_ci    ZoneMap<int, BasicBlock*>* mapping;
12481cb0ef41Sopenharmony_ci    auto entry = common_dominator_cache_.find(id1);
12491cb0ef41Sopenharmony_ci    if (entry == common_dominator_cache_.end()) {
12501cb0ef41Sopenharmony_ci      mapping = zone_->New<ZoneMap<int, BasicBlock*>>(zone_);
12511cb0ef41Sopenharmony_ci      common_dominator_cache_[id1] = mapping;
12521cb0ef41Sopenharmony_ci    } else {
12531cb0ef41Sopenharmony_ci      mapping = entry->second;
12541cb0ef41Sopenharmony_ci    }
12551cb0ef41Sopenharmony_ci    // If there was an existing entry, we would have found it earlier.
12561cb0ef41Sopenharmony_ci    DCHECK_EQ(mapping->find(id2), mapping->end());
12571cb0ef41Sopenharmony_ci    mapping->insert({id2, result});
12581cb0ef41Sopenharmony_ci  }
12591cb0ef41Sopenharmony_ci  return result;
12601cb0ef41Sopenharmony_ci}
12611cb0ef41Sopenharmony_ci
12621cb0ef41Sopenharmony_civoid Scheduler::PropagateImmediateDominators(BasicBlock* block) {
12631cb0ef41Sopenharmony_ci  for (/*nop*/; block != nullptr; block = block->rpo_next()) {
12641cb0ef41Sopenharmony_ci    auto pred = block->predecessors().begin();
12651cb0ef41Sopenharmony_ci    auto end = block->predecessors().end();
12661cb0ef41Sopenharmony_ci    DCHECK(pred != end);  // All blocks except start have predecessors.
12671cb0ef41Sopenharmony_ci    BasicBlock* dominator = *pred;
12681cb0ef41Sopenharmony_ci    bool deferred = dominator->deferred();
12691cb0ef41Sopenharmony_ci    // For multiple predecessors, walk up the dominator tree until a common
12701cb0ef41Sopenharmony_ci    // dominator is found. Visitation order guarantees that all predecessors
12711cb0ef41Sopenharmony_ci    // except for backwards edges have been visited.
12721cb0ef41Sopenharmony_ci    // We use a one-element cache for previously-seen dominators. This gets
12731cb0ef41Sopenharmony_ci    // hit a lot for functions that have long chains of diamonds, and in
12741cb0ef41Sopenharmony_ci    // those cases turns quadratic into linear complexity.
12751cb0ef41Sopenharmony_ci    BasicBlock* cache = nullptr;
12761cb0ef41Sopenharmony_ci    for (++pred; pred != end; ++pred) {
12771cb0ef41Sopenharmony_ci      // Don't examine backwards edges.
12781cb0ef41Sopenharmony_ci      if ((*pred)->dominator_depth() < 0) continue;
12791cb0ef41Sopenharmony_ci      if ((*pred)->dominator_depth() > 3 &&
12801cb0ef41Sopenharmony_ci          ((*pred)->dominator()->dominator() == cache ||
12811cb0ef41Sopenharmony_ci           (*pred)->dominator()->dominator()->dominator() == cache)) {
12821cb0ef41Sopenharmony_ci        // Nothing to do, the last iteration covered this case.
12831cb0ef41Sopenharmony_ci        DCHECK_EQ(dominator, BasicBlock::GetCommonDominator(dominator, *pred));
12841cb0ef41Sopenharmony_ci      } else {
12851cb0ef41Sopenharmony_ci        dominator = BasicBlock::GetCommonDominator(dominator, *pred);
12861cb0ef41Sopenharmony_ci      }
12871cb0ef41Sopenharmony_ci      cache = (*pred)->dominator();
12881cb0ef41Sopenharmony_ci      deferred = deferred & (*pred)->deferred();
12891cb0ef41Sopenharmony_ci    }
12901cb0ef41Sopenharmony_ci    block->set_dominator(dominator);
12911cb0ef41Sopenharmony_ci    block->set_dominator_depth(dominator->dominator_depth() + 1);
12921cb0ef41Sopenharmony_ci    block->set_deferred(deferred | block->deferred());
12931cb0ef41Sopenharmony_ci    TRACE("Block id:%d's idom is id:%d, depth = %d\n", block->id().ToInt(),
12941cb0ef41Sopenharmony_ci          dominator->id().ToInt(), block->dominator_depth());
12951cb0ef41Sopenharmony_ci  }
12961cb0ef41Sopenharmony_ci}
12971cb0ef41Sopenharmony_ci
12981cb0ef41Sopenharmony_civoid Scheduler::GenerateDominatorTree(Schedule* schedule) {
12991cb0ef41Sopenharmony_ci  // Seed start block to be the first dominator.
13001cb0ef41Sopenharmony_ci  schedule->start()->set_dominator_depth(0);
13011cb0ef41Sopenharmony_ci
13021cb0ef41Sopenharmony_ci  // Build the block dominator tree resulting from the above seed.
13031cb0ef41Sopenharmony_ci  PropagateImmediateDominators(schedule->start()->rpo_next());
13041cb0ef41Sopenharmony_ci}
13051cb0ef41Sopenharmony_ci
13061cb0ef41Sopenharmony_civoid Scheduler::GenerateDominatorTree() {
13071cb0ef41Sopenharmony_ci  TRACE("--- IMMEDIATE BLOCK DOMINATORS -----------------------------\n");
13081cb0ef41Sopenharmony_ci  GenerateDominatorTree(schedule_);
13091cb0ef41Sopenharmony_ci}
13101cb0ef41Sopenharmony_ci
13111cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
13121cb0ef41Sopenharmony_ci// Phase 3: Prepare use counts for nodes.
13131cb0ef41Sopenharmony_ci
13141cb0ef41Sopenharmony_ci
13151cb0ef41Sopenharmony_ciclass PrepareUsesVisitor {
13161cb0ef41Sopenharmony_ci public:
13171cb0ef41Sopenharmony_ci  explicit PrepareUsesVisitor(Scheduler* scheduler, Graph* graph, Zone* zone)
13181cb0ef41Sopenharmony_ci      : scheduler_(scheduler),
13191cb0ef41Sopenharmony_ci        schedule_(scheduler->schedule_),
13201cb0ef41Sopenharmony_ci        graph_(graph),
13211cb0ef41Sopenharmony_ci        visited_(graph_->NodeCount(), false, zone),
13221cb0ef41Sopenharmony_ci        stack_(zone) {}
13231cb0ef41Sopenharmony_ci
13241cb0ef41Sopenharmony_ci  void Run() {
13251cb0ef41Sopenharmony_ci    InitializePlacement(graph_->end());
13261cb0ef41Sopenharmony_ci    while (!stack_.empty()) {
13271cb0ef41Sopenharmony_ci      Node* node = stack_.top();
13281cb0ef41Sopenharmony_ci      stack_.pop();
13291cb0ef41Sopenharmony_ci      VisitInputs(node);
13301cb0ef41Sopenharmony_ci    }
13311cb0ef41Sopenharmony_ci  }
13321cb0ef41Sopenharmony_ci
13331cb0ef41Sopenharmony_ci private:
13341cb0ef41Sopenharmony_ci  void InitializePlacement(Node* node) {
13351cb0ef41Sopenharmony_ci    TRACE("Pre #%d:%s\n", node->id(), node->op()->mnemonic());
13361cb0ef41Sopenharmony_ci    DCHECK(!Visited(node));
13371cb0ef41Sopenharmony_ci    if (scheduler_->InitializePlacement(node) == Scheduler::kFixed) {
13381cb0ef41Sopenharmony_ci      // Fixed nodes are always roots for schedule late.
13391cb0ef41Sopenharmony_ci      scheduler_->schedule_root_nodes_.push_back(node);
13401cb0ef41Sopenharmony_ci      if (!schedule_->IsScheduled(node)) {
13411cb0ef41Sopenharmony_ci        // Make sure root nodes are scheduled in their respective blocks.
13421cb0ef41Sopenharmony_ci        TRACE("Scheduling fixed position node #%d:%s\n", node->id(),
13431cb0ef41Sopenharmony_ci              node->op()->mnemonic());
13441cb0ef41Sopenharmony_ci        IrOpcode::Value opcode = node->opcode();
13451cb0ef41Sopenharmony_ci        BasicBlock* block =
13461cb0ef41Sopenharmony_ci            opcode == IrOpcode::kParameter
13471cb0ef41Sopenharmony_ci                ? schedule_->start()
13481cb0ef41Sopenharmony_ci                : schedule_->block(NodeProperties::GetControlInput(node));
13491cb0ef41Sopenharmony_ci        DCHECK_NOT_NULL(block);
13501cb0ef41Sopenharmony_ci        schedule_->AddNode(block, node);
13511cb0ef41Sopenharmony_ci      }
13521cb0ef41Sopenharmony_ci    }
13531cb0ef41Sopenharmony_ci    stack_.push(node);
13541cb0ef41Sopenharmony_ci    visited_[node->id()] = true;
13551cb0ef41Sopenharmony_ci  }
13561cb0ef41Sopenharmony_ci
13571cb0ef41Sopenharmony_ci  void VisitInputs(Node* node) {
13581cb0ef41Sopenharmony_ci    DCHECK_NE(scheduler_->GetPlacement(node), Scheduler::kUnknown);
13591cb0ef41Sopenharmony_ci    bool is_scheduled = schedule_->IsScheduled(node);
13601cb0ef41Sopenharmony_ci    base::Optional<int> coupled_control_edge =
13611cb0ef41Sopenharmony_ci        scheduler_->GetCoupledControlEdge(node);
13621cb0ef41Sopenharmony_ci    for (auto edge : node->input_edges()) {
13631cb0ef41Sopenharmony_ci      Node* to = edge.to();
13641cb0ef41Sopenharmony_ci      DCHECK_EQ(node, edge.from());
13651cb0ef41Sopenharmony_ci      if (!Visited(to)) {
13661cb0ef41Sopenharmony_ci        InitializePlacement(to);
13671cb0ef41Sopenharmony_ci      }
13681cb0ef41Sopenharmony_ci      TRACE("PostEdge #%d:%s->#%d:%s\n", node->id(), node->op()->mnemonic(),
13691cb0ef41Sopenharmony_ci            to->id(), to->op()->mnemonic());
13701cb0ef41Sopenharmony_ci      DCHECK_NE(scheduler_->GetPlacement(to), Scheduler::kUnknown);
13711cb0ef41Sopenharmony_ci      if (!is_scheduled && edge.index() != coupled_control_edge) {
13721cb0ef41Sopenharmony_ci        scheduler_->IncrementUnscheduledUseCount(to, node);
13731cb0ef41Sopenharmony_ci      }
13741cb0ef41Sopenharmony_ci    }
13751cb0ef41Sopenharmony_ci  }
13761cb0ef41Sopenharmony_ci
13771cb0ef41Sopenharmony_ci  bool Visited(Node* node) { return visited_[node->id()]; }
13781cb0ef41Sopenharmony_ci
13791cb0ef41Sopenharmony_ci  Scheduler* scheduler_;
13801cb0ef41Sopenharmony_ci  Schedule* schedule_;
13811cb0ef41Sopenharmony_ci  Graph* graph_;
13821cb0ef41Sopenharmony_ci  BoolVector visited_;
13831cb0ef41Sopenharmony_ci  ZoneStack<Node*> stack_;
13841cb0ef41Sopenharmony_ci};
13851cb0ef41Sopenharmony_ci
13861cb0ef41Sopenharmony_ci
13871cb0ef41Sopenharmony_civoid Scheduler::PrepareUses() {
13881cb0ef41Sopenharmony_ci  TRACE("--- PREPARE USES -------------------------------------------\n");
13891cb0ef41Sopenharmony_ci
13901cb0ef41Sopenharmony_ci  // Count the uses of every node, which is used to ensure that all of a
13911cb0ef41Sopenharmony_ci  // node's uses are scheduled before the node itself.
13921cb0ef41Sopenharmony_ci  PrepareUsesVisitor prepare_uses(this, graph_, zone_);
13931cb0ef41Sopenharmony_ci  prepare_uses.Run();
13941cb0ef41Sopenharmony_ci}
13951cb0ef41Sopenharmony_ci
13961cb0ef41Sopenharmony_ci
13971cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
13981cb0ef41Sopenharmony_ci// Phase 4: Schedule nodes early.
13991cb0ef41Sopenharmony_ci
14001cb0ef41Sopenharmony_ci
14011cb0ef41Sopenharmony_ciclass ScheduleEarlyNodeVisitor {
14021cb0ef41Sopenharmony_ci public:
14031cb0ef41Sopenharmony_ci  ScheduleEarlyNodeVisitor(Zone* zone, Scheduler* scheduler)
14041cb0ef41Sopenharmony_ci      : scheduler_(scheduler), schedule_(scheduler->schedule_), queue_(zone) {}
14051cb0ef41Sopenharmony_ci
14061cb0ef41Sopenharmony_ci  // Run the schedule early algorithm on a set of fixed root nodes.
14071cb0ef41Sopenharmony_ci  void Run(NodeVector* roots) {
14081cb0ef41Sopenharmony_ci    for (Node* const root : *roots) {
14091cb0ef41Sopenharmony_ci      queue_.push(root);
14101cb0ef41Sopenharmony_ci    }
14111cb0ef41Sopenharmony_ci
14121cb0ef41Sopenharmony_ci    while (!queue_.empty()) {
14131cb0ef41Sopenharmony_ci      scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
14141cb0ef41Sopenharmony_ci      VisitNode(queue_.front());
14151cb0ef41Sopenharmony_ci      queue_.pop();
14161cb0ef41Sopenharmony_ci    }
14171cb0ef41Sopenharmony_ci  }
14181cb0ef41Sopenharmony_ci
14191cb0ef41Sopenharmony_ci private:
14201cb0ef41Sopenharmony_ci  // Visits one node from the queue and propagates its current schedule early
14211cb0ef41Sopenharmony_ci  // position to all uses. This in turn might push more nodes onto the queue.
14221cb0ef41Sopenharmony_ci  void VisitNode(Node* node) {
14231cb0ef41Sopenharmony_ci    Scheduler::SchedulerData* data = scheduler_->GetData(node);
14241cb0ef41Sopenharmony_ci
14251cb0ef41Sopenharmony_ci    // Fixed nodes already know their schedule early position.
14261cb0ef41Sopenharmony_ci    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) {
14271cb0ef41Sopenharmony_ci      data->minimum_block_ = schedule_->block(node);
14281cb0ef41Sopenharmony_ci      TRACE("Fixing #%d:%s minimum_block = id:%d, dominator_depth = %d\n",
14291cb0ef41Sopenharmony_ci            node->id(), node->op()->mnemonic(),
14301cb0ef41Sopenharmony_ci            data->minimum_block_->id().ToInt(),
14311cb0ef41Sopenharmony_ci            data->minimum_block_->dominator_depth());
14321cb0ef41Sopenharmony_ci    }
14331cb0ef41Sopenharmony_ci
14341cb0ef41Sopenharmony_ci    // No need to propagate unconstrained schedule early positions.
14351cb0ef41Sopenharmony_ci    if (data->minimum_block_ == schedule_->start()) return;
14361cb0ef41Sopenharmony_ci
14371cb0ef41Sopenharmony_ci    // Propagate schedule early position.
14381cb0ef41Sopenharmony_ci    DCHECK_NOT_NULL(data->minimum_block_);
14391cb0ef41Sopenharmony_ci    for (auto use : node->uses()) {
14401cb0ef41Sopenharmony_ci      if (scheduler_->IsLive(use)) {
14411cb0ef41Sopenharmony_ci        PropagateMinimumPositionToNode(data->minimum_block_, use);
14421cb0ef41Sopenharmony_ci      }
14431cb0ef41Sopenharmony_ci    }
14441cb0ef41Sopenharmony_ci  }
14451cb0ef41Sopenharmony_ci
14461cb0ef41Sopenharmony_ci  // Propagates {block} as another minimum position into the given {node}. This
14471cb0ef41Sopenharmony_ci  // has the net effect of computing the minimum dominator block of {node} that
14481cb0ef41Sopenharmony_ci  // still post-dominates all inputs to {node} when the queue is processed.
14491cb0ef41Sopenharmony_ci  void PropagateMinimumPositionToNode(BasicBlock* block, Node* node) {
14501cb0ef41Sopenharmony_ci    Scheduler::SchedulerData* data = scheduler_->GetData(node);
14511cb0ef41Sopenharmony_ci
14521cb0ef41Sopenharmony_ci    // No need to propagate to fixed node, it's guaranteed to be a root.
14531cb0ef41Sopenharmony_ci    if (scheduler_->GetPlacement(node) == Scheduler::kFixed) return;
14541cb0ef41Sopenharmony_ci
14551cb0ef41Sopenharmony_ci    // Coupled nodes influence schedule early position of their control.
14561cb0ef41Sopenharmony_ci    if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
14571cb0ef41Sopenharmony_ci      Node* control = NodeProperties::GetControlInput(node);
14581cb0ef41Sopenharmony_ci      PropagateMinimumPositionToNode(block, control);
14591cb0ef41Sopenharmony_ci    }
14601cb0ef41Sopenharmony_ci
14611cb0ef41Sopenharmony_ci    // Propagate new position if it is deeper down the dominator tree than the
14621cb0ef41Sopenharmony_ci    // current. Note that all inputs need to have minimum block position inside
14631cb0ef41Sopenharmony_ci    // the dominator chain of {node}'s minimum block position.
14641cb0ef41Sopenharmony_ci    DCHECK(InsideSameDominatorChain(block, data->minimum_block_));
14651cb0ef41Sopenharmony_ci    if (block->dominator_depth() > data->minimum_block_->dominator_depth()) {
14661cb0ef41Sopenharmony_ci      data->minimum_block_ = block;
14671cb0ef41Sopenharmony_ci      queue_.push(node);
14681cb0ef41Sopenharmony_ci      TRACE("Propagating #%d:%s minimum_block = id:%d, dominator_depth = %d\n",
14691cb0ef41Sopenharmony_ci            node->id(), node->op()->mnemonic(),
14701cb0ef41Sopenharmony_ci            data->minimum_block_->id().ToInt(),
14711cb0ef41Sopenharmony_ci            data->minimum_block_->dominator_depth());
14721cb0ef41Sopenharmony_ci    }
14731cb0ef41Sopenharmony_ci  }
14741cb0ef41Sopenharmony_ci
14751cb0ef41Sopenharmony_ci#if DEBUG
14761cb0ef41Sopenharmony_ci  bool InsideSameDominatorChain(BasicBlock* b1, BasicBlock* b2) {
14771cb0ef41Sopenharmony_ci    BasicBlock* dominator = BasicBlock::GetCommonDominator(b1, b2);
14781cb0ef41Sopenharmony_ci    return dominator == b1 || dominator == b2;
14791cb0ef41Sopenharmony_ci  }
14801cb0ef41Sopenharmony_ci#endif
14811cb0ef41Sopenharmony_ci
14821cb0ef41Sopenharmony_ci  Scheduler* scheduler_;
14831cb0ef41Sopenharmony_ci  Schedule* schedule_;
14841cb0ef41Sopenharmony_ci  ZoneQueue<Node*> queue_;
14851cb0ef41Sopenharmony_ci};
14861cb0ef41Sopenharmony_ci
14871cb0ef41Sopenharmony_ci
14881cb0ef41Sopenharmony_civoid Scheduler::ScheduleEarly() {
14891cb0ef41Sopenharmony_ci  if (!special_rpo_->HasLoopBlocks()) {
14901cb0ef41Sopenharmony_ci    TRACE("--- NO LOOPS SO SKIPPING SCHEDULE EARLY --------------------\n");
14911cb0ef41Sopenharmony_ci    return;
14921cb0ef41Sopenharmony_ci  }
14931cb0ef41Sopenharmony_ci
14941cb0ef41Sopenharmony_ci  TRACE("--- SCHEDULE EARLY -----------------------------------------\n");
14951cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
14961cb0ef41Sopenharmony_ci    TRACE("roots: ");
14971cb0ef41Sopenharmony_ci    for (Node* node : schedule_root_nodes_) {
14981cb0ef41Sopenharmony_ci      TRACE("#%d:%s ", node->id(), node->op()->mnemonic());
14991cb0ef41Sopenharmony_ci    }
15001cb0ef41Sopenharmony_ci    TRACE("\n");
15011cb0ef41Sopenharmony_ci  }
15021cb0ef41Sopenharmony_ci
15031cb0ef41Sopenharmony_ci  // Compute the minimum block for each node thereby determining the earliest
15041cb0ef41Sopenharmony_ci  // position each node could be placed within a valid schedule.
15051cb0ef41Sopenharmony_ci  ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this);
15061cb0ef41Sopenharmony_ci  schedule_early_visitor.Run(&schedule_root_nodes_);
15071cb0ef41Sopenharmony_ci}
15081cb0ef41Sopenharmony_ci
15091cb0ef41Sopenharmony_ci
15101cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
15111cb0ef41Sopenharmony_ci// Phase 5: Schedule nodes late.
15121cb0ef41Sopenharmony_ci
15131cb0ef41Sopenharmony_ci
15141cb0ef41Sopenharmony_ciclass ScheduleLateNodeVisitor {
15151cb0ef41Sopenharmony_ci public:
15161cb0ef41Sopenharmony_ci  ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler)
15171cb0ef41Sopenharmony_ci      : zone_(zone),
15181cb0ef41Sopenharmony_ci        scheduler_(scheduler),
15191cb0ef41Sopenharmony_ci        schedule_(scheduler_->schedule_),
15201cb0ef41Sopenharmony_ci        marked_(scheduler->zone_),
15211cb0ef41Sopenharmony_ci        marking_queue_(scheduler->zone_) {}
15221cb0ef41Sopenharmony_ci
15231cb0ef41Sopenharmony_ci  // Run the schedule late algorithm on a set of fixed root nodes.
15241cb0ef41Sopenharmony_ci  void Run(NodeVector* roots) {
15251cb0ef41Sopenharmony_ci    for (Node* const root : *roots) {
15261cb0ef41Sopenharmony_ci      ProcessQueue(root);
15271cb0ef41Sopenharmony_ci    }
15281cb0ef41Sopenharmony_ci  }
15291cb0ef41Sopenharmony_ci
15301cb0ef41Sopenharmony_ci private:
15311cb0ef41Sopenharmony_ci  void ProcessQueue(Node* root) {
15321cb0ef41Sopenharmony_ci    ZoneQueue<Node*>* queue = &(scheduler_->schedule_queue_);
15331cb0ef41Sopenharmony_ci    for (Node* node : root->inputs()) {
15341cb0ef41Sopenharmony_ci      // Don't schedule coupled nodes on their own.
15351cb0ef41Sopenharmony_ci      if (scheduler_->GetPlacement(node) == Scheduler::kCoupled) {
15361cb0ef41Sopenharmony_ci        node = NodeProperties::GetControlInput(node);
15371cb0ef41Sopenharmony_ci      }
15381cb0ef41Sopenharmony_ci
15391cb0ef41Sopenharmony_ci      // Test schedulability condition by looking at unscheduled use count.
15401cb0ef41Sopenharmony_ci      if (scheduler_->GetData(node)->unscheduled_count_ != 0) continue;
15411cb0ef41Sopenharmony_ci
15421cb0ef41Sopenharmony_ci      queue->push(node);
15431cb0ef41Sopenharmony_ci      do {
15441cb0ef41Sopenharmony_ci        scheduler_->tick_counter_->TickAndMaybeEnterSafepoint();
15451cb0ef41Sopenharmony_ci        Node* const n = queue->front();
15461cb0ef41Sopenharmony_ci        queue->pop();
15471cb0ef41Sopenharmony_ci        VisitNode(n);
15481cb0ef41Sopenharmony_ci      } while (!queue->empty());
15491cb0ef41Sopenharmony_ci    }
15501cb0ef41Sopenharmony_ci  }
15511cb0ef41Sopenharmony_ci
15521cb0ef41Sopenharmony_ci  // Visits one node from the queue of schedulable nodes and determines its
15531cb0ef41Sopenharmony_ci  // schedule late position. Also hoists nodes out of loops to find a more
15541cb0ef41Sopenharmony_ci  // optimal scheduling position.
15551cb0ef41Sopenharmony_ci  void VisitNode(Node* node) {
15561cb0ef41Sopenharmony_ci    DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_);
15571cb0ef41Sopenharmony_ci
15581cb0ef41Sopenharmony_ci    // Don't schedule nodes that are already scheduled.
15591cb0ef41Sopenharmony_ci    if (schedule_->IsScheduled(node)) return;
15601cb0ef41Sopenharmony_ci    DCHECK_EQ(Scheduler::kSchedulable, scheduler_->GetPlacement(node));
15611cb0ef41Sopenharmony_ci
15621cb0ef41Sopenharmony_ci    // Determine the dominating block for all of the uses of this node. It is
15631cb0ef41Sopenharmony_ci    // the latest block that this node can be scheduled in.
15641cb0ef41Sopenharmony_ci    TRACE("Scheduling #%d:%s\n", node->id(), node->op()->mnemonic());
15651cb0ef41Sopenharmony_ci    BasicBlock* block = GetCommonDominatorOfUses(node);
15661cb0ef41Sopenharmony_ci    DCHECK_NOT_NULL(block);
15671cb0ef41Sopenharmony_ci
15681cb0ef41Sopenharmony_ci    // The schedule early block dominates the schedule late block.
15691cb0ef41Sopenharmony_ci    BasicBlock* min_block = scheduler_->GetData(node)->minimum_block_;
15701cb0ef41Sopenharmony_ci    DCHECK_EQ(min_block, BasicBlock::GetCommonDominator(block, min_block));
15711cb0ef41Sopenharmony_ci
15721cb0ef41Sopenharmony_ci    TRACE(
15731cb0ef41Sopenharmony_ci        "Schedule late of #%d:%s is id:%d at loop depth %d, minimum = id:%d\n",
15741cb0ef41Sopenharmony_ci        node->id(), node->op()->mnemonic(), block->id().ToInt(),
15751cb0ef41Sopenharmony_ci        block->loop_depth(), min_block->id().ToInt());
15761cb0ef41Sopenharmony_ci
15771cb0ef41Sopenharmony_ci    // Hoist nodes out of loops if possible. Nodes can be hoisted iteratively
15781cb0ef41Sopenharmony_ci    // into enclosing loop pre-headers until they would precede their schedule
15791cb0ef41Sopenharmony_ci    // early position.
15801cb0ef41Sopenharmony_ci    BasicBlock* hoist_block = GetHoistBlock(block);
15811cb0ef41Sopenharmony_ci    if (hoist_block &&
15821cb0ef41Sopenharmony_ci        hoist_block->dominator_depth() >= min_block->dominator_depth()) {
15831cb0ef41Sopenharmony_ci      DCHECK(scheduler_->special_rpo_->HasLoopBlocks());
15841cb0ef41Sopenharmony_ci      do {
15851cb0ef41Sopenharmony_ci        TRACE("  hoisting #%d:%s to block id:%d\n", node->id(),
15861cb0ef41Sopenharmony_ci              node->op()->mnemonic(), hoist_block->id().ToInt());
15871cb0ef41Sopenharmony_ci        DCHECK_LT(hoist_block->loop_depth(), block->loop_depth());
15881cb0ef41Sopenharmony_ci        block = hoist_block;
15891cb0ef41Sopenharmony_ci        hoist_block = GetHoistBlock(hoist_block);
15901cb0ef41Sopenharmony_ci      } while (hoist_block &&
15911cb0ef41Sopenharmony_ci               hoist_block->dominator_depth() >= min_block->dominator_depth());
15921cb0ef41Sopenharmony_ci    } else if (scheduler_->flags_ & Scheduler::kSplitNodes) {
15931cb0ef41Sopenharmony_ci      // Split the {node} if beneficial and return the new {block} for it.
15941cb0ef41Sopenharmony_ci      block = SplitNode(block, node);
15951cb0ef41Sopenharmony_ci    }
15961cb0ef41Sopenharmony_ci
15971cb0ef41Sopenharmony_ci    // Schedule the node or a floating control structure.
15981cb0ef41Sopenharmony_ci    if (IrOpcode::IsMergeOpcode(node->opcode())) {
15991cb0ef41Sopenharmony_ci      ScheduleFloatingControl(block, node);
16001cb0ef41Sopenharmony_ci    } else if (node->opcode() == IrOpcode::kFinishRegion) {
16011cb0ef41Sopenharmony_ci      ScheduleRegion(block, node);
16021cb0ef41Sopenharmony_ci    } else {
16031cb0ef41Sopenharmony_ci      ScheduleNode(block, node);
16041cb0ef41Sopenharmony_ci    }
16051cb0ef41Sopenharmony_ci  }
16061cb0ef41Sopenharmony_ci
16071cb0ef41Sopenharmony_ci  bool IsMarked(BasicBlock* block) const {
16081cb0ef41Sopenharmony_ci    DCHECK_LT(block->id().ToSize(), marked_.size());
16091cb0ef41Sopenharmony_ci    return marked_[block->id().ToSize()];
16101cb0ef41Sopenharmony_ci  }
16111cb0ef41Sopenharmony_ci
16121cb0ef41Sopenharmony_ci  void Mark(BasicBlock* block) { marked_[block->id().ToSize()] = true; }
16131cb0ef41Sopenharmony_ci
16141cb0ef41Sopenharmony_ci  // Mark {block} and push its non-marked predecessor on the marking queue.
16151cb0ef41Sopenharmony_ci  void MarkBlock(BasicBlock* block) {
16161cb0ef41Sopenharmony_ci    DCHECK_LT(block->id().ToSize(), marked_.size());
16171cb0ef41Sopenharmony_ci    Mark(block);
16181cb0ef41Sopenharmony_ci    for (BasicBlock* pred_block : block->predecessors()) {
16191cb0ef41Sopenharmony_ci      if (IsMarked(pred_block)) continue;
16201cb0ef41Sopenharmony_ci      marking_queue_.push_back(pred_block);
16211cb0ef41Sopenharmony_ci    }
16221cb0ef41Sopenharmony_ci  }
16231cb0ef41Sopenharmony_ci
16241cb0ef41Sopenharmony_ci  BasicBlock* SplitNode(BasicBlock* block, Node* node) {
16251cb0ef41Sopenharmony_ci    // For now, we limit splitting to pure nodes.
16261cb0ef41Sopenharmony_ci    if (!node->op()->HasProperty(Operator::kPure)) return block;
16271cb0ef41Sopenharmony_ci    // TODO(titzer): fix the special case of splitting of projections.
16281cb0ef41Sopenharmony_ci    if (node->opcode() == IrOpcode::kProjection) return block;
16291cb0ef41Sopenharmony_ci
16301cb0ef41Sopenharmony_ci    // The {block} is common dominator of all uses of {node}, so we cannot
16311cb0ef41Sopenharmony_ci    // split anything unless the {block} has at least two successors.
16321cb0ef41Sopenharmony_ci    DCHECK_EQ(block, GetCommonDominatorOfUses(node));
16331cb0ef41Sopenharmony_ci    if (block->SuccessorCount() < 2) return block;
16341cb0ef41Sopenharmony_ci
16351cb0ef41Sopenharmony_ci    // Clear marking bits.
16361cb0ef41Sopenharmony_ci    DCHECK(marking_queue_.empty());
16371cb0ef41Sopenharmony_ci    std::fill(marked_.begin(), marked_.end(), false);
16381cb0ef41Sopenharmony_ci    marked_.resize(schedule_->BasicBlockCount() + 1, false);
16391cb0ef41Sopenharmony_ci
16401cb0ef41Sopenharmony_ci    // Check if the {node} has uses in {block}.
16411cb0ef41Sopenharmony_ci    for (Edge edge : node->use_edges()) {
16421cb0ef41Sopenharmony_ci      if (!scheduler_->IsLive(edge.from())) continue;
16431cb0ef41Sopenharmony_ci      BasicBlock* use_block = GetBlockForUse(edge);
16441cb0ef41Sopenharmony_ci      if (use_block == nullptr || IsMarked(use_block)) continue;
16451cb0ef41Sopenharmony_ci      if (use_block == block) {
16461cb0ef41Sopenharmony_ci        TRACE("  not splitting #%d:%s, it is used in id:%d\n", node->id(),
16471cb0ef41Sopenharmony_ci              node->op()->mnemonic(), block->id().ToInt());
16481cb0ef41Sopenharmony_ci        marking_queue_.clear();
16491cb0ef41Sopenharmony_ci        return block;
16501cb0ef41Sopenharmony_ci      }
16511cb0ef41Sopenharmony_ci      MarkBlock(use_block);
16521cb0ef41Sopenharmony_ci    }
16531cb0ef41Sopenharmony_ci
16541cb0ef41Sopenharmony_ci    // Compute transitive marking closure; a block is marked if all its
16551cb0ef41Sopenharmony_ci    // successors are marked.
16561cb0ef41Sopenharmony_ci    do {
16571cb0ef41Sopenharmony_ci      BasicBlock* top_block = marking_queue_.front();
16581cb0ef41Sopenharmony_ci      marking_queue_.pop_front();
16591cb0ef41Sopenharmony_ci      if (IsMarked(top_block)) continue;
16601cb0ef41Sopenharmony_ci      bool marked = true;
16611cb0ef41Sopenharmony_ci      for (BasicBlock* successor : top_block->successors()) {
16621cb0ef41Sopenharmony_ci        if (!IsMarked(successor)) {
16631cb0ef41Sopenharmony_ci          marked = false;
16641cb0ef41Sopenharmony_ci          break;
16651cb0ef41Sopenharmony_ci        }
16661cb0ef41Sopenharmony_ci      }
16671cb0ef41Sopenharmony_ci      if (marked) MarkBlock(top_block);
16681cb0ef41Sopenharmony_ci    } while (!marking_queue_.empty());
16691cb0ef41Sopenharmony_ci
16701cb0ef41Sopenharmony_ci    // If the (common dominator) {block} is marked, we know that all paths from
16711cb0ef41Sopenharmony_ci    // {block} to the end contain at least one use of {node}, and hence there's
16721cb0ef41Sopenharmony_ci    // no point in splitting the {node} in this case.
16731cb0ef41Sopenharmony_ci    if (IsMarked(block)) {
16741cb0ef41Sopenharmony_ci      TRACE("  not splitting #%d:%s, its common dominator id:%d is perfect\n",
16751cb0ef41Sopenharmony_ci            node->id(), node->op()->mnemonic(), block->id().ToInt());
16761cb0ef41Sopenharmony_ci      return block;
16771cb0ef41Sopenharmony_ci    }
16781cb0ef41Sopenharmony_ci
16791cb0ef41Sopenharmony_ci    // Split {node} for uses according to the previously computed marking
16801cb0ef41Sopenharmony_ci    // closure. Every marking partition has a unique dominator, which get's a
16811cb0ef41Sopenharmony_ci    // copy of the {node} with the exception of the first partition, which get's
16821cb0ef41Sopenharmony_ci    // the {node} itself.
16831cb0ef41Sopenharmony_ci    ZoneMap<BasicBlock*, Node*> dominators(scheduler_->zone_);
16841cb0ef41Sopenharmony_ci    for (Edge edge : node->use_edges()) {
16851cb0ef41Sopenharmony_ci      if (!scheduler_->IsLive(edge.from())) continue;
16861cb0ef41Sopenharmony_ci      BasicBlock* use_block = GetBlockForUse(edge);
16871cb0ef41Sopenharmony_ci      if (use_block == nullptr) continue;
16881cb0ef41Sopenharmony_ci      while (IsMarked(use_block->dominator())) {
16891cb0ef41Sopenharmony_ci        use_block = use_block->dominator();
16901cb0ef41Sopenharmony_ci      }
16911cb0ef41Sopenharmony_ci      auto& use_node = dominators[use_block];
16921cb0ef41Sopenharmony_ci      if (use_node == nullptr) {
16931cb0ef41Sopenharmony_ci        if (dominators.size() == 1u) {
16941cb0ef41Sopenharmony_ci          // Place the {node} at {use_block}.
16951cb0ef41Sopenharmony_ci          block = use_block;
16961cb0ef41Sopenharmony_ci          use_node = node;
16971cb0ef41Sopenharmony_ci          TRACE("  pushing #%d:%s down to id:%d\n", node->id(),
16981cb0ef41Sopenharmony_ci                node->op()->mnemonic(), block->id().ToInt());
16991cb0ef41Sopenharmony_ci        } else {
17001cb0ef41Sopenharmony_ci          // Place a copy of {node} at {use_block}.
17011cb0ef41Sopenharmony_ci          use_node = CloneNode(node);
17021cb0ef41Sopenharmony_ci          TRACE("  cloning #%d:%s for id:%d\n", use_node->id(),
17031cb0ef41Sopenharmony_ci                use_node->op()->mnemonic(), use_block->id().ToInt());
17041cb0ef41Sopenharmony_ci          scheduler_->schedule_queue_.push(use_node);
17051cb0ef41Sopenharmony_ci        }
17061cb0ef41Sopenharmony_ci      }
17071cb0ef41Sopenharmony_ci      edge.UpdateTo(use_node);
17081cb0ef41Sopenharmony_ci    }
17091cb0ef41Sopenharmony_ci    return block;
17101cb0ef41Sopenharmony_ci  }
17111cb0ef41Sopenharmony_ci
17121cb0ef41Sopenharmony_ci  BasicBlock* GetHoistBlock(BasicBlock* block) {
17131cb0ef41Sopenharmony_ci    if (!scheduler_->special_rpo_->HasLoopBlocks()) return nullptr;
17141cb0ef41Sopenharmony_ci    if (block->IsLoopHeader()) return block->dominator();
17151cb0ef41Sopenharmony_ci    // We have to check to make sure that the {block} dominates all
17161cb0ef41Sopenharmony_ci    // of the outgoing blocks.  If it doesn't, then there is a path
17171cb0ef41Sopenharmony_ci    // out of the loop which does not execute this {block}, so we
17181cb0ef41Sopenharmony_ci    // can't hoist operations from this {block} out of the loop, as
17191cb0ef41Sopenharmony_ci    // that would introduce additional computations.
17201cb0ef41Sopenharmony_ci    if (BasicBlock* header_block = block->loop_header()) {
17211cb0ef41Sopenharmony_ci      for (BasicBlock* outgoing_block :
17221cb0ef41Sopenharmony_ci           scheduler_->special_rpo_->GetOutgoingBlocks(header_block)) {
17231cb0ef41Sopenharmony_ci        if (scheduler_->GetCommonDominator(block, outgoing_block) != block) {
17241cb0ef41Sopenharmony_ci          return nullptr;
17251cb0ef41Sopenharmony_ci        }
17261cb0ef41Sopenharmony_ci      }
17271cb0ef41Sopenharmony_ci      return header_block->dominator();
17281cb0ef41Sopenharmony_ci    }
17291cb0ef41Sopenharmony_ci    return nullptr;
17301cb0ef41Sopenharmony_ci  }
17311cb0ef41Sopenharmony_ci
17321cb0ef41Sopenharmony_ci  BasicBlock* GetCommonDominatorOfUses(Node* node) {
17331cb0ef41Sopenharmony_ci    BasicBlock* block = nullptr;
17341cb0ef41Sopenharmony_ci    for (Edge edge : node->use_edges()) {
17351cb0ef41Sopenharmony_ci      if (!scheduler_->IsLive(edge.from())) continue;
17361cb0ef41Sopenharmony_ci      BasicBlock* use_block = GetBlockForUse(edge);
17371cb0ef41Sopenharmony_ci      block = block == nullptr
17381cb0ef41Sopenharmony_ci                  ? use_block
17391cb0ef41Sopenharmony_ci                  : use_block == nullptr
17401cb0ef41Sopenharmony_ci                        ? block
17411cb0ef41Sopenharmony_ci                        : scheduler_->GetCommonDominator(block, use_block);
17421cb0ef41Sopenharmony_ci    }
17431cb0ef41Sopenharmony_ci    return block;
17441cb0ef41Sopenharmony_ci  }
17451cb0ef41Sopenharmony_ci
17461cb0ef41Sopenharmony_ci  BasicBlock* FindPredecessorBlock(Node* node) {
17471cb0ef41Sopenharmony_ci    return scheduler_->control_flow_builder_->FindPredecessorBlock(node);
17481cb0ef41Sopenharmony_ci  }
17491cb0ef41Sopenharmony_ci
17501cb0ef41Sopenharmony_ci  BasicBlock* GetBlockForUse(Edge edge) {
17511cb0ef41Sopenharmony_ci    // TODO(titzer): ignore uses from dead nodes (not visited in PrepareUses()).
17521cb0ef41Sopenharmony_ci    // Dead uses only occur if the graph is not trimmed before scheduling.
17531cb0ef41Sopenharmony_ci    Node* use = edge.from();
17541cb0ef41Sopenharmony_ci    if (IrOpcode::IsPhiOpcode(use->opcode())) {
17551cb0ef41Sopenharmony_ci      // If the use is from a coupled (i.e. floating) phi, compute the common
17561cb0ef41Sopenharmony_ci      // dominator of its uses. This will not recurse more than one level.
17571cb0ef41Sopenharmony_ci      if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) {
17581cb0ef41Sopenharmony_ci        TRACE("  inspecting uses of coupled #%d:%s\n", use->id(),
17591cb0ef41Sopenharmony_ci              use->op()->mnemonic());
17601cb0ef41Sopenharmony_ci        // TODO(titzer): reenable once above TODO is addressed.
17611cb0ef41Sopenharmony_ci        //        DCHECK_EQ(edge.to(), NodeProperties::GetControlInput(use));
17621cb0ef41Sopenharmony_ci        return GetCommonDominatorOfUses(use);
17631cb0ef41Sopenharmony_ci      }
17641cb0ef41Sopenharmony_ci      // If the use is from a fixed (i.e. non-floating) phi, we use the
17651cb0ef41Sopenharmony_ci      // predecessor block of the corresponding control input to the merge.
17661cb0ef41Sopenharmony_ci      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
17671cb0ef41Sopenharmony_ci        TRACE("  input@%d into a fixed phi #%d:%s\n", edge.index(), use->id(),
17681cb0ef41Sopenharmony_ci              use->op()->mnemonic());
17691cb0ef41Sopenharmony_ci        Node* merge = NodeProperties::GetControlInput(use, 0);
17701cb0ef41Sopenharmony_ci        DCHECK(IrOpcode::IsMergeOpcode(merge->opcode()));
17711cb0ef41Sopenharmony_ci        Node* input = NodeProperties::GetControlInput(merge, edge.index());
17721cb0ef41Sopenharmony_ci        return FindPredecessorBlock(input);
17731cb0ef41Sopenharmony_ci      }
17741cb0ef41Sopenharmony_ci    } else if (IrOpcode::IsMergeOpcode(use->opcode())) {
17751cb0ef41Sopenharmony_ci      // If the use is from a fixed (i.e. non-floating) merge, we use the
17761cb0ef41Sopenharmony_ci      // predecessor block of the current input to the merge.
17771cb0ef41Sopenharmony_ci      if (scheduler_->GetPlacement(use) == Scheduler::kFixed) {
17781cb0ef41Sopenharmony_ci        TRACE("  input@%d into a fixed merge #%d:%s\n", edge.index(), use->id(),
17791cb0ef41Sopenharmony_ci              use->op()->mnemonic());
17801cb0ef41Sopenharmony_ci        return FindPredecessorBlock(edge.to());
17811cb0ef41Sopenharmony_ci      }
17821cb0ef41Sopenharmony_ci    }
17831cb0ef41Sopenharmony_ci    BasicBlock* result = schedule_->block(use);
17841cb0ef41Sopenharmony_ci    if (result == nullptr) return nullptr;
17851cb0ef41Sopenharmony_ci    TRACE("  must dominate use #%d:%s in id:%d\n", use->id(),
17861cb0ef41Sopenharmony_ci          use->op()->mnemonic(), result->id().ToInt());
17871cb0ef41Sopenharmony_ci    return result;
17881cb0ef41Sopenharmony_ci  }
17891cb0ef41Sopenharmony_ci
17901cb0ef41Sopenharmony_ci  void ScheduleFloatingControl(BasicBlock* block, Node* node) {
17911cb0ef41Sopenharmony_ci    scheduler_->FuseFloatingControl(block, node);
17921cb0ef41Sopenharmony_ci  }
17931cb0ef41Sopenharmony_ci
17941cb0ef41Sopenharmony_ci  void ScheduleRegion(BasicBlock* block, Node* region_end) {
17951cb0ef41Sopenharmony_ci    // We only allow regions of instructions connected into a linear
17961cb0ef41Sopenharmony_ci    // effect chain. The only value allowed to be produced by a node
17971cb0ef41Sopenharmony_ci    // in the chain must be the value consumed by the FinishRegion node.
17981cb0ef41Sopenharmony_ci
17991cb0ef41Sopenharmony_ci    // We schedule back to front; we first schedule FinishRegion.
18001cb0ef41Sopenharmony_ci    CHECK_EQ(IrOpcode::kFinishRegion, region_end->opcode());
18011cb0ef41Sopenharmony_ci    ScheduleNode(block, region_end);
18021cb0ef41Sopenharmony_ci
18031cb0ef41Sopenharmony_ci    // Schedule the chain.
18041cb0ef41Sopenharmony_ci    Node* node = NodeProperties::GetEffectInput(region_end);
18051cb0ef41Sopenharmony_ci    while (node->opcode() != IrOpcode::kBeginRegion) {
18061cb0ef41Sopenharmony_ci      DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_);
18071cb0ef41Sopenharmony_ci      DCHECK_EQ(1, node->op()->EffectInputCount());
18081cb0ef41Sopenharmony_ci      DCHECK_EQ(1, node->op()->EffectOutputCount());
18091cb0ef41Sopenharmony_ci      DCHECK_EQ(0, node->op()->ControlOutputCount());
18101cb0ef41Sopenharmony_ci      // The value output (if there is any) must be consumed
18111cb0ef41Sopenharmony_ci      // by the EndRegion node.
18121cb0ef41Sopenharmony_ci      DCHECK(node->op()->ValueOutputCount() == 0 ||
18131cb0ef41Sopenharmony_ci             node == region_end->InputAt(0));
18141cb0ef41Sopenharmony_ci      ScheduleNode(block, node);
18151cb0ef41Sopenharmony_ci      node = NodeProperties::GetEffectInput(node);
18161cb0ef41Sopenharmony_ci    }
18171cb0ef41Sopenharmony_ci    // Schedule the BeginRegion node.
18181cb0ef41Sopenharmony_ci    DCHECK_EQ(0, scheduler_->GetData(node)->unscheduled_count_);
18191cb0ef41Sopenharmony_ci    ScheduleNode(block, node);
18201cb0ef41Sopenharmony_ci  }
18211cb0ef41Sopenharmony_ci
18221cb0ef41Sopenharmony_ci  void ScheduleNode(BasicBlock* block, Node* node) {
18231cb0ef41Sopenharmony_ci    schedule_->PlanNode(block, node);
18241cb0ef41Sopenharmony_ci    size_t block_id = block->id().ToSize();
18251cb0ef41Sopenharmony_ci    if (!scheduler_->scheduled_nodes_[block_id]) {
18261cb0ef41Sopenharmony_ci      scheduler_->scheduled_nodes_[block_id] = zone_->New<NodeVector>(zone_);
18271cb0ef41Sopenharmony_ci    }
18281cb0ef41Sopenharmony_ci    scheduler_->scheduled_nodes_[block_id]->push_back(node);
18291cb0ef41Sopenharmony_ci    scheduler_->UpdatePlacement(node, Scheduler::kScheduled);
18301cb0ef41Sopenharmony_ci  }
18311cb0ef41Sopenharmony_ci
18321cb0ef41Sopenharmony_ci  Node* CloneNode(Node* node) {
18331cb0ef41Sopenharmony_ci    int const input_count = node->InputCount();
18341cb0ef41Sopenharmony_ci    base::Optional<int> coupled_control_edge =
18351cb0ef41Sopenharmony_ci        scheduler_->GetCoupledControlEdge(node);
18361cb0ef41Sopenharmony_ci    for (int index = 0; index < input_count; ++index) {
18371cb0ef41Sopenharmony_ci      if (index != coupled_control_edge) {
18381cb0ef41Sopenharmony_ci        Node* const input = node->InputAt(index);
18391cb0ef41Sopenharmony_ci        scheduler_->IncrementUnscheduledUseCount(input, node);
18401cb0ef41Sopenharmony_ci      }
18411cb0ef41Sopenharmony_ci    }
18421cb0ef41Sopenharmony_ci    Node* const copy = scheduler_->graph_->CloneNode(node);
18431cb0ef41Sopenharmony_ci    TRACE(("clone #%d:%s -> #%d\n"), node->id(), node->op()->mnemonic(),
18441cb0ef41Sopenharmony_ci          copy->id());
18451cb0ef41Sopenharmony_ci    scheduler_->node_data_.resize(copy->id() + 1,
18461cb0ef41Sopenharmony_ci                                  scheduler_->DefaultSchedulerData());
18471cb0ef41Sopenharmony_ci    scheduler_->node_data_[copy->id()] = scheduler_->node_data_[node->id()];
18481cb0ef41Sopenharmony_ci    return copy;
18491cb0ef41Sopenharmony_ci  }
18501cb0ef41Sopenharmony_ci
18511cb0ef41Sopenharmony_ci  Zone* zone_;
18521cb0ef41Sopenharmony_ci  Scheduler* scheduler_;
18531cb0ef41Sopenharmony_ci  Schedule* schedule_;
18541cb0ef41Sopenharmony_ci  BoolVector marked_;
18551cb0ef41Sopenharmony_ci  ZoneDeque<BasicBlock*> marking_queue_;
18561cb0ef41Sopenharmony_ci};
18571cb0ef41Sopenharmony_ci
18581cb0ef41Sopenharmony_ci
18591cb0ef41Sopenharmony_civoid Scheduler::ScheduleLate() {
18601cb0ef41Sopenharmony_ci  TRACE("--- SCHEDULE LATE ------------------------------------------\n");
18611cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
18621cb0ef41Sopenharmony_ci    TRACE("roots: ");
18631cb0ef41Sopenharmony_ci    for (Node* node : schedule_root_nodes_) {
18641cb0ef41Sopenharmony_ci      TRACE("#%d:%s ", node->id(), node->op()->mnemonic());
18651cb0ef41Sopenharmony_ci    }
18661cb0ef41Sopenharmony_ci    TRACE("\n");
18671cb0ef41Sopenharmony_ci  }
18681cb0ef41Sopenharmony_ci
18691cb0ef41Sopenharmony_ci  // Schedule: Places nodes in dominator block of all their uses.
18701cb0ef41Sopenharmony_ci  ScheduleLateNodeVisitor schedule_late_visitor(zone_, this);
18711cb0ef41Sopenharmony_ci  schedule_late_visitor.Run(&schedule_root_nodes_);
18721cb0ef41Sopenharmony_ci}
18731cb0ef41Sopenharmony_ci
18741cb0ef41Sopenharmony_ci
18751cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
18761cb0ef41Sopenharmony_ci// Phase 6: Seal the final schedule.
18771cb0ef41Sopenharmony_ci
18781cb0ef41Sopenharmony_ci
18791cb0ef41Sopenharmony_civoid Scheduler::SealFinalSchedule() {
18801cb0ef41Sopenharmony_ci  TRACE("--- SEAL FINAL SCHEDULE ------------------------------------\n");
18811cb0ef41Sopenharmony_ci
18821cb0ef41Sopenharmony_ci  // Serialize the assembly order and reverse-post-order numbering.
18831cb0ef41Sopenharmony_ci  special_rpo_->SerializeRPOIntoSchedule();
18841cb0ef41Sopenharmony_ci  special_rpo_->PrintAndVerifySpecialRPO();
18851cb0ef41Sopenharmony_ci
18861cb0ef41Sopenharmony_ci  // Add collected nodes for basic blocks to their blocks in the right order.
18871cb0ef41Sopenharmony_ci  int block_num = 0;
18881cb0ef41Sopenharmony_ci  for (NodeVector* nodes : scheduled_nodes_) {
18891cb0ef41Sopenharmony_ci    BasicBlock::Id id = BasicBlock::Id::FromInt(block_num++);
18901cb0ef41Sopenharmony_ci    BasicBlock* block = schedule_->GetBlockById(id);
18911cb0ef41Sopenharmony_ci    if (nodes) {
18921cb0ef41Sopenharmony_ci      for (Node* node : base::Reversed(*nodes)) {
18931cb0ef41Sopenharmony_ci        schedule_->AddNode(block, node);
18941cb0ef41Sopenharmony_ci      }
18951cb0ef41Sopenharmony_ci    }
18961cb0ef41Sopenharmony_ci  }
18971cb0ef41Sopenharmony_ci}
18981cb0ef41Sopenharmony_ci
18991cb0ef41Sopenharmony_ci
19001cb0ef41Sopenharmony_ci// -----------------------------------------------------------------------------
19011cb0ef41Sopenharmony_ci
19021cb0ef41Sopenharmony_ci
19031cb0ef41Sopenharmony_civoid Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
19041cb0ef41Sopenharmony_ci  TRACE("--- FUSE FLOATING CONTROL ----------------------------------\n");
19051cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
19061cb0ef41Sopenharmony_ci    StdoutStream{} << "Schedule before control flow fusion:\n" << *schedule_;
19071cb0ef41Sopenharmony_ci  }
19081cb0ef41Sopenharmony_ci
19091cb0ef41Sopenharmony_ci  // Iterate on phase 1: Build control-flow graph.
19101cb0ef41Sopenharmony_ci  control_flow_builder_->Run(block, node);
19111cb0ef41Sopenharmony_ci
19121cb0ef41Sopenharmony_ci  // Iterate on phase 2: Compute special RPO and dominator tree.
19131cb0ef41Sopenharmony_ci  special_rpo_->UpdateSpecialRPO(block, schedule_->block(node));
19141cb0ef41Sopenharmony_ci  // TODO(turbofan): Currently "iterate on" means "re-run". Fix that.
19151cb0ef41Sopenharmony_ci  for (BasicBlock* b = block->rpo_next(); b != nullptr; b = b->rpo_next()) {
19161cb0ef41Sopenharmony_ci    b->set_dominator_depth(-1);
19171cb0ef41Sopenharmony_ci    b->set_dominator(nullptr);
19181cb0ef41Sopenharmony_ci  }
19191cb0ef41Sopenharmony_ci  PropagateImmediateDominators(block->rpo_next());
19201cb0ef41Sopenharmony_ci
19211cb0ef41Sopenharmony_ci  // Iterate on phase 4: Schedule nodes early.
19221cb0ef41Sopenharmony_ci  // TODO(turbofan): The following loop gathering the propagation roots is a
19231cb0ef41Sopenharmony_ci  // temporary solution and should be merged into the rest of the scheduler as
19241cb0ef41Sopenharmony_ci  // soon as the approach settled for all floating loops.
19251cb0ef41Sopenharmony_ci  NodeVector propagation_roots(control_flow_builder_->control_);
19261cb0ef41Sopenharmony_ci  for (Node* control : control_flow_builder_->control_) {
19271cb0ef41Sopenharmony_ci    for (Node* use : control->uses()) {
19281cb0ef41Sopenharmony_ci      if (NodeProperties::IsPhi(use) && IsLive(use)) {
19291cb0ef41Sopenharmony_ci        propagation_roots.push_back(use);
19301cb0ef41Sopenharmony_ci      }
19311cb0ef41Sopenharmony_ci    }
19321cb0ef41Sopenharmony_ci  }
19331cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
19341cb0ef41Sopenharmony_ci    TRACE("propagation roots: ");
19351cb0ef41Sopenharmony_ci    for (Node* r : propagation_roots) {
19361cb0ef41Sopenharmony_ci      TRACE("#%d:%s ", r->id(), r->op()->mnemonic());
19371cb0ef41Sopenharmony_ci    }
19381cb0ef41Sopenharmony_ci    TRACE("\n");
19391cb0ef41Sopenharmony_ci  }
19401cb0ef41Sopenharmony_ci  ScheduleEarlyNodeVisitor schedule_early_visitor(zone_, this);
19411cb0ef41Sopenharmony_ci  schedule_early_visitor.Run(&propagation_roots);
19421cb0ef41Sopenharmony_ci
19431cb0ef41Sopenharmony_ci  // Move previously planned nodes.
19441cb0ef41Sopenharmony_ci  // TODO(turbofan): Improve that by supporting bulk moves.
19451cb0ef41Sopenharmony_ci  scheduled_nodes_.resize(schedule_->BasicBlockCount());
19461cb0ef41Sopenharmony_ci  MovePlannedNodes(block, schedule_->block(node));
19471cb0ef41Sopenharmony_ci
19481cb0ef41Sopenharmony_ci  if (FLAG_trace_turbo_scheduler) {
19491cb0ef41Sopenharmony_ci    StdoutStream{} << "Schedule after control flow fusion:\n" << *schedule_;
19501cb0ef41Sopenharmony_ci  }
19511cb0ef41Sopenharmony_ci}
19521cb0ef41Sopenharmony_ci
19531cb0ef41Sopenharmony_ci
19541cb0ef41Sopenharmony_civoid Scheduler::MovePlannedNodes(BasicBlock* from, BasicBlock* to) {
19551cb0ef41Sopenharmony_ci  TRACE("Move planned nodes from id:%d to id:%d\n", from->id().ToInt(),
19561cb0ef41Sopenharmony_ci        to->id().ToInt());
19571cb0ef41Sopenharmony_ci  NodeVector* from_nodes = scheduled_nodes_[from->id().ToSize()];
19581cb0ef41Sopenharmony_ci  NodeVector* to_nodes = scheduled_nodes_[to->id().ToSize()];
19591cb0ef41Sopenharmony_ci  if (!from_nodes) return;
19601cb0ef41Sopenharmony_ci
19611cb0ef41Sopenharmony_ci  for (Node* const node : *from_nodes) {
19621cb0ef41Sopenharmony_ci    schedule_->SetBlockForNode(to, node);
19631cb0ef41Sopenharmony_ci  }
19641cb0ef41Sopenharmony_ci  if (to_nodes) {
19651cb0ef41Sopenharmony_ci    to_nodes->insert(to_nodes->end(), from_nodes->begin(), from_nodes->end());
19661cb0ef41Sopenharmony_ci    from_nodes->clear();
19671cb0ef41Sopenharmony_ci  } else {
19681cb0ef41Sopenharmony_ci    std::swap(scheduled_nodes_[from->id().ToSize()],
19691cb0ef41Sopenharmony_ci              scheduled_nodes_[to->id().ToSize()]);
19701cb0ef41Sopenharmony_ci  }
19711cb0ef41Sopenharmony_ci}
19721cb0ef41Sopenharmony_ci
19731cb0ef41Sopenharmony_ci#undef TRACE
19741cb0ef41Sopenharmony_ci
19751cb0ef41Sopenharmony_ci}  // namespace compiler
19761cb0ef41Sopenharmony_ci}  // namespace internal
19771cb0ef41Sopenharmony_ci}  // namespace v8
1978