node.h 18.2 KB
Newer Older
1 2 3 4 5 6 7 8 9
// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_NODE_H_
#define V8_COMPILER_NODE_H_

#include "src/compiler/opcodes.h"
#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 15 16 17

namespace v8 {
namespace internal {
namespace compiler {

18
// Forward declarations.
danno's avatar
danno committed
19
class Edge;
20 21
class Graph;

22

23 24 25 26 27
// Marks are used during traversal of the graph to distinguish states of nodes.
// Each node has a mark which is a monotonically increasing integer, and a
// {NodeMarker} has a range of values that indicate states of a node.
typedef uint32_t Mark;

28

29 30
// NodeIds are identifying numbers for nodes that can be used to index auxiliary
// out-of-line data associated with each node.
31
typedef uint32_t NodeId;
32

33

34 35 36 37 38 39 40 41 42
// A Node is the basic primitive of graphs. Nodes are chained together by
// input/use chains but by default otherwise contain only an identifying number
// which specific applications of graphs and nodes can use to index auxiliary
// out-of-line data, especially transient data.
//
// In addition Nodes only contain a mutable Operator that may change during
// compilation, e.g. during lowering passes. Other information that needs to be
// associated with Nodes during compilation must be stored out-of-line indexed
// 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 47
                   Node* const* inputs, bool has_extensible_inputs);
  static Node* Clone(Zone* zone, NodeId id, const Node* node);
48

49
  inline bool IsDead() const;
50
  void Kill();
51

52 53 54
  const Operator* op() const { return op_; }

  IrOpcode::Value opcode() const {
55
    DCHECK_GE(IrOpcode::kLast, op_->opcode());
56 57 58
    return static_cast<IrOpcode::Value>(op_->opcode());
  }

59 60 61 62 63 64
  NodeId id() const { return IdField::decode(bit_field_); }

  int InputCount() const {
    return has_inline_inputs() ? InlineCountField::decode(bit_field_)
                               : inputs_.outline_->count_;
  }
65

66
#ifdef DEBUG
67
  void Verify();
68 69 70 71 72 73
#define BOUNDS_CHECK(index)                                                   \
  do {                                                                        \
    if (index < 0 || index >= InputCount()) {                                 \
      FATAL("Node #%d:%s->InputAt(%d) out of bounds", id(), op()->mnemonic(), \
            index);                                                           \
    }                                                                         \
74 75 76 77 78 79 80
  } while (false)
#else
  // No bounds checks or verification in release mode.
  inline void Verify() {}
#define BOUNDS_CHECK(index) \
  do {                      \
  } while (false)
81
#endif
82 83 84 85

  Node* InputAt(int index) const {
    BOUNDS_CHECK(index);
    return *GetInputPtrConst(index);
86
  }
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

  void ReplaceInput(int index, Node* new_to) {
    BOUNDS_CHECK(index);
    Node** input_ptr = GetInputPtr(index);
    Node* old_to = *input_ptr;
    if (old_to != new_to) {
      Use* use = GetUsePtr(index);
      if (old_to) old_to->RemoveUse(use);
      *input_ptr = new_to;
      if (new_to) new_to->AppendUse(use);
    }
  }

#undef BOUNDS_CHECK

102 103
  void AppendInput(Zone* zone, Node* new_to);
  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 113
  class InputEdges;
  inline InputEdges input_edges();
114

115 116
  class Inputs;
  inline Inputs inputs() const;
danno's avatar
danno committed
117

118
  class UseEdges final {
danno's avatar
danno committed
119
   public:
120 121
    typedef Edge value_type;

danno's avatar
danno committed
122
    class iterator;
123 124 125
    inline iterator begin() const;
    inline iterator end() const;

danno's avatar
danno committed
126 127 128 129 130 131 132
    bool empty() const;

    explicit UseEdges(Node* node) : node_(node) {}

   private:
    Node* node_;
  };
133

134 135
  UseEdges use_edges() { return UseEdges(this); }

136
  class V8_EXPORT_PRIVATE Uses final {
137
   public:
138 139 140 141 142 143
    typedef Node* value_type;

    class const_iterator;
    inline const_iterator begin() const;
    inline const_iterator end() const;

danno's avatar
danno committed
144
    bool empty() const;
145 146 147 148 149 150 151 152 153

    explicit Uses(Node* node) : node_(node) {}

   private:
    Node* node_;
  };

  Uses uses() { return Uses(this); }

154 155
  // Returns true if {owner} is the user of {this} node.
  bool OwnedBy(Node* owner) const {
156
    return first_use_ && first_use_->from() == owner && !first_use_->next;
157
  }
158

159 160
  // Returns true if {owner1} and {owner2} are the only users of {this} node.
  bool OwnedBy(Node const* owner1, Node const* owner2) const;
161

162
  void Print() const;
163

164
 private:
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
  struct Use;
  // Out of line storage for inputs when the number of inputs overflowed the
  // capacity of the inline-allocated space.
  struct OutOfLineInputs {
    Node* node_;
    int count_;
    int capacity_;
    Node* inputs_[1];

    static OutOfLineInputs* New(Zone* zone, int capacity);
    void ExtractFrom(Use* use_ptr, Node** input_ptr, int count);
  };

  // A link in the use chain for a node. Every input {i} to a node {n} has an
  // associated {Use} which is linked into the use chain of the {i} node.
  struct Use {
181 182
    Use* next;
    Use* prev;
183 184 185 186 187 188 189 190 191 192 193 194
    uint32_t bit_field_;

    int input_index() const { return InputIndexField::decode(bit_field_); }
    bool is_inline_use() const { return InlineField::decode(bit_field_); }
    Node** input_ptr() {
      int index = input_index();
      Use* start = this + 1 + index;
      Node** inputs = is_inline_use()
                          ? reinterpret_cast<Node*>(start)->inputs_.inline_
                          : reinterpret_cast<OutOfLineInputs*>(start)->inputs_;
      return &inputs[index];
    }
195

196 197 198 199 200
    Node* from() {
      Use* start = this + 1 + input_index();
      return is_inline_use() ? reinterpret_cast<Node*>(start)
                             : reinterpret_cast<OutOfLineInputs*>(start)->node_;
    }
201

202 203
    typedef BitField<bool, 0, 1> InlineField;
    typedef BitField<unsigned, 1, 17> InputIndexField;
204 205
    // Leaving some space in the bitset in case we ever decide to record
    // the output index.
206 207
  };

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
  //============================================================================
  //== Memory layout ===========================================================
  //============================================================================
  // Saving space for big graphs is important. We use a memory layout trick to
  // be able to map {Node} objects to {Use} objects and vice-versa in a
  // space-efficient manner.
  //
  // {Use} links are laid out in memory directly before a {Node}, followed by
  // direct pointers to input {Nodes}.
  //
  // inline case:
  // |Use #N  |Use #N-1|...|Use #1  |Use #0  |Node xxxx |I#0|I#1|...|I#N-1|I#N|
  //          ^                              ^                  ^
  //          + Use                          + Node             + Input
  //
  // Since every {Use} instance records its {input_index}, pointer arithmetic
  // can compute the {Node}.
  //
  // out-of-line case:
  //     |Node xxxx |
  //     ^       + outline ------------------+
  //     +----------------------------------------+
  //                                         |    |
  //                                         v    | node
  // |Use #N  |Use #N-1|...|Use #1  |Use #0  |OOL xxxxx |I#0|I#1|...|I#N-1|I#N|
  //          ^                                                 ^
  //          + Use                                             + Input
  //
  // Out-of-line storage of input lists is needed if appending an input to
  // a node exceeds the maximum inline capacity.

  Node(NodeId id, const Operator* op, int inline_count, int inline_capacity);

  Node* const* GetInputPtrConst(int input_index) const {
    return has_inline_inputs() ? &(inputs_.inline_[input_index])
                               : &inputs_.outline_->inputs_[input_index];
244
  }
245 246 247 248 249 250 251 252
  Node** GetInputPtr(int input_index) {
    return has_inline_inputs() ? &(inputs_.inline_[input_index])
                               : &inputs_.outline_->inputs_[input_index];
  }
  Use* GetUsePtr(int input_index) {
    Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
                                   : reinterpret_cast<Use*>(inputs_.outline_);
    return &ptr[-1 - input_index];
253 254
  }

255 256
  void AppendUse(Use* use);
  void RemoveUse(Use* use);
257 258 259

  void* operator new(size_t, void* location) { return location; }

260 261 262
  // Only NodeProperties should manipulate the op.
  void set_op(const Operator* op) { op_ = op; }

263
  // Only NodeProperties should manipulate the type.
264 265
  Type type() const { return type_; }
  void set_type(Type type) { type_ = type; }
266 267

  // Only NodeMarkers should manipulate the marks on nodes.
268
  Mark mark() const { return mark_; }
269 270
  void set_mark(Mark mark) { mark_ = mark; }

271 272
  inline bool has_inline_inputs() const {
    return InlineCountField::decode(bit_field_) != kOutlineMarker;
273 274
  }

275
  void ClearInputs(int start, int count);
276

277 278 279 280 281 282
  typedef BitField<NodeId, 0, 24> IdField;
  typedef BitField<unsigned, 24, 4> InlineCountField;
  typedef BitField<unsigned, 28, 4> InlineCapacityField;
  static const int kOutlineMarker = InlineCountField::kMax;
  static const int kMaxInlineCount = InlineCountField::kMax - 1;
  static const int kMaxInlineCapacity = InlineCapacityField::kMax - 1;
283

284
  const Operator* op_;
285
  Type type_;
286
  Mark mark_;
287
  uint32_t bit_field_;
288
  Use* first_use_;
289
  union {
290 291 292
    // Inline storage for inputs or out-of-line storage.
    Node* inline_[1];
    OutOfLineInputs* outline_;
293 294
  } inputs_;

295 296 297 298
  friend class Edge;
  friend class NodeMarkerBase;
  friend class NodeProperties;

299 300 301
  DISALLOW_COPY_AND_ASSIGN(Node);
};

302

303 304 305 306 307
std::ostream& operator<<(std::ostream& os, const Node& n);


// Typedefs to shorten commonly used Node containers.
typedef ZoneDeque<Node*> NodeDeque;
308
typedef ZoneSet<Node*> NodeSet;
309 310 311 312
typedef ZoneVector<Node*> NodeVector;
typedef ZoneVector<NodeVector> NodeVectorVector;


313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
class Node::InputEdges final {
 public:
  typedef Edge value_type;

  class iterator;
  inline iterator begin() const;
  inline iterator end() const;

  bool empty() const { return count_ == 0; }
  int count() const { return count_; }

  inline value_type operator[](int index) const;

  InputEdges(Node** input_root, Use* use_root, int count)
      : input_root_(input_root), use_root_(use_root), count_(count) {}

 private:
  Node** input_root_;
  Use* use_root_;
  int count_;
};

class V8_EXPORT_PRIVATE Node::Inputs final {
 public:
  typedef Node* value_type;

  class const_iterator;
  inline const_iterator begin() const;
  inline const_iterator end() const;

  bool empty() const { return count_ == 0; }
  int count() const { return count_; }

  inline value_type operator[](int index) const;

  explicit Inputs(Node* const* input_root, int count)
      : input_root_(input_root), count_(count) {}

 private:
  Node* const* input_root_;
  int count_;
};
355

356 357
// An encapsulation for information associated with a single use of node as a
// input from another node, allowing access to both the defining node and
danno's avatar
danno committed
358
// the node having the input.
359
class Edge final {
360
 public:
361 362
  Node* from() const { return use_->from(); }
  Node* to() const { return *input_ptr_; }
363
  int index() const {
364 365
    int const index = use_->input_index();
    DCHECK_LT(index, use_->from()->InputCount());
366 367 368
    return index;
  }

369
  bool operator==(const Edge& other) { return input_ptr_ == other.input_ptr_; }
danno's avatar
danno committed
370 371
  bool operator!=(const Edge& other) { return !(*this == other); }

372 373 374 375 376 377 378 379
  void UpdateTo(Node* new_to) {
    Node* old_to = *input_ptr_;
    if (old_to != new_to) {
      if (old_to) old_to->RemoveUse(use_);
      *input_ptr_ = new_to;
      if (new_to) new_to->AppendUse(use_);
    }
  }
danno's avatar
danno committed
380

381
 private:
danno's avatar
danno committed
382
  friend class Node::UseEdges::iterator;
383
  friend class Node::InputEdges;
danno's avatar
danno committed
384
  friend class Node::InputEdges::iterator;
385

386 387 388 389 390
  Edge(Node::Use* use, Node** input_ptr) : use_(use), input_ptr_(input_ptr) {
    DCHECK_NOT_NULL(use);
    DCHECK_NOT_NULL(input_ptr);
    DCHECK_EQ(input_ptr, use->input_ptr());
  }
391

392 393
  Node::Use* use_;
  Node** input_ptr_;
394 395
};

396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
bool Node::IsDead() const {
  Node::Inputs inputs = this->inputs();
  return inputs.count() > 0 && inputs[0] == nullptr;
}

Node::InputEdges Node::input_edges() {
  int inline_count = InlineCountField::decode(bit_field_);
  if (inline_count != kOutlineMarker) {
    return InputEdges(inputs_.inline_, reinterpret_cast<Use*>(this) - 1,
                      inline_count);
  } else {
    return InputEdges(inputs_.outline_->inputs_,
                      reinterpret_cast<Use*>(inputs_.outline_) - 1,
                      inputs_.outline_->count_);
  }
}

Node::Inputs Node::inputs() const {
  int inline_count = InlineCountField::decode(bit_field_);
  if (inline_count != kOutlineMarker) {
    return Inputs(inputs_.inline_, inline_count);
  } else {
    return Inputs(inputs_.outline_->inputs_, inputs_.outline_->count_);
  }
}
421

422
// A forward iterator to visit the edges for the input dependencies of a node.
423
class Node::InputEdges::iterator final {
danno's avatar
danno committed
424 425
 public:
  typedef std::forward_iterator_tag iterator_category;
426
  typedef std::ptrdiff_t difference_type;
danno's avatar
danno committed
427 428 429
  typedef Edge value_type;
  typedef Edge* pointer;
  typedef Edge& reference;
430

431
  iterator() : use_(nullptr), input_ptr_(nullptr) {}
432
  iterator(const iterator& other) = default;
danno's avatar
danno committed
433

434
  Edge operator*() const { return Edge(use_, input_ptr_); }
435
  bool operator==(const iterator& other) const {
436
    return input_ptr_ == other.input_ptr_;
437 438
  }
  bool operator!=(const iterator& other) const { return !(*this == other); }
danno's avatar
danno committed
439
  iterator& operator++() {
440 441
    input_ptr_++;
    use_--;
danno's avatar
danno committed
442 443
    return *this;
  }
444
  iterator operator++(int);
445 446 447 448 449 450 451 452 453
  iterator& operator+=(difference_type offset) {
    input_ptr_ += offset;
    use_ -= offset;
    return *this;
  }
  iterator operator+(difference_type offset) const {
    return iterator(use_ - offset, input_ptr_ + offset);
  }
  difference_type operator-(const iterator& other) const {
454
    return input_ptr_ - other.input_ptr_;
455
  }
danno's avatar
danno committed
456 457 458 459

 private:
  friend class Node;

460 461 462
  explicit iterator(Use* use, Node** input_ptr)
      : use_(use), input_ptr_(input_ptr) {}

463 464
  Use* use_;
  Node** input_ptr_;
danno's avatar
danno committed
465 466 467
};


468
Node::InputEdges::iterator Node::InputEdges::begin() const {
469
  return Node::InputEdges::iterator(use_root_, input_root_);
470 471 472 473
}


Node::InputEdges::iterator Node::InputEdges::end() const {
474
  return Node::InputEdges::iterator(use_root_ - count_, input_root_ + count_);
475 476
}

477 478 479
Edge Node::InputEdges::operator[](int index) const {
  return Edge(use_root_ + index, input_root_ + index);
}
480

danno's avatar
danno committed
481
// A forward iterator to visit the inputs of a node.
482
class Node::Inputs::const_iterator final {
483
 public:
danno's avatar
danno committed
484
  typedef std::forward_iterator_tag iterator_category;
485
  typedef std::ptrdiff_t difference_type;
danno's avatar
danno committed
486
  typedef Node* value_type;
487 488
  typedef const value_type* pointer;
  typedef value_type& reference;
danno's avatar
danno committed
489

490
  const_iterator(const const_iterator& other) = default;
491

492
  Node* operator*() const { return *input_ptr_; }
493
  bool operator==(const const_iterator& other) const {
494
    return input_ptr_ == other.input_ptr_;
495 496 497 498 499
  }
  bool operator!=(const const_iterator& other) const {
    return !(*this == other);
  }
  const_iterator& operator++() {
500
    ++input_ptr_;
501 502
    return *this;
  }
503
  const_iterator operator++(int);
504
  const_iterator& operator+=(difference_type offset) {
505
    input_ptr_ += offset;
506 507 508
    return *this;
  }
  const_iterator operator+(difference_type offset) const {
509
    return const_iterator(input_ptr_ + offset);
510 511
  }
  difference_type operator-(const const_iterator& other) const {
512
    return input_ptr_ - other.input_ptr_;
513
  }
danno's avatar
danno committed
514 515 516 517

 private:
  friend class Node::Inputs;

518
  explicit const_iterator(Node* const* input_ptr) : input_ptr_(input_ptr) {}
519

520
  Node* const* input_ptr_;
danno's avatar
danno committed
521 522
};

523 524

Node::Inputs::const_iterator Node::Inputs::begin() const {
525
  return const_iterator(input_root_);
526 527 528 529
}


Node::Inputs::const_iterator Node::Inputs::end() const {
530
  return const_iterator(input_root_ + count_);
531 532
}

533
Node* Node::Inputs::operator[](int index) const { return input_root_[index]; }
534

535
// A forward iterator to visit the uses edges of a node.
536
class Node::UseEdges::iterator final {
danno's avatar
danno committed
537
 public:
538
  iterator(const iterator& other) = default;
danno's avatar
danno committed
539

540
  Edge operator*() const { return Edge(current_, current_->input_ptr()); }
541 542 543 544
  bool operator==(const iterator& other) const {
    return current_ == other.current_;
  }
  bool operator!=(const iterator& other) const { return !(*this == other); }
danno's avatar
danno committed
545
  iterator& operator++() {
546
    DCHECK_NOT_NULL(current_);
danno's avatar
danno committed
547
    current_ = next_;
548
    next_ = current_ ? current_->next : nullptr;
549 550
    return *this;
  }
551
  iterator operator++(int);
552 553

 private:
danno's avatar
danno committed
554 555
  friend class Node::UseEdges;

556
  iterator() : current_(nullptr), next_(nullptr) {}
danno's avatar
danno committed
557 558
  explicit iterator(Node* node)
      : current_(node->first_use_),
559
        next_(current_ ? current_->next : nullptr) {}
560

danno's avatar
danno committed
561 562
  Node::Use* current_;
  Node::Use* next_;
563 564
};

565

566
Node::UseEdges::iterator Node::UseEdges::begin() const {
danno's avatar
danno committed
567 568 569 570
  return Node::UseEdges::iterator(this->node_);
}


571 572
Node::UseEdges::iterator Node::UseEdges::end() const {
  return Node::UseEdges::iterator();
573 574 575
}


576
// A forward iterator to visit the uses of a node.
577
class Node::Uses::const_iterator final {
578 579 580 581 582 583
 public:
  typedef std::forward_iterator_tag iterator_category;
  typedef int difference_type;
  typedef Node* value_type;
  typedef Node** pointer;
  typedef Node*& reference;
584

585
  Node* operator*() const { return current_->from(); }
586 587
  bool operator==(const const_iterator& other) const {
    return other.current_ == current_;
588
  }
589 590
  bool operator!=(const const_iterator& other) const {
    return other.current_ != current_;
591
  }
592 593
  const_iterator& operator++() {
    DCHECK_NOT_NULL(current_);
594 595
    // Checking no use gets mutated while iterating through them, a potential
    // very tricky cause of bug.
596
    current_ = current_->next;
597 598 599 600
#ifdef DEBUG
    DCHECK_EQ(current_, next_);
    next_ = current_ ? current_->next : nullptr;
#endif
601
    return *this;
602
  }
603
  const_iterator operator++(int);
604

605 606
 private:
  friend class Node::Uses;
607

608
  const_iterator() : current_(nullptr) {}
609 610 611 612 613 614 615 616
  explicit const_iterator(Node* node)
      : current_(node->first_use_)
#ifdef DEBUG
        ,
        next_(current_ ? current_->next : nullptr)
#endif
  {
  }
617

618
  Node::Use* current_;
619 620 621
#ifdef DEBUG
  Node::Use* next_;
#endif
622
};
623 624


625 626
Node::Uses::const_iterator Node::Uses::begin() const {
  return const_iterator(this->node_);
627 628 629
}


630
Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
631

632 633 634
}  // namespace compiler
}  // namespace internal
}  // namespace v8
635 636

#endif  // V8_COMPILER_NODE_H_