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