• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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