|  | // 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/compiler/graph.h" | 
|  | #include "src/compiler/node.h" | 
|  | #include "src/globals.h" | 
|  | #include "src/zone/zone-containers.h" | 
|  |  | 
|  | namespace v8 { | 
|  | namespace internal { | 
|  | 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; | 
|  |  | 
|  | typedef base::iterator_range<Node**> NodeRange; | 
|  |  | 
|  | // 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<int>(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<Loop*>& 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<size_t>(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<Loop*> 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<Loop*>& 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<int>(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<Loop*> outer_loops_; | 
|  | ZoneVector<Loop> all_loops_; | 
|  | ZoneVector<int> node_to_loop_num_; | 
|  | ZoneVector<Node*> loop_nodes_; | 
|  | }; | 
|  |  | 
|  | class V8_EXPORT_PRIVATE LoopFinder { | 
|  | public: | 
|  | // Build a loop tree for the entire graph. | 
|  | static LoopTree* BuildLoopTree(Graph* graph, Zone* temp_zone); | 
|  | }; | 
|  |  | 
|  |  | 
|  | }  // namespace compiler | 
|  | }  // namespace internal | 
|  | }  // namespace v8 | 
|  |  | 
|  | #endif  // V8_COMPILER_LOOP_ANALYSIS_H_ |