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/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 
     49   inline bool IsDead() const;
     50   void Kill();
     51 
     52   const Operator* op() const { return op_; }
     53 
     54   IrOpcode::Value opcode() const {
     55     DCHECK(op_->opcode() <= IrOpcode::kLast);
     56     return static_cast<IrOpcode::Value>(op_->opcode());
     57   }
     58 
     59   NodeId id() const { return IdField::decode(bit_field_); }
     60 
     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.
     77   inline void Verify() {}
     78 #define BOUNDS_CHECK(index) \
     79   do {                      \
     80   } while (false)
     81 #endif
     82 
     83   Node* InputAt(int index) const {
     84     BOUNDS_CHECK(index);
     85     return *GetInputPtrConst(index);
     86   }
     87 
     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;
    113   inline InputEdges input_edges();
    114 
    115   class Inputs;
    116   inline Inputs inputs() const;
    117 
    118   class UseEdges final {
    119    public:
    120     typedef Edge value_type;
    121 
    122     class iterator;
    123     inline iterator begin() const;
    124     inline iterator end() const;
    125 
    126     bool empty() const;
    127 
    128     explicit UseEdges(Node* node) : node_(node) {}
    129 
    130    private:
    131     Node* node_;
    132   };
    133 
    134   UseEdges use_edges() { return UseEdges(this); }
    135 
    136   class V8_EXPORT_PRIVATE Uses final {
    137    public:
    138     typedef Node* value_type;
    139 
    140     class const_iterator;
    141     inline const_iterator begin() const;
    142     inline const_iterator end() const;
    143 
    144     bool empty() const;
    145 
    146     explicit Uses(Node* node) : node_(node) {}
    147 
    148    private:
    149     Node* node_;
    150   };
    151 
    152   Uses uses() { return Uses(this); }
    153 
    154   // Returns true if {owner} is the user of {this} node.
    155   bool OwnedBy(Node* owner) const {
    156     return first_use_ && first_use_->from() == owner && !first_use_->next;
    157   }
    158 
    159   // Returns true if {owner1} and {owner2} are the only users of {this} node.
    160   bool OwnedBy(Node const* owner1, Node const* owner2) const;
    161 
    162   // Returns true if addressing related operands (such as load, store, lea)
    163   // are the only users of {this} node.
    164   bool OwnedByAddressingOperand() const;
    165   void Print() const;
    166 
    167  private:
    168   struct Use;
    169   // Out of line storage for inputs when the number of inputs overflowed the
    170   // capacity of the inline-allocated space.
    171   struct OutOfLineInputs {
    172     Node* node_;
    173     int count_;
    174     int capacity_;
    175     Node* inputs_[1];
    176 
    177     static OutOfLineInputs* New(Zone* zone, int capacity);
    178     void ExtractFrom(Use* use_ptr, Node** input_ptr, int count);
    179   };
    180 
    181   // A link in the use chain for a node. Every input {i} to a node {n} has an
    182   // associated {Use} which is linked into the use chain of the {i} node.
    183   struct Use {
    184     Use* next;
    185     Use* prev;
    186     uint32_t bit_field_;
    187 
    188     int input_index() const { return InputIndexField::decode(bit_field_); }
    189     bool is_inline_use() const { return InlineField::decode(bit_field_); }
    190     Node** input_ptr() {
    191       int index = input_index();
    192       Use* start = this + 1 + index;
    193       Node** inputs = is_inline_use()
    194                           ? reinterpret_cast<Node*>(start)->inputs_.inline_
    195                           : reinterpret_cast<OutOfLineInputs*>(start)->inputs_;
    196       return &inputs[index];
    197     }
    198 
    199     Node* from() {
    200       Use* start = this + 1 + input_index();
    201       return is_inline_use() ? reinterpret_cast<Node*>(start)
    202                              : reinterpret_cast<OutOfLineInputs*>(start)->node_;
    203     }
    204 
    205     typedef BitField<bool, 0, 1> InlineField;
    206     typedef BitField<unsigned, 1, 17> InputIndexField;
    207     // Leaving some space in the bitset in case we ever decide to record
    208     // the output index.
    209   };
    210 
    211   //============================================================================
    212   //== Memory layout ===========================================================
    213   //============================================================================
    214   // Saving space for big graphs is important. We use a memory layout trick to
    215   // be able to map {Node} objects to {Use} objects and vice-versa in a
    216   // space-efficient manner.
    217   //
    218   // {Use} links are laid out in memory directly before a {Node}, followed by
    219   // direct pointers to input {Nodes}.
    220   //
    221   // inline case:
    222   // |Use #N  |Use #N-1|...|Use #1  |Use #0  |Node xxxx |I#0|I#1|...|I#N-1|I#N|
    223   //          ^                              ^                  ^
    224   //          + Use                          + Node             + Input
    225   //
    226   // Since every {Use} instance records its {input_index}, pointer arithmetic
    227   // can compute the {Node}.
    228   //
    229   // out-of-line case:
    230   //     |Node xxxx |
    231   //     ^       + outline ------------------+
    232   //     +----------------------------------------+
    233   //                                         |    |
    234   //                                         v    | node
    235   // |Use #N  |Use #N-1|...|Use #1  |Use #0  |OOL xxxxx |I#0|I#1|...|I#N-1|I#N|
    236   //          ^                                                 ^
    237   //          + Use                                             + Input
    238   //
    239   // Out-of-line storage of input lists is needed if appending an input to
    240   // a node exceeds the maximum inline capacity.
    241 
    242   Node(NodeId id, const Operator* op, int inline_count, int inline_capacity);
    243 
    244   Node* const* GetInputPtrConst(int input_index) const {
    245     return has_inline_inputs() ? &(inputs_.inline_[input_index])
    246                                : &inputs_.outline_->inputs_[input_index];
    247   }
    248   Node** GetInputPtr(int input_index) {
    249     return has_inline_inputs() ? &(inputs_.inline_[input_index])
    250                                : &inputs_.outline_->inputs_[input_index];
    251   }
    252   Use* GetUsePtr(int input_index) {
    253     Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
    254                                    : reinterpret_cast<Use*>(inputs_.outline_);
    255     return &ptr[-1 - input_index];
    256   }
    257 
    258   void AppendUse(Use* use);
    259   void RemoveUse(Use* use);
    260 
    261   void* operator new(size_t, void* location) { return location; }
    262 
    263   // Only NodeProperties should manipulate the op.
    264   void set_op(const Operator* op) { op_ = op; }
    265 
    266   // Only NodeProperties should manipulate the type.
    267   Type* type() const { return type_; }
    268   void set_type(Type* type) { type_ = type; }
    269 
    270   // Only NodeMarkers should manipulate the marks on nodes.
    271   Mark mark() const { return mark_; }
    272   void set_mark(Mark mark) { mark_ = mark; }
    273 
    274   inline bool has_inline_inputs() const {
    275     return InlineCountField::decode(bit_field_) != kOutlineMarker;
    276   }
    277 
    278   void ClearInputs(int start, int count);
    279 
    280   typedef BitField<NodeId, 0, 24> IdField;
    281   typedef BitField<unsigned, 24, 4> InlineCountField;
    282   typedef BitField<unsigned, 28, 4> InlineCapacityField;
    283   static const int kOutlineMarker = InlineCountField::kMax;
    284   static const int kMaxInlineCount = InlineCountField::kMax - 1;
    285   static const int kMaxInlineCapacity = InlineCapacityField::kMax - 1;
    286 
    287   const Operator* op_;
    288   Type* type_;
    289   Mark mark_;
    290   uint32_t bit_field_;
    291   Use* first_use_;
    292   union {
    293     // Inline storage for inputs or out-of-line storage.
    294     Node* inline_[1];
    295     OutOfLineInputs* outline_;
    296   } inputs_;
    297 
    298   friend class Edge;
    299   friend class NodeMarkerBase;
    300   friend class NodeProperties;
    301 
    302   DISALLOW_COPY_AND_ASSIGN(Node);
    303 };
    304 
    305 
    306 std::ostream& operator<<(std::ostream& os, const Node& n);
    307 
    308 
    309 // Typedefs to shorten commonly used Node containers.
    310 typedef ZoneDeque<Node*> NodeDeque;
    311 typedef ZoneSet<Node*> NodeSet;
    312 typedef ZoneVector<Node*> NodeVector;
    313 typedef ZoneVector<NodeVector> NodeVectorVector;
    314 
    315 
    316 // Helper to extract parameters from Operator1<*> nodes.
    317 template <typename T>
    318 static inline const T& OpParameter(const Node* node) {
    319   return OpParameter<T>(node->op());
    320 }
    321 
    322 class Node::InputEdges final {
    323  public:
    324   typedef Edge value_type;
    325 
    326   class iterator;
    327   inline iterator begin() const;
    328   inline iterator end() const;
    329 
    330   bool empty() const { return count_ == 0; }
    331   int count() const { return count_; }
    332 
    333   inline value_type operator[](int index) const;
    334 
    335   InputEdges(Node** input_root, Use* use_root, int count)
    336       : input_root_(input_root), use_root_(use_root), count_(count) {}
    337 
    338  private:
    339   Node** input_root_;
    340   Use* use_root_;
    341   int count_;
    342 };
    343 
    344 class V8_EXPORT_PRIVATE Node::Inputs final {
    345  public:
    346   typedef Node* value_type;
    347 
    348   class const_iterator;
    349   inline const_iterator begin() const;
    350   inline const_iterator end() const;
    351 
    352   bool empty() const { return count_ == 0; }
    353   int count() const { return count_; }
    354 
    355   inline value_type operator[](int index) const;
    356 
    357   explicit Inputs(Node* const* input_root, int count)
    358       : input_root_(input_root), count_(count) {}
    359 
    360  private:
    361   Node* const* input_root_;
    362   int count_;
    363 };
    364 
    365 // An encapsulation for information associated with a single use of node as a
    366 // input from another node, allowing access to both the defining node and
    367 // the node having the input.
    368 class Edge final {
    369  public:
    370   Node* from() const { return use_->from(); }
    371   Node* to() const { return *input_ptr_; }
    372   int index() const {
    373     int const index = use_->input_index();
    374     DCHECK_LT(index, use_->from()->InputCount());
    375     return index;
    376   }
    377 
    378   bool operator==(const Edge& other) { return input_ptr_ == other.input_ptr_; }
    379   bool operator!=(const Edge& other) { return !(*this == other); }
    380 
    381   void UpdateTo(Node* new_to) {
    382     Node* old_to = *input_ptr_;
    383     if (old_to != new_to) {
    384       if (old_to) old_to->RemoveUse(use_);
    385       *input_ptr_ = new_to;
    386       if (new_to) new_to->AppendUse(use_);
    387     }
    388   }
    389 
    390  private:
    391   friend class Node::UseEdges::iterator;
    392   friend class Node::InputEdges;
    393   friend class Node::InputEdges::iterator;
    394 
    395   Edge(Node::Use* use, Node** input_ptr) : use_(use), input_ptr_(input_ptr) {
    396     DCHECK_NOT_NULL(use);
    397     DCHECK_NOT_NULL(input_ptr);
    398     DCHECK_EQ(input_ptr, use->input_ptr());
    399   }
    400 
    401   Node::Use* use_;
    402   Node** input_ptr_;
    403 };
    404 
    405 bool Node::IsDead() const {
    406   Node::Inputs inputs = this->inputs();
    407   return inputs.count() > 0 && inputs[0] == nullptr;
    408 }
    409 
    410 Node::InputEdges Node::input_edges() {
    411   int inline_count = InlineCountField::decode(bit_field_);
    412   if (inline_count != kOutlineMarker) {
    413     return InputEdges(inputs_.inline_, reinterpret_cast<Use*>(this) - 1,
    414                       inline_count);
    415   } else {
    416     return InputEdges(inputs_.outline_->inputs_,
    417                       reinterpret_cast<Use*>(inputs_.outline_) - 1,
    418                       inputs_.outline_->count_);
    419   }
    420 }
    421 
    422 Node::Inputs Node::inputs() const {
    423   int inline_count = InlineCountField::decode(bit_field_);
    424   if (inline_count != kOutlineMarker) {
    425     return Inputs(inputs_.inline_, inline_count);
    426   } else {
    427     return Inputs(inputs_.outline_->inputs_, inputs_.outline_->count_);
    428   }
    429 }
    430 
    431 // A forward iterator to visit the edges for the input dependencies of a node.
    432 class Node::InputEdges::iterator final {
    433  public:
    434   typedef std::forward_iterator_tag iterator_category;
    435   typedef std::ptrdiff_t difference_type;
    436   typedef Edge value_type;
    437   typedef Edge* pointer;
    438   typedef Edge& reference;
    439 
    440   iterator() : use_(nullptr), input_ptr_(nullptr) {}
    441   iterator(const iterator& other)
    442       : use_(other.use_), input_ptr_(other.input_ptr_) {}
    443 
    444   Edge operator*() const { return Edge(use_, input_ptr_); }
    445   bool operator==(const iterator& other) const {
    446     return input_ptr_ == other.input_ptr_;
    447   }
    448   bool operator!=(const iterator& other) const { return !(*this == other); }
    449   iterator& operator++() {
    450     input_ptr_++;
    451     use_--;
    452     return *this;
    453   }
    454   iterator operator++(int);
    455   iterator& operator+=(difference_type offset) {
    456     input_ptr_ += offset;
    457     use_ -= offset;
    458     return *this;
    459   }
    460   iterator operator+(difference_type offset) const {
    461     return iterator(use_ - offset, input_ptr_ + offset);
    462   }
    463   difference_type operator-(const iterator& other) const {
    464     return input_ptr_ - other.input_ptr_;
    465   }
    466 
    467  private:
    468   friend class Node;
    469 
    470   explicit iterator(Use* use, Node** input_ptr)
    471       : use_(use), input_ptr_(input_ptr) {}
    472 
    473   Use* use_;
    474   Node** input_ptr_;
    475 };
    476 
    477 
    478 Node::InputEdges::iterator Node::InputEdges::begin() const {
    479   return Node::InputEdges::iterator(use_root_, input_root_);
    480 }
    481 
    482 
    483 Node::InputEdges::iterator Node::InputEdges::end() const {
    484   return Node::InputEdges::iterator(use_root_ - count_, input_root_ + count_);
    485 }
    486 
    487 Edge Node::InputEdges::operator[](int index) const {
    488   return Edge(use_root_ + index, input_root_ + index);
    489 }
    490 
    491 // A forward iterator to visit the inputs of a node.
    492 class Node::Inputs::const_iterator final {
    493  public:
    494   typedef std::forward_iterator_tag iterator_category;
    495   typedef std::ptrdiff_t difference_type;
    496   typedef Node* value_type;
    497   typedef const value_type* pointer;
    498   typedef value_type& reference;
    499 
    500   const_iterator(const const_iterator& other) : input_ptr_(other.input_ptr_) {}
    501 
    502   Node* operator*() const { return *input_ptr_; }
    503   bool operator==(const const_iterator& other) const {
    504     return input_ptr_ == other.input_ptr_;
    505   }
    506   bool operator!=(const const_iterator& other) const {
    507     return !(*this == other);
    508   }
    509   const_iterator& operator++() {
    510     ++input_ptr_;
    511     return *this;
    512   }
    513   const_iterator operator++(int);
    514   const_iterator& operator+=(difference_type offset) {
    515     input_ptr_ += offset;
    516     return *this;
    517   }
    518   const_iterator operator+(difference_type offset) const {
    519     return const_iterator(input_ptr_ + offset);
    520   }
    521   difference_type operator-(const const_iterator& other) const {
    522     return input_ptr_ - other.input_ptr_;
    523   }
    524 
    525  private:
    526   friend class Node::Inputs;
    527 
    528   explicit const_iterator(Node* const* input_ptr) : input_ptr_(input_ptr) {}
    529 
    530   Node* const* input_ptr_;
    531 };
    532 
    533 
    534 Node::Inputs::const_iterator Node::Inputs::begin() const {
    535   return const_iterator(input_root_);
    536 }
    537 
    538 
    539 Node::Inputs::const_iterator Node::Inputs::end() const {
    540   return const_iterator(input_root_ + count_);
    541 }
    542 
    543 Node* Node::Inputs::operator[](int index) const { return input_root_[index]; }
    544 
    545 // A forward iterator to visit the uses edges of a node.
    546 class Node::UseEdges::iterator final {
    547  public:
    548   iterator(const iterator& other)
    549       : current_(other.current_), next_(other.next_) {}
    550 
    551   Edge operator*() const { return Edge(current_, current_->input_ptr()); }
    552   bool operator==(const iterator& other) const {
    553     return current_ == other.current_;
    554   }
    555   bool operator!=(const iterator& other) const { return !(*this == other); }
    556   iterator& operator++() {
    557     DCHECK_NOT_NULL(current_);
    558     current_ = next_;
    559     next_ = current_ ? current_->next : nullptr;
    560     return *this;
    561   }
    562   iterator operator++(int);
    563 
    564  private:
    565   friend class Node::UseEdges;
    566 
    567   iterator() : current_(nullptr), next_(nullptr) {}
    568   explicit iterator(Node* node)
    569       : current_(node->first_use_),
    570         next_(current_ ? current_->next : nullptr) {}
    571 
    572   Node::Use* current_;
    573   Node::Use* next_;
    574 };
    575 
    576 
    577 Node::UseEdges::iterator Node::UseEdges::begin() const {
    578   return Node::UseEdges::iterator(this->node_);
    579 }
    580 
    581 
    582 Node::UseEdges::iterator Node::UseEdges::end() const {
    583   return Node::UseEdges::iterator();
    584 }
    585 
    586 
    587 // A forward iterator to visit the uses of a node.
    588 class Node::Uses::const_iterator final {
    589  public:
    590   typedef std::forward_iterator_tag iterator_category;
    591   typedef int difference_type;
    592   typedef Node* value_type;
    593   typedef Node** pointer;
    594   typedef Node*& reference;
    595 
    596   const_iterator(const const_iterator& other) : current_(other.current_) {}
    597 
    598   Node* operator*() const { return current_->from(); }
    599   bool operator==(const const_iterator& other) const {
    600     return other.current_ == current_;
    601   }
    602   bool operator!=(const const_iterator& other) const {
    603     return other.current_ != current_;
    604   }
    605   const_iterator& operator++() {
    606     DCHECK_NOT_NULL(current_);
    607     current_ = current_->next;
    608     return *this;
    609   }
    610   const_iterator operator++(int);
    611 
    612  private:
    613   friend class Node::Uses;
    614 
    615   const_iterator() : current_(nullptr) {}
    616   explicit const_iterator(Node* node) : current_(node->first_use_) {}
    617 
    618   Node::Use* current_;
    619 };
    620 
    621 
    622 Node::Uses::const_iterator Node::Uses::begin() const {
    623   return const_iterator(this->node_);
    624 }
    625 
    626 
    627 Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
    628 
    629 }  // namespace compiler
    630 }  // namespace internal
    631 }  // namespace v8
    632 
    633 #endif  // V8_COMPILER_NODE_H_
    634