• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace v8 {
14 namespace internal {
15 namespace compiler {
16 
17 // Forward declarations.
18 class Edge;
19 class 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.
25 typedef 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.
30 typedef 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.
42 class 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 
IsDead()48   bool IsDead() const { return InputCount() > 0 && !InputAt(0); }
49   void Kill();
50 
op()51   const Operator* op() const { return op_; }
52 
opcode()53   IrOpcode::Value opcode() const {
54     DCHECK(op_->opcode() <= IrOpcode::kLast);
55     return static_cast<IrOpcode::Value>(op_->opcode());
56   }
57 
id()58   NodeId id() const { return IdField::decode(bit_field_); }
59 
InputCount()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.
Verify()76   inline void Verify() {}
77 #define BOUNDS_CHECK(index) \
78   do {                      \
79   } while (false)
80 #endif
81 
InputAt(int index)82   Node* InputAt(int index) const {
83     BOUNDS_CHECK(index);
84     return *GetInputPtrConst(index);
85   }
86 
ReplaceInput(int index,Node * new_to)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 
InputEdges(Node * node)120     explicit InputEdges(Node* node) : node_(node) {}
121 
122    private:
123     Node* node_;
124   };
125 
input_edges()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 
Inputs(Node * node)138     explicit Inputs(Node* node) : node_(node) {}
139 
140    private:
141     Node* node_;
142   };
143 
inputs()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 
UseEdges(Node * node)156     explicit UseEdges(Node* node) : node_(node) {}
157 
158    private:
159     Node* node_;
160   };
161 
use_edges()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 
Uses(Node * node)174     explicit Uses(Node* node) : node_(node) {}
175 
176    private:
177     Node* node_;
178   };
179 
uses()180   Uses uses() { return Uses(this); }
181 
182   // Returns true if {owner} is the user of {this} node.
OwnedBy(Node * owner)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 
input_indexUse212     int input_index() const { return InputIndexField::decode(bit_field_); }
is_inline_useUse213     bool is_inline_use() const { return InlineField::decode(bit_field_); }
input_ptrUse214     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 
fromUse223     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 
GetInputPtrConst(int input_index)268   Node* const* GetInputPtrConst(int input_index) const {
269     return has_inline_inputs() ? &(inputs_.inline_[input_index])
270                                : &inputs_.outline_->inputs_[input_index];
271   }
GetInputPtr(int input_index)272   Node** GetInputPtr(int input_index) {
273     return has_inline_inputs() ? &(inputs_.inline_[input_index])
274                                : &inputs_.outline_->inputs_[input_index];
275   }
GetUsePtr(int input_index)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 
new(size_t,void * location)285   void* operator new(size_t, void* location) { return location; }
286 
287   // Only NodeProperties should manipulate the op.
set_op(const Operator * op)288   void set_op(const Operator* op) { op_ = op; }
289 
290   // Only NodeProperties should manipulate the type.
type()291   Type* type() const { return type_; }
set_type(Type * type)292   void set_type(Type* type) { type_ = type; }
293 
294   // Only NodeMarkers should manipulate the marks on nodes.
mark()295   Mark mark() { return mark_; }
set_mark(Mark mark)296   void set_mark(Mark mark) { mark_ = mark; }
297 
has_inline_inputs()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 
330 std::ostream& operator<<(std::ostream& os, const Node& n);
331 
332 
333 // Typedefs to shorten commonly used Node containers.
334 typedef ZoneDeque<Node*> NodeDeque;
335 typedef ZoneSet<Node*> NodeSet;
336 typedef ZoneVector<Node*> NodeVector;
337 typedef ZoneVector<NodeVector> NodeVectorVector;
338 
339 
340 // Helper to extract parameters from Operator1<*> nodes.
341 template <typename T>
OpParameter(const Node * node)342 static 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.
350 class Edge final {
351  public:
from()352   Node* from() const { return use_->from(); }
to()353   Node* to() const { return *input_ptr_; }
index()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 
UpdateTo(Node * new_to)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 
Edge(Node::Use * use,Node ** input_ptr)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.
388 class 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 
iterator()396   iterator() : use_(nullptr), input_ptr_(nullptr) {}
iterator(const iterator & other)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 
begin()423 Node::InputEdges::iterator Node::InputEdges::begin() const {
424   return Node::InputEdges::iterator(this->node_, 0);
425 }
426 
427 
end()428 Node::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.
434 class 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 
const_iterator(const const_iterator & other)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 
const_iterator(Node * node,int index)460   const_iterator(Node* node, int index) : iter_(node, index) {}
461 
462   Node::InputEdges::iterator iter_;
463 };
464 
465 
begin()466 Node::Inputs::const_iterator Node::Inputs::begin() const {
467   return const_iterator(this->node_, 0);
468 }
469 
470 
end()471 Node::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.
477 class Node::UseEdges::iterator final {
478  public:
iterator(const iterator & other)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 
iterator()498   iterator() : current_(nullptr), next_(nullptr) {}
iterator(Node * node)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 
begin()508 Node::UseEdges::iterator Node::UseEdges::begin() const {
509   return Node::UseEdges::iterator(this->node_);
510 }
511 
512 
end()513 Node::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.
519 class 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 
const_iterator(const const_iterator & other)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 
const_iterator()546   const_iterator() : current_(nullptr) {}
const_iterator(Node * node)547   explicit const_iterator(Node* node) : current_(node->first_use_) {}
548 
549   Node::Use* current_;
550 };
551 
552 
begin()553 Node::Uses::const_iterator Node::Uses::begin() const {
554   return const_iterator(this->node_);
555 }
556 
557 
end()558 Node::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