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#ifndef V8_COMPILER_LOOP_ANALYSIS_H_
61cb0ef41Sopenharmony_ci#define V8_COMPILER_LOOP_ANALYSIS_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/base/iterator.h"
91cb0ef41Sopenharmony_ci#include "src/common/globals.h"
101cb0ef41Sopenharmony_ci#include "src/compiler/compiler-source-position-table.h"
111cb0ef41Sopenharmony_ci#include "src/compiler/graph.h"
121cb0ef41Sopenharmony_ci#include "src/compiler/node-marker.h"
131cb0ef41Sopenharmony_ci#include "src/compiler/node-origin-table.h"
141cb0ef41Sopenharmony_ci#include "src/compiler/node-properties.h"
151cb0ef41Sopenharmony_ci#include "src/compiler/node.h"
161cb0ef41Sopenharmony_ci#include "src/zone/zone-containers.h"
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_cinamespace v8 {
191cb0ef41Sopenharmony_cinamespace internal {
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ciclass TickCounter;
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cinamespace compiler {
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci// TODO(titzer): don't assume entry edges have a particular index.
261cb0ef41Sopenharmony_cistatic const int kAssumedLoopEntryIndex = 0;  // assume loops are entered here.
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ciclass LoopFinderImpl;
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ciusing NodeRange = base::iterator_range<Node**>;
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci// Represents a tree of loops in a graph.
331cb0ef41Sopenharmony_ciclass LoopTree : public ZoneObject {
341cb0ef41Sopenharmony_ci public:
351cb0ef41Sopenharmony_ci  LoopTree(size_t num_nodes, Zone* zone)
361cb0ef41Sopenharmony_ci      : zone_(zone),
371cb0ef41Sopenharmony_ci        outer_loops_(zone),
381cb0ef41Sopenharmony_ci        all_loops_(zone),
391cb0ef41Sopenharmony_ci        node_to_loop_num_(static_cast<int>(num_nodes), -1, zone),
401cb0ef41Sopenharmony_ci        loop_nodes_(zone) {}
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  // Represents a loop in the tree of loops, including the header nodes,
431cb0ef41Sopenharmony_ci  // the body, and any nested loops.
441cb0ef41Sopenharmony_ci  class Loop {
451cb0ef41Sopenharmony_ci   public:
461cb0ef41Sopenharmony_ci    Loop* parent() const { return parent_; }
471cb0ef41Sopenharmony_ci    const ZoneVector<Loop*>& children() const { return children_; }
481cb0ef41Sopenharmony_ci    uint32_t HeaderSize() const { return body_start_ - header_start_; }
491cb0ef41Sopenharmony_ci    uint32_t BodySize() const { return exits_start_ - body_start_; }
501cb0ef41Sopenharmony_ci    uint32_t ExitsSize() const { return exits_end_ - exits_start_; }
511cb0ef41Sopenharmony_ci    uint32_t TotalSize() const { return exits_end_ - header_start_; }
521cb0ef41Sopenharmony_ci    uint32_t depth() const { return depth_; }
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci   private:
551cb0ef41Sopenharmony_ci    friend class LoopTree;
561cb0ef41Sopenharmony_ci    friend class LoopFinderImpl;
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci    explicit Loop(Zone* zone)
591cb0ef41Sopenharmony_ci        : parent_(nullptr),
601cb0ef41Sopenharmony_ci          depth_(0),
611cb0ef41Sopenharmony_ci          children_(zone),
621cb0ef41Sopenharmony_ci          header_start_(-1),
631cb0ef41Sopenharmony_ci          body_start_(-1),
641cb0ef41Sopenharmony_ci          exits_start_(-1),
651cb0ef41Sopenharmony_ci          exits_end_(-1) {}
661cb0ef41Sopenharmony_ci    Loop* parent_;
671cb0ef41Sopenharmony_ci    int depth_;
681cb0ef41Sopenharmony_ci    ZoneVector<Loop*> children_;
691cb0ef41Sopenharmony_ci    int header_start_;
701cb0ef41Sopenharmony_ci    int body_start_;
711cb0ef41Sopenharmony_ci    int exits_start_;
721cb0ef41Sopenharmony_ci    int exits_end_;
731cb0ef41Sopenharmony_ci  };
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ci  // Return the innermost nested loop, if any, that contains {node}.
761cb0ef41Sopenharmony_ci  Loop* ContainingLoop(Node* node) {
771cb0ef41Sopenharmony_ci    if (node->id() >= node_to_loop_num_.size()) return nullptr;
781cb0ef41Sopenharmony_ci    int num = node_to_loop_num_[node->id()];
791cb0ef41Sopenharmony_ci    return num > 0 ? &all_loops_[num - 1] : nullptr;
801cb0ef41Sopenharmony_ci  }
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci  // Check if the {loop} contains the {node}, either directly or by containing
831cb0ef41Sopenharmony_ci  // a nested loop that contains {node}.
841cb0ef41Sopenharmony_ci  bool Contains(const Loop* loop, Node* node) {
851cb0ef41Sopenharmony_ci    for (Loop* c = ContainingLoop(node); c != nullptr; c = c->parent_) {
861cb0ef41Sopenharmony_ci      if (c == loop) return true;
871cb0ef41Sopenharmony_ci    }
881cb0ef41Sopenharmony_ci    return false;
891cb0ef41Sopenharmony_ci  }
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  // Return the list of outer loops.
921cb0ef41Sopenharmony_ci  const ZoneVector<Loop*>& outer_loops() const { return outer_loops_; }
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci  // Return a new vector containing the inner loops.
951cb0ef41Sopenharmony_ci  ZoneVector<const Loop*> inner_loops() const {
961cb0ef41Sopenharmony_ci    ZoneVector<const Loop*> inner_loops(zone_);
971cb0ef41Sopenharmony_ci    for (const Loop& loop : all_loops_) {
981cb0ef41Sopenharmony_ci      if (loop.children().empty()) {
991cb0ef41Sopenharmony_ci        inner_loops.push_back(&loop);
1001cb0ef41Sopenharmony_ci      }
1011cb0ef41Sopenharmony_ci    }
1021cb0ef41Sopenharmony_ci    return inner_loops;
1031cb0ef41Sopenharmony_ci  }
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  // Return the unique loop number for a given loop. Loop numbers start at {1}.
1061cb0ef41Sopenharmony_ci  int LoopNum(const Loop* loop) const {
1071cb0ef41Sopenharmony_ci    return 1 + static_cast<int>(loop - &all_loops_[0]);
1081cb0ef41Sopenharmony_ci  }
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  // Return a range which can iterate over the header nodes of {loop}.
1111cb0ef41Sopenharmony_ci  NodeRange HeaderNodes(const Loop* loop) {
1121cb0ef41Sopenharmony_ci    return NodeRange(&loop_nodes_[0] + loop->header_start_,
1131cb0ef41Sopenharmony_ci                     &loop_nodes_[0] + loop->body_start_);
1141cb0ef41Sopenharmony_ci  }
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  // Return the header control node for a loop.
1171cb0ef41Sopenharmony_ci  Node* HeaderNode(const Loop* loop);
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  // Return a range which can iterate over the body nodes of {loop}.
1201cb0ef41Sopenharmony_ci  NodeRange BodyNodes(const Loop* loop) {
1211cb0ef41Sopenharmony_ci    return NodeRange(&loop_nodes_[0] + loop->body_start_,
1221cb0ef41Sopenharmony_ci                     &loop_nodes_[0] + loop->exits_start_);
1231cb0ef41Sopenharmony_ci  }
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  // Return a range which can iterate over the body nodes of {loop}.
1261cb0ef41Sopenharmony_ci  NodeRange ExitNodes(const Loop* loop) {
1271cb0ef41Sopenharmony_ci    return NodeRange(&loop_nodes_[0] + loop->exits_start_,
1281cb0ef41Sopenharmony_ci                     &loop_nodes_[0] + loop->exits_end_);
1291cb0ef41Sopenharmony_ci  }
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  // Return a range which can iterate over the nodes of {loop}.
1321cb0ef41Sopenharmony_ci  NodeRange LoopNodes(const Loop* loop) {
1331cb0ef41Sopenharmony_ci    return NodeRange(&loop_nodes_[0] + loop->header_start_,
1341cb0ef41Sopenharmony_ci                     &loop_nodes_[0] + loop->exits_end_);
1351cb0ef41Sopenharmony_ci  }
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  // Return the node that represents the control, i.e. the loop node itself.
1381cb0ef41Sopenharmony_ci  Node* GetLoopControl(const Loop* loop) {
1391cb0ef41Sopenharmony_ci    // TODO(turbofan): make the loop control node always first?
1401cb0ef41Sopenharmony_ci    for (Node* node : HeaderNodes(loop)) {
1411cb0ef41Sopenharmony_ci      if (node->opcode() == IrOpcode::kLoop) return node;
1421cb0ef41Sopenharmony_ci    }
1431cb0ef41Sopenharmony_ci    UNREACHABLE();
1441cb0ef41Sopenharmony_ci  }
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  Zone* zone() const { return zone_; }
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci private:
1491cb0ef41Sopenharmony_ci  friend class LoopFinderImpl;
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  Loop* NewLoop() {
1521cb0ef41Sopenharmony_ci    all_loops_.push_back(Loop(zone_));
1531cb0ef41Sopenharmony_ci    Loop* result = &all_loops_.back();
1541cb0ef41Sopenharmony_ci    return result;
1551cb0ef41Sopenharmony_ci  }
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  void SetParent(Loop* parent, Loop* child) {
1581cb0ef41Sopenharmony_ci    if (parent != nullptr) {
1591cb0ef41Sopenharmony_ci      parent->children_.push_back(child);
1601cb0ef41Sopenharmony_ci      child->parent_ = parent;
1611cb0ef41Sopenharmony_ci      child->depth_ = parent->depth_ + 1;
1621cb0ef41Sopenharmony_ci    } else {
1631cb0ef41Sopenharmony_ci      outer_loops_.push_back(child);
1641cb0ef41Sopenharmony_ci    }
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  Zone* zone_;
1681cb0ef41Sopenharmony_ci  ZoneVector<Loop*> outer_loops_;
1691cb0ef41Sopenharmony_ci  ZoneVector<Loop> all_loops_;
1701cb0ef41Sopenharmony_ci  ZoneVector<int> node_to_loop_num_;
1711cb0ef41Sopenharmony_ci  ZoneVector<Node*> loop_nodes_;
1721cb0ef41Sopenharmony_ci};
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE LoopFinder {
1751cb0ef41Sopenharmony_ci public:
1761cb0ef41Sopenharmony_ci  // Build a loop tree for the entire graph.
1771cb0ef41Sopenharmony_ci  static LoopTree* BuildLoopTree(Graph* graph, TickCounter* tick_counter,
1781cb0ef41Sopenharmony_ci                                 Zone* temp_zone);
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci  static bool HasMarkedExits(LoopTree* loop_tree_, const LoopTree::Loop* loop);
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci#if V8_ENABLE_WEBASSEMBLY
1831cb0ef41Sopenharmony_ci  // Find all nodes in the loop headed by {loop_header} if it contains no nested
1841cb0ef41Sopenharmony_ci  // loops.
1851cb0ef41Sopenharmony_ci  // Assumption: *if* this loop has no nested loops, all exits from the loop are
1861cb0ef41Sopenharmony_ci  // marked with LoopExit, LoopExitEffect, LoopExitValue, or End nodes.
1871cb0ef41Sopenharmony_ci  // Returns {nullptr} if
1881cb0ef41Sopenharmony_ci  // 1) the loop size (in graph nodes) exceeds {max_size},
1891cb0ef41Sopenharmony_ci  // 2) {calls_are_large} and a function call is found in the loop, excluding
1901cb0ef41Sopenharmony_ci  //    calls to a set of wasm builtins,
1911cb0ef41Sopenharmony_ci  // 3) a nested loop is found in the loop.
1921cb0ef41Sopenharmony_ci  static ZoneUnorderedSet<Node*>* FindSmallInnermostLoopFromHeader(
1931cb0ef41Sopenharmony_ci      Node* loop_header, Zone* zone, size_t max_size, bool calls_are_large);
1941cb0ef41Sopenharmony_ci#endif
1951cb0ef41Sopenharmony_ci};
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci// Copies a range of nodes any number of times.
1981cb0ef41Sopenharmony_ciclass NodeCopier {
1991cb0ef41Sopenharmony_ci public:
2001cb0ef41Sopenharmony_ci  // {max}: The maximum number of nodes that this copier will track, including
2011cb0ef41Sopenharmony_ci  //        the original nodes and all copies.
2021cb0ef41Sopenharmony_ci  // {p}: A vector that holds the original nodes and all copies.
2031cb0ef41Sopenharmony_ci  // {copy_count}: How many times the nodes should be copied.
2041cb0ef41Sopenharmony_ci  NodeCopier(Graph* graph, uint32_t max, NodeVector* p, uint32_t copy_count)
2051cb0ef41Sopenharmony_ci      : node_map_(graph, max), copies_(p), copy_count_(copy_count) {
2061cb0ef41Sopenharmony_ci    DCHECK_GT(copy_count, 0);
2071cb0ef41Sopenharmony_ci  }
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci  // Returns the mapping of {node} in the {copy_index}'th copy, or {node} itself
2101cb0ef41Sopenharmony_ci  // if it is not present in the mapping. The copies are 0-indexed.
2111cb0ef41Sopenharmony_ci  Node* map(Node* node, uint32_t copy_index);
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  // Helper version of {map} for one copy.
2141cb0ef41Sopenharmony_ci  V8_INLINE Node* map(Node* node) { return map(node, 0); }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  // Insert a new mapping from {original} to {new_copies} into the copier.
2171cb0ef41Sopenharmony_ci  void Insert(Node* original, const NodeVector& new_copies);
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ci  // Helper version of {Insert} for one copy.
2201cb0ef41Sopenharmony_ci  void Insert(Node* original, Node* copy);
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  template <typename InputIterator>
2231cb0ef41Sopenharmony_ci  void CopyNodes(Graph* graph, Zone* tmp_zone_, Node* dead,
2241cb0ef41Sopenharmony_ci                 base::iterator_range<InputIterator> nodes,
2251cb0ef41Sopenharmony_ci                 SourcePositionTable* source_positions,
2261cb0ef41Sopenharmony_ci                 NodeOriginTable* node_origins) {
2271cb0ef41Sopenharmony_ci    // Copy all the nodes first.
2281cb0ef41Sopenharmony_ci    for (Node* original : nodes) {
2291cb0ef41Sopenharmony_ci      SourcePositionTable::Scope position(
2301cb0ef41Sopenharmony_ci          source_positions, source_positions->GetSourcePosition(original));
2311cb0ef41Sopenharmony_ci      NodeOriginTable::Scope origin_scope(node_origins, "copy nodes", original);
2321cb0ef41Sopenharmony_ci      node_map_.Set(original, copies_->size() + 1);
2331cb0ef41Sopenharmony_ci      copies_->push_back(original);
2341cb0ef41Sopenharmony_ci      for (uint32_t copy_index = 0; copy_index < copy_count_; copy_index++) {
2351cb0ef41Sopenharmony_ci        Node* copy = graph->CloneNode(original);
2361cb0ef41Sopenharmony_ci        copies_->push_back(copy);
2371cb0ef41Sopenharmony_ci      }
2381cb0ef41Sopenharmony_ci    }
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ci    // Fix inputs of the copies.
2411cb0ef41Sopenharmony_ci    for (Node* original : nodes) {
2421cb0ef41Sopenharmony_ci      for (uint32_t copy_index = 0; copy_index < copy_count_; copy_index++) {
2431cb0ef41Sopenharmony_ci        Node* copy = map(original, copy_index);
2441cb0ef41Sopenharmony_ci        for (int i = 0; i < copy->InputCount(); i++) {
2451cb0ef41Sopenharmony_ci          copy->ReplaceInput(i, map(original->InputAt(i), copy_index));
2461cb0ef41Sopenharmony_ci        }
2471cb0ef41Sopenharmony_ci      }
2481cb0ef41Sopenharmony_ci    }
2491cb0ef41Sopenharmony_ci  }
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci  bool Marked(Node* node) { return node_map_.Get(node) > 0; }
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci private:
2541cb0ef41Sopenharmony_ci  // Maps a node to its index in the {copies_} vector.
2551cb0ef41Sopenharmony_ci  NodeMarker<size_t> node_map_;
2561cb0ef41Sopenharmony_ci  // The vector which contains the mapped nodes.
2571cb0ef41Sopenharmony_ci  NodeVector* copies_;
2581cb0ef41Sopenharmony_ci  // How many copies of the nodes should be generated.
2591cb0ef41Sopenharmony_ci  const uint32_t copy_count_;
2601cb0ef41Sopenharmony_ci};
2611cb0ef41Sopenharmony_ci
2621cb0ef41Sopenharmony_ci}  // namespace compiler
2631cb0ef41Sopenharmony_ci}  // namespace internal
2641cb0ef41Sopenharmony_ci}  // namespace v8
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci#endif  // V8_COMPILER_LOOP_ANALYSIS_H_
267