OLD | NEW |
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 Loading... |
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 |
OLD | NEW |