node.h 18.8 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
  NodeId id() const { return IdField::decode(bit_field_); }

  int InputCount() const {
    return has_inline_inputs() ? InlineCountField::decode(bit_field_)
63
                               : outline_inputs()->count_;
64
  }
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
  void Print(std::ostream&) const;
164

165
 private:
166 167 168 169 170 171 172
  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_;
173 174 175

    // Inputs are allocated right behind the OutOfLineInputs instance.
    inline Node** inputs();
176 177 178 179 180 181 182 183

    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 {
184 185
    Use* next;
    Use* prev;
186 187 188 189 190 191 192 193
    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()
194 195
                          ? reinterpret_cast<Node*>(start)->inline_inputs()
                          : reinterpret_cast<OutOfLineInputs*>(start)->inputs();
196 197
      return &inputs[index];
    }
198

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

205 206
    typedef BitField<bool, 0, 1> InlineField;
    typedef BitField<unsigned, 1, 17> InputIndexField;
207 208
    // Leaving some space in the bitset in case we ever decide to record
    // the output index.
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);

244 245 246 247 248 249 250 251 252 253 254 255
  inline Address inputs_location() const;

  Node** inline_inputs() const {
    return reinterpret_cast<Node**>(inputs_location());
  }
  OutOfLineInputs* outline_inputs() const {
    return *reinterpret_cast<OutOfLineInputs**>(inputs_location());
  }
  void set_outline_inputs(OutOfLineInputs* outline) {
    *reinterpret_cast<OutOfLineInputs**>(inputs_location()) = outline;
  }

256
  Node* const* GetInputPtrConst(int input_index) const {
257 258
    return has_inline_inputs() ? &(inline_inputs()[input_index])
                               : &(outline_inputs()->inputs()[input_index]);
259
  }
260
  Node** GetInputPtr(int input_index) {
261 262
    return has_inline_inputs() ? &(inline_inputs()[input_index])
                               : &(outline_inputs()->inputs()[input_index]);
263 264 265
  }
  Use* GetUsePtr(int input_index) {
    Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
266
                                   : reinterpret_cast<Use*>(outline_inputs());
267
    return &ptr[-1 - input_index];
268 269
  }

270 271
  void AppendUse(Use* use);
  void RemoveUse(Use* use);
272 273 274

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

275 276 277
  // Only NodeProperties should manipulate the op.
  void set_op(const Operator* op) { op_ = op; }

278
  // Only NodeProperties should manipulate the type.
279 280
  Type type() const { return type_; }
  void set_type(Type type) { type_ = type; }
281 282

  // Only NodeMarkers should manipulate the marks on nodes.
283
  Mark mark() const { return mark_; }
284 285
  void set_mark(Mark mark) { mark_ = mark; }

286 287
  inline bool has_inline_inputs() const {
    return InlineCountField::decode(bit_field_) != kOutlineMarker;
288 289
  }

290
  void ClearInputs(int start, int count);
291

292 293 294 295 296 297
  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;
298

299
  const Operator* op_;
300
  Type type_;
301
  Mark mark_;
302
  uint32_t bit_field_;
303
  Use* first_use_;
304

305 306 307 308
  friend class Edge;
  friend class NodeMarkerBase;
  friend class NodeProperties;

309 310 311
  DISALLOW_COPY_AND_ASSIGN(Node);
};

312 313 314 315 316 317 318 319
Address Node::inputs_location() const {
  return reinterpret_cast<Address>(this) + sizeof(Node);
}

Node** Node::OutOfLineInputs::inputs() {
  return reinterpret_cast<Node**>(reinterpret_cast<Address>(this) +
                                  sizeof(Node::OutOfLineInputs));
}
320

321 322 323 324 325
std::ostream& operator<<(std::ostream& os, const Node& n);


// Typedefs to shorten commonly used Node containers.
typedef ZoneDeque<Node*> NodeDeque;
326
typedef ZoneSet<Node*> NodeSet;
327 328 329 330
typedef ZoneVector<Node*> NodeVector;
typedef ZoneVector<NodeVector> NodeVectorVector;


331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
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_;
};
373

374 375
// 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
376
// the node having the input.
377
class Edge final {
378
 public:
379 380
  Node* from() const { return use_->from(); }
  Node* to() const { return *input_ptr_; }
381
  int index() const {
382 383
    int const index = use_->input_index();
    DCHECK_LT(index, use_->from()->InputCount());
384 385 386
    return index;
  }

387
  bool operator==(const Edge& other) { return input_ptr_ == other.input_ptr_; }
danno's avatar
danno committed
388 389
  bool operator!=(const Edge& other) { return !(*this == other); }

390 391 392 393 394 395 396 397
  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
398

399
 private:
danno's avatar
danno committed
400
  friend class Node::UseEdges::iterator;
401
  friend class Node::InputEdges;
danno's avatar
danno committed
402
  friend class Node::InputEdges::iterator;
403

404 405 406 407 408
  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());
  }
409

410 411
  Node::Use* use_;
  Node** input_ptr_;
412 413
};

414 415 416 417 418 419 420 421
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) {
422
    return InputEdges(inline_inputs(), reinterpret_cast<Use*>(this) - 1,
423 424
                      inline_count);
  } else {
425 426 427
    return InputEdges(outline_inputs()->inputs(),
                      reinterpret_cast<Use*>(outline_inputs()) - 1,
                      outline_inputs()->count_);
428 429 430 431 432 433
  }
}

Node::Inputs Node::inputs() const {
  int inline_count = InlineCountField::decode(bit_field_);
  if (inline_count != kOutlineMarker) {
434
    return Inputs(inline_inputs(), inline_count);
435
  } else {
436
    return Inputs(outline_inputs()->inputs(), outline_inputs()->count_);
437 438
  }
}
439

440
// A forward iterator to visit the edges for the input dependencies of a node.
441
class Node::InputEdges::iterator final {
danno's avatar
danno committed
442 443
 public:
  typedef std::forward_iterator_tag iterator_category;
444
  typedef std::ptrdiff_t difference_type;
danno's avatar
danno committed
445 446 447
  typedef Edge value_type;
  typedef Edge* pointer;
  typedef Edge& reference;
448

449
  iterator() : use_(nullptr), input_ptr_(nullptr) {}
450
  iterator(const iterator& other) = default;
danno's avatar
danno committed
451

452
  Edge operator*() const { return Edge(use_, input_ptr_); }
453
  bool operator==(const iterator& other) const {
454
    return input_ptr_ == other.input_ptr_;
455 456
  }
  bool operator!=(const iterator& other) const { return !(*this == other); }
danno's avatar
danno committed
457
  iterator& operator++() {
458 459
    input_ptr_++;
    use_--;
danno's avatar
danno committed
460 461
    return *this;
  }
462
  iterator operator++(int);
463 464 465 466 467 468 469 470 471
  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 {
472
    return input_ptr_ - other.input_ptr_;
473
  }
danno's avatar
danno committed
474 475 476 477

 private:
  friend class Node;

478 479 480
  explicit iterator(Use* use, Node** input_ptr)
      : use_(use), input_ptr_(input_ptr) {}

481 482
  Use* use_;
  Node** input_ptr_;
danno's avatar
danno committed
483 484 485
};


486
Node::InputEdges::iterator Node::InputEdges::begin() const {
487
  return Node::InputEdges::iterator(use_root_, input_root_);
488 489 490 491
}


Node::InputEdges::iterator Node::InputEdges::end() const {
492
  return Node::InputEdges::iterator(use_root_ - count_, input_root_ + count_);
493 494
}

495 496 497
Edge Node::InputEdges::operator[](int index) const {
  return Edge(use_root_ + index, input_root_ + index);
}
498

danno's avatar
danno committed
499
// A forward iterator to visit the inputs of a node.
500
class Node::Inputs::const_iterator final {
501
 public:
danno's avatar
danno committed
502
  typedef std::forward_iterator_tag iterator_category;
503
  typedef std::ptrdiff_t difference_type;
danno's avatar
danno committed
504
  typedef Node* value_type;
505 506
  typedef const value_type* pointer;
  typedef value_type& reference;
danno's avatar
danno committed
507

508
  const_iterator(const const_iterator& other) = default;
509

510
  Node* operator*() const { return *input_ptr_; }
511
  bool operator==(const const_iterator& other) const {
512
    return input_ptr_ == other.input_ptr_;
513 514 515 516 517
  }
  bool operator!=(const const_iterator& other) const {
    return !(*this == other);
  }
  const_iterator& operator++() {
518
    ++input_ptr_;
519 520
    return *this;
  }
521
  const_iterator operator++(int);
522
  const_iterator& operator+=(difference_type offset) {
523
    input_ptr_ += offset;
524 525 526
    return *this;
  }
  const_iterator operator+(difference_type offset) const {
527
    return const_iterator(input_ptr_ + offset);
528 529
  }
  difference_type operator-(const const_iterator& other) const {
530
    return input_ptr_ - other.input_ptr_;
531
  }
danno's avatar
danno committed
532 533 534 535

 private:
  friend class Node::Inputs;

536
  explicit const_iterator(Node* const* input_ptr) : input_ptr_(input_ptr) {}
537

538
  Node* const* input_ptr_;
danno's avatar
danno committed
539 540
};

541 542

Node::Inputs::const_iterator Node::Inputs::begin() const {
543
  return const_iterator(input_root_);
544 545 546 547
}


Node::Inputs::const_iterator Node::Inputs::end() const {
548
  return const_iterator(input_root_ + count_);
549 550
}

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

553
// A forward iterator to visit the uses edges of a node.
554
class Node::UseEdges::iterator final {
danno's avatar
danno committed
555
 public:
556
  iterator(const iterator& other) = default;
danno's avatar
danno committed
557

558
  Edge operator*() const { return Edge(current_, current_->input_ptr()); }
559 560 561 562
  bool operator==(const iterator& other) const {
    return current_ == other.current_;
  }
  bool operator!=(const iterator& other) const { return !(*this == other); }
danno's avatar
danno committed
563
  iterator& operator++() {
564
    DCHECK_NOT_NULL(current_);
danno's avatar
danno committed
565
    current_ = next_;
566
    next_ = current_ ? current_->next : nullptr;
567 568
    return *this;
  }
569
  iterator operator++(int);
570 571

 private:
danno's avatar
danno committed
572 573
  friend class Node::UseEdges;

574
  iterator() : current_(nullptr), next_(nullptr) {}
danno's avatar
danno committed
575 576
  explicit iterator(Node* node)
      : current_(node->first_use_),
577
        next_(current_ ? current_->next : nullptr) {}
578

danno's avatar
danno committed
579 580
  Node::Use* current_;
  Node::Use* next_;
581 582
};

583

584
Node::UseEdges::iterator Node::UseEdges::begin() const {
danno's avatar
danno committed
585 586 587 588
  return Node::UseEdges::iterator(this->node_);
}


589 590
Node::UseEdges::iterator Node::UseEdges::end() const {
  return Node::UseEdges::iterator();
591 592 593
}


594
// A forward iterator to visit the uses of a node.
595
class Node::Uses::const_iterator final {
596 597 598 599 600 601
 public:
  typedef std::forward_iterator_tag iterator_category;
  typedef int difference_type;
  typedef Node* value_type;
  typedef Node** pointer;
  typedef Node*& reference;
602

603
  Node* operator*() const { return current_->from(); }
604 605
  bool operator==(const const_iterator& other) const {
    return other.current_ == current_;
606
  }
607 608
  bool operator!=(const const_iterator& other) const {
    return other.current_ != current_;
609
  }
610 611
  const_iterator& operator++() {
    DCHECK_NOT_NULL(current_);
612 613
    // Checking no use gets mutated while iterating through them, a potential
    // very tricky cause of bug.
614
    current_ = current_->next;
615 616 617 618
#ifdef DEBUG
    DCHECK_EQ(current_, next_);
    next_ = current_ ? current_->next : nullptr;
#endif
619
    return *this;
620
  }
621
  const_iterator operator++(int);
622

623 624
 private:
  friend class Node::Uses;
625

626
  const_iterator() : current_(nullptr) {}
627 628 629 630 631 632 633 634
  explicit const_iterator(Node* node)
      : current_(node->first_use_)
#ifdef DEBUG
        ,
        next_(current_ ? current_->next : nullptr)
#endif
  {
  }
635

636
  Node::Use* current_;
637 638 639
#ifdef DEBUG
  Node::Use* next_;
#endif
640
};
641 642


643 644
Node::Uses::const_iterator Node::Uses::begin() const {
  return const_iterator(this->node_);
645 646 647
}


648
Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); }
649

650 651 652
}  // namespace compiler
}  // namespace internal
}  // namespace v8
653 654

#endif  // V8_COMPILER_NODE_H_