// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_COMPILER_LOOP_ANALYSIS_H_ #define V8_COMPILER_LOOP_ANALYSIS_H_ #include "src/base/iterator.h" #include "src/common/globals.h" #include "src/compiler/graph.h" #include "src/compiler/node.h" #include "src/zone/zone-containers.h" namespace v8 { namespace internal { class TickCounter; namespace compiler { // TODO(titzer): don't assume entry edges have a particular index. static const int kAssumedLoopEntryIndex = 0; // assume loops are entered here. class LoopFinderImpl; using NodeRange = base::iterator_range; // Represents a tree of loops in a graph. class LoopTree : public ZoneObject { public: LoopTree(size_t num_nodes, Zone* zone) : zone_(zone), outer_loops_(zone), all_loops_(zone), node_to_loop_num_(static_cast(num_nodes), -1, zone), loop_nodes_(zone) {} // Represents a loop in the tree of loops, including the header nodes, // the body, and any nested loops. class Loop { public: Loop* parent() const { return parent_; } const ZoneVector& children() const { return children_; } size_t HeaderSize() const { return body_start_ - header_start_; } size_t BodySize() const { return exits_start_ - body_start_; } size_t ExitsSize() const { return exits_end_ - exits_start_; } size_t TotalSize() const { return exits_end_ - header_start_; } size_t depth() const { return static_cast(depth_); } private: friend class LoopTree; friend class LoopFinderImpl; explicit Loop(Zone* zone) : parent_(nullptr), depth_(0), children_(zone), header_start_(-1), body_start_(-1), exits_start_(-1), exits_end_(-1) {} Loop* parent_; int depth_; ZoneVector children_; int header_start_; int body_start_; int exits_start_; int exits_end_; }; // Return the innermost nested loop, if any, that contains {node}. Loop* ContainingLoop(Node* node) { if (node->id() >= node_to_loop_num_.size()) return nullptr; int num = node_to_loop_num_[node->id()]; return num > 0 ? &all_loops_[num - 1] : nullptr; } // Check if the {loop} contains the {node}, either directly or by containing // a nested loop that contains {node}. bool Contains(Loop* loop, Node* node) { for (Loop* c = ContainingLoop(node); c != nullptr; c = c->parent_) { if (c == loop) return true; } return false; } // Return the list of outer loops. const ZoneVector& outer_loops() const { return outer_loops_; } // Return the unique loop number for a given loop. Loop numbers start at {1}. int LoopNum(Loop* loop) const { return 1 + static_cast(loop - &all_loops_[0]); } // Return a range which can iterate over the header nodes of {loop}. NodeRange HeaderNodes(Loop* loop) { return NodeRange(&loop_nodes_[0] + loop->header_start_, &loop_nodes_[0] + loop->body_start_); } // Return the header control node for a loop. Node* HeaderNode(Loop* loop); // Return a range which can iterate over the body nodes of {loop}. NodeRange BodyNodes(Loop* loop) { return NodeRange(&loop_nodes_[0] + loop->body_start_, &loop_nodes_[0] + loop->exits_start_); } // Return a range which can iterate over the body nodes of {loop}. NodeRange ExitNodes(Loop* loop) { return NodeRange(&loop_nodes_[0] + loop->exits_start_, &loop_nodes_[0] + loop->exits_end_); } // Return a range which can iterate over the nodes of {loop}. NodeRange LoopNodes(Loop* loop) { return NodeRange(&loop_nodes_[0] + loop->header_start_, &loop_nodes_[0] + loop->exits_end_); } // Return the node that represents the control, i.e. the loop node itself. Node* GetLoopControl(Loop* loop) { // TODO(turbofan): make the loop control node always first? for (Node* node : HeaderNodes(loop)) { if (node->opcode() == IrOpcode::kLoop) return node; } UNREACHABLE(); } Zone* zone() const { return zone_; } private: friend class LoopFinderImpl; Loop* NewLoop() { all_loops_.push_back(Loop(zone_)); Loop* result = &all_loops_.back(); return result; } void SetParent(Loop* parent, Loop* child) { if (parent != nullptr) { parent->children_.push_back(child); child->parent_ = parent; child->depth_ = parent->depth_ + 1; } else { outer_loops_.push_back(child); } } Zone* zone_; ZoneVector outer_loops_; ZoneVector all_loops_; ZoneVector node_to_loop_num_; ZoneVector loop_nodes_; }; class V8_EXPORT_PRIVATE LoopFinder { public: // Build a loop tree for the entire graph. static LoopTree* BuildLoopTree(Graph* graph, TickCounter* tick_counter, Zone* temp_zone); }; } // namespace compiler } // namespace internal } // namespace v8 #endif // V8_COMPILER_LOOP_ANALYSIS_H_