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

Side by Side Diff: src/compiler/state-values-utils.cc

Issue 2509623002: [turbofan] Sparse representation for state values (Closed)
Patch Set: Remove the optimized_out input entirely, return nullptr when iterating Created 4 years, 1 month 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
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 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/state-values-utils.h" 5 #include "src/compiler/state-values-utils.h"
6 6
7 namespace v8 { 7 namespace v8 {
8 namespace internal { 8 namespace internal {
9 namespace compiler { 9 namespace compiler {
10 10
11 // A (Typed)StateValues node's has a bitmask specifying if its inputs are
12 // represented sparsely. If the bitmask value is 0, then the inputs are not
13 // sparse; otherwise, they should be interpreted as follows:
14 //
15 // * The bitmask represents which values are live, with 1 for live values
16 // and 0 for dead (optimized out) values.
17 // * The inputs to the node are the live values, in the order of the 1s from
18 // least- to most-significant
19 // * The top bit of the bitmask is a guard indicating the end of the values,
20 // whether live or dead (and is not representative of a live node)
21 //
22 // So, for N 1s in the bitmask, there are N - 1 inputs into the node.
23
11 StateValuesCache::StateValuesCache(JSGraph* js_graph) 24 StateValuesCache::StateValuesCache(JSGraph* js_graph)
12 : js_graph_(js_graph), 25 : js_graph_(js_graph),
13 hash_map_(AreKeysEqual, ZoneHashMap::kDefaultHashMapCapacity, 26 hash_map_(AreKeysEqual, ZoneHashMap::kDefaultHashMapCapacity,
14 ZoneAllocationPolicy(zone())), 27 ZoneAllocationPolicy(zone())),
15 working_space_(zone()), 28 working_space_(zone()),
16 empty_state_values_(nullptr) {} 29 empty_state_values_(nullptr) {}
17 30
18 31
19 // static 32 // static
20 bool StateValuesCache::AreKeysEqual(void* key1, void* key2) { 33 bool StateValuesCache::AreKeysEqual(void* key1, void* key2) {
(...skipping 19 matching lines...) Expand all
40 } 53 }
41 UNREACHABLE(); 54 UNREACHABLE();
42 } 55 }
43 56
44 57
45 // static 58 // static
46 bool StateValuesCache::IsKeysEqualToNode(StateValuesKey* key, Node* node) { 59 bool StateValuesCache::IsKeysEqualToNode(StateValuesKey* key, Node* node) {
47 if (key->count != static_cast<size_t>(node->InputCount())) { 60 if (key->count != static_cast<size_t>(node->InputCount())) {
48 return false; 61 return false;
49 } 62 }
63
64 uint32_t node_mask;
65 if (node->opcode() == IrOpcode::kStateValues) {
66 node_mask = OpParameter<uint32_t>(node);
67 } else if (node->opcode() == IrOpcode::kTypedStateValues) {
Jarin 2016/11/16 15:32:42 Does the TypedStateValues actually ever get here?
Leszek Swirski 2016/11/17 09:23:04 Good point, probably not.
68 node_mask = OpParameter<std::pair<const void*, uint32_t>>(node).second;
69 } else {
70 return false;
71 }
72
73 if (node_mask != key->mask) {
74 return false;
75 }
76
50 for (size_t i = 0; i < key->count; i++) { 77 for (size_t i = 0; i < key->count; i++) {
51 if (key->values[i] != node->InputAt(static_cast<int>(i))) { 78 if (key->values[i] != node->InputAt(static_cast<int>(i))) {
52 return false; 79 return false;
53 } 80 }
54 } 81 }
55 return true; 82 return true;
56 } 83 }
57 84
58 85
59 // static 86 // static
60 bool StateValuesCache::AreValueKeysEqual(StateValuesKey* key1, 87 bool StateValuesCache::AreValueKeysEqual(StateValuesKey* key1,
61 StateValuesKey* key2) { 88 StateValuesKey* key2) {
62 if (key1->count != key2->count) { 89 if (key1->count != key2->count) {
63 return false; 90 return false;
64 } 91 }
92 if (key1->mask != key2->mask) {
93 return false;
94 }
65 for (size_t i = 0; i < key1->count; i++) { 95 for (size_t i = 0; i < key1->count; i++) {
66 if (key1->values[i] != key2->values[i]) { 96 if (key1->values[i] != key2->values[i]) {
67 return false; 97 return false;
68 } 98 }
69 } 99 }
70 return true; 100 return true;
71 } 101 }
72 102
73 103
74 Node* StateValuesCache::GetEmptyStateValues() { 104 Node* StateValuesCache::GetEmptyStateValues() {
75 if (empty_state_values_ == nullptr) { 105 if (empty_state_values_ == nullptr) {
76 empty_state_values_ = graph()->NewNode(common()->StateValues(0)); 106 empty_state_values_ = graph()->NewNode(common()->StateValues(0, 0u));
77 } 107 }
78 return empty_state_values_; 108 return empty_state_values_;
79 } 109 }
80 110
81 111
82 NodeVector* StateValuesCache::GetWorkingSpace(size_t level) { 112 NodeVector* StateValuesCache::GetWorkingSpace(size_t level) {
83 while (working_space_.size() <= level) { 113 while (working_space_.size() <= level) {
84 void* space = zone()->New(sizeof(NodeVector)); 114 void* space = zone()->New(sizeof(NodeVector));
85 working_space_.push_back(new (space) 115 working_space_.push_back(new (space)
86 NodeVector(kMaxInputCount, nullptr, zone())); 116 NodeVector(kMaxInputCount, nullptr, zone()));
87 } 117 }
88 return working_space_[level]; 118 return working_space_[level];
89 } 119 }
90 120
91 namespace { 121 namespace {
92 122
93 int StateValuesHashKey(Node** nodes, size_t count) { 123 int StateValuesHashKey(Node** nodes, size_t count) {
94 size_t hash = count; 124 size_t hash = count;
95 for (size_t i = 0; i < count; i++) { 125 for (size_t i = 0; i < count; i++) {
96 hash = hash * 23 + nodes[i]->id(); 126 hash = hash * 23 + nodes[i]->id();
97 } 127 }
98 return static_cast<int>(hash & 0x7fffffff); 128 return static_cast<int>(hash & 0x7fffffff);
99 } 129 }
100 130
101 } // namespace 131 } // namespace
102 132
103 133 Node* StateValuesCache::GetValuesNodeFromCache(Node** nodes, size_t count,
104 Node* StateValuesCache::GetValuesNodeFromCache(Node** nodes, size_t count) { 134 uint32_t mask) {
105 StateValuesKey key(count, nodes); 135 StateValuesKey key(count, mask, nodes);
106 int hash = StateValuesHashKey(nodes, count); 136 int hash = StateValuesHashKey(nodes, count);
107 ZoneHashMap::Entry* lookup = 137 ZoneHashMap::Entry* lookup =
108 hash_map_.LookupOrInsert(&key, hash, ZoneAllocationPolicy(zone())); 138 hash_map_.LookupOrInsert(&key, hash, ZoneAllocationPolicy(zone()));
109 DCHECK_NOT_NULL(lookup); 139 DCHECK_NOT_NULL(lookup);
110 Node* node; 140 Node* node;
111 if (lookup->value == nullptr) { 141 if (lookup->value == nullptr) {
112 int input_count = static_cast<int>(count); 142 int input_count = static_cast<int>(count);
113 node = graph()->NewNode(common()->StateValues(input_count), input_count, 143 node = graph()->NewNode(common()->StateValues(input_count, mask),
114 nodes); 144 input_count, nodes);
115 NodeKey* new_key = new (zone()->New(sizeof(NodeKey))) NodeKey(node); 145 NodeKey* new_key = new (zone()->New(sizeof(NodeKey))) NodeKey(node);
116 lookup->key = new_key; 146 lookup->key = new_key;
117 lookup->value = node; 147 lookup->value = node;
118 } else { 148 } else {
119 node = reinterpret_cast<Node*>(lookup->value); 149 node = reinterpret_cast<Node*>(lookup->value);
120 } 150 }
121 return node; 151 return node;
122 } 152 }
123 153
124 154
(...skipping 25 matching lines...) Expand all
150 Node* StateValuesCache::BuildTree(ValueArrayIterator* it, size_t max_height) { 180 Node* StateValuesCache::BuildTree(ValueArrayIterator* it, size_t max_height) {
151 if (max_height == 0) { 181 if (max_height == 0) {
152 Node* node = it->node(); 182 Node* node = it->node();
153 it->Advance(); 183 it->Advance();
154 return node; 184 return node;
155 } 185 }
156 DCHECK(!it->done()); 186 DCHECK(!it->done());
157 187
158 NodeVector* buffer = GetWorkingSpace(max_height); 188 NodeVector* buffer = GetWorkingSpace(max_height);
159 size_t count = 0; 189 size_t count = 0;
160 for (; count < kMaxInputCount; count++) { 190 size_t idx = 0;
191 uint32_t mask = 0;
192 bool use_mask = false;
193 while (count < kMaxInputCount && (!use_mask || idx < 31)) {
161 if (it->done()) break; 194 if (it->done()) break;
162 (*buffer)[count] = BuildTree(it, max_height - 1); 195
196 Node* subtree = BuildTree(it, max_height - 1);
197 if (subtree == js_graph_->OptimizedOutConstant() && idx < 31) {
198 use_mask = true;
199 idx++;
200 } else {
201 mask |= 1 << idx;
202 (*buffer)[count] = subtree;
203 idx++;
204 count++;
205 }
163 } 206 }
164 if (count == 1) { 207
208 if (use_mask) {
209 DCHECK(idx < 32);
210 mask |= 1 << idx;
211 }
212
213 if (count == 1 && !use_mask) {
165 return (*buffer)[0]; 214 return (*buffer)[0];
166 } else { 215 } else {
167 return GetValuesNodeFromCache(&(buffer->front()), count); 216 return GetValuesNodeFromCache(&(buffer->front()), count,
217 use_mask ? mask : 0u);
168 } 218 }
169 } 219 }
170 220
171 221
172 Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) { 222 Node* StateValuesCache::GetNodeForValues(Node** values, size_t count) {
173 #if DEBUG 223 #if DEBUG
174 for (size_t i = 0; i < count; i++) { 224 for (size_t i = 0; i < count; i++) {
175 DCHECK_NE(values[i]->opcode(), IrOpcode::kStateValues); 225 DCHECK_NE(values[i]->opcode(), IrOpcode::kStateValues);
176 DCHECK_NE(values[i]->opcode(), IrOpcode::kTypedStateValues); 226 DCHECK_NE(values[i]->opcode(), IrOpcode::kTypedStateValues);
177 } 227 }
178 #endif 228 #endif
179 if (count == 0) { 229 if (count == 0) {
180 return GetEmptyStateValues(); 230 return GetEmptyStateValues();
181 } 231 }
182 size_t height = 0; 232 size_t height = 0;
183 size_t max_nodes = 1; 233 size_t max_nodes = 1;
184 while (count > max_nodes) { 234 while (count > max_nodes) {
185 height++; 235 height++;
Jarin 2016/11/16 15:32:43 I am guesisng this will get the tree height wrong
Leszek Swirski 2016/11/17 09:23:04 Yes, this was my guess too. However, I think that
186 max_nodes *= kMaxInputCount; 236 max_nodes *= kMaxInputCount;
187 } 237 }
188 238
189 ValueArrayIterator it(values, count); 239 ValueArrayIterator it(values, count);
190 240
191 Node* tree = BuildTree(&it, height); 241 Node* tree = BuildTree(&it, height);
192 242
193 // If the 'tree' is a single node, equip it with a StateValues wrapper. 243 // If the 'tree' is a single node, equip it with a StateValues wrapper.
194 if (tree->opcode() != IrOpcode::kStateValues && 244 if (tree->opcode() != IrOpcode::kStateValues &&
195 tree->opcode() != IrOpcode::kTypedStateValues) { 245 tree->opcode() != IrOpcode::kTypedStateValues) {
196 tree = GetValuesNodeFromCache(&tree, 1); 246 tree = GetValuesNodeFromCache(&tree, 1, 0u);
197 } 247 }
198 248
249 #if DEBUG
250 {
251 DCHECK_EQ(count, StateValuesAccess(tree).size());
252 size_t i = 0;
253 auto access = StateValuesAccess(tree);
254 auto it = access.begin();
255 auto itend = access.end();
256 for (; it != itend; ++it) {
257 DCHECK(values[i] == (*it).node ||
258 values[i] == js_graph_->OptimizedOutConstant() &&
259 (*it).node == nullptr);
260 ++i;
261 }
262 DCHECK_EQ(i, count);
263 }
264 #endif
265
199 return tree; 266 return tree;
200 } 267 }
201 268
202 269
203 StateValuesAccess::iterator::iterator(Node* node) : current_depth_(0) { 270 StateValuesAccess::iterator::iterator(Node* node) : current_depth_(0) {
204 // A hacky way initialize - just set the index before the node we want
205 // to process and then advance to it.
206 stack_[current_depth_].node = node; 271 stack_[current_depth_].node = node;
207 stack_[current_depth_].index = -1; 272 stack_[current_depth_].index = 0;
208 Advance(); 273
274 uint32_t input_mask;
275 if (node->opcode() == IrOpcode::kStateValues) {
276 input_mask = OpParameter<uint32_t>(node);
277 } else {
278 DCHECK_EQ(node->opcode(), IrOpcode::kTypedStateValues);
279 input_mask = OpParameter<std::pair<const void*, uint32_t>>(node).second;
280 }
281 stack_[current_depth_].mask = input_mask;
282
283 EnsureValid();
209 } 284 }
210 285
211 286
212 StateValuesAccess::iterator::StatePos* StateValuesAccess::iterator::Top() { 287 StateValuesAccess::iterator::StatePos* StateValuesAccess::iterator::Top() {
213 DCHECK(current_depth_ >= 0); 288 DCHECK(current_depth_ >= 0);
214 DCHECK(current_depth_ < kMaxInlineDepth); 289 DCHECK(current_depth_ < kMaxInlineDepth);
215 return &(stack_[current_depth_]); 290 return &(stack_[current_depth_]);
216 } 291 }
217 292
218 293 void StateValuesAccess::iterator::Push(Node* node, uint32_t mask) {
219 void StateValuesAccess::iterator::Push(Node* node) {
220 current_depth_++; 294 current_depth_++;
221 CHECK(current_depth_ < kMaxInlineDepth); 295 CHECK(current_depth_ < kMaxInlineDepth);
222 stack_[current_depth_].node = node; 296 stack_[current_depth_].node = node;
297 stack_[current_depth_].mask = mask;
223 stack_[current_depth_].index = 0; 298 stack_[current_depth_].index = 0;
224 } 299 }
225 300
226 301
227 void StateValuesAccess::iterator::Pop() { 302 void StateValuesAccess::iterator::Pop() {
228 DCHECK(current_depth_ >= 0); 303 DCHECK(current_depth_ >= 0);
229 current_depth_--; 304 current_depth_--;
230 } 305 }
231 306
232 307
233 bool StateValuesAccess::iterator::done() { return current_depth_ < 0; } 308 bool StateValuesAccess::iterator::done() { return current_depth_ < 0; }
234 309
235 310
236 void StateValuesAccess::iterator::Advance() { 311 void StateValuesAccess::iterator::Advance() {
237 // Advance the current index. 312 MoveToNextSibling();
238 Top()->index++; 313 EnsureValid();
314 }
239 315
240 // Fix up the position to point to a valid node. 316 void StateValuesAccess::iterator::MoveToNextSibling() {
317 int mask = Top()->mask;
318 if (mask == 0 || (mask & 0x1) == 1) {
319 Top()->index++;
320 }
321 Top()->mask >>= 1;
322 }
323
324 void StateValuesAccess::iterator::EnsureValid() {
241 while (true) { 325 while (true) {
242 // TODO(jarin): Factor to a separate method. 326 uint32_t mask = Top()->mask;
327 int index = Top()->index;
243 Node* node = Top()->node; 328 Node* node = Top()->node;
244 int index = Top()->index;
245 329
246 if (index >= node->InputCount()) { 330 if (mask != 0 && (mask & 0x1) == 0) {
247 // Pop stack and move to the next sibling. 331 // We are on a valid (dead) node.
332 return;
333 }
334
335 if (mask == 1 || (mask == 0 && index >= node->InputCount())) {
336 // We have hit the guard bit or exhausted our inputs. Pop the stack and
337 // move to the next sibling.
248 Pop(); 338 Pop();
249 if (done()) { 339 if (done()) {
250 // Stack is exhausted, we have reached the end. 340 // Stack is exhausted, we have reached the end.
251 return; 341 return;
252 } 342 }
253 Top()->index++; 343 MoveToNextSibling();
254 } else if (node->InputAt(index)->opcode() == IrOpcode::kStateValues || 344 continue;
255 node->InputAt(index)->opcode() == IrOpcode::kTypedStateValues) { 345 }
346
347 // At this point the value is known to be live and within our input nodes.
348 Node* value_node = node->InputAt(Top()->index);
349
350 if (value_node->opcode() == IrOpcode::kStateValues ||
351 value_node->opcode() == IrOpcode::kTypedStateValues) {
256 // Nested state, we need to push to the stack. 352 // Nested state, we need to push to the stack.
257 Push(node->InputAt(index)); 353 uint32_t input_mask;
258 } else { 354 if (node->InputAt(index)->opcode() == IrOpcode::kStateValues) {
259 // We are on a valid node, we can stop the iteration. 355 input_mask = OpParameter<uint32_t>(node->InputAt(index));
260 return; 356 } else {
357 input_mask =
358 OpParameter<std::pair<const void*, uint32_t>>(node->InputAt(index))
359 .second;
360 }
361 Push(node->InputAt(index), input_mask);
362 continue;
261 } 363 }
364
365 // We are on a valid node, we can stop the iteration.
366 return;
262 } 367 }
263 } 368 }
264 369
265 370
266 Node* StateValuesAccess::iterator::node() { 371 Node* StateValuesAccess::iterator::node() {
267 return Top()->node->InputAt(Top()->index); 372 if (Top()->mask != 0 && (Top()->mask & 0x1) == 0) {
373 return nullptr;
374 } else {
375 return Top()->node->InputAt(Top()->index);
376 }
268 } 377 }
269 378
270 379
271 MachineType StateValuesAccess::iterator::type() { 380 MachineType StateValuesAccess::iterator::type() {
272 Node* state = Top()->node; 381 Node* state = Top()->node;
273 if (state->opcode() == IrOpcode::kStateValues) { 382 if (state->opcode() == IrOpcode::kStateValues) {
274 return MachineType::AnyTagged(); 383 return MachineType::AnyTagged();
275 } else { 384 } else {
276 DCHECK_EQ(IrOpcode::kTypedStateValues, state->opcode()); 385 DCHECK_EQ(IrOpcode::kTypedStateValues, state->opcode());
277 ZoneVector<MachineType> const* types = MachineTypesOf(state->op()); 386
278 return (*types)[Top()->index]; 387 if (Top()->mask != 0 && (Top()->mask & 0x1) == 0) {
388 return MachineType::None();
389 } else {
390 ZoneVector<MachineType> const* types = MachineTypesOf(state->op());
391 return (*types)[Top()->index];
392 }
279 } 393 }
280 } 394 }
281 395
282 396
283 bool StateValuesAccess::iterator::operator!=(iterator& other) { 397 bool StateValuesAccess::iterator::operator!=(iterator& other) {
284 // We only allow comparison with end(). 398 // We only allow comparison with end().
285 CHECK(other.done()); 399 CHECK(other.done());
286 return !done(); 400 return !done();
287 } 401 }
288 402
289 403
290 StateValuesAccess::iterator& StateValuesAccess::iterator::operator++() { 404 StateValuesAccess::iterator& StateValuesAccess::iterator::operator++() {
291 Advance(); 405 Advance();
292 return *this; 406 return *this;
293 } 407 }
294 408
295 409
296 StateValuesAccess::TypedNode StateValuesAccess::iterator::operator*() { 410 StateValuesAccess::TypedNode StateValuesAccess::iterator::operator*() {
297 return TypedNode(node(), type()); 411 return TypedNode(node(), type());
298 } 412 }
299 413
300 414
301 size_t StateValuesAccess::size() { 415 size_t StateValuesAccess::size() {
302 size_t count = 0; 416 size_t count = 0;
303 for (int i = 0; i < node_->InputCount(); i++) { 417 uint32_t mask = 0;
304 if (node_->InputAt(i)->opcode() == IrOpcode::kStateValues || 418 if (node_->opcode() == IrOpcode::kStateValues) {
305 node_->InputAt(i)->opcode() == IrOpcode::kTypedStateValues) { 419 mask = OpParameter<uint32_t>(node_);
306 count += StateValuesAccess(node_->InputAt(i)).size(); 420 } else if (node_->opcode() == IrOpcode::kTypedStateValues) {
421 mask = OpParameter<std::pair<const void*, uint32_t>>(node_).second;
422 }
423
424 int i = 0;
425 while ((mask == 0 && i < node_->InputCount()) || (mask != 0 && mask != 1)) {
426 if (mask != 0 && (mask & 1) == 0) {
427 count++;
307 } else { 428 } else {
308 count++; 429 if (node_->InputAt(i)->opcode() == IrOpcode::kStateValues ||
430 node_->InputAt(i)->opcode() == IrOpcode::kTypedStateValues) {
431 count += StateValuesAccess(node_->InputAt(i)).size();
432 } else {
433 count++;
434 }
435 i++;
309 } 436 }
437 mask >>= 1;
310 } 438 }
439
311 return count; 440 return count;
312 } 441 }
313 442
314 } // namespace compiler 443 } // namespace compiler
315 } // namespace internal 444 } // namespace internal
316 } // namespace v8 445 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698