Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(782)

Side by Side Diff: src/compiler/node.cc

Issue 1150923003: [turbofan] Rework Node guts to save space. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Avoid quadratic verification explosion. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/compiler/node.h ('k') | test/cctest/compiler/test-control-reducer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 the V8 project authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/compiler/node.h" 5 #include "src/compiler/node.h"
6 6
7 #include <algorithm>
8
9 namespace v8 { 7 namespace v8 {
10 namespace internal { 8 namespace internal {
11 namespace compiler { 9 namespace compiler {
12 10
13 Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count, 11 Node::OutOfLineInputs* Node::OutOfLineInputs::New(Zone* zone, int capacity) {
14 Node** inputs, bool has_extensible_inputs) { 12 size_t size =
15 size_t node_size = sizeof(Node) - sizeof(Input); 13 sizeof(OutOfLineInputs) + capacity * (sizeof(Node*) + sizeof(Use));
16 int reserve_input_count = has_extensible_inputs ? kDefaultReservedInputs : 0; 14 intptr_t raw_buffer = reinterpret_cast<intptr_t>(zone->New(size));
17 size_t inputs_size = std::max<size_t>( 15 Node::OutOfLineInputs* outline =
18 (input_count + reserve_input_count) * sizeof(Input), sizeof(InputDeque*)); 16 reinterpret_cast<OutOfLineInputs*>(raw_buffer + capacity * sizeof(Use));
19 size_t uses_size = input_count * sizeof(Use); 17 outline->capacity_ = capacity;
20 int size = static_cast<int>(node_size + inputs_size + uses_size); 18 outline->count_ = 0;
21 void* buffer = zone->New(size); 19 return outline;
22 Node* result = new (buffer) Node(id, op, input_count, reserve_input_count);
23 Input* input = result->inputs_.static_;
24 Use* use =
25 reinterpret_cast<Use*>(reinterpret_cast<char*>(input) + inputs_size);
26
27 for (int current = 0; current < input_count; ++current) {
28 Node* to = *inputs++;
29 input->to = to;
30 input->use = use;
31 use->input_index = current;
32 use->from = result;
33 to->AppendUse(use);
34 ++use;
35 ++input;
36 }
37 return result;
38 } 20 }
39 21
40 22
23 void Node::OutOfLineInputs::ExtractFrom(Use* old_use_ptr, Node** old_input_ptr,
24 int count) {
25 // Extract the inputs from the old use and input pointers and copy them
26 // to this out-of-line-storage.
27 Use* new_use_ptr = reinterpret_cast<Use*>(this) - 1;
28 Node** new_input_ptr = inputs_;
29 for (int current = 0; current < count; current++) {
30 new_use_ptr->bit_field_ =
31 Use::InputIndexField::encode(current) | Use::InlineField::encode(false);
32 DCHECK_EQ(old_input_ptr, old_use_ptr->input_ptr());
33 DCHECK_EQ(new_input_ptr, new_use_ptr->input_ptr());
34 Node* old_to = *old_input_ptr;
35 if (old_to) {
36 *old_input_ptr = nullptr;
37 old_to->RemoveUse(old_use_ptr);
38 *new_input_ptr = old_to;
39 old_to->AppendUse(new_use_ptr);
40 } else {
41 *new_input_ptr = nullptr;
42 }
43 old_input_ptr++;
44 new_input_ptr++;
45 old_use_ptr--;
46 new_use_ptr--;
47 }
48 this->count_ = count;
49 }
50
51
52 Node* Node::New(Zone* zone, NodeId id, const Operator* op, int input_count,
53 Node** inputs, bool has_extensible_inputs) {
54 Node** input_ptr;
55 Use* use_ptr;
56 Node* node;
57 bool is_inline;
58
59 if (input_count > kMaxInlineCapacity) {
60 // Allocate out-of-line inputs.
61 int capacity =
62 has_extensible_inputs ? input_count + kMaxInlineCapacity : input_count;
63 OutOfLineInputs* outline = OutOfLineInputs::New(zone, capacity);
64
65 // Allocate node.
66 void* node_buffer = zone->New(sizeof(Node));
67 node = new (node_buffer) Node(id, op, kOutlineMarker, 0);
68 node->inputs_.outline_ = outline;
69
70 outline->node_ = node;
71 outline->count_ = input_count;
72
73 input_ptr = outline->inputs_;
74 use_ptr = reinterpret_cast<Use*>(outline);
75 is_inline = false;
76 } else {
77 // Allocate node with inline inputs.
78 int capacity = input_count;
79 if (has_extensible_inputs) {
80 const int max = kMaxInlineCapacity;
81 capacity = std::min(input_count + 3, max);
82 }
83
84 size_t size = sizeof(Node) + capacity * (sizeof(Node*) + sizeof(Use));
85 intptr_t raw_buffer = reinterpret_cast<intptr_t>(zone->New(size));
86 void* node_buffer =
87 reinterpret_cast<void*>(raw_buffer + capacity * sizeof(Use));
88
89 node = new (node_buffer) Node(id, op, input_count, capacity);
90 input_ptr = node->inputs_.inline_;
91 use_ptr = reinterpret_cast<Use*>(node);
92 is_inline = true;
93 }
94
95 // Initialize the input pointers and the uses.
96 for (int current = 0; current < input_count; ++current) {
97 Node* to = *inputs++;
98 input_ptr[current] = to;
99 Use* use = use_ptr - 1 - current;
100 use->bit_field_ = Use::InputIndexField::encode(current) |
101 Use::InlineField::encode(is_inline);
102 to->AppendUse(use);
103 }
104 node->Verify();
105 return node;
106 }
107
108
41 void Node::Kill() { 109 void Node::Kill() {
42 DCHECK_NOT_NULL(op()); 110 DCHECK_NOT_NULL(op());
43 NullAllInputs(); 111 NullAllInputs();
44 DCHECK(uses().empty()); 112 DCHECK(uses().empty());
45 } 113 }
46 114
47 115
48 void Node::AppendInput(Zone* zone, Node* new_to) { 116 void Node::AppendInput(Zone* zone, Node* new_to) {
49 DCHECK_NOT_NULL(zone); 117 DCHECK_NOT_NULL(zone);
50 DCHECK_NOT_NULL(new_to); 118 DCHECK_NOT_NULL(new_to);
51 Use* new_use = new (zone) Use; 119
52 Input new_input; 120 int inline_count = InlineCountField::decode(bit_field_);
53 new_input.to = new_to; 121 int inline_capacity = InlineCapacityField::decode(bit_field_);
54 new_input.use = new_use; 122 if (inline_count < inline_capacity) {
55 if (reserved_input_count() > 0) { 123 // Append inline input.
56 DCHECK(!has_appendable_inputs()); 124 bit_field_ = InlineCountField::update(bit_field_, inline_count + 1);
57 set_reserved_input_count(reserved_input_count() - 1); 125 *GetInputPtr(inline_count) = new_to;
58 inputs_.static_[input_count()] = new_input; 126 Use* use = GetUsePtr(inline_count);
127 use->bit_field_ = Use::InputIndexField::encode(inline_count) |
128 Use::InlineField::encode(true);
129 new_to->AppendUse(use);
59 } else { 130 } else {
60 EnsureAppendableInputs(zone); 131 // Append out-of-line input.
61 inputs_.appendable_->push_back(new_input); 132 int input_count = InputCount();
133 OutOfLineInputs* outline = nullptr;
134 if (inline_count != kOutlineMarker) {
135 // switch to out of line inputs.
136 outline = OutOfLineInputs::New(zone, input_count * 2 + 3);
137 outline->node_ = this;
138 outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
139 bit_field_ = InlineCountField::update(bit_field_, kOutlineMarker);
140 inputs_.outline_ = outline;
141 } else {
142 // use current out of line inputs.
143 outline = inputs_.outline_;
144 if (input_count >= outline->capacity_) {
145 // out of space in out-of-line inputs.
146 outline = OutOfLineInputs::New(zone, input_count * 2 + 3);
147 outline->node_ = this;
148 outline->ExtractFrom(GetUsePtr(0), GetInputPtr(0), input_count);
149 inputs_.outline_ = outline;
150 }
151 }
152 outline->count_++;
153 *GetInputPtr(input_count) = new_to;
154 Use* use = GetUsePtr(input_count);
155 use->bit_field_ = Use::InputIndexField::encode(input_count) |
156 Use::InlineField::encode(false);
157 new_to->AppendUse(use);
62 } 158 }
63 new_use->input_index = input_count(); 159 Verify();
64 new_use->from = this;
65 new_to->AppendUse(new_use);
66 set_input_count(input_count() + 1);
67 } 160 }
68 161
69 162
70 void Node::InsertInput(Zone* zone, int index, Node* new_to) { 163 void Node::InsertInput(Zone* zone, int index, Node* new_to) {
71 DCHECK_NOT_NULL(zone); 164 DCHECK_NOT_NULL(zone);
72 DCHECK_LE(0, index); 165 DCHECK_LE(0, index);
73 DCHECK_LT(index, InputCount()); 166 DCHECK_LT(index, InputCount());
74 AppendInput(zone, InputAt(InputCount() - 1)); 167 AppendInput(zone, InputAt(InputCount() - 1));
75 for (int i = InputCount() - 1; i > index; --i) { 168 for (int i = InputCount() - 1; i > index; --i) {
76 ReplaceInput(i, InputAt(i - 1)); 169 ReplaceInput(i, InputAt(i - 1));
77 } 170 }
78 ReplaceInput(index, new_to); 171 ReplaceInput(index, new_to);
172 Verify();
79 } 173 }
80 174
81 175
82 void Node::RemoveInput(int index) { 176 void Node::RemoveInput(int index) {
83 DCHECK_LE(0, index); 177 DCHECK_LE(0, index);
84 DCHECK_LT(index, InputCount()); 178 DCHECK_LT(index, InputCount());
85 for (; index < InputCount() - 1; ++index) { 179 for (; index < InputCount() - 1; ++index) {
86 ReplaceInput(index, InputAt(index + 1)); 180 ReplaceInput(index, InputAt(index + 1));
87 } 181 }
88 TrimInputCount(InputCount() - 1); 182 TrimInputCount(InputCount() - 1);
183 Verify();
89 } 184 }
90 185
91 186
92 void Node::NullAllInputs() { 187 void Node::ClearInputs(int start, int count) {
93 for (Edge edge : input_edges()) edge.UpdateTo(nullptr); 188 Node** input_ptr = GetInputPtr(start);
189 Use* use_ptr = GetUsePtr(start);
190 while (count-- > 0) {
191 DCHECK_EQ(input_ptr, use_ptr->input_ptr());
192 Node* input = *input_ptr;
193 *input_ptr = nullptr;
194 if (input) input->RemoveUse(use_ptr);
195 input_ptr++;
196 use_ptr--;
197 }
198 Verify();
94 } 199 }
95 200
96 201
202 void Node::NullAllInputs() { ClearInputs(0, InputCount()); }
203
204
97 void Node::TrimInputCount(int new_input_count) { 205 void Node::TrimInputCount(int new_input_count) {
98 DCHECK_LE(new_input_count, input_count()); 206 int current_count = InputCount();
99 if (new_input_count == input_count()) return; // Nothing to do. 207 DCHECK_LE(new_input_count, current_count);
100 for (int index = new_input_count; index < input_count(); ++index) { 208 if (new_input_count == current_count) return; // Nothing to do.
101 ReplaceInput(index, nullptr); 209 ClearInputs(new_input_count, current_count - new_input_count);
210 if (has_inline_inputs()) {
211 bit_field_ = InlineCountField::update(bit_field_, new_input_count);
212 } else {
213 inputs_.outline_->count_ = new_input_count;
102 } 214 }
103 if (has_appendable_inputs()) {
104 inputs_.appendable_->resize(new_input_count);
105 } else {
106 set_reserved_input_count(std::min<int>(
107 ReservedInputCountField::kMax,
108 reserved_input_count() + (input_count() - new_input_count)));
109 }
110 set_input_count(new_input_count);
111 } 215 }
112 216
113 217
114 int Node::UseCount() const { 218 int Node::UseCount() const {
115 int use_count = 0; 219 int use_count = 0;
116 for (const Use* use = first_use_; use; use = use->next) { 220 for (const Use* use = first_use_; use; use = use->next) {
117 ++use_count; 221 ++use_count;
118 } 222 }
119 return use_count; 223 return use_count;
120 } 224 }
121 225
122 226
123 void Node::ReplaceUses(Node* that) { 227 void Node::ReplaceUses(Node* that) {
124 DCHECK(this->first_use_ == nullptr || this->first_use_->prev == nullptr); 228 DCHECK(this->first_use_ == nullptr || this->first_use_->prev == nullptr);
125 DCHECK(that->first_use_ == nullptr || that->first_use_->prev == nullptr); 229 DCHECK(that->first_use_ == nullptr || that->first_use_->prev == nullptr);
126 230
127 // Update the pointers to {this} to point to {that}. 231 // Update the pointers to {this} to point to {that}.
128 Use* last_use = nullptr; 232 Use* last_use = nullptr;
129 for (Use* use = this->first_use_; use; use = use->next) { 233 for (Use* use = this->first_use_; use; use = use->next) {
130 use->from->GetInputRecordPtr(use->input_index)->to = that; 234 *use->input_ptr() = that;
131 last_use = use; 235 last_use = use;
132 } 236 }
133 if (last_use) { 237 if (last_use) {
134 // Concat the use list of {this} and {that}. 238 // Concat the use list of {this} and {that}.
135 last_use->next = that->first_use_; 239 last_use->next = that->first_use_;
136 if (that->first_use_) that->first_use_->prev = last_use; 240 if (that->first_use_) that->first_use_->prev = last_use;
137 that->first_use_ = this->first_use_; 241 that->first_use_ = this->first_use_;
138 } 242 }
139 first_use_ = nullptr; 243 first_use_ = nullptr;
140 } 244 }
141 245
142 246
143 bool Node::OwnedBy(Node const* owner1, Node const* owner2) const { 247 bool Node::OwnedBy(Node const* owner1, Node const* owner2) const {
144 unsigned mask = 0; 248 unsigned mask = 0;
145 for (Use* use = first_use_; use; use = use->next) { 249 for (Use* use = first_use_; use; use = use->next) {
146 if (use->from == owner1) { 250 Node* from = use->from();
251 if (from == owner1) {
147 mask |= 1; 252 mask |= 1;
148 } else if (use->from == owner2) { 253 } else if (from == owner2) {
149 mask |= 2; 254 mask |= 2;
150 } else { 255 } else {
151 return false; 256 return false;
152 } 257 }
153 } 258 }
154 return mask == 3; 259 return mask == 3;
155 } 260 }
156 261
157 262
158 void Node::Input::Update(Node* new_to) { 263 Node::Node(NodeId id, const Operator* op, int inline_count, int inline_capacity)
159 Node* old_to = this->to; 264 : op_(op),
160 if (new_to == old_to) return; // Nothing to do. 265 mark_(0),
161 // Snip out the use from where it used to be 266 bit_field_(IdField::encode(id) | InlineCountField::encode(inline_count) |
162 if (old_to) { 267 InlineCapacityField::encode(inline_capacity)),
163 old_to->RemoveUse(use); 268 first_use_(nullptr) {
164 } 269 // Inputs must either be out of line or within the inline capacity.
165 to = new_to; 270 DCHECK(inline_capacity <= kMaxInlineCapacity);
166 // And put it into the new node's use list. 271 DCHECK(inline_count == kOutlineMarker || inline_count <= inline_capacity);
167 if (new_to) {
168 new_to->AppendUse(use);
169 } else {
170 use->next = nullptr;
171 use->prev = nullptr;
172 }
173 } 272 }
174 273
175 274
176 Node::Node(NodeId id, const Operator* op, int input_count, 275 void Node::AppendUse(Use* use) {
177 int reserved_input_count)
178 : op_(op),
179 mark_(0),
180 id_(id),
181 bit_field_(InputCountField::encode(input_count) |
182 ReservedInputCountField::encode(reserved_input_count) |
183 HasAppendableInputsField::encode(false)),
184 first_use_(nullptr) {}
185
186
187 void Node::EnsureAppendableInputs(Zone* zone) {
188 if (!has_appendable_inputs()) {
189 void* deque_buffer = zone->New(sizeof(InputDeque));
190 InputDeque* deque = new (deque_buffer) InputDeque(zone);
191 for (int i = 0; i < input_count(); ++i) {
192 deque->push_back(inputs_.static_[i]);
193 }
194 inputs_.appendable_ = deque;
195 set_has_appendable_inputs(true);
196 }
197 }
198
199
200 void Node::AppendUse(Use* const use) {
201 DCHECK(first_use_ == nullptr || first_use_->prev == nullptr); 276 DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
277 DCHECK_EQ(this, *use->input_ptr());
202 use->next = first_use_; 278 use->next = first_use_;
203 use->prev = nullptr; 279 use->prev = nullptr;
204 if (first_use_) first_use_->prev = use; 280 if (first_use_) first_use_->prev = use;
205 first_use_ = use; 281 first_use_ = use;
206 } 282 }
207 283
208 284
209 void Node::RemoveUse(Use* const use) { 285 void Node::RemoveUse(Use* use) {
210 DCHECK(first_use_ == nullptr || first_use_->prev == nullptr); 286 DCHECK(first_use_ == nullptr || first_use_->prev == nullptr);
211 if (use->prev) { 287 if (use->prev) {
212 DCHECK_NE(first_use_, use); 288 DCHECK_NE(first_use_, use);
213 use->prev->next = use->next; 289 use->prev->next = use->next;
214 } else { 290 } else {
215 DCHECK_EQ(first_use_, use); 291 DCHECK_EQ(first_use_, use);
216 first_use_ = use->next; 292 first_use_ = use->next;
217 } 293 }
218 if (use->next) { 294 if (use->next) {
219 use->next->prev = use->prev; 295 use->next->prev = use->prev;
220 } 296 }
221 } 297 }
222 298
223 299
300 #if DEBUG
301 void Node::Verify() {
302 // Check basic sanity of input data structures.
303 fflush(stdout);
304 int count = this->InputCount();
305 // Avoid quadratic explosion for mega nodes; only verify if the input
306 // count is less than 200 or is a round number of 100s.
307 if (count > 200 && count % 100) return;
308
309 for (int i = 0; i < count; i++) {
310 CHECK_EQ(i, this->GetUsePtr(i)->input_index());
311 CHECK_EQ(this->GetInputPtr(i), this->GetUsePtr(i)->input_ptr());
312 CHECK_EQ(count, this->InputCount());
313 }
314 { // Direct input iteration.
315 int index = 0;
316 for (Node* input : this->inputs()) {
317 CHECK_EQ(this->InputAt(index), input);
318 index++;
319 }
320 CHECK_EQ(count, index);
321 CHECK_EQ(this->InputCount(), index);
322 }
323 { // Input edge iteration.
324 int index = 0;
325 for (Edge edge : this->input_edges()) {
326 CHECK_EQ(edge.from(), this);
327 CHECK_EQ(index, edge.index());
328 CHECK_EQ(this->InputAt(index), edge.to());
329 index++;
330 }
331 CHECK_EQ(count, index);
332 CHECK_EQ(this->InputCount(), index);
333 }
334 }
335 #endif
336
337
224 std::ostream& operator<<(std::ostream& os, const Node& n) { 338 std::ostream& operator<<(std::ostream& os, const Node& n) {
225 os << n.id() << ": " << *n.op(); 339 os << n.id() << ": " << *n.op();
226 if (n.InputCount() > 0) { 340 if (n.InputCount() > 0) {
227 os << "("; 341 os << "(";
228 for (int i = 0; i < n.InputCount(); ++i) { 342 for (int i = 0; i < n.InputCount(); ++i) {
229 if (i != 0) os << ", "; 343 if (i != 0) os << ", ";
230 os << n.InputAt(i)->id(); 344 os << n.InputAt(i)->id();
231 } 345 }
232 os << ")"; 346 os << ")";
233 } 347 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 ++(*this); 384 ++(*this);
271 return result; 385 return result;
272 } 386 }
273 387
274 388
275 bool Node::Uses::empty() const { return begin() == end(); } 389 bool Node::Uses::empty() const { return begin() == end(); }
276 390
277 } // namespace compiler 391 } // namespace compiler
278 } // namespace internal 392 } // namespace internal
279 } // namespace v8 393 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/node.h ('k') | test/cctest/compiler/test-control-reducer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698