summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/load-elimination.cc
blob: e19368d107623f6975c687b8c455b52d13c2d1a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/compiler/load-elimination.h"

#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/simplified-operator.h"
#include "src/types.h"

namespace v8 {
namespace internal {
namespace compiler {

LoadElimination::~LoadElimination() {}

Reduction LoadElimination::Reduce(Node* node) {
  switch (node->opcode()) {
    case IrOpcode::kLoadField:
      return ReduceLoadField(node);
    default:
      break;
  }
  return NoChange();
}

Reduction LoadElimination::ReduceLoadField(Node* node) {
  DCHECK_EQ(IrOpcode::kLoadField, node->opcode());
  FieldAccess const access = FieldAccessOf(node->op());
  Node* object = NodeProperties::GetValueInput(node, 0);
  for (Node* effect = NodeProperties::GetEffectInput(node);;
       effect = NodeProperties::GetEffectInput(effect)) {
    switch (effect->opcode()) {
      case IrOpcode::kLoadField: {
        if (object == NodeProperties::GetValueInput(effect, 0) &&
            access == FieldAccessOf(effect->op())) {
          Node* const value = effect;
          ReplaceWithValue(node, value);
          return Replace(value);
        }
        break;
      }
      case IrOpcode::kStoreField: {
        if (access == FieldAccessOf(effect->op())) {
          if (object == NodeProperties::GetValueInput(effect, 0)) {
            Node* const value = NodeProperties::GetValueInput(effect, 1);
            Type* stored_value_type = NodeProperties::GetType(value);
            Type* load_type = NodeProperties::GetType(node);
            // Make sure the replacement's type is a subtype of the node's
            // type. Otherwise we could confuse optimizations that were
            // based on the original type.
            if (stored_value_type->Is(load_type)) {
              ReplaceWithValue(node, value);
              return Replace(value);
            } else {
              Node* renamed = graph()->NewNode(
                  common()->Guard(Type::Intersect(stored_value_type, load_type,
                                                  graph()->zone())),
                  value, NodeProperties::GetControlInput(node));
              ReplaceWithValue(node, renamed);
              return Replace(renamed);
            }
          }
          // TODO(turbofan): Alias analysis to the rescue?
          return NoChange();
        }
        break;
      }
      case IrOpcode::kBeginRegion:
      case IrOpcode::kStoreBuffer:
      case IrOpcode::kStoreElement: {
        // These can never interfere with field loads.
        break;
      }
      case IrOpcode::kFinishRegion: {
        // "Look through" FinishRegion nodes to make LoadElimination capable
        // of looking into atomic regions.
        if (object == effect) object = NodeProperties::GetValueInput(effect, 0);
        break;
      }
      case IrOpcode::kAllocate: {
        // Allocations don't interfere with field loads. In case we see the
        // actual allocation for the {object} we can abort.
        if (object == effect) return NoChange();
        break;
      }
      default: {
        if (!effect->op()->HasProperty(Operator::kNoWrite) ||
            effect->op()->EffectInputCount() != 1) {
          return NoChange();
        }
        break;
      }
    }
  }
  UNREACHABLE();
  return NoChange();
}

}  // namespace compiler
}  // namespace internal
}  // namespace v8