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