blob: c73482fa69f72ad69efc0600801a1158699e7641 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// Copyright 2013 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_NODE_H_
6#define V8_COMPILER_NODE_H_
7
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008#include "src/compiler/opcodes.h"
9#include "src/compiler/operator.h"
10#include "src/types.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011#include "src/zone-containers.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012
13namespace v8 {
14namespace internal {
15namespace compiler {
16
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017// Forward declarations.
18class Edge;
19class Graph;
20
21
22// Marks are used during traversal of the graph to distinguish states of nodes.
23// Each node has a mark which is a monotonically increasing integer, and a
24// {NodeMarker} has a range of values that indicate states of a node.
25typedef uint32_t Mark;
26
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000027
Emily Bernierd0a1eb72015-03-24 16:35:39 -040028// NodeIds are identifying numbers for nodes that can be used to index auxiliary
29// out-of-line data associated with each node.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000030typedef uint32_t NodeId;
31
Emily Bernierd0a1eb72015-03-24 16:35:39 -040032
33// A Node is the basic primitive of graphs. Nodes are chained together by
34// input/use chains but by default otherwise contain only an identifying number
35// which specific applications of graphs and nodes can use to index auxiliary
36// out-of-line data, especially transient data.
37//
38// In addition Nodes only contain a mutable Operator that may change during
39// compilation, e.g. during lowering passes. Other information that needs to be
40// associated with Nodes during compilation must be stored out-of-line indexed
41// by the Node's id.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042class Node final {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000043 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000044 static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count,
45 Node* const* inputs, bool has_extensible_inputs);
46 static Node* Clone(Zone* zone, NodeId id, const Node* node);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040047
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000048 bool IsDead() const { return InputCount() > 0 && !InputAt(0); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040049 void Kill();
50
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051 const Operator* op() const { return op_; }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000052
53 IrOpcode::Value opcode() const {
54 DCHECK(op_->opcode() <= IrOpcode::kLast);
55 return static_cast<IrOpcode::Value>(op_->opcode());
56 }
57
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000058 NodeId id() const { return IdField::decode(bit_field_); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040059
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000060 int InputCount() const {
61 return has_inline_inputs() ? InlineCountField::decode(bit_field_)
62 : inputs_.outline_->count_;
63 }
64
65#if DEBUG
66 void Verify();
67#define BOUNDS_CHECK(index) \
68 do { \
69 if (index < 0 || index >= InputCount()) { \
70 V8_Fatal(__FILE__, __LINE__, "Node #%d:%s->InputAt(%d) out of bounds", \
71 id(), op()->mnemonic(), index); \
72 } \
73 } while (false)
74#else
75 // No bounds checks or verification in release mode.
76 inline void Verify() {}
77#define BOUNDS_CHECK(index) \
78 do { \
79 } while (false)
80#endif
81
82 Node* InputAt(int index) const {
83 BOUNDS_CHECK(index);
84 return *GetInputPtrConst(index);
85 }
86
87 void ReplaceInput(int index, Node* new_to) {
88 BOUNDS_CHECK(index);
89 Node** input_ptr = GetInputPtr(index);
90 Node* old_to = *input_ptr;
91 if (old_to != new_to) {
92 Use* use = GetUsePtr(index);
93 if (old_to) old_to->RemoveUse(use);
94 *input_ptr = new_to;
95 if (new_to) new_to->AppendUse(use);
96 }
97 }
98
99#undef BOUNDS_CHECK
100
101 void AppendInput(Zone* zone, Node* new_to);
102 void InsertInput(Zone* zone, int index, Node* new_to);
103 void RemoveInput(int index);
104 void NullAllInputs();
105 void TrimInputCount(int new_input_count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400106
107 int UseCount() const;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 void ReplaceUses(Node* replace_to);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400109
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000110 class InputEdges final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400111 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000112 typedef Edge value_type;
113
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400114 class iterator;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 inline iterator begin() const;
116 inline iterator end() const;
117
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400118 bool empty() const;
119
120 explicit InputEdges(Node* node) : node_(node) {}
121
122 private:
123 Node* node_;
124 };
125
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 InputEdges input_edges() { return InputEdges(this); }
127
128 class Inputs final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400129 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000130 typedef Node* value_type;
131
132 class const_iterator;
133 inline const_iterator begin() const;
134 inline const_iterator end() const;
135
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400136 bool empty() const;
137
138 explicit Inputs(Node* node) : node_(node) {}
139
140 private:
141 Node* node_;
142 };
143
144 Inputs inputs() { return Inputs(this); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400145
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000146 class UseEdges final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400147 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000148 typedef Edge value_type;
149
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150 class iterator;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000151 inline iterator begin() const;
152 inline iterator end() const;
153
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400154 bool empty() const;
155
156 explicit UseEdges(Node* node) : node_(node) {}
157
158 private:
159 Node* node_;
160 };
161
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000162 UseEdges use_edges() { return UseEdges(this); }
163
164 class Uses final {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400165 public:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166 typedef Node* value_type;
167
168 class const_iterator;
169 inline const_iterator begin() const;
170 inline const_iterator end() const;
171
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400172 bool empty() const;
173
174 explicit Uses(Node* node) : node_(node) {}
175
176 private:
177 Node* node_;
178 };
179
180 Uses uses() { return Uses(this); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400181
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 // Returns true if {owner} is the user of {this} node.
183 bool OwnedBy(Node* owner) const {
184 return first_use_ && first_use_->from() == owner && !first_use_->next;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 }
186
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187 // Returns true if {owner1} and {owner2} are the only users of {this} node.
188 bool OwnedBy(Node const* owner1, Node const* owner2) const;
189 void Print() const;
190
191 private:
192 struct Use;
193 // Out of line storage for inputs when the number of inputs overflowed the
194 // capacity of the inline-allocated space.
195 struct OutOfLineInputs {
196 Node* node_;
197 int count_;
198 int capacity_;
199 Node* inputs_[1];
200
201 static OutOfLineInputs* New(Zone* zone, int capacity);
202 void ExtractFrom(Use* use_ptr, Node** input_ptr, int count);
203 };
204
205 // A link in the use chain for a node. Every input {i} to a node {n} has an
206 // associated {Use} which is linked into the use chain of the {i} node.
207 struct Use {
208 Use* next;
209 Use* prev;
210 uint32_t bit_field_;
211
212 int input_index() const { return InputIndexField::decode(bit_field_); }
213 bool is_inline_use() const { return InlineField::decode(bit_field_); }
214 Node** input_ptr() {
215 int index = input_index();
216 Use* start = this + 1 + index;
217 Node** inputs = is_inline_use()
218 ? reinterpret_cast<Node*>(start)->inputs_.inline_
219 : reinterpret_cast<OutOfLineInputs*>(start)->inputs_;
220 return &inputs[index];
221 }
222
223 Node* from() {
224 Use* start = this + 1 + input_index();
225 return is_inline_use() ? reinterpret_cast<Node*>(start)
226 : reinterpret_cast<OutOfLineInputs*>(start)->node_;
227 }
228
229 typedef BitField<bool, 0, 1> InlineField;
230 typedef BitField<unsigned, 1, 17> InputIndexField;
231 // Leaving some space in the bitset in case we ever decide to record
232 // the output index.
233 };
234
235 //============================================================================
236 //== Memory layout ===========================================================
237 //============================================================================
238 // Saving space for big graphs is important. We use a memory layout trick to
239 // be able to map {Node} objects to {Use} objects and vice-versa in a
240 // space-efficient manner.
241 //
242 // {Use} links are laid out in memory directly before a {Node}, followed by
243 // direct pointers to input {Nodes}.
244 //
245 // inline case:
246 // |Use #N |Use #N-1|...|Use #1 |Use #0 |Node xxxx |I#0|I#1|...|I#N-1|I#N|
247 // ^ ^ ^
248 // + Use + Node + Input
249 //
250 // Since every {Use} instance records its {input_index}, pointer arithmetic
251 // can compute the {Node}.
252 //
253 // out-of-line case:
254 // |Node xxxx |
255 // ^ + outline ------------------+
256 // +----------------------------------------+
257 // | |
258 // v | node
259 // |Use #N |Use #N-1|...|Use #1 |Use #0 |OOL xxxxx |I#0|I#1|...|I#N-1|I#N|
260 // ^ ^
261 // + Use + Input
262 //
263 // Out-of-line storage of input lists is needed if appending an input to
264 // a node exceeds the maximum inline capacity.
265
266 Node(NodeId id, const Operator* op, int inline_count, int inline_capacity);
267
268 Node* const* GetInputPtrConst(int input_index) const {
269 return has_inline_inputs() ? &(inputs_.inline_[input_index])
270 : &inputs_.outline_->inputs_[input_index];
271 }
272 Node** GetInputPtr(int input_index) {
273 return has_inline_inputs() ? &(inputs_.inline_[input_index])
274 : &inputs_.outline_->inputs_[input_index];
275 }
276 Use* GetUsePtr(int input_index) {
277 Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
278 : reinterpret_cast<Use*>(inputs_.outline_);
279 return &ptr[-1 - input_index];
280 }
281
282 void AppendUse(Use* use);
283 void RemoveUse(Use* use);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400284
285 void* operator new(size_t, void* location) { return location; }
286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 // Only NodeProperties should manipulate the op.
288 void set_op(const Operator* op) { op_ = op; }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400289
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290 // Only NodeProperties should manipulate the type.
291 Type* type() const { return type_; }
292 void set_type(Type* type) { type_ = type; }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400293
294 // Only NodeMarkers should manipulate the marks on nodes.
295 Mark mark() { return mark_; }
296 void set_mark(Mark mark) { mark_ = mark; }
297
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 inline bool has_inline_inputs() const {
299 return InlineCountField::decode(bit_field_) != kOutlineMarker;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400300 }
301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302 void ClearInputs(int start, int count);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400303
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304 typedef BitField<NodeId, 0, 24> IdField;
305 typedef BitField<unsigned, 24, 4> InlineCountField;
306 typedef BitField<unsigned, 28, 4> InlineCapacityField;
307 static const int kOutlineMarker = InlineCountField::kMax;
308 static const int kMaxInlineCount = InlineCountField::kMax - 1;
309 static const int kMaxInlineCapacity = InlineCapacityField::kMax - 1;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400310
311 const Operator* op_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 Type* type_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400313 Mark mark_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 uint32_t bit_field_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400315 Use* first_use_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 union {
317 // Inline storage for inputs or out-of-line storage.
318 Node* inline_[1];
319 OutOfLineInputs* outline_;
320 } inputs_;
321
322 friend class Edge;
323 friend class NodeMarkerBase;
324 friend class NodeProperties;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400325
326 DISALLOW_COPY_AND_ASSIGN(Node);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000327};
328
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400329
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400330std::ostream& operator<<(std::ostream& os, const Node& n);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000331
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000332
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000333// Typedefs to shorten commonly used Node containers.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400334typedef ZoneDeque<Node*> NodeDeque;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335typedef ZoneSet<Node*> NodeSet;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336typedef ZoneVector<Node*> NodeVector;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337typedef ZoneVector<NodeVector> NodeVectorVector;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000339
340// Helper to extract parameters from Operator1<*> nodes.
341template <typename T>
342static inline const T& OpParameter(const Node* node) {
343 return OpParameter<T>(node->op());
344}
345
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000346
347// An encapsulation for information associated with a single use of node as a
348// input from another node, allowing access to both the defining node and
349// the node having the input.
350class Edge final {
351 public:
352 Node* from() const { return use_->from(); }
353 Node* to() const { return *input_ptr_; }
354 int index() const {
355 int const index = use_->input_index();
356 DCHECK_LT(index, use_->from()->InputCount());
357 return index;
358 }
359
360 bool operator==(const Edge& other) { return input_ptr_ == other.input_ptr_; }
361 bool operator!=(const Edge& other) { return !(*this == other); }
362
363 void UpdateTo(Node* new_to) {
364 Node* old_to = *input_ptr_;
365 if (old_to != new_to) {
366 if (old_to) old_to->RemoveUse(use_);
367 *input_ptr_ = new_to;
368 if (new_to) new_to->AppendUse(use_);
369 }
370 }
371
372 private:
373 friend class Node::UseEdges::iterator;
374 friend class Node::InputEdges::iterator;
375
376 Edge(Node::Use* use, Node** input_ptr) : use_(use), input_ptr_(input_ptr) {
377 DCHECK_NOT_NULL(use);
378 DCHECK_NOT_NULL(input_ptr);
379 DCHECK_EQ(input_ptr, use->input_ptr());
380 }
381
382 Node::Use* use_;
383 Node** input_ptr_;
384};
385
386
387// A forward iterator to visit the edges for the input dependencies of a node.
388class Node::InputEdges::iterator final {
389 public:
390 typedef std::forward_iterator_tag iterator_category;
391 typedef int difference_type;
392 typedef Edge value_type;
393 typedef Edge* pointer;
394 typedef Edge& reference;
395
396 iterator() : use_(nullptr), input_ptr_(nullptr) {}
397 iterator(const iterator& other)
398 : use_(other.use_), input_ptr_(other.input_ptr_) {}
399
400 Edge operator*() const { return Edge(use_, input_ptr_); }
401 bool operator==(const iterator& other) const {
402 return input_ptr_ == other.input_ptr_;
403 }
404 bool operator!=(const iterator& other) const { return !(*this == other); }
405 iterator& operator++() {
406 input_ptr_++;
407 use_--;
408 return *this;
409 }
410 iterator operator++(int);
411
412 private:
413 friend class Node;
414
415 explicit iterator(Node* from, int index = 0)
416 : use_(from->GetUsePtr(index)), input_ptr_(from->GetInputPtr(index)) {}
417
418 Use* use_;
419 Node** input_ptr_;
420};
421
422
423Node::InputEdges::iterator Node::InputEdges::begin() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400424 return Node::InputEdges::iterator(this->node_, 0);
425}
426
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000427
428Node::InputEdges::iterator Node::InputEdges::end() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400429 return Node::InputEdges::iterator(this->node_, this->node_->InputCount());
430}
431
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000432
433// A forward iterator to visit the inputs of a node.
434class Node::Inputs::const_iterator final {
435 public:
436 typedef std::forward_iterator_tag iterator_category;
437 typedef int difference_type;
438 typedef Node* value_type;
439 typedef Node** pointer;
440 typedef Node*& reference;
441
442 const_iterator(const const_iterator& other) : iter_(other.iter_) {}
443
444 Node* operator*() const { return (*iter_).to(); }
445 bool operator==(const const_iterator& other) const {
446 return iter_ == other.iter_;
447 }
448 bool operator!=(const const_iterator& other) const {
449 return !(*this == other);
450 }
451 const_iterator& operator++() {
452 ++iter_;
453 return *this;
454 }
455 const_iterator operator++(int);
456
457 private:
458 friend class Node::Inputs;
459
460 const_iterator(Node* node, int index) : iter_(node, index) {}
461
462 Node::InputEdges::iterator iter_;
463};
464
465
466Node::Inputs::const_iterator Node::Inputs::begin() const {
467 return const_iterator(this->node_, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400468}
469
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000470
471Node::Inputs::const_iterator Node::Inputs::end() const {
472 return const_iterator(this->node_, this->node_->InputCount());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400473}
474
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475
476// A forward iterator to visit the uses edges of a node.
477class Node::UseEdges::iterator final {
478 public:
479 iterator(const iterator& other)
480 : current_(other.current_), next_(other.next_) {}
481
482 Edge operator*() const { return Edge(current_, current_->input_ptr()); }
483 bool operator==(const iterator& other) const {
484 return current_ == other.current_;
485 }
486 bool operator!=(const iterator& other) const { return !(*this == other); }
487 iterator& operator++() {
488 DCHECK_NOT_NULL(current_);
489 current_ = next_;
490 next_ = current_ ? current_->next : nullptr;
491 return *this;
492 }
493 iterator operator++(int);
494
495 private:
496 friend class Node::UseEdges;
497
498 iterator() : current_(nullptr), next_(nullptr) {}
499 explicit iterator(Node* node)
500 : current_(node->first_use_),
501 next_(current_ ? current_->next : nullptr) {}
502
503 Node::Use* current_;
504 Node::Use* next_;
505};
506
507
508Node::UseEdges::iterator Node::UseEdges::begin() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400509 return Node::UseEdges::iterator(this->node_);
510}
511
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000512
513Node::UseEdges::iterator Node::UseEdges::end() const {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400514 return Node::UseEdges::iterator();
515}
516
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000517
518// A forward iterator to visit the uses of a node.
519class Node::Uses::const_iterator final {
520 public:
521 typedef std::forward_iterator_tag iterator_category;
522 typedef int difference_type;
523 typedef Node* value_type;
524 typedef Node** pointer;
525 typedef Node*& reference;
526
527 const_iterator(const const_iterator& other) : current_(other.current_) {}
528
529 Node* operator*() const { return current_->from(); }
530 bool operator==(const const_iterator& other) const {
531 return other.current_ == current_;
532 }
533 bool operator!=(const const_iterator& other) const {
534 return other.current_ != current_;
535 }
536 const_iterator& operator++() {
537 DCHECK_NOT_NULL(current_);
538 current_ = current_->next;
539 return *this;
540 }
541 const_iterator operator++(int);
542
543 private:
544 friend class Node::Uses;
545
546 const_iterator() : current_(nullptr) {}
547 explicit const_iterator(Node* node) : current_(node->first_use_) {}
548
549 Node::Use* current_;
550};
551
552
553Node::Uses::const_iterator Node::Uses::begin() const {
554 return const_iterator(this->node_);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400555}
556
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400557
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000558Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400559
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000560} // namespace compiler
561} // namespace internal
562} // namespace v8
563
564#endif // V8_COMPILER_NODE_H_