Home | History | Annotate | Download | only in compiler
      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 
     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 
    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>
    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:
    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.
    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 
    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 
    423 Node::InputEdges::iterator Node::InputEdges::begin() const {
    424   return Node::InputEdges::iterator(this->node_, 0);
    425 }
    426 
    427 
    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 
    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 
    466 Node::Inputs::const_iterator Node::Inputs::begin() const {
    467   return const_iterator(this->node_, 0);
    468 }
    469 
    470 
    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:
    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 
    508 Node::UseEdges::iterator Node::UseEdges::begin() const {
    509   return Node::UseEdges::iterator(this->node_);
    510 }
    511 
    512 
    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 
    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 
    553 Node::Uses::const_iterator Node::Uses::begin() const {
    554   return const_iterator(this->node_);
    555 }
    556 
    557 
    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