11cb0ef41Sopenharmony_ci// Copyright 2014 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/loop-analysis.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/codegen/tick-counter.h" 81cb0ef41Sopenharmony_ci#include "src/compiler/common-operator.h" 91cb0ef41Sopenharmony_ci#include "src/compiler/graph.h" 101cb0ef41Sopenharmony_ci#include "src/compiler/node-marker.h" 111cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h" 121cb0ef41Sopenharmony_ci#include "src/compiler/node.h" 131cb0ef41Sopenharmony_ci#include "src/zone/zone.h" 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 161cb0ef41Sopenharmony_ci#include "src/wasm/wasm-code-manager.h" 171cb0ef41Sopenharmony_ci#endif 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_cinamespace v8 { 201cb0ef41Sopenharmony_cinamespace internal { 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ciclass TickCounter; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_cinamespace compiler { 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci#define OFFSET(x) ((x)&0x1F) 271cb0ef41Sopenharmony_ci#define BIT(x) (1u << OFFSET(x)) 281cb0ef41Sopenharmony_ci#define INDEX(x) ((x) >> 5) 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci// Temporary information for each node during marking. 311cb0ef41Sopenharmony_cistruct NodeInfo { 321cb0ef41Sopenharmony_ci Node* node; 331cb0ef41Sopenharmony_ci NodeInfo* next; // link in chaining loop members 341cb0ef41Sopenharmony_ci bool backwards_visited; 351cb0ef41Sopenharmony_ci}; 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci// Temporary loop info needed during traversal and building the loop tree. 391cb0ef41Sopenharmony_cistruct TempLoopInfo { 401cb0ef41Sopenharmony_ci Node* header; 411cb0ef41Sopenharmony_ci NodeInfo* header_list; 421cb0ef41Sopenharmony_ci NodeInfo* exit_list; 431cb0ef41Sopenharmony_ci NodeInfo* body_list; 441cb0ef41Sopenharmony_ci LoopTree::Loop* loop; 451cb0ef41Sopenharmony_ci}; 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci// Encapsulation of the loop finding algorithm. 481cb0ef41Sopenharmony_ci// ----------------------------------------------------------------------------- 491cb0ef41Sopenharmony_ci// Conceptually, the contents of a loop are those nodes that are "between" the 501cb0ef41Sopenharmony_ci// loop header and the backedges of the loop. Graphs in the soup of nodes can 511cb0ef41Sopenharmony_ci// form improper cycles, so standard loop finding algorithms that work on CFGs 521cb0ef41Sopenharmony_ci// aren't sufficient. However, in valid TurboFan graphs, all cycles involve 531cb0ef41Sopenharmony_ci// either a {Loop} node or a phi. The {Loop} node itself and its accompanying 541cb0ef41Sopenharmony_ci// phis are treated together as a set referred to here as the loop header. 551cb0ef41Sopenharmony_ci// This loop finding algorithm works by traversing the graph in two directions, 561cb0ef41Sopenharmony_ci// first from nodes to their inputs, starting at {end}, then in the reverse 571cb0ef41Sopenharmony_ci// direction, from nodes to their uses, starting at loop headers. 581cb0ef41Sopenharmony_ci// 1 bit per loop per node per direction are required during the marking phase. 591cb0ef41Sopenharmony_ci// To handle nested loops correctly, the algorithm must filter some reachability 601cb0ef41Sopenharmony_ci// marks on edges into/out-of the loop header nodes. 611cb0ef41Sopenharmony_ci// Note: this algorithm assumes there are no unreachable loop header nodes 621cb0ef41Sopenharmony_ci// (including loop phis). 631cb0ef41Sopenharmony_ciclass LoopFinderImpl { 641cb0ef41Sopenharmony_ci public: 651cb0ef41Sopenharmony_ci LoopFinderImpl(Graph* graph, LoopTree* loop_tree, TickCounter* tick_counter, 661cb0ef41Sopenharmony_ci Zone* zone) 671cb0ef41Sopenharmony_ci : zone_(zone), 681cb0ef41Sopenharmony_ci end_(graph->end()), 691cb0ef41Sopenharmony_ci queue_(zone), 701cb0ef41Sopenharmony_ci queued_(graph, 2), 711cb0ef41Sopenharmony_ci info_(graph->NodeCount(), {nullptr, nullptr, false}, zone), 721cb0ef41Sopenharmony_ci loops_(zone), 731cb0ef41Sopenharmony_ci loop_num_(graph->NodeCount(), -1, zone), 741cb0ef41Sopenharmony_ci loop_tree_(loop_tree), 751cb0ef41Sopenharmony_ci loops_found_(0), 761cb0ef41Sopenharmony_ci width_(0), 771cb0ef41Sopenharmony_ci backward_(nullptr), 781cb0ef41Sopenharmony_ci forward_(nullptr), 791cb0ef41Sopenharmony_ci tick_counter_(tick_counter) {} 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci void Run() { 821cb0ef41Sopenharmony_ci PropagateBackward(); 831cb0ef41Sopenharmony_ci PropagateForward(); 841cb0ef41Sopenharmony_ci FinishLoopTree(); 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci void Print() { 881cb0ef41Sopenharmony_ci // Print out the results. 891cb0ef41Sopenharmony_ci for (NodeInfo& ni : info_) { 901cb0ef41Sopenharmony_ci if (ni.node == nullptr) continue; 911cb0ef41Sopenharmony_ci for (int i = 1; i <= loops_found_; i++) { 921cb0ef41Sopenharmony_ci int index = ni.node->id() * width_ + INDEX(i); 931cb0ef41Sopenharmony_ci bool marked_forward = forward_[index] & BIT(i); 941cb0ef41Sopenharmony_ci bool marked_backward = backward_[index] & BIT(i); 951cb0ef41Sopenharmony_ci if (marked_forward && marked_backward) { 961cb0ef41Sopenharmony_ci PrintF("X"); 971cb0ef41Sopenharmony_ci } else if (marked_forward) { 981cb0ef41Sopenharmony_ci PrintF(">"); 991cb0ef41Sopenharmony_ci } else if (marked_backward) { 1001cb0ef41Sopenharmony_ci PrintF("<"); 1011cb0ef41Sopenharmony_ci } else { 1021cb0ef41Sopenharmony_ci PrintF(" "); 1031cb0ef41Sopenharmony_ci } 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci PrintF(" #%d:%s\n", ni.node->id(), ni.node->op()->mnemonic()); 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci int i = 0; 1091cb0ef41Sopenharmony_ci for (TempLoopInfo& li : loops_) { 1101cb0ef41Sopenharmony_ci PrintF("Loop %d headed at #%d\n", i, li.header->id()); 1111cb0ef41Sopenharmony_ci i++; 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { 1151cb0ef41Sopenharmony_ci PrintLoop(loop); 1161cb0ef41Sopenharmony_ci } 1171cb0ef41Sopenharmony_ci } 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci private: 1201cb0ef41Sopenharmony_ci Zone* zone_; 1211cb0ef41Sopenharmony_ci Node* end_; 1221cb0ef41Sopenharmony_ci NodeDeque queue_; 1231cb0ef41Sopenharmony_ci NodeMarker<bool> queued_; 1241cb0ef41Sopenharmony_ci ZoneVector<NodeInfo> info_; 1251cb0ef41Sopenharmony_ci ZoneVector<TempLoopInfo> loops_; 1261cb0ef41Sopenharmony_ci ZoneVector<int> loop_num_; 1271cb0ef41Sopenharmony_ci LoopTree* loop_tree_; 1281cb0ef41Sopenharmony_ci int loops_found_; 1291cb0ef41Sopenharmony_ci int width_; 1301cb0ef41Sopenharmony_ci uint32_t* backward_; 1311cb0ef41Sopenharmony_ci uint32_t* forward_; 1321cb0ef41Sopenharmony_ci TickCounter* const tick_counter_; 1331cb0ef41Sopenharmony_ci 1341cb0ef41Sopenharmony_ci int num_nodes() { 1351cb0ef41Sopenharmony_ci return static_cast<int>(loop_tree_->node_to_loop_num_.size()); 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_ci // Tb = Tb | (Fb - loop_filter) 1391cb0ef41Sopenharmony_ci bool PropagateBackwardMarks(Node* from, Node* to, int loop_filter) { 1401cb0ef41Sopenharmony_ci if (from == to) return false; 1411cb0ef41Sopenharmony_ci uint32_t* fp = &backward_[from->id() * width_]; 1421cb0ef41Sopenharmony_ci uint32_t* tp = &backward_[to->id() * width_]; 1431cb0ef41Sopenharmony_ci bool change = false; 1441cb0ef41Sopenharmony_ci for (int i = 0; i < width_; i++) { 1451cb0ef41Sopenharmony_ci uint32_t mask = i == INDEX(loop_filter) ? ~BIT(loop_filter) : 0xFFFFFFFF; 1461cb0ef41Sopenharmony_ci uint32_t prev = tp[i]; 1471cb0ef41Sopenharmony_ci uint32_t next = prev | (fp[i] & mask); 1481cb0ef41Sopenharmony_ci tp[i] = next; 1491cb0ef41Sopenharmony_ci if (!change && (prev != next)) change = true; 1501cb0ef41Sopenharmony_ci } 1511cb0ef41Sopenharmony_ci return change; 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci // Tb = Tb | B 1551cb0ef41Sopenharmony_ci bool SetBackwardMark(Node* to, int loop_num) { 1561cb0ef41Sopenharmony_ci uint32_t* tp = &backward_[to->id() * width_ + INDEX(loop_num)]; 1571cb0ef41Sopenharmony_ci uint32_t prev = tp[0]; 1581cb0ef41Sopenharmony_ci uint32_t next = prev | BIT(loop_num); 1591cb0ef41Sopenharmony_ci tp[0] = next; 1601cb0ef41Sopenharmony_ci return next != prev; 1611cb0ef41Sopenharmony_ci } 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci // Tf = Tf | B 1641cb0ef41Sopenharmony_ci bool SetForwardMark(Node* to, int loop_num) { 1651cb0ef41Sopenharmony_ci uint32_t* tp = &forward_[to->id() * width_ + INDEX(loop_num)]; 1661cb0ef41Sopenharmony_ci uint32_t prev = tp[0]; 1671cb0ef41Sopenharmony_ci uint32_t next = prev | BIT(loop_num); 1681cb0ef41Sopenharmony_ci tp[0] = next; 1691cb0ef41Sopenharmony_ci return next != prev; 1701cb0ef41Sopenharmony_ci } 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci // Tf = Tf | (Ff & Tb) 1731cb0ef41Sopenharmony_ci bool PropagateForwardMarks(Node* from, Node* to) { 1741cb0ef41Sopenharmony_ci if (from == to) return false; 1751cb0ef41Sopenharmony_ci bool change = false; 1761cb0ef41Sopenharmony_ci int findex = from->id() * width_; 1771cb0ef41Sopenharmony_ci int tindex = to->id() * width_; 1781cb0ef41Sopenharmony_ci for (int i = 0; i < width_; i++) { 1791cb0ef41Sopenharmony_ci uint32_t marks = backward_[tindex + i] & forward_[findex + i]; 1801cb0ef41Sopenharmony_ci uint32_t prev = forward_[tindex + i]; 1811cb0ef41Sopenharmony_ci uint32_t next = prev | marks; 1821cb0ef41Sopenharmony_ci forward_[tindex + i] = next; 1831cb0ef41Sopenharmony_ci if (!change && (prev != next)) change = true; 1841cb0ef41Sopenharmony_ci } 1851cb0ef41Sopenharmony_ci return change; 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci bool IsInLoop(Node* node, int loop_num) { 1891cb0ef41Sopenharmony_ci int offset = node->id() * width_ + INDEX(loop_num); 1901cb0ef41Sopenharmony_ci return backward_[offset] & forward_[offset] & BIT(loop_num); 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci 1931cb0ef41Sopenharmony_ci // Propagate marks backward from loop headers. 1941cb0ef41Sopenharmony_ci void PropagateBackward() { 1951cb0ef41Sopenharmony_ci ResizeBackwardMarks(); 1961cb0ef41Sopenharmony_ci SetBackwardMark(end_, 0); 1971cb0ef41Sopenharmony_ci Queue(end_); 1981cb0ef41Sopenharmony_ci 1991cb0ef41Sopenharmony_ci while (!queue_.empty()) { 2001cb0ef41Sopenharmony_ci tick_counter_->TickAndMaybeEnterSafepoint(); 2011cb0ef41Sopenharmony_ci Node* node = queue_.front(); 2021cb0ef41Sopenharmony_ci info(node).backwards_visited = true; 2031cb0ef41Sopenharmony_ci queue_.pop_front(); 2041cb0ef41Sopenharmony_ci queued_.Set(node, false); 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci int loop_num = -1; 2071cb0ef41Sopenharmony_ci // Setup loop headers first. 2081cb0ef41Sopenharmony_ci if (node->opcode() == IrOpcode::kLoop) { 2091cb0ef41Sopenharmony_ci // found the loop node first. 2101cb0ef41Sopenharmony_ci loop_num = CreateLoopInfo(node); 2111cb0ef41Sopenharmony_ci } else if (NodeProperties::IsPhi(node)) { 2121cb0ef41Sopenharmony_ci // found a phi first. 2131cb0ef41Sopenharmony_ci Node* merge = node->InputAt(node->InputCount() - 1); 2141cb0ef41Sopenharmony_ci if (merge->opcode() == IrOpcode::kLoop) { 2151cb0ef41Sopenharmony_ci loop_num = CreateLoopInfo(merge); 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci } else if (node->opcode() == IrOpcode::kLoopExit) { 2181cb0ef41Sopenharmony_ci // Intentionally ignore return value. Loop exit node marks 2191cb0ef41Sopenharmony_ci // are propagated normally. 2201cb0ef41Sopenharmony_ci CreateLoopInfo(node->InputAt(1)); 2211cb0ef41Sopenharmony_ci } else if (node->opcode() == IrOpcode::kLoopExitValue || 2221cb0ef41Sopenharmony_ci node->opcode() == IrOpcode::kLoopExitEffect) { 2231cb0ef41Sopenharmony_ci Node* loop_exit = NodeProperties::GetControlInput(node); 2241cb0ef41Sopenharmony_ci // Intentionally ignore return value. Loop exit node marks 2251cb0ef41Sopenharmony_ci // are propagated normally. 2261cb0ef41Sopenharmony_ci CreateLoopInfo(loop_exit->InputAt(1)); 2271cb0ef41Sopenharmony_ci } 2281cb0ef41Sopenharmony_ci 2291cb0ef41Sopenharmony_ci // Propagate marks backwards from this node. 2301cb0ef41Sopenharmony_ci for (int i = 0; i < node->InputCount(); i++) { 2311cb0ef41Sopenharmony_ci Node* input = node->InputAt(i); 2321cb0ef41Sopenharmony_ci if (IsBackedge(node, i)) { 2331cb0ef41Sopenharmony_ci // Only propagate the loop mark on backedges. 2341cb0ef41Sopenharmony_ci if (SetBackwardMark(input, loop_num) || 2351cb0ef41Sopenharmony_ci !info(input).backwards_visited) { 2361cb0ef41Sopenharmony_ci Queue(input); 2371cb0ef41Sopenharmony_ci } 2381cb0ef41Sopenharmony_ci } else { 2391cb0ef41Sopenharmony_ci // Entry or normal edge. Propagate all marks except loop_num. 2401cb0ef41Sopenharmony_ci // TODO(manoskouk): Add test that needs backwards_visited to function 2411cb0ef41Sopenharmony_ci // correctly, probably using wasm loop unrolling when it is available. 2421cb0ef41Sopenharmony_ci if (PropagateBackwardMarks(node, input, loop_num) || 2431cb0ef41Sopenharmony_ci !info(input).backwards_visited) { 2441cb0ef41Sopenharmony_ci Queue(input); 2451cb0ef41Sopenharmony_ci } 2461cb0ef41Sopenharmony_ci } 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci } 2491cb0ef41Sopenharmony_ci } 2501cb0ef41Sopenharmony_ci 2511cb0ef41Sopenharmony_ci // Make a new loop if necessary for the given node. 2521cb0ef41Sopenharmony_ci int CreateLoopInfo(Node* node) { 2531cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kLoop, node->opcode()); 2541cb0ef41Sopenharmony_ci int loop_num = LoopNum(node); 2551cb0ef41Sopenharmony_ci if (loop_num > 0) return loop_num; 2561cb0ef41Sopenharmony_ci 2571cb0ef41Sopenharmony_ci loop_num = ++loops_found_; 2581cb0ef41Sopenharmony_ci if (INDEX(loop_num) >= width_) ResizeBackwardMarks(); 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci // Create a new loop. 2611cb0ef41Sopenharmony_ci loops_.push_back({node, nullptr, nullptr, nullptr, nullptr}); 2621cb0ef41Sopenharmony_ci loop_tree_->NewLoop(); 2631cb0ef41Sopenharmony_ci SetLoopMarkForLoopHeader(node, loop_num); 2641cb0ef41Sopenharmony_ci return loop_num; 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci void SetLoopMark(Node* node, int loop_num) { 2681cb0ef41Sopenharmony_ci info(node); // create the NodeInfo 2691cb0ef41Sopenharmony_ci SetBackwardMark(node, loop_num); 2701cb0ef41Sopenharmony_ci loop_tree_->node_to_loop_num_[node->id()] = loop_num; 2711cb0ef41Sopenharmony_ci } 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci void SetLoopMarkForLoopHeader(Node* node, int loop_num) { 2741cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kLoop, node->opcode()); 2751cb0ef41Sopenharmony_ci SetLoopMark(node, loop_num); 2761cb0ef41Sopenharmony_ci for (Node* use : node->uses()) { 2771cb0ef41Sopenharmony_ci if (NodeProperties::IsPhi(use)) { 2781cb0ef41Sopenharmony_ci SetLoopMark(use, loop_num); 2791cb0ef41Sopenharmony_ci } 2801cb0ef41Sopenharmony_ci 2811cb0ef41Sopenharmony_ci // Do not keep the loop alive if it does not have any backedges. 2821cb0ef41Sopenharmony_ci if (node->InputCount() <= 1) continue; 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci if (use->opcode() == IrOpcode::kLoopExit) { 2851cb0ef41Sopenharmony_ci SetLoopMark(use, loop_num); 2861cb0ef41Sopenharmony_ci for (Node* exit_use : use->uses()) { 2871cb0ef41Sopenharmony_ci if (exit_use->opcode() == IrOpcode::kLoopExitValue || 2881cb0ef41Sopenharmony_ci exit_use->opcode() == IrOpcode::kLoopExitEffect) { 2891cb0ef41Sopenharmony_ci SetLoopMark(exit_use, loop_num); 2901cb0ef41Sopenharmony_ci } 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci } 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci 2961cb0ef41Sopenharmony_ci void ResizeBackwardMarks() { 2971cb0ef41Sopenharmony_ci int new_width = width_ + 1; 2981cb0ef41Sopenharmony_ci int max = num_nodes(); 2991cb0ef41Sopenharmony_ci uint32_t* new_backward = zone_->NewArray<uint32_t>(new_width * max); 3001cb0ef41Sopenharmony_ci memset(new_backward, 0, new_width * max * sizeof(uint32_t)); 3011cb0ef41Sopenharmony_ci if (width_ > 0) { // copy old matrix data. 3021cb0ef41Sopenharmony_ci for (int i = 0; i < max; i++) { 3031cb0ef41Sopenharmony_ci uint32_t* np = &new_backward[i * new_width]; 3041cb0ef41Sopenharmony_ci uint32_t* op = &backward_[i * width_]; 3051cb0ef41Sopenharmony_ci for (int j = 0; j < width_; j++) np[j] = op[j]; 3061cb0ef41Sopenharmony_ci } 3071cb0ef41Sopenharmony_ci } 3081cb0ef41Sopenharmony_ci width_ = new_width; 3091cb0ef41Sopenharmony_ci backward_ = new_backward; 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci void ResizeForwardMarks() { 3131cb0ef41Sopenharmony_ci int max = num_nodes(); 3141cb0ef41Sopenharmony_ci forward_ = zone_->NewArray<uint32_t>(width_ * max); 3151cb0ef41Sopenharmony_ci memset(forward_, 0, width_ * max * sizeof(uint32_t)); 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci 3181cb0ef41Sopenharmony_ci // Propagate marks forward from loops. 3191cb0ef41Sopenharmony_ci void PropagateForward() { 3201cb0ef41Sopenharmony_ci ResizeForwardMarks(); 3211cb0ef41Sopenharmony_ci for (TempLoopInfo& li : loops_) { 3221cb0ef41Sopenharmony_ci SetForwardMark(li.header, LoopNum(li.header)); 3231cb0ef41Sopenharmony_ci Queue(li.header); 3241cb0ef41Sopenharmony_ci } 3251cb0ef41Sopenharmony_ci // Propagate forward on paths that were backward reachable from backedges. 3261cb0ef41Sopenharmony_ci while (!queue_.empty()) { 3271cb0ef41Sopenharmony_ci tick_counter_->TickAndMaybeEnterSafepoint(); 3281cb0ef41Sopenharmony_ci Node* node = queue_.front(); 3291cb0ef41Sopenharmony_ci queue_.pop_front(); 3301cb0ef41Sopenharmony_ci queued_.Set(node, false); 3311cb0ef41Sopenharmony_ci for (Edge edge : node->use_edges()) { 3321cb0ef41Sopenharmony_ci Node* use = edge.from(); 3331cb0ef41Sopenharmony_ci if (!IsBackedge(use, edge.index())) { 3341cb0ef41Sopenharmony_ci if (PropagateForwardMarks(node, use)) Queue(use); 3351cb0ef41Sopenharmony_ci } 3361cb0ef41Sopenharmony_ci } 3371cb0ef41Sopenharmony_ci } 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci 3401cb0ef41Sopenharmony_ci bool IsLoopHeaderNode(Node* node) { 3411cb0ef41Sopenharmony_ci return node->opcode() == IrOpcode::kLoop || NodeProperties::IsPhi(node); 3421cb0ef41Sopenharmony_ci } 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_ci bool IsLoopExitNode(Node* node) { 3451cb0ef41Sopenharmony_ci return node->opcode() == IrOpcode::kLoopExit || 3461cb0ef41Sopenharmony_ci node->opcode() == IrOpcode::kLoopExitValue || 3471cb0ef41Sopenharmony_ci node->opcode() == IrOpcode::kLoopExitEffect; 3481cb0ef41Sopenharmony_ci } 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci bool IsBackedge(Node* use, int index) { 3511cb0ef41Sopenharmony_ci if (LoopNum(use) <= 0) return false; 3521cb0ef41Sopenharmony_ci if (NodeProperties::IsPhi(use)) { 3531cb0ef41Sopenharmony_ci return index != NodeProperties::FirstControlIndex(use) && 3541cb0ef41Sopenharmony_ci index != kAssumedLoopEntryIndex; 3551cb0ef41Sopenharmony_ci } else if (use->opcode() == IrOpcode::kLoop) { 3561cb0ef41Sopenharmony_ci return index != kAssumedLoopEntryIndex; 3571cb0ef41Sopenharmony_ci } 3581cb0ef41Sopenharmony_ci DCHECK(IsLoopExitNode(use)); 3591cb0ef41Sopenharmony_ci return false; 3601cb0ef41Sopenharmony_ci } 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_ci int LoopNum(Node* node) { return loop_tree_->node_to_loop_num_[node->id()]; } 3631cb0ef41Sopenharmony_ci 3641cb0ef41Sopenharmony_ci NodeInfo& info(Node* node) { 3651cb0ef41Sopenharmony_ci NodeInfo& i = info_[node->id()]; 3661cb0ef41Sopenharmony_ci if (i.node == nullptr) i.node = node; 3671cb0ef41Sopenharmony_ci return i; 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci 3701cb0ef41Sopenharmony_ci void Queue(Node* node) { 3711cb0ef41Sopenharmony_ci if (!queued_.Get(node)) { 3721cb0ef41Sopenharmony_ci queue_.push_back(node); 3731cb0ef41Sopenharmony_ci queued_.Set(node, true); 3741cb0ef41Sopenharmony_ci } 3751cb0ef41Sopenharmony_ci } 3761cb0ef41Sopenharmony_ci 3771cb0ef41Sopenharmony_ci void AddNodeToLoop(NodeInfo* node_info, TempLoopInfo* loop, int loop_num) { 3781cb0ef41Sopenharmony_ci if (LoopNum(node_info->node) == loop_num) { 3791cb0ef41Sopenharmony_ci if (IsLoopHeaderNode(node_info->node)) { 3801cb0ef41Sopenharmony_ci node_info->next = loop->header_list; 3811cb0ef41Sopenharmony_ci loop->header_list = node_info; 3821cb0ef41Sopenharmony_ci } else { 3831cb0ef41Sopenharmony_ci DCHECK(IsLoopExitNode(node_info->node)); 3841cb0ef41Sopenharmony_ci node_info->next = loop->exit_list; 3851cb0ef41Sopenharmony_ci loop->exit_list = node_info; 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci } else { 3881cb0ef41Sopenharmony_ci node_info->next = loop->body_list; 3891cb0ef41Sopenharmony_ci loop->body_list = node_info; 3901cb0ef41Sopenharmony_ci } 3911cb0ef41Sopenharmony_ci } 3921cb0ef41Sopenharmony_ci 3931cb0ef41Sopenharmony_ci void FinishLoopTree() { 3941cb0ef41Sopenharmony_ci DCHECK(loops_found_ == static_cast<int>(loops_.size())); 3951cb0ef41Sopenharmony_ci DCHECK(loops_found_ == static_cast<int>(loop_tree_->all_loops_.size())); 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci // Degenerate cases. 3981cb0ef41Sopenharmony_ci if (loops_found_ == 0) return; 3991cb0ef41Sopenharmony_ci if (loops_found_ == 1) return FinishSingleLoop(); 4001cb0ef41Sopenharmony_ci 4011cb0ef41Sopenharmony_ci for (int i = 1; i <= loops_found_; i++) ConnectLoopTree(i); 4021cb0ef41Sopenharmony_ci 4031cb0ef41Sopenharmony_ci size_t count = 0; 4041cb0ef41Sopenharmony_ci // Place the node into the innermost nested loop of which it is a member. 4051cb0ef41Sopenharmony_ci for (NodeInfo& ni : info_) { 4061cb0ef41Sopenharmony_ci if (ni.node == nullptr) continue; 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci TempLoopInfo* innermost = nullptr; 4091cb0ef41Sopenharmony_ci int innermost_index = 0; 4101cb0ef41Sopenharmony_ci int pos = ni.node->id() * width_; 4111cb0ef41Sopenharmony_ci // Search the marks word by word. 4121cb0ef41Sopenharmony_ci for (int i = 0; i < width_; i++) { 4131cb0ef41Sopenharmony_ci uint32_t marks = backward_[pos + i] & forward_[pos + i]; 4141cb0ef41Sopenharmony_ci 4151cb0ef41Sopenharmony_ci for (int j = 0; j < 32; j++) { 4161cb0ef41Sopenharmony_ci if (marks & (1u << j)) { 4171cb0ef41Sopenharmony_ci int loop_num = i * 32 + j; 4181cb0ef41Sopenharmony_ci if (loop_num == 0) continue; 4191cb0ef41Sopenharmony_ci TempLoopInfo* loop = &loops_[loop_num - 1]; 4201cb0ef41Sopenharmony_ci if (innermost == nullptr || 4211cb0ef41Sopenharmony_ci loop->loop->depth_ > innermost->loop->depth_) { 4221cb0ef41Sopenharmony_ci innermost = loop; 4231cb0ef41Sopenharmony_ci innermost_index = loop_num; 4241cb0ef41Sopenharmony_ci } 4251cb0ef41Sopenharmony_ci } 4261cb0ef41Sopenharmony_ci } 4271cb0ef41Sopenharmony_ci } 4281cb0ef41Sopenharmony_ci if (innermost == nullptr) continue; 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ci // Return statements should never be found by forward or backward walk. 4311cb0ef41Sopenharmony_ci CHECK(ni.node->opcode() != IrOpcode::kReturn); 4321cb0ef41Sopenharmony_ci 4331cb0ef41Sopenharmony_ci AddNodeToLoop(&ni, innermost, innermost_index); 4341cb0ef41Sopenharmony_ci count++; 4351cb0ef41Sopenharmony_ci } 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci // Serialize the node lists for loops into the loop tree. 4381cb0ef41Sopenharmony_ci loop_tree_->loop_nodes_.reserve(count); 4391cb0ef41Sopenharmony_ci for (LoopTree::Loop* loop : loop_tree_->outer_loops_) { 4401cb0ef41Sopenharmony_ci SerializeLoop(loop); 4411cb0ef41Sopenharmony_ci } 4421cb0ef41Sopenharmony_ci } 4431cb0ef41Sopenharmony_ci 4441cb0ef41Sopenharmony_ci // Handle the simpler case of a single loop (no checks for nesting necessary). 4451cb0ef41Sopenharmony_ci void FinishSingleLoop() { 4461cb0ef41Sopenharmony_ci // Place nodes into the loop header and body. 4471cb0ef41Sopenharmony_ci TempLoopInfo* li = &loops_[0]; 4481cb0ef41Sopenharmony_ci li->loop = &loop_tree_->all_loops_[0]; 4491cb0ef41Sopenharmony_ci loop_tree_->SetParent(nullptr, li->loop); 4501cb0ef41Sopenharmony_ci size_t count = 0; 4511cb0ef41Sopenharmony_ci for (NodeInfo& ni : info_) { 4521cb0ef41Sopenharmony_ci if (ni.node == nullptr || !IsInLoop(ni.node, 1)) continue; 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci // Return statements should never be found by forward or backward walk. 4551cb0ef41Sopenharmony_ci CHECK(ni.node->opcode() != IrOpcode::kReturn); 4561cb0ef41Sopenharmony_ci 4571cb0ef41Sopenharmony_ci AddNodeToLoop(&ni, li, 1); 4581cb0ef41Sopenharmony_ci count++; 4591cb0ef41Sopenharmony_ci } 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ci // Serialize the node lists for the loop into the loop tree. 4621cb0ef41Sopenharmony_ci loop_tree_->loop_nodes_.reserve(count); 4631cb0ef41Sopenharmony_ci SerializeLoop(li->loop); 4641cb0ef41Sopenharmony_ci } 4651cb0ef41Sopenharmony_ci 4661cb0ef41Sopenharmony_ci // Recursively serialize the list of header nodes and body nodes 4671cb0ef41Sopenharmony_ci // so that nested loops occupy nested intervals. 4681cb0ef41Sopenharmony_ci void SerializeLoop(LoopTree::Loop* loop) { 4691cb0ef41Sopenharmony_ci int loop_num = loop_tree_->LoopNum(loop); 4701cb0ef41Sopenharmony_ci TempLoopInfo& li = loops_[loop_num - 1]; 4711cb0ef41Sopenharmony_ci 4721cb0ef41Sopenharmony_ci // Serialize the header. 4731cb0ef41Sopenharmony_ci loop->header_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); 4741cb0ef41Sopenharmony_ci for (NodeInfo* ni = li.header_list; ni != nullptr; ni = ni->next) { 4751cb0ef41Sopenharmony_ci loop_tree_->loop_nodes_.push_back(ni->node); 4761cb0ef41Sopenharmony_ci loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num; 4771cb0ef41Sopenharmony_ci } 4781cb0ef41Sopenharmony_ci 4791cb0ef41Sopenharmony_ci // Serialize the body. 4801cb0ef41Sopenharmony_ci loop->body_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); 4811cb0ef41Sopenharmony_ci for (NodeInfo* ni = li.body_list; ni != nullptr; ni = ni->next) { 4821cb0ef41Sopenharmony_ci loop_tree_->loop_nodes_.push_back(ni->node); 4831cb0ef41Sopenharmony_ci loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num; 4841cb0ef41Sopenharmony_ci } 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ci // Serialize nested loops. 4871cb0ef41Sopenharmony_ci for (LoopTree::Loop* child : loop->children_) SerializeLoop(child); 4881cb0ef41Sopenharmony_ci 4891cb0ef41Sopenharmony_ci // Serialize the exits. 4901cb0ef41Sopenharmony_ci loop->exits_start_ = static_cast<int>(loop_tree_->loop_nodes_.size()); 4911cb0ef41Sopenharmony_ci for (NodeInfo* ni = li.exit_list; ni != nullptr; ni = ni->next) { 4921cb0ef41Sopenharmony_ci loop_tree_->loop_nodes_.push_back(ni->node); 4931cb0ef41Sopenharmony_ci loop_tree_->node_to_loop_num_[ni->node->id()] = loop_num; 4941cb0ef41Sopenharmony_ci } 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci loop->exits_end_ = static_cast<int>(loop_tree_->loop_nodes_.size()); 4971cb0ef41Sopenharmony_ci } 4981cb0ef41Sopenharmony_ci 4991cb0ef41Sopenharmony_ci // Connect the LoopTree loops to their parents recursively. 5001cb0ef41Sopenharmony_ci LoopTree::Loop* ConnectLoopTree(int loop_num) { 5011cb0ef41Sopenharmony_ci TempLoopInfo& li = loops_[loop_num - 1]; 5021cb0ef41Sopenharmony_ci if (li.loop != nullptr) return li.loop; 5031cb0ef41Sopenharmony_ci 5041cb0ef41Sopenharmony_ci NodeInfo& ni = info(li.header); 5051cb0ef41Sopenharmony_ci LoopTree::Loop* parent = nullptr; 5061cb0ef41Sopenharmony_ci for (int i = 1; i <= loops_found_; i++) { 5071cb0ef41Sopenharmony_ci if (i == loop_num) continue; 5081cb0ef41Sopenharmony_ci if (IsInLoop(ni.node, i)) { 5091cb0ef41Sopenharmony_ci // recursively create potential parent loops first. 5101cb0ef41Sopenharmony_ci LoopTree::Loop* upper = ConnectLoopTree(i); 5111cb0ef41Sopenharmony_ci if (parent == nullptr || upper->depth_ > parent->depth_) { 5121cb0ef41Sopenharmony_ci parent = upper; 5131cb0ef41Sopenharmony_ci } 5141cb0ef41Sopenharmony_ci } 5151cb0ef41Sopenharmony_ci } 5161cb0ef41Sopenharmony_ci li.loop = &loop_tree_->all_loops_[loop_num - 1]; 5171cb0ef41Sopenharmony_ci loop_tree_->SetParent(parent, li.loop); 5181cb0ef41Sopenharmony_ci return li.loop; 5191cb0ef41Sopenharmony_ci } 5201cb0ef41Sopenharmony_ci 5211cb0ef41Sopenharmony_ci void PrintLoop(LoopTree::Loop* loop) { 5221cb0ef41Sopenharmony_ci for (int i = 0; i < loop->depth_; i++) PrintF(" "); 5231cb0ef41Sopenharmony_ci PrintF("Loop depth = %d ", loop->depth_); 5241cb0ef41Sopenharmony_ci int i = loop->header_start_; 5251cb0ef41Sopenharmony_ci while (i < loop->body_start_) { 5261cb0ef41Sopenharmony_ci PrintF(" H#%d", loop_tree_->loop_nodes_[i++]->id()); 5271cb0ef41Sopenharmony_ci } 5281cb0ef41Sopenharmony_ci while (i < loop->exits_start_) { 5291cb0ef41Sopenharmony_ci PrintF(" B#%d", loop_tree_->loop_nodes_[i++]->id()); 5301cb0ef41Sopenharmony_ci } 5311cb0ef41Sopenharmony_ci while (i < loop->exits_end_) { 5321cb0ef41Sopenharmony_ci PrintF(" E#%d", loop_tree_->loop_nodes_[i++]->id()); 5331cb0ef41Sopenharmony_ci } 5341cb0ef41Sopenharmony_ci PrintF("\n"); 5351cb0ef41Sopenharmony_ci for (LoopTree::Loop* child : loop->children_) PrintLoop(child); 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci}; 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_ciLoopTree* LoopFinder::BuildLoopTree(Graph* graph, TickCounter* tick_counter, 5401cb0ef41Sopenharmony_ci Zone* zone) { 5411cb0ef41Sopenharmony_ci LoopTree* loop_tree = 5421cb0ef41Sopenharmony_ci graph->zone()->New<LoopTree>(graph->NodeCount(), graph->zone()); 5431cb0ef41Sopenharmony_ci LoopFinderImpl finder(graph, loop_tree, tick_counter, zone); 5441cb0ef41Sopenharmony_ci finder.Run(); 5451cb0ef41Sopenharmony_ci if (FLAG_trace_turbo_loop) { 5461cb0ef41Sopenharmony_ci finder.Print(); 5471cb0ef41Sopenharmony_ci } 5481cb0ef41Sopenharmony_ci return loop_tree; 5491cb0ef41Sopenharmony_ci} 5501cb0ef41Sopenharmony_ci 5511cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY 5521cb0ef41Sopenharmony_ci// static 5531cb0ef41Sopenharmony_ciZoneUnorderedSet<Node*>* LoopFinder::FindSmallInnermostLoopFromHeader( 5541cb0ef41Sopenharmony_ci Node* loop_header, Zone* zone, size_t max_size, bool calls_are_large) { 5551cb0ef41Sopenharmony_ci auto* visited = zone->New<ZoneUnorderedSet<Node*>>(zone); 5561cb0ef41Sopenharmony_ci std::vector<Node*> queue; 5571cb0ef41Sopenharmony_ci 5581cb0ef41Sopenharmony_ci DCHECK_EQ(loop_header->opcode(), IrOpcode::kLoop); 5591cb0ef41Sopenharmony_ci 5601cb0ef41Sopenharmony_ci queue.push_back(loop_header); 5611cb0ef41Sopenharmony_ci 5621cb0ef41Sopenharmony_ci#define ENQUEUE_USES(use_name, condition) \ 5631cb0ef41Sopenharmony_ci for (Node * use_name : node->uses()) { \ 5641cb0ef41Sopenharmony_ci if (condition && visited->count(use_name) == 0) queue.push_back(use_name); \ 5651cb0ef41Sopenharmony_ci } 5661cb0ef41Sopenharmony_ci 5671cb0ef41Sopenharmony_ci while (!queue.empty()) { 5681cb0ef41Sopenharmony_ci Node* node = queue.back(); 5691cb0ef41Sopenharmony_ci queue.pop_back(); 5701cb0ef41Sopenharmony_ci if (node->opcode() == IrOpcode::kEnd) { 5711cb0ef41Sopenharmony_ci // We reached the end of the graph. The end node is not part of the loop. 5721cb0ef41Sopenharmony_ci continue; 5731cb0ef41Sopenharmony_ci } 5741cb0ef41Sopenharmony_ci visited->insert(node); 5751cb0ef41Sopenharmony_ci if (visited->size() > max_size) return nullptr; 5761cb0ef41Sopenharmony_ci switch (node->opcode()) { 5771cb0ef41Sopenharmony_ci case IrOpcode::kLoop: 5781cb0ef41Sopenharmony_ci // Found nested loop. 5791cb0ef41Sopenharmony_ci if (node != loop_header) return nullptr; 5801cb0ef41Sopenharmony_ci ENQUEUE_USES(use, true); 5811cb0ef41Sopenharmony_ci break; 5821cb0ef41Sopenharmony_ci case IrOpcode::kLoopExit: 5831cb0ef41Sopenharmony_ci // Found nested loop. 5841cb0ef41Sopenharmony_ci if (node->InputAt(1) != loop_header) return nullptr; 5851cb0ef41Sopenharmony_ci // LoopExitValue/Effect uses are inside the loop. The rest are not. 5861cb0ef41Sopenharmony_ci ENQUEUE_USES(use, (use->opcode() == IrOpcode::kLoopExitEffect || 5871cb0ef41Sopenharmony_ci use->opcode() == IrOpcode::kLoopExitValue)) 5881cb0ef41Sopenharmony_ci break; 5891cb0ef41Sopenharmony_ci case IrOpcode::kLoopExitEffect: 5901cb0ef41Sopenharmony_ci case IrOpcode::kLoopExitValue: 5911cb0ef41Sopenharmony_ci if (NodeProperties::GetControlInput(node)->InputAt(1) != loop_header) { 5921cb0ef41Sopenharmony_ci // Found nested loop. 5931cb0ef41Sopenharmony_ci return nullptr; 5941cb0ef41Sopenharmony_ci } 5951cb0ef41Sopenharmony_ci // All uses are outside the loop, do nothing. 5961cb0ef41Sopenharmony_ci break; 5971cb0ef41Sopenharmony_ci // If {calls_are_large}, call nodes are considered to have unbounded size, 5981cb0ef41Sopenharmony_ci // i.e. >max_size, with the exception of certain wasm builtins. 5991cb0ef41Sopenharmony_ci case IrOpcode::kTailCall: 6001cb0ef41Sopenharmony_ci case IrOpcode::kJSWasmCall: 6011cb0ef41Sopenharmony_ci case IrOpcode::kJSCall: 6021cb0ef41Sopenharmony_ci if (calls_are_large) return nullptr; 6031cb0ef41Sopenharmony_ci ENQUEUE_USES(use, true) 6041cb0ef41Sopenharmony_ci break; 6051cb0ef41Sopenharmony_ci case IrOpcode::kCall: { 6061cb0ef41Sopenharmony_ci if (!calls_are_large) { 6071cb0ef41Sopenharmony_ci ENQUEUE_USES(use, true); 6081cb0ef41Sopenharmony_ci break; 6091cb0ef41Sopenharmony_ci } 6101cb0ef41Sopenharmony_ci Node* callee = node->InputAt(0); 6111cb0ef41Sopenharmony_ci if (callee->opcode() != IrOpcode::kRelocatableInt32Constant && 6121cb0ef41Sopenharmony_ci callee->opcode() != IrOpcode::kRelocatableInt64Constant) { 6131cb0ef41Sopenharmony_ci return nullptr; 6141cb0ef41Sopenharmony_ci } 6151cb0ef41Sopenharmony_ci intptr_t info = 6161cb0ef41Sopenharmony_ci OpParameter<RelocatablePtrConstantInfo>(callee->op()).value(); 6171cb0ef41Sopenharmony_ci using WasmCode = v8::internal::wasm::WasmCode; 6181cb0ef41Sopenharmony_ci constexpr intptr_t unrollable_builtins[] = { 6191cb0ef41Sopenharmony_ci // Exists in every stack check. 6201cb0ef41Sopenharmony_ci WasmCode::kWasmStackGuard, 6211cb0ef41Sopenharmony_ci // Fast table operations. 6221cb0ef41Sopenharmony_ci WasmCode::kWasmTableGet, WasmCode::kWasmTableSet, 6231cb0ef41Sopenharmony_ci WasmCode::kWasmTableGrow, 6241cb0ef41Sopenharmony_ci // Atomics. 6251cb0ef41Sopenharmony_ci WasmCode::kWasmAtomicNotify, WasmCode::kWasmI32AtomicWait32, 6261cb0ef41Sopenharmony_ci WasmCode::kWasmI32AtomicWait64, WasmCode::kWasmI64AtomicWait32, 6271cb0ef41Sopenharmony_ci WasmCode::kWasmI64AtomicWait64, 6281cb0ef41Sopenharmony_ci // Exceptions. 6291cb0ef41Sopenharmony_ci WasmCode::kWasmAllocateFixedArray, WasmCode::kWasmThrow, 6301cb0ef41Sopenharmony_ci WasmCode::kWasmRethrow, WasmCode::kWasmRethrowExplicitContext, 6311cb0ef41Sopenharmony_ci // Fast wasm-gc operations. 6321cb0ef41Sopenharmony_ci WasmCode::kWasmRefFunc}; 6331cb0ef41Sopenharmony_ci if (std::count(unrollable_builtins, 6341cb0ef41Sopenharmony_ci unrollable_builtins + arraysize(unrollable_builtins), 6351cb0ef41Sopenharmony_ci info) == 0) { 6361cb0ef41Sopenharmony_ci return nullptr; 6371cb0ef41Sopenharmony_ci } 6381cb0ef41Sopenharmony_ci ENQUEUE_USES(use, true) 6391cb0ef41Sopenharmony_ci break; 6401cb0ef41Sopenharmony_ci } 6411cb0ef41Sopenharmony_ci default: 6421cb0ef41Sopenharmony_ci ENQUEUE_USES(use, true) 6431cb0ef41Sopenharmony_ci break; 6441cb0ef41Sopenharmony_ci } 6451cb0ef41Sopenharmony_ci } 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci // Check that there is no floating control other than direct nodes to start(). 6481cb0ef41Sopenharmony_ci // We do this by checking that all non-start control inputs of loop nodes are 6491cb0ef41Sopenharmony_ci // also in the loop. 6501cb0ef41Sopenharmony_ci // TODO(manoskouk): This is a safety check. Consider making it DEBUG-only when 6511cb0ef41Sopenharmony_ci // we are confident there is no incompatible floating control generated in 6521cb0ef41Sopenharmony_ci // wasm. 6531cb0ef41Sopenharmony_ci for (Node* node : *visited) { 6541cb0ef41Sopenharmony_ci // The loop header is allowed to point outside the loop. 6551cb0ef41Sopenharmony_ci if (node == loop_header) continue; 6561cb0ef41Sopenharmony_ci 6571cb0ef41Sopenharmony_ci for (Edge edge : node->input_edges()) { 6581cb0ef41Sopenharmony_ci Node* input = edge.to(); 6591cb0ef41Sopenharmony_ci if (NodeProperties::IsControlEdge(edge) && visited->count(input) == 0 && 6601cb0ef41Sopenharmony_ci input->opcode() != IrOpcode::kStart) { 6611cb0ef41Sopenharmony_ci FATAL( 6621cb0ef41Sopenharmony_ci "Floating control detected in wasm turbofan graph: Node #%d:%s is " 6631cb0ef41Sopenharmony_ci "inside loop headed by #%d, but its control dependency #%d:%s is " 6641cb0ef41Sopenharmony_ci "outside", 6651cb0ef41Sopenharmony_ci node->id(), node->op()->mnemonic(), loop_header->id(), input->id(), 6661cb0ef41Sopenharmony_ci input->op()->mnemonic()); 6671cb0ef41Sopenharmony_ci } 6681cb0ef41Sopenharmony_ci } 6691cb0ef41Sopenharmony_ci } 6701cb0ef41Sopenharmony_ci 6711cb0ef41Sopenharmony_ci return visited; 6721cb0ef41Sopenharmony_ci} 6731cb0ef41Sopenharmony_ci#endif // V8_ENABLE_WEBASSEMBLY 6741cb0ef41Sopenharmony_ci 6751cb0ef41Sopenharmony_cibool LoopFinder::HasMarkedExits(LoopTree* loop_tree, 6761cb0ef41Sopenharmony_ci const LoopTree::Loop* loop) { 6771cb0ef41Sopenharmony_ci // Look for returns and if projections that are outside the loop but whose 6781cb0ef41Sopenharmony_ci // control input is inside the loop. 6791cb0ef41Sopenharmony_ci Node* loop_node = loop_tree->GetLoopControl(loop); 6801cb0ef41Sopenharmony_ci for (Node* node : loop_tree->LoopNodes(loop)) { 6811cb0ef41Sopenharmony_ci for (Node* use : node->uses()) { 6821cb0ef41Sopenharmony_ci if (!loop_tree->Contains(loop, use)) { 6831cb0ef41Sopenharmony_ci bool unmarked_exit; 6841cb0ef41Sopenharmony_ci switch (node->opcode()) { 6851cb0ef41Sopenharmony_ci case IrOpcode::kLoopExit: 6861cb0ef41Sopenharmony_ci unmarked_exit = (node->InputAt(1) != loop_node); 6871cb0ef41Sopenharmony_ci break; 6881cb0ef41Sopenharmony_ci case IrOpcode::kLoopExitValue: 6891cb0ef41Sopenharmony_ci case IrOpcode::kLoopExitEffect: 6901cb0ef41Sopenharmony_ci unmarked_exit = (node->InputAt(1)->InputAt(1) != loop_node); 6911cb0ef41Sopenharmony_ci break; 6921cb0ef41Sopenharmony_ci default: 6931cb0ef41Sopenharmony_ci unmarked_exit = (use->opcode() != IrOpcode::kTerminate); 6941cb0ef41Sopenharmony_ci } 6951cb0ef41Sopenharmony_ci if (unmarked_exit) { 6961cb0ef41Sopenharmony_ci if (FLAG_trace_turbo_loop) { 6971cb0ef41Sopenharmony_ci PrintF( 6981cb0ef41Sopenharmony_ci "Cannot peel loop %i. Loop exit without explicit mark: Node %i " 6991cb0ef41Sopenharmony_ci "(%s) is inside loop, but its use %i (%s) is outside.\n", 7001cb0ef41Sopenharmony_ci loop_node->id(), node->id(), node->op()->mnemonic(), use->id(), 7011cb0ef41Sopenharmony_ci use->op()->mnemonic()); 7021cb0ef41Sopenharmony_ci } 7031cb0ef41Sopenharmony_ci return false; 7041cb0ef41Sopenharmony_ci } 7051cb0ef41Sopenharmony_ci } 7061cb0ef41Sopenharmony_ci } 7071cb0ef41Sopenharmony_ci } 7081cb0ef41Sopenharmony_ci return true; 7091cb0ef41Sopenharmony_ci} 7101cb0ef41Sopenharmony_ci 7111cb0ef41Sopenharmony_ciNode* LoopTree::HeaderNode(const Loop* loop) { 7121cb0ef41Sopenharmony_ci Node* first = *HeaderNodes(loop).begin(); 7131cb0ef41Sopenharmony_ci if (first->opcode() == IrOpcode::kLoop) return first; 7141cb0ef41Sopenharmony_ci DCHECK(IrOpcode::IsPhiOpcode(first->opcode())); 7151cb0ef41Sopenharmony_ci Node* header = NodeProperties::GetControlInput(first); 7161cb0ef41Sopenharmony_ci DCHECK_EQ(IrOpcode::kLoop, header->opcode()); 7171cb0ef41Sopenharmony_ci return header; 7181cb0ef41Sopenharmony_ci} 7191cb0ef41Sopenharmony_ci 7201cb0ef41Sopenharmony_ciNode* NodeCopier::map(Node* node, uint32_t copy_index) { 7211cb0ef41Sopenharmony_ci DCHECK_LT(copy_index, copy_count_); 7221cb0ef41Sopenharmony_ci if (node_map_.Get(node) == 0) return node; 7231cb0ef41Sopenharmony_ci return copies_->at(node_map_.Get(node) + copy_index); 7241cb0ef41Sopenharmony_ci} 7251cb0ef41Sopenharmony_ci 7261cb0ef41Sopenharmony_civoid NodeCopier::Insert(Node* original, const NodeVector& new_copies) { 7271cb0ef41Sopenharmony_ci DCHECK_EQ(new_copies.size(), copy_count_); 7281cb0ef41Sopenharmony_ci node_map_.Set(original, copies_->size() + 1); 7291cb0ef41Sopenharmony_ci copies_->push_back(original); 7301cb0ef41Sopenharmony_ci copies_->insert(copies_->end(), new_copies.begin(), new_copies.end()); 7311cb0ef41Sopenharmony_ci} 7321cb0ef41Sopenharmony_ci 7331cb0ef41Sopenharmony_civoid NodeCopier::Insert(Node* original, Node* copy) { 7341cb0ef41Sopenharmony_ci DCHECK_EQ(copy_count_, 1); 7351cb0ef41Sopenharmony_ci node_map_.Set(original, copies_->size() + 1); 7361cb0ef41Sopenharmony_ci copies_->push_back(original); 7371cb0ef41Sopenharmony_ci copies_->push_back(copy); 7381cb0ef41Sopenharmony_ci} 7391cb0ef41Sopenharmony_ci 7401cb0ef41Sopenharmony_ci} // namespace compiler 7411cb0ef41Sopenharmony_ci} // namespace internal 7421cb0ef41Sopenharmony_ci} // namespace v8 743