Line data Source code
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 3104774117 : return static_cast<IrOpcode::Value>(op_->opcode());
57 : }
58 :
59 : NodeId id() const { return IdField::decode(bit_field_); }
60 :
61 634897832 : int InputCount() const {
62 : return has_inline_inputs() ? InlineCountField::decode(bit_field_)
63 732146581 : : 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 1237779955 : return *GetInputPtrConst(index);
86 : }
87 :
88 120956785 : void ReplaceInput(int index, Node* new_to) {
89 : BOUNDS_CHECK(index);
90 : Node** input_ptr = GetInputPtr(index);
91 120956785 : Node* old_to = *input_ptr;
92 120956785 : if (old_to != new_to) {
93 : Use* use = GetUsePtr(index);
94 82694830 : if (old_to) old_to->RemoveUse(use);
95 82694841 : *input_ptr = new_to;
96 82694841 : if (new_to) new_to->AppendUse(use);
97 : }
98 120956805 : }
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 6380694 : bool OwnedBy(Node* owner) const {
156 12761434 : 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 3512621425 : int input_index() const { return InputIndexField::decode(bit_field_); }
189 : bool is_inline_use() const { return InlineField::decode(bit_field_); }
190 1069134620 : Node** input_ptr() {
191 : int index = input_index();
192 1069134620 : Use* start = this + 1 + index;
193 : Node** inputs = is_inline_use()
194 : ? reinterpret_cast<Node*>(start)->inputs_.inline_
195 1030101942 : : reinterpret_cast<OutOfLineInputs*>(start)->inputs_;
196 1030101942 : return &inputs[index];
197 : }
198 :
199 2006876207 : Node* from() {
200 2214871578 : Use* start = this + 1 + input_index();
201 : return is_inline_use() ? reinterpret_cast<Node*>(start)
202 2274619057 : : 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 888055562 : Node* const* GetInputPtrConst(int input_index) const {
245 : return has_inline_inputs() ? &(inputs_.inline_[input_index])
246 1237779955 : : &inputs_.outline_->inputs_[input_index];
247 : }
248 156032466 : Node** GetInputPtr(int input_index) {
249 : return has_inline_inputs() ? &(inputs_.inline_[input_index])
250 158364538 : : &inputs_.outline_->inputs_[input_index];
251 : }
252 17749181 : Use* GetUsePtr(int input_index) {
253 : Use* ptr = has_inline_inputs() ? reinterpret_cast<Use*>(this)
254 120102583 : : reinterpret_cast<Use*>(inputs_.outline_);
255 113856848 : 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 22903540 : void set_op(const Operator* op) { op_ = op; }
265 :
266 : // Only NodeProperties should manipulate the type.
267 : Type* type() const { return type_; }
268 39861828 : void set_type(Type* type) { type_ = type; }
269 :
270 : // Only NodeMarkers should manipulate the marks on nodes.
271 3054448835 : Mark mark() const { return mark_; }
272 1023055963 : 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 3392916 : 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 541410536 : Node* to() const { return *input_ptr_; }
372 : int index() const {
373 436610598 : 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 82176825 : void UpdateTo(Node* new_to) {
382 82176825 : Node* old_to = *input_ptr_;
383 82176825 : if (old_to != new_to) {
384 78190557 : if (old_to) old_to->RemoveUse(use_);
385 78190686 : *input_ptr_ = new_to;
386 78190686 : if (new_to) new_to->AppendUse(use_);
387 : }
388 82177085 : }
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 1440287839 : return inputs.count() > 0 && inputs[0] == nullptr;
408 : }
409 :
410 : Node::InputEdges Node::input_edges() {
411 702047794 : int inline_count = InlineCountField::decode(bit_field_);
412 380693460 : if (inline_count != kOutlineMarker) {
413 : return InputEdges(inputs_.inline_, reinterpret_cast<Use*>(this) - 1,
414 293111750 : inline_count);
415 : } else {
416 : return InputEdges(inputs_.outline_->inputs_,
417 : reinterpret_cast<Use*>(inputs_.outline_) - 1,
418 87581710 : inputs_.outline_->count_);
419 : }
420 : }
421 :
422 : Node::Inputs Node::inputs() const {
423 2538261795 : int inline_count = InlineCountField::decode(bit_field_);
424 1867351338 : if (inline_count != kOutlineMarker) {
425 1653227353 : return Inputs(inputs_.inline_, inline_count);
426 : } else {
427 214123985 : 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 70184639 : : use_(other.use_), input_ptr_(other.input_ptr_) {}
443 :
444 292192116 : Edge operator*() const { return Edge(use_, input_ptr_); }
445 : bool operator==(const iterator& other) const {
446 : return input_ptr_ == other.input_ptr_;
447 : }
448 24229525 : bool operator!=(const iterator& other) const { return !(*this == other); }
449 : iterator& operator++() {
450 458392770 : input_ptr_++;
451 373500234 : 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 59339126 : : 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 315931326 : 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 0 : const_iterator(const const_iterator& other) : input_ptr_(other.input_ptr_) {}
501 :
502 836224721 : 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 827594563 : ++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 0 : 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 355110507 : return const_iterator(input_root_ + count_);
541 : }
542 :
543 2206503585 : 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 10846017 : : 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 5914 : return current_ == other.current_;
554 : }
555 26325760 : bool operator!=(const iterator& other) const { return !(*this == other); }
556 : iterator& operator++() {
557 : DCHECK_NOT_NULL(current_);
558 15479772 : current_ = next_;
559 1053350049 : 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 411030264 : 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 5914 : 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 247580 : const_iterator(const const_iterator& other) : current_(other.current_) {}
597 :
598 247580 : Node* operator*() const { return current_->from(); }
599 : bool operator==(const const_iterator& other) const {
600 1750565 : return other.current_ == current_;
601 : }
602 : bool operator!=(const const_iterator& other) const {
603 25164 : return other.current_ != current_;
604 : }
605 : const_iterator& operator++() {
606 : DCHECK_NOT_NULL(current_);
607 450221497 : 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 173816612 : 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 1750565 : 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_
|