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