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