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