v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
loop-analysis.h
Go to the documentation of this file.
1// Copyright 2014 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_COMPILER_LOOP_ANALYSIS_H_
6#define V8_COMPILER_LOOP_ANALYSIS_H_
7
8#include "src/base/iterator.h"
14#include "src/compiler/node.h"
17
18namespace v8 {
19namespace internal {
20
21class TickCounter;
22
23namespace compiler {
24
25// TODO(titzer): don't assume entry edges have a particular index.
26static const int kAssumedLoopEntryIndex = 0; // assume loops are entered here.
27
28class LoopFinderImpl;
29class AllNodes;
30
32
33// Represents a tree of loops in a graph.
34class LoopTree : public ZoneObject {
35 public:
36 LoopTree(size_t num_nodes, Zone* zone)
37 : zone_(zone),
40 node_to_loop_num_(static_cast<int>(num_nodes), -1, zone),
42
43 // Represents a loop in the tree of loops, including the header nodes,
44 // the body, and any nested loops.
45 class Loop {
46 public:
47 Loop* parent() const { return parent_; }
48 const ZoneVector<Loop*>& children() const { return children_; }
49 uint32_t HeaderSize() const { return body_start_ - header_start_; }
50 uint32_t BodySize() const { return exits_start_ - body_start_; }
51 uint32_t ExitsSize() const { return exits_end_ - exits_start_; }
52 uint32_t TotalSize() const { return exits_end_ - header_start_; }
53 uint32_t depth() const { return depth_; }
54
55 private:
56 friend class LoopTree;
57 friend class LoopFinderImpl;
58
59 explicit Loop(Zone* zone)
60 : parent_(nullptr),
61 depth_(0),
63 header_start_(-1),
64 body_start_(-1),
65 exits_start_(-1),
66 exits_end_(-1) {}
68 int depth_;
74 };
75
76 // Return the innermost nested loop, if any, that contains {node}.
78 if (node->id() >= node_to_loop_num_.size()) return nullptr;
79 int num = node_to_loop_num_[node->id()];
80 return num > 0 ? &all_loops_[num - 1] : nullptr;
81 }
82
83 // Check if the {loop} contains the {node}, either directly or by containing
84 // a nested loop that contains {node}.
85 bool Contains(const Loop* loop, Node* node) {
86 for (Loop* c = ContainingLoop(node); c != nullptr; c = c->parent_) {
87 if (c == loop) return true;
88 }
89 return false;
90 }
91
92 // Return the list of outer loops.
93 const ZoneVector<Loop*>& outer_loops() const { return outer_loops_; }
94
95 // Return a new vector containing the inner loops.
98 for (const Loop& loop : all_loops_) {
99 if (loop.children().empty()) {
100 inner_loops.push_back(&loop);
101 }
102 }
103 return inner_loops;
104 }
105
106 // Return the unique loop number for a given loop. Loop numbers start at {1}.
107 int LoopNum(const Loop* loop) const {
108 return 1 + static_cast<int>(loop - &all_loops_[0]);
109 }
110
111 // Return a range which can iterate over the header nodes of {loop}.
113 return NodeRange(&loop_nodes_[0] + loop->header_start_,
114 &loop_nodes_[0] + loop->body_start_);
115 }
116
117 // Return the header control node for a loop.
118 Node* HeaderNode(const Loop* loop);
119
120 // Return a range which can iterate over the body nodes of {loop}.
121 NodeRange BodyNodes(const Loop* loop) {
122 return NodeRange(&loop_nodes_[0] + loop->body_start_,
123 &loop_nodes_[0] + loop->exits_start_);
124 }
125
126 // Return a range which can iterate over the body nodes of {loop}.
127 NodeRange ExitNodes(const Loop* loop) {
128 return NodeRange(&loop_nodes_[0] + loop->exits_start_,
129 &loop_nodes_[0] + loop->exits_end_);
130 }
131
132 // Return a range which can iterate over the nodes of {loop}.
133 NodeRange LoopNodes(const Loop* loop) {
134 return NodeRange(&loop_nodes_[0] + loop->header_start_,
135 &loop_nodes_[0] + loop->exits_end_);
136 }
137
138 // Return the node that represents the control, i.e. the loop node itself.
139 Node* GetLoopControl(const Loop* loop) {
140 // TODO(turbofan): make the loop control node always first?
141 for (Node* node : HeaderNodes(loop)) {
142 if (node->opcode() == IrOpcode::kLoop) return node;
143 }
144 UNREACHABLE();
145 }
146
147 Zone* zone() const { return zone_; }
148
149 private:
150 friend class LoopFinderImpl;
151
153 all_loops_.push_back(Loop(zone_));
154 Loop* result = &all_loops_.back();
155 return result;
156 }
157
158 void SetParent(Loop* parent, Loop* child) {
159 if (parent != nullptr) {
160 parent->children_.push_back(child);
161 child->parent_ = parent;
162 child->depth_ = parent->depth_ + 1;
163 } else {
164 outer_loops_.push_back(child);
165 }
166 }
167
173};
174
176 public:
177 // Build a loop tree for the entire graph.
178 static LoopTree* BuildLoopTree(TFGraph* graph, TickCounter* tick_counter,
179 Zone* temp_zone);
180
181 static bool HasMarkedExits(LoopTree* loop_tree, const LoopTree::Loop* loop);
182
183#if V8_ENABLE_WEBASSEMBLY
184 enum class Purpose { kLoopPeeling, kLoopUnrolling };
185
186 // Find all nodes in the loop headed by {loop_header} if it contains no nested
187 // loops.
188 // Assumption: *if* this loop has no nested loops, all exits from the loop are
189 // marked with LoopExit, LoopExitEffect, LoopExitValue, or End nodes.
190 // Returns {nullptr} if
191 // 1) the loop size (in graph nodes) exceeds {max_size},
192 // 2) {calls_are_large} and a function call is found in the loop, excluding
193 // calls to a set of wasm builtins,
194 // 3) a nested loop is found in the loop.
195 static ZoneUnorderedSet<Node*>* FindSmallInnermostLoopFromHeader(
196 Node* loop_header, AllNodes& all_nodes, Zone* zone, size_t max_size,
197 Purpose purpose);
198#endif
199};
200
201// Copies a range of nodes any number of times.
203 public:
204 // {max}: The maximum number of nodes that this copier will track, including
205 // the original nodes and all copies.
206 // {p}: A vector that holds the original nodes and all copies.
207 // {copy_count}: How many times the nodes should be copied.
208 NodeCopier(TFGraph* graph, uint32_t max, NodeVector* p, uint32_t copy_count)
209 : node_map_(graph, max), copies_(p), copy_count_(copy_count) {
210 DCHECK_GT(copy_count, 0);
211 }
212
213 // Returns the mapping of {node} in the {copy_index}'th copy, or {node} itself
214 // if it is not present in the mapping. The copies are 0-indexed.
215 Node* map(Node* node, uint32_t copy_index);
216
217 // Helper version of {map} for one copy.
218 V8_INLINE Node* map(Node* node) { return map(node, 0); }
219
220 // Insert a new mapping from {original} to {new_copies} into the copier.
221 void Insert(Node* original, const NodeVector& new_copies);
222
223 // Helper version of {Insert} for one copy.
224 void Insert(Node* original, Node* copy);
225
226 template <typename InputIterator>
227 void CopyNodes(TFGraph* graph, Zone* tmp_zone_, Node* dead,
230 NodeOriginTable* node_origins) {
231 // Copy all the nodes first.
232 for (Node* original : nodes) {
234 source_positions, source_positions->GetSourcePosition(original));
235 NodeOriginTable::Scope origin_scope(node_origins, "copy nodes", original);
236 node_map_.Set(original, copies_->size() + 1);
237 copies_->push_back(original);
238 for (uint32_t copy_index = 0; copy_index < copy_count_; copy_index++) {
239 Node* copy = graph->CloneNode(original);
240 copies_->push_back(copy);
241 }
242 }
243
244 // Fix inputs of the copies.
245 for (Node* original : nodes) {
246 for (uint32_t copy_index = 0; copy_index < copy_count_; copy_index++) {
247 Node* copy = map(original, copy_index);
248 for (int i = 0; i < copy->InputCount(); i++) {
249 copy->ReplaceInput(i, map(original->InputAt(i), copy_index));
250 }
251 }
252 }
253 }
254
255 bool Marked(Node* node) { return node_map_.Get(node) > 0; }
256
257 private:
258 // Maps a node to its index in the {copies_} vector.
260 // The vector which contains the mapped nodes.
262 // How many copies of the nodes should be generated.
263 const uint32_t copy_count_;
264};
265
266} // namespace compiler
267} // namespace internal
268} // namespace v8
269
270#endif // V8_COMPILER_LOOP_ANALYSIS_H_
void push_back(const T &value)
const ZoneVector< Loop * > & children() const
Node * GetLoopControl(const Loop *loop)
NodeRange HeaderNodes(const Loop *loop)
ZoneVector< Loop * > outer_loops_
int LoopNum(const Loop *loop) const
ZoneVector< Node * > loop_nodes_
void SetParent(Loop *parent, Loop *child)
Node * HeaderNode(const Loop *loop)
NodeRange LoopNodes(const Loop *loop)
const ZoneVector< Loop * > & outer_loops() const
Loop * ContainingLoop(Node *node)
bool Contains(const Loop *loop, Node *node)
ZoneVector< const Loop * > inner_loops() const
NodeRange ExitNodes(const Loop *loop)
LoopTree(size_t num_nodes, Zone *zone)
NodeRange BodyNodes(const Loop *loop)
void CopyNodes(TFGraph *graph, Zone *tmp_zone_, Node *dead, base::iterator_range< InputIterator > nodes, SourcePositionTable *source_positions, NodeOriginTable *node_origins)
V8_INLINE Node * map(Node *node)
NodeCopier(TFGraph *graph, uint32_t max, NodeVector *p, uint32_t copy_count)
void Insert(Node *original, const NodeVector &new_copies)
V8_INLINE void Set(Node *node, State state)
Definition node-marker.h:69
V8_INLINE State Get(const Node *node)
Definition node-marker.h:65
int InputCount() const
Definition node.h:59
void ReplaceInput(int index, Node *new_to)
Definition node.h:76
SourcePositionTable * source_positions
std::map< const std::string, const std::string > map
Node * node
ZoneVector< RpoNumber > & result
int position
Definition liveedit.cc:290
static const int kAssumedLoopEntryIndex
base::iterator_range< Node ** > NodeRange
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_INLINE
Definition v8config.h:500