| // 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_ |