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/types.h"
11#include "src/zone-containers.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17// 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
27
28// NodeIds are identifying numbers for nodes that can be used to index auxiliary
29// out-of-line data associated with each node.
30typedef uint32_t NodeId;
31
32
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.
42class Node final {
43 public:
44  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);
47
48  bool IsDead() const { return InputCount() > 0 && !InputAt(0); }
49  void Kill();
50
51  const Operator* op() const { return op_; }
52
53  IrOpcode::Value opcode() const {
54    DCHECK(op_->opcode() <= IrOpcode::kLast);
55    return static_cast<IrOpcode::Value>(op_->opcode());
56  }
57
58  NodeId id() const { return IdField::decode(bit_field_); }
59
60  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);
106
107  int UseCount() const;
108  void ReplaceUses(Node* replace_to);
109
110  class InputEdges final {
111   public:
112    typedef Edge value_type;
113
114    class iterator;
115    inline iterator begin() const;
116    inline iterator end() const;
117
118    bool empty() const;
119
120    explicit InputEdges(Node* node) : node_(node) {}
121
122   private:
123    Node* node_;
124  };
125
126  InputEdges input_edges() { return InputEdges(this); }
127
128  class Inputs final {
129   public:
130    typedef Node* value_type;
131
132    class const_iterator;
133    inline const_iterator begin() const;
134    inline const_iterator end() const;
135
136    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); }
145
146  class UseEdges final {
147   public:
148    typedef Edge value_type;
149
150    class iterator;
151    inline iterator begin() const;
152    inline iterator end() const;
153
154    bool empty() const;
155
156    explicit UseEdges(Node* node) : node_(node) {}
157
158   private:
159    Node* node_;
160  };
161
162  UseEdges use_edges() { return UseEdges(this); }
163
164  class Uses final {
165   public:
166    typedef Node* value_type;
167
168    class const_iterator;
169    inline const_iterator begin() const;
170    inline const_iterator end() const;
171
172    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); }
181
182  // 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;
185  }
186
187  // 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);
284
285  void* operator new(size_t, void* location) { return location; }
286
287  // Only NodeProperties should manipulate the op.
288  void set_op(const Operator* op) { op_ = op; }
289
290  // Only NodeProperties should manipulate the type.
291  Type* type() const { return type_; }
292  void set_type(Type* type) { type_ = type; }
293
294  // Only NodeMarkers should manipulate the marks on nodes.
295  Mark mark() { return mark_; }
296  void set_mark(Mark mark) { mark_ = mark; }
297
298  inline bool has_inline_inputs() const {
299    return InlineCountField::decode(bit_field_) != kOutlineMarker;
300  }
301
302  void ClearInputs(int start, int count);
303
304  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;
310
311  const Operator* op_;
312  Type* type_;
313  Mark mark_;
314  uint32_t bit_field_;
315  Use* first_use_;
316  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;
325
326  DISALLOW_COPY_AND_ASSIGN(Node);
327};
328
329
330std::ostream& operator<<(std::ostream& os, const Node& n);
331
332
333// Typedefs to shorten commonly used Node containers.
334typedef ZoneDeque<Node*> NodeDeque;
335typedef ZoneSet<Node*> NodeSet;
336typedef ZoneVector<Node*> NodeVector;
337typedef ZoneVector<NodeVector> NodeVectorVector;
338
339
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
346
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 {
424  return Node::InputEdges::iterator(this->node_, 0);
425}
426
427
428Node::InputEdges::iterator Node::InputEdges::end() const {
429  return Node::InputEdges::iterator(this->node_, this->node_->InputCount());
430}
431
432
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);
468}
469
470
471Node::Inputs::const_iterator Node::Inputs::end() const {
472  return const_iterator(this->node_, this->node_->InputCount());
473}
474
475
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 {
509  return Node::UseEdges::iterator(this->node_);
510}
511
512
513Node::UseEdges::iterator Node::UseEdges::end() const {
514  return Node::UseEdges::iterator();
515}
516
517
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_);
555}
556
557
558Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
559
560}  // namespace compiler
561}  // namespace internal
562}  // namespace v8
563
564#endif  // V8_COMPILER_NODE_H_
565