blob: ad787f80928be553075a3e130fd534b9fc478eaa [file] [log] [blame]
Ben Murdochf91f0612016-11-29 16:50:11 +00001// Copyright 2016 the V8 project authors. All rights reserved.
Emily Bernier958fae72015-03-24 16:35:39 -04002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/compiler/load-elimination.h"
6
Ben Murdochf91f0612016-11-29 16:50:11 +00007#include "src/compiler/js-graph.h"
Ben Murdoch014dc512016-03-22 12:00:34 +00008#include "src/compiler/node-properties.h"
Emily Bernier958fae72015-03-24 16:35:39 -04009#include "src/compiler/simplified-operator.h"
10
11namespace v8 {
12namespace internal {
13namespace compiler {
14
Ben Murdochf91f0612016-11-29 16:50:11 +000015namespace {
16
17enum Aliasing { kNoAlias, kMayAlias, kMustAlias };
18
19Aliasing QueryAlias(Node* a, Node* b) {
20 if (a == b) return kMustAlias;
21 if (!NodeProperties::GetType(a)->Maybe(NodeProperties::GetType(b))) {
22 return kNoAlias;
23 }
24 if (b->opcode() == IrOpcode::kAllocate) {
25 switch (a->opcode()) {
26 case IrOpcode::kAllocate:
27 case IrOpcode::kHeapConstant:
28 case IrOpcode::kParameter:
29 return kNoAlias;
30 case IrOpcode::kFinishRegion:
31 return QueryAlias(a->InputAt(0), b);
32 default:
33 break;
34 }
35 }
36 if (a->opcode() == IrOpcode::kAllocate) {
37 switch (b->opcode()) {
38 case IrOpcode::kHeapConstant:
39 case IrOpcode::kParameter:
40 return kNoAlias;
41 case IrOpcode::kFinishRegion:
42 return QueryAlias(a, b->InputAt(0));
43 default:
44 break;
45 }
46 }
47 return kMayAlias;
48}
49
50bool MayAlias(Node* a, Node* b) { return QueryAlias(a, b) != kNoAlias; }
51
52bool MustAlias(Node* a, Node* b) { return QueryAlias(a, b) == kMustAlias; }
53
54} // namespace
Emily Bernier958fae72015-03-24 16:35:39 -040055
Emily Bernier958fae72015-03-24 16:35:39 -040056Reduction LoadElimination::Reduce(Node* node) {
57 switch (node->opcode()) {
Ben Murdochf91f0612016-11-29 16:50:11 +000058 case IrOpcode::kCheckMaps:
59 return ReduceCheckMaps(node);
60 case IrOpcode::kEnsureWritableFastElements:
61 return ReduceEnsureWritableFastElements(node);
62 case IrOpcode::kMaybeGrowFastElements:
63 return ReduceMaybeGrowFastElements(node);
64 case IrOpcode::kTransitionElementsKind:
65 return ReduceTransitionElementsKind(node);
Emily Bernier958fae72015-03-24 16:35:39 -040066 case IrOpcode::kLoadField:
67 return ReduceLoadField(node);
Ben Murdochf91f0612016-11-29 16:50:11 +000068 case IrOpcode::kStoreField:
69 return ReduceStoreField(node);
70 case IrOpcode::kLoadElement:
71 return ReduceLoadElement(node);
72 case IrOpcode::kStoreElement:
73 return ReduceStoreElement(node);
74 case IrOpcode::kStoreTypedElement:
75 return ReduceStoreTypedElement(node);
76 case IrOpcode::kEffectPhi:
77 return ReduceEffectPhi(node);
78 case IrOpcode::kDead:
Emily Bernier958fae72015-03-24 16:35:39 -040079 break;
Ben Murdochf91f0612016-11-29 16:50:11 +000080 case IrOpcode::kStart:
81 return ReduceStart(node);
82 default:
83 return ReduceOtherNode(node);
Emily Bernier958fae72015-03-24 16:35:39 -040084 }
85 return NoChange();
86}
87
Ben Murdochf91f0612016-11-29 16:50:11 +000088Node* LoadElimination::AbstractElements::Lookup(Node* object,
89 Node* index) const {
90 for (Element const element : elements_) {
91 if (element.object == nullptr) continue;
92 DCHECK_NOT_NULL(element.index);
93 DCHECK_NOT_NULL(element.value);
94 if (MustAlias(object, element.object) && MustAlias(index, element.index)) {
95 return element.value;
96 }
97 }
98 return nullptr;
99}
100
101LoadElimination::AbstractElements const*
102LoadElimination::AbstractElements::Kill(Node* object, Node* index,
103 Zone* zone) const {
104 for (Element const element : this->elements_) {
105 if (element.object == nullptr) continue;
106 if (MayAlias(object, element.object)) {
107 AbstractElements* that = new (zone) AbstractElements(zone);
108 for (Element const element : this->elements_) {
109 if (element.object == nullptr) continue;
110 DCHECK_NOT_NULL(element.index);
111 DCHECK_NOT_NULL(element.value);
112 if (!MayAlias(object, element.object) ||
113 !MayAlias(index, element.index)) {
114 that->elements_[that->next_index_++] = element;
Emily Bernier958fae72015-03-24 16:35:39 -0400115 }
Emily Bernier958fae72015-03-24 16:35:39 -0400116 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000117 that->next_index_ %= arraysize(elements_);
118 return that;
119 }
120 }
121 return this;
122}
123
124bool LoadElimination::AbstractElements::Equals(
125 AbstractElements const* that) const {
126 if (this == that) return true;
127 for (size_t i = 0; i < arraysize(elements_); ++i) {
128 Element this_element = this->elements_[i];
129 if (this_element.object == nullptr) continue;
130 for (size_t j = 0;; ++j) {
131 if (j == arraysize(elements_)) return false;
132 Element that_element = that->elements_[j];
133 if (this_element.object == that_element.object &&
134 this_element.index == that_element.index &&
135 this_element.value == that_element.value) {
Emily Bernier958fae72015-03-24 16:35:39 -0400136 break;
137 }
138 }
139 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000140 for (size_t i = 0; i < arraysize(elements_); ++i) {
141 Element that_element = that->elements_[i];
142 if (that_element.object == nullptr) continue;
143 for (size_t j = 0;; ++j) {
144 if (j == arraysize(elements_)) return false;
145 Element this_element = this->elements_[j];
146 if (that_element.object == this_element.object &&
147 that_element.index == this_element.index &&
148 that_element.value == this_element.value) {
149 break;
150 }
151 }
152 }
153 return true;
154}
155
156LoadElimination::AbstractElements const*
157LoadElimination::AbstractElements::Merge(AbstractElements const* that,
158 Zone* zone) const {
159 if (this->Equals(that)) return this;
160 AbstractElements* copy = new (zone) AbstractElements(zone);
161 for (Element const this_element : this->elements_) {
162 if (this_element.object == nullptr) continue;
163 for (Element const that_element : that->elements_) {
164 if (this_element.object == that_element.object &&
165 this_element.index == that_element.index &&
166 this_element.value == that_element.value) {
167 copy->elements_[copy->next_index_++] = this_element;
168 }
169 }
170 }
171 copy->next_index_ %= arraysize(elements_);
172 return copy;
173}
174
175Node* LoadElimination::AbstractField::Lookup(Node* object) const {
176 for (auto pair : info_for_node_) {
177 if (MustAlias(object, pair.first)) return pair.second;
178 }
179 return nullptr;
180}
181
182LoadElimination::AbstractField const* LoadElimination::AbstractField::Kill(
183 Node* object, Zone* zone) const {
184 for (auto pair : this->info_for_node_) {
185 if (MayAlias(object, pair.first)) {
186 AbstractField* that = new (zone) AbstractField(zone);
187 for (auto pair : this->info_for_node_) {
188 if (!MayAlias(object, pair.first)) that->info_for_node_.insert(pair);
189 }
190 return that;
191 }
192 }
193 return this;
194}
195
196bool LoadElimination::AbstractState::Equals(AbstractState const* that) const {
197 if (this->elements_) {
198 if (!that->elements_ || !that->elements_->Equals(this->elements_)) {
199 return false;
200 }
201 } else if (that->elements_) {
202 return false;
203 }
204 for (size_t i = 0u; i < arraysize(fields_); ++i) {
205 AbstractField const* this_field = this->fields_[i];
206 AbstractField const* that_field = that->fields_[i];
207 if (this_field) {
208 if (!that_field || !that_field->Equals(this_field)) return false;
209 } else if (that_field) {
210 return false;
211 }
212 }
213 return true;
214}
215
216void LoadElimination::AbstractState::Merge(AbstractState const* that,
217 Zone* zone) {
218 // Merge the information we have about the elements.
219 if (this->elements_) {
220 this->elements_ = that->elements_
221 ? that->elements_->Merge(this->elements_, zone)
222 : that->elements_;
223 } else {
224 this->elements_ = that->elements_;
225 }
226
227 // Merge the information we have about the fields.
228 for (size_t i = 0; i < arraysize(fields_); ++i) {
229 if (this->fields_[i]) {
230 if (that->fields_[i]) {
231 this->fields_[i] = this->fields_[i]->Merge(that->fields_[i], zone);
232 } else {
233 this->fields_[i] = nullptr;
234 }
235 }
236 }
237}
238
239Node* LoadElimination::AbstractState::LookupElement(Node* object,
240 Node* index) const {
241 if (this->elements_) {
242 return this->elements_->Lookup(object, index);
243 }
244 return nullptr;
245}
246
247LoadElimination::AbstractState const*
248LoadElimination::AbstractState::AddElement(Node* object, Node* index,
249 Node* value, Zone* zone) const {
250 AbstractState* that = new (zone) AbstractState(*this);
251 if (that->elements_) {
252 that->elements_ = that->elements_->Extend(object, index, value, zone);
253 } else {
254 that->elements_ = new (zone) AbstractElements(object, index, value, zone);
255 }
256 return that;
257}
258
259LoadElimination::AbstractState const*
260LoadElimination::AbstractState::KillElement(Node* object, Node* index,
261 Zone* zone) const {
262 if (this->elements_) {
263 AbstractElements const* that_elements =
264 this->elements_->Kill(object, index, zone);
265 if (this->elements_ != that_elements) {
266 AbstractState* that = new (zone) AbstractState(*this);
267 that->elements_ = that_elements;
268 return that;
269 }
270 }
271 return this;
272}
273
274LoadElimination::AbstractState const* LoadElimination::AbstractState::AddField(
275 Node* object, size_t index, Node* value, Zone* zone) const {
276 AbstractState* that = new (zone) AbstractState(*this);
277 if (that->fields_[index]) {
278 that->fields_[index] = that->fields_[index]->Extend(object, value, zone);
279 } else {
280 that->fields_[index] = new (zone) AbstractField(object, value, zone);
281 }
282 return that;
283}
284
285LoadElimination::AbstractState const* LoadElimination::AbstractState::KillField(
286 Node* object, size_t index, Zone* zone) const {
287 if (AbstractField const* this_field = this->fields_[index]) {
288 this_field = this_field->Kill(object, zone);
289 if (this->fields_[index] != this_field) {
290 AbstractState* that = new (zone) AbstractState(*this);
291 that->fields_[index] = this_field;
292 return that;
293 }
294 }
295 return this;
296}
297
298Node* LoadElimination::AbstractState::LookupField(Node* object,
299 size_t index) const {
300 if (AbstractField const* this_field = this->fields_[index]) {
301 return this_field->Lookup(object);
302 }
303 return nullptr;
304}
305
306LoadElimination::AbstractState const*
307LoadElimination::AbstractStateForEffectNodes::Get(Node* node) const {
308 size_t const id = node->id();
309 if (id < info_for_node_.size()) return info_for_node_[id];
310 return nullptr;
311}
312
313void LoadElimination::AbstractStateForEffectNodes::Set(
314 Node* node, AbstractState const* state) {
315 size_t const id = node->id();
316 if (id >= info_for_node_.size()) info_for_node_.resize(id + 1, nullptr);
317 info_for_node_[id] = state;
318}
319
320Reduction LoadElimination::ReduceCheckMaps(Node* node) {
321 Node* const object = NodeProperties::GetValueInput(node, 0);
322 Node* const effect = NodeProperties::GetEffectInput(node);
323 AbstractState const* state = node_states_.Get(effect);
324 if (state == nullptr) return NoChange();
325 int const map_input_count = node->op()->ValueInputCount() - 1;
326 if (Node* const object_map = state->LookupField(object, 0)) {
327 for (int i = 0; i < map_input_count; ++i) {
328 Node* map = NodeProperties::GetValueInput(node, 1 + i);
329 if (map == object_map) return Replace(effect);
330 }
331 }
332 if (map_input_count == 1) {
333 Node* const map0 = NodeProperties::GetValueInput(node, 1);
334 state = state->AddField(object, 0, map0, zone());
335 }
336 return UpdateState(node, state);
337}
338
339Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) {
340 Node* const object = NodeProperties::GetValueInput(node, 0);
341 Node* const elements = NodeProperties::GetValueInput(node, 1);
342 Node* const effect = NodeProperties::GetEffectInput(node);
343 AbstractState const* state = node_states_.Get(effect);
344 if (state == nullptr) return NoChange();
345 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant();
346 if (Node* const elements_map = state->LookupField(elements, 0)) {
347 // Check if the {elements} already have the fixed array map.
348 if (elements_map == fixed_array_map) {
349 ReplaceWithValue(node, elements, effect);
350 return Replace(elements);
351 }
352 }
353 // We know that the resulting elements have the fixed array map.
354 state = state->AddField(node, 0, fixed_array_map, zone());
355 // Kill the previous elements on {object}.
356 state = state->KillField(object, 2, zone());
357 // Add the new elements on {object}.
358 state = state->AddField(object, 2, node, zone());
359 return UpdateState(node, state);
360}
361
362Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
363 GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op());
364 Node* const object = NodeProperties::GetValueInput(node, 0);
365 Node* const effect = NodeProperties::GetEffectInput(node);
366 AbstractState const* state = node_states_.Get(effect);
367 if (state == nullptr) return NoChange();
368 if (flags & GrowFastElementsFlag::kDoubleElements) {
369 // We know that the resulting elements have the fixed double array map.
370 Node* fixed_double_array_map = jsgraph()->FixedDoubleArrayMapConstant();
371 state = state->AddField(node, 0, fixed_double_array_map, zone());
372 } else {
373 // We know that the resulting elements have the fixed array map.
374 Node* fixed_array_map = jsgraph()->FixedArrayMapConstant();
375 state = state->AddField(node, 0, fixed_array_map, zone());
376 }
377 if (flags & GrowFastElementsFlag::kArrayObject) {
378 // Kill the previous Array::length on {object}.
379 state = state->KillField(object, 3, zone());
380 }
381 // Kill the previous elements on {object}.
382 state = state->KillField(object, 2, zone());
383 // Add the new elements on {object}.
384 state = state->AddField(object, 2, node, zone());
385 return UpdateState(node, state);
386}
387
388Reduction LoadElimination::ReduceTransitionElementsKind(Node* node) {
389 Node* const object = NodeProperties::GetValueInput(node, 0);
390 Node* const source_map = NodeProperties::GetValueInput(node, 1);
391 Node* const target_map = NodeProperties::GetValueInput(node, 2);
392 Node* const effect = NodeProperties::GetEffectInput(node);
393 AbstractState const* state = node_states_.Get(effect);
394 if (state == nullptr) return NoChange();
395 if (Node* const object_map = state->LookupField(object, 0)) {
396 if (target_map == object_map) {
397 // The {object} already has the {target_map}, so this TransitionElements
398 // {node} is fully redundant (independent of what {source_map} is).
399 return Replace(effect);
400 }
401 state = state->KillField(object, 0, zone());
402 if (source_map == object_map) {
403 state = state->AddField(object, 0, target_map, zone());
404 }
405 } else {
406 state = state->KillField(object, 0, zone());
407 }
408 ElementsTransition transition = ElementsTransitionOf(node->op());
409 switch (transition) {
410 case ElementsTransition::kFastTransition:
411 break;
412 case ElementsTransition::kSlowTransition:
413 // Kill the elements as well.
414 state = state->KillField(object, 2, zone());
415 break;
416 }
417 return UpdateState(node, state);
418}
419
420Reduction LoadElimination::ReduceLoadField(Node* node) {
421 FieldAccess const& access = FieldAccessOf(node->op());
422 Node* const object = NodeProperties::GetValueInput(node, 0);
423 Node* const effect = NodeProperties::GetEffectInput(node);
424 AbstractState const* state = node_states_.Get(effect);
425 if (state == nullptr) return NoChange();
426 int field_index = FieldIndexOf(access);
427 if (field_index >= 0) {
428 if (Node* const replacement = state->LookupField(object, field_index)) {
429 // Make sure the {replacement} has at least as good type
430 // as the original {node}.
431 if (!replacement->IsDead() &&
432 NodeProperties::GetType(replacement)
433 ->Is(NodeProperties::GetType(node))) {
434 ReplaceWithValue(node, replacement, effect);
435 return Replace(replacement);
436 }
437 }
438 state = state->AddField(object, field_index, node, zone());
439 }
440 return UpdateState(node, state);
441}
442
443Reduction LoadElimination::ReduceStoreField(Node* node) {
444 FieldAccess const& access = FieldAccessOf(node->op());
445 Node* const object = NodeProperties::GetValueInput(node, 0);
446 Node* const new_value = NodeProperties::GetValueInput(node, 1);
447 Node* const effect = NodeProperties::GetEffectInput(node);
448 AbstractState const* state = node_states_.Get(effect);
449 if (state == nullptr) return NoChange();
450 int field_index = FieldIndexOf(access);
451 if (field_index >= 0) {
452 Node* const old_value = state->LookupField(object, field_index);
453 if (old_value == new_value) {
454 // This store is fully redundant.
455 return Replace(effect);
456 }
457 // Kill all potentially aliasing fields and record the new value.
458 state = state->KillField(object, field_index, zone());
459 state = state->AddField(object, field_index, new_value, zone());
460 } else {
461 // Unsupported StoreField operator.
462 state = empty_state();
463 }
464 return UpdateState(node, state);
465}
466
467Reduction LoadElimination::ReduceLoadElement(Node* node) {
468 Node* const object = NodeProperties::GetValueInput(node, 0);
469 Node* const index = NodeProperties::GetValueInput(node, 1);
470 Node* const effect = NodeProperties::GetEffectInput(node);
471 AbstractState const* state = node_states_.Get(effect);
472 if (state == nullptr) return NoChange();
473 if (Node* const replacement = state->LookupElement(object, index)) {
474 // Make sure the {replacement} has at least as good type
475 // as the original {node}.
476 if (!replacement->IsDead() &&
477 NodeProperties::GetType(replacement)
478 ->Is(NodeProperties::GetType(node))) {
479 ReplaceWithValue(node, replacement, effect);
480 return Replace(replacement);
481 }
482 }
483 state = state->AddElement(object, index, node, zone());
484 return UpdateState(node, state);
485}
486
487Reduction LoadElimination::ReduceStoreElement(Node* node) {
488 ElementAccess const& access = ElementAccessOf(node->op());
489 Node* const object = NodeProperties::GetValueInput(node, 0);
490 Node* const index = NodeProperties::GetValueInput(node, 1);
491 Node* const new_value = NodeProperties::GetValueInput(node, 2);
492 Node* const effect = NodeProperties::GetEffectInput(node);
493 AbstractState const* state = node_states_.Get(effect);
494 if (state == nullptr) return NoChange();
495 Node* const old_value = state->LookupElement(object, index);
496 if (old_value == new_value) {
497 // This store is fully redundant.
498 return Replace(effect);
499 }
500 // Kill all potentially aliasing elements.
501 state = state->KillElement(object, index, zone());
502 // Only record the new value if the store doesn't have an implicit truncation.
503 switch (access.machine_type.representation()) {
504 case MachineRepresentation::kNone:
505 case MachineRepresentation::kBit:
506 UNREACHABLE();
507 break;
508 case MachineRepresentation::kWord8:
509 case MachineRepresentation::kWord16:
510 case MachineRepresentation::kWord32:
511 case MachineRepresentation::kWord64:
512 case MachineRepresentation::kFloat32:
513 // TODO(turbofan): Add support for doing the truncations.
514 break;
515 case MachineRepresentation::kFloat64:
516 case MachineRepresentation::kSimd128:
517 case MachineRepresentation::kTaggedSigned:
518 case MachineRepresentation::kTaggedPointer:
519 case MachineRepresentation::kTagged:
520 state = state->AddElement(object, index, new_value, zone());
521 break;
522 }
523 return UpdateState(node, state);
524}
525
526Reduction LoadElimination::ReduceStoreTypedElement(Node* node) {
527 Node* const effect = NodeProperties::GetEffectInput(node);
528 AbstractState const* state = node_states_.Get(effect);
529 if (state == nullptr) return NoChange();
530 return UpdateState(node, state);
531}
532
533Reduction LoadElimination::ReduceEffectPhi(Node* node) {
534 Node* const effect0 = NodeProperties::GetEffectInput(node, 0);
535 Node* const control = NodeProperties::GetControlInput(node);
536 AbstractState const* state0 = node_states_.Get(effect0);
537 if (state0 == nullptr) return NoChange();
538 if (control->opcode() == IrOpcode::kLoop) {
539 // Here we rely on having only reducible loops:
540 // The loop entry edge always dominates the header, so we can just take
541 // the state from the first input, and compute the loop state based on it.
542 AbstractState const* state = ComputeLoopState(node, state0);
543 return UpdateState(node, state);
544 }
545 DCHECK_EQ(IrOpcode::kMerge, control->opcode());
546
547 // Shortcut for the case when we do not know anything about some input.
548 int const input_count = node->op()->EffectInputCount();
549 for (int i = 1; i < input_count; ++i) {
550 Node* const effect = NodeProperties::GetEffectInput(node, i);
551 if (node_states_.Get(effect) == nullptr) return NoChange();
552 }
553
554 // Make a copy of the first input's state and merge with the state
555 // from other inputs.
556 AbstractState* state = new (zone()) AbstractState(*state0);
557 for (int i = 1; i < input_count; ++i) {
558 Node* const input = NodeProperties::GetEffectInput(node, i);
559 state->Merge(node_states_.Get(input), zone());
560 }
561 return UpdateState(node, state);
562}
563
564Reduction LoadElimination::ReduceStart(Node* node) {
565 return UpdateState(node, empty_state());
566}
567
568Reduction LoadElimination::ReduceOtherNode(Node* node) {
569 if (node->op()->EffectInputCount() == 1) {
570 if (node->op()->EffectOutputCount() == 1) {
571 Node* const effect = NodeProperties::GetEffectInput(node);
572 AbstractState const* state = node_states_.Get(effect);
573 // If we do not know anything about the predecessor, do not propagate
574 // just yet because we will have to recompute anyway once we compute
575 // the predecessor.
576 if (state == nullptr) return NoChange();
577 // Check if this {node} has some uncontrolled side effects.
578 if (!node->op()->HasProperty(Operator::kNoWrite)) {
579 state = empty_state();
580 }
581 return UpdateState(node, state);
582 } else {
583 // Effect terminators should be handled specially.
584 return NoChange();
585 }
586 }
587 DCHECK_EQ(0, node->op()->EffectInputCount());
588 DCHECK_EQ(0, node->op()->EffectOutputCount());
Emily Bernier958fae72015-03-24 16:35:39 -0400589 return NoChange();
590}
591
Ben Murdochf91f0612016-11-29 16:50:11 +0000592Reduction LoadElimination::UpdateState(Node* node, AbstractState const* state) {
593 AbstractState const* original = node_states_.Get(node);
594 // Only signal that the {node} has Changed, if the information about {state}
595 // has changed wrt. the {original}.
596 if (state != original) {
597 if (original == nullptr || !state->Equals(original)) {
598 node_states_.Set(node, state);
599 return Changed(node);
600 }
601 }
602 return NoChange();
603}
604
605LoadElimination::AbstractState const* LoadElimination::ComputeLoopState(
606 Node* node, AbstractState const* state) const {
607 Node* const control = NodeProperties::GetControlInput(node);
608 ZoneQueue<Node*> queue(zone());
609 ZoneSet<Node*> visited(zone());
610 visited.insert(node);
611 for (int i = 1; i < control->InputCount(); ++i) {
612 queue.push(node->InputAt(i));
613 }
614 while (!queue.empty()) {
615 Node* const current = queue.front();
616 queue.pop();
617 if (visited.find(current) == visited.end()) {
618 visited.insert(current);
619 if (!current->op()->HasProperty(Operator::kNoWrite)) {
620 switch (current->opcode()) {
621 case IrOpcode::kEnsureWritableFastElements: {
622 Node* const object = NodeProperties::GetValueInput(current, 0);
623 state = state->KillField(object, 2, zone());
624 break;
625 }
626 case IrOpcode::kMaybeGrowFastElements: {
627 GrowFastElementsFlags flags =
628 GrowFastElementsFlagsOf(current->op());
629 Node* const object = NodeProperties::GetValueInput(current, 0);
630 state = state->KillField(object, 2, zone());
631 if (flags & GrowFastElementsFlag::kArrayObject) {
632 state = state->KillField(object, 3, zone());
633 }
634 break;
635 }
636 case IrOpcode::kTransitionElementsKind: {
637 Node* const object = NodeProperties::GetValueInput(current, 0);
638 state = state->KillField(object, 0, zone());
639 state = state->KillField(object, 2, zone());
640 break;
641 }
642 case IrOpcode::kStoreField: {
643 FieldAccess const& access = FieldAccessOf(current->op());
644 Node* const object = NodeProperties::GetValueInput(current, 0);
645 int field_index = FieldIndexOf(access);
646 if (field_index < 0) return empty_state();
647 state = state->KillField(object, field_index, zone());
648 break;
649 }
650 case IrOpcode::kStoreElement: {
651 Node* const object = NodeProperties::GetValueInput(current, 0);
652 Node* const index = NodeProperties::GetValueInput(current, 1);
653 state = state->KillElement(object, index, zone());
654 break;
655 }
656 case IrOpcode::kStoreBuffer:
657 case IrOpcode::kStoreTypedElement: {
658 // Doesn't affect anything we track with the state currently.
659 break;
660 }
661 default:
662 return empty_state();
663 }
664 }
665 for (int i = 0; i < current->op()->EffectInputCount(); ++i) {
666 queue.push(NodeProperties::GetEffectInput(current, i));
667 }
668 }
669 }
670 return state;
671}
672
673// static
674int LoadElimination::FieldIndexOf(FieldAccess const& access) {
675 MachineRepresentation rep = access.machine_type.representation();
676 switch (rep) {
677 case MachineRepresentation::kNone:
678 case MachineRepresentation::kBit:
679 UNREACHABLE();
680 break;
681 case MachineRepresentation::kWord32:
682 case MachineRepresentation::kWord64:
683 if (rep != MachineType::PointerRepresentation()) {
684 return -1; // We currently only track pointer size fields.
685 }
686 break;
687 case MachineRepresentation::kWord8:
688 case MachineRepresentation::kWord16:
689 case MachineRepresentation::kFloat32:
690 return -1; // Currently untracked.
691 case MachineRepresentation::kFloat64:
692 case MachineRepresentation::kSimd128:
693 return -1; // Currently untracked.
694 case MachineRepresentation::kTaggedSigned:
695 case MachineRepresentation::kTaggedPointer:
696 case MachineRepresentation::kTagged:
697 // TODO(bmeurer): Check that we never do overlapping load/stores of
698 // individual parts of Float64/Simd128 values.
699 break;
700 }
701 DCHECK_EQ(kTaggedBase, access.base_is_tagged);
702 DCHECK_EQ(0, access.offset % kPointerSize);
703 int field_index = access.offset / kPointerSize;
704 if (field_index >= static_cast<int>(kMaxTrackedFields)) return -1;
705 return field_index;
706}
707
Emily Bernier958fae72015-03-24 16:35:39 -0400708} // namespace compiler
709} // namespace internal
710} // namespace v8