1 // Copyright 2014 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 #include "src/compiler/load-elimination.h"
6
7 #include "src/compiler/graph.h"
8 #include "src/compiler/node-properties.h"
9 #include "src/compiler/simplified-operator.h"
10 #include "src/types.h"
11
12 namespace v8 {
13 namespace internal {
14 namespace compiler {
15
~LoadElimination()16 LoadElimination::~LoadElimination() {}
17
Reduce(Node * node)18 Reduction LoadElimination::Reduce(Node* node) {
19 switch (node->opcode()) {
20 case IrOpcode::kLoadField:
21 return ReduceLoadField(node);
22 default:
23 break;
24 }
25 return NoChange();
26 }
27
ReduceLoadField(Node * node)28 Reduction LoadElimination::ReduceLoadField(Node* node) {
29 DCHECK_EQ(IrOpcode::kLoadField, node->opcode());
30 FieldAccess const access = FieldAccessOf(node->op());
31 Node* object = NodeProperties::GetValueInput(node, 0);
32 for (Node* effect = NodeProperties::GetEffectInput(node);;
33 effect = NodeProperties::GetEffectInput(effect)) {
34 switch (effect->opcode()) {
35 case IrOpcode::kLoadField: {
36 FieldAccess const effect_access = FieldAccessOf(effect->op());
37 if (object == NodeProperties::GetValueInput(effect, 0) &&
38 access == effect_access && effect_access.type->Is(access.type)) {
39 Node* const value = effect;
40 ReplaceWithValue(node, value);
41 return Replace(value);
42 }
43 break;
44 }
45 case IrOpcode::kStoreField: {
46 if (access == FieldAccessOf(effect->op())) {
47 if (object == NodeProperties::GetValueInput(effect, 0)) {
48 Node* const value = NodeProperties::GetValueInput(effect, 1);
49 Type* stored_value_type = NodeProperties::GetType(value);
50 Type* load_type = NodeProperties::GetType(node);
51 // Make sure the replacement's type is a subtype of the node's
52 // type. Otherwise we could confuse optimizations that were
53 // based on the original type.
54 if (stored_value_type->Is(load_type)) {
55 ReplaceWithValue(node, value);
56 return Replace(value);
57 } else {
58 Node* renamed = graph()->NewNode(
59 simplified()->TypeGuard(Type::Intersect(
60 stored_value_type, load_type, graph()->zone())),
61 value, NodeProperties::GetControlInput(node));
62 ReplaceWithValue(node, renamed);
63 return Replace(renamed);
64 }
65 }
66 // TODO(turbofan): Alias analysis to the rescue?
67 return NoChange();
68 }
69 break;
70 }
71 case IrOpcode::kBeginRegion:
72 case IrOpcode::kStoreBuffer:
73 case IrOpcode::kStoreElement: {
74 // These can never interfere with field loads.
75 break;
76 }
77 case IrOpcode::kFinishRegion: {
78 // "Look through" FinishRegion nodes to make LoadElimination capable
79 // of looking into atomic regions.
80 if (object == effect) object = NodeProperties::GetValueInput(effect, 0);
81 break;
82 }
83 case IrOpcode::kAllocate: {
84 // Allocations don't interfere with field loads. In case we see the
85 // actual allocation for the {object} we can abort.
86 if (object == effect) return NoChange();
87 break;
88 }
89 default: {
90 if (!effect->op()->HasProperty(Operator::kNoWrite) ||
91 effect->op()->EffectInputCount() != 1) {
92 return NoChange();
93 }
94 break;
95 }
96 }
97 }
98 UNREACHABLE();
99 return NoChange();
100 }
101
102 } // namespace compiler
103 } // namespace internal
104 } // namespace v8
105