OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/load-elimination.h" | 5 #include "src/compiler/load-elimination.h" |
6 #include "src/compiler/access-builder.h" | 6 #include "src/compiler/access-builder.h" |
7 #include "src/compiler/node.h" | 7 #include "src/compiler/node.h" |
8 #include "src/compiler/simplified-operator.h" | 8 #include "src/compiler/simplified-operator.h" |
| 9 #include "test/unittests/compiler/graph-reducer-unittest.h" |
9 #include "test/unittests/compiler/graph-unittest.h" | 10 #include "test/unittests/compiler/graph-unittest.h" |
10 #include "test/unittests/compiler/node-test-utils.h" | 11 #include "test/unittests/compiler/node-test-utils.h" |
| 12 #include "testing/gmock-support.h" |
| 13 |
| 14 using testing::_; |
| 15 using testing::StrictMock; |
11 | 16 |
12 namespace v8 { | 17 namespace v8 { |
13 namespace internal { | 18 namespace internal { |
14 namespace compiler { | 19 namespace compiler { |
15 | 20 |
16 class LoadEliminationTest : public TypedGraphTest { | 21 class LoadEliminationTest : public TypedGraphTest { |
17 public: | 22 public: |
18 LoadEliminationTest() : TypedGraphTest(3), simplified_(zone()) {} | 23 LoadEliminationTest() : TypedGraphTest(3), simplified_(zone()) {} |
19 ~LoadEliminationTest() override {} | 24 ~LoadEliminationTest() override {} |
20 | 25 |
21 protected: | 26 protected: |
22 void Run() { | |
23 LoadElimination load_elimination(graph(), zone()); | |
24 load_elimination.Run(); | |
25 } | |
26 | |
27 SimplifiedOperatorBuilder* simplified() { return &simplified_; } | 27 SimplifiedOperatorBuilder* simplified() { return &simplified_; } |
28 | 28 |
29 private: | 29 private: |
30 SimplifiedOperatorBuilder simplified_; | 30 SimplifiedOperatorBuilder simplified_; |
31 }; | 31 }; |
32 | 32 |
| 33 TEST_F(LoadEliminationTest, LoadElementAndLoadElement) { |
| 34 Node* object = Parameter(Type::Any(), 0); |
| 35 Node* effect = graph()->start(); |
| 36 Node* control = graph()->start(); |
| 37 Node* index = Parameter(Type::UnsignedSmall(), 1); |
| 38 ElementAccess const access = {kTaggedBase, kPointerSize, Type::Any(), |
| 39 MachineType::AnyTagged(), kNoWriteBarrier}; |
| 40 |
| 41 StrictMock<MockAdvancedReducerEditor> editor; |
| 42 LoadElimination load_elimination(&editor, zone()); |
| 43 |
| 44 load_elimination.Reduce(graph()->start()); |
| 45 |
| 46 Node* load1 = effect = graph()->NewNode(simplified()->LoadElement(access), |
| 47 object, index, effect, control); |
| 48 load_elimination.Reduce(load1); |
| 49 |
| 50 Node* load2 = effect = graph()->NewNode(simplified()->LoadElement(access), |
| 51 object, index, effect, control); |
| 52 EXPECT_CALL(editor, ReplaceWithValue(load2, load1, load1, _)); |
| 53 Reduction r = load_elimination.Reduce(load2); |
| 54 ASSERT_TRUE(r.Changed()); |
| 55 EXPECT_EQ(load1, r.replacement()); |
| 56 } |
| 57 |
| 58 TEST_F(LoadEliminationTest, StoreElementAndLoadElement) { |
| 59 Node* object = Parameter(Type::Any(), 0); |
| 60 Node* effect = graph()->start(); |
| 61 Node* control = graph()->start(); |
| 62 Node* index = Parameter(Type::UnsignedSmall(), 1); |
| 63 Node* value = Parameter(Type::Any(), 2); |
| 64 ElementAccess const access = {kTaggedBase, kPointerSize, Type::Any(), |
| 65 MachineType::AnyTagged(), kNoWriteBarrier}; |
| 66 |
| 67 StrictMock<MockAdvancedReducerEditor> editor; |
| 68 LoadElimination load_elimination(&editor, zone()); |
| 69 |
| 70 load_elimination.Reduce(graph()->start()); |
| 71 |
| 72 Node* store = effect = |
| 73 graph()->NewNode(simplified()->StoreElement(access), object, index, value, |
| 74 effect, control); |
| 75 load_elimination.Reduce(store); |
| 76 |
| 77 Node* load = effect = graph()->NewNode(simplified()->LoadElement(access), |
| 78 object, index, effect, control); |
| 79 EXPECT_CALL(editor, ReplaceWithValue(load, value, store, _)); |
| 80 Reduction r = load_elimination.Reduce(load); |
| 81 ASSERT_TRUE(r.Changed()); |
| 82 EXPECT_EQ(value, r.replacement()); |
| 83 } |
| 84 |
| 85 TEST_F(LoadEliminationTest, StoreElementAndStoreFieldAndLoadElement) { |
| 86 Node* object = Parameter(Type::Any(), 0); |
| 87 Node* effect = graph()->start(); |
| 88 Node* control = graph()->start(); |
| 89 Node* index = Parameter(Type::UnsignedSmall(), 1); |
| 90 Node* value = Parameter(Type::Any(), 2); |
| 91 ElementAccess const access = {kTaggedBase, kPointerSize, Type::Any(), |
| 92 MachineType::AnyTagged(), kNoWriteBarrier}; |
| 93 |
| 94 StrictMock<MockAdvancedReducerEditor> editor; |
| 95 LoadElimination load_elimination(&editor, zone()); |
| 96 |
| 97 load_elimination.Reduce(graph()->start()); |
| 98 |
| 99 Node* store1 = effect = |
| 100 graph()->NewNode(simplified()->StoreElement(access), object, index, value, |
| 101 effect, control); |
| 102 load_elimination.Reduce(store1); |
| 103 |
| 104 Node* store2 = effect = |
| 105 graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), |
| 106 object, value, effect, control); |
| 107 load_elimination.Reduce(store2); |
| 108 |
| 109 Node* load = effect = graph()->NewNode(simplified()->LoadElement(access), |
| 110 object, index, effect, control); |
| 111 EXPECT_CALL(editor, ReplaceWithValue(load, value, store2, _)); |
| 112 Reduction r = load_elimination.Reduce(load); |
| 113 ASSERT_TRUE(r.Changed()); |
| 114 EXPECT_EQ(value, r.replacement()); |
| 115 } |
| 116 |
33 TEST_F(LoadEliminationTest, LoadFieldAndLoadField) { | 117 TEST_F(LoadEliminationTest, LoadFieldAndLoadField) { |
34 Node* object = Parameter(Type::Any(), 0); | 118 Node* object = Parameter(Type::Any(), 0); |
35 Node* effect = graph()->start(); | 119 Node* effect = graph()->start(); |
36 Node* control = graph()->start(); | 120 Node* control = graph()->start(); |
37 FieldAccess access = {kTaggedBase, | 121 FieldAccess const access = {kTaggedBase, |
38 kPointerSize, | 122 kPointerSize, |
39 MaybeHandle<Name>(), | 123 MaybeHandle<Name>(), |
40 Type::Any(), | 124 Type::Any(), |
41 MachineType::AnyTagged(), | 125 MachineType::AnyTagged(), |
42 kNoWriteBarrier}; | 126 kNoWriteBarrier}; |
| 127 |
| 128 StrictMock<MockAdvancedReducerEditor> editor; |
| 129 LoadElimination load_elimination(&editor, zone()); |
| 130 |
| 131 load_elimination.Reduce(graph()->start()); |
| 132 |
43 Node* load1 = effect = graph()->NewNode(simplified()->LoadField(access), | 133 Node* load1 = effect = graph()->NewNode(simplified()->LoadField(access), |
44 object, effect, control); | 134 object, effect, control); |
| 135 load_elimination.Reduce(load1); |
| 136 |
45 Node* load2 = effect = graph()->NewNode(simplified()->LoadField(access), | 137 Node* load2 = effect = graph()->NewNode(simplified()->LoadField(access), |
46 object, effect, control); | 138 object, effect, control); |
47 control = graph()->NewNode(common()->Return(), load2, effect, control); | 139 EXPECT_CALL(editor, ReplaceWithValue(load2, load1, load1, _)); |
48 graph()->end()->ReplaceInput(0, control); | 140 Reduction r = load_elimination.Reduce(load2); |
49 | 141 ASSERT_TRUE(r.Changed()); |
50 Run(); | 142 EXPECT_EQ(load1, r.replacement()); |
51 | |
52 EXPECT_THAT(graph()->end(), IsEnd(IsReturn(load1, load1, graph()->start()))); | |
53 } | 143 } |
54 | 144 |
55 TEST_F(LoadEliminationTest, StoreFieldAndLoadField) { | 145 TEST_F(LoadEliminationTest, StoreFieldAndLoadField) { |
56 Node* object = Parameter(Type::Any(), 0); | 146 Node* object = Parameter(Type::Any(), 0); |
57 Node* value = Parameter(Type::Any(), 1); | 147 Node* value = Parameter(Type::Any(), 1); |
58 Node* effect = graph()->start(); | 148 Node* effect = graph()->start(); |
59 Node* control = graph()->start(); | 149 Node* control = graph()->start(); |
60 FieldAccess access = {kTaggedBase, | 150 FieldAccess access = {kTaggedBase, |
61 kPointerSize, | 151 kPointerSize, |
62 MaybeHandle<Name>(), | 152 MaybeHandle<Name>(), |
63 Type::Any(), | 153 Type::Any(), |
64 MachineType::AnyTagged(), | 154 MachineType::AnyTagged(), |
65 kNoWriteBarrier}; | 155 kNoWriteBarrier}; |
| 156 |
| 157 StrictMock<MockAdvancedReducerEditor> editor; |
| 158 LoadElimination load_elimination(&editor, zone()); |
| 159 |
| 160 load_elimination.Reduce(graph()->start()); |
| 161 |
66 Node* store = effect = graph()->NewNode(simplified()->StoreField(access), | 162 Node* store = effect = graph()->NewNode(simplified()->StoreField(access), |
67 object, value, effect, control); | 163 object, value, effect, control); |
| 164 load_elimination.Reduce(store); |
| 165 |
68 Node* load = effect = graph()->NewNode(simplified()->LoadField(access), | 166 Node* load = effect = graph()->NewNode(simplified()->LoadField(access), |
69 object, effect, control); | 167 object, effect, control); |
70 control = graph()->NewNode(common()->Return(), load, effect, control); | 168 EXPECT_CALL(editor, ReplaceWithValue(load, value, store, _)); |
71 graph()->end()->ReplaceInput(0, control); | 169 Reduction r = load_elimination.Reduce(load); |
| 170 ASSERT_TRUE(r.Changed()); |
| 171 EXPECT_EQ(value, r.replacement()); |
| 172 } |
72 | 173 |
73 Run(); | 174 TEST_F(LoadEliminationTest, StoreFieldAndStoreElementAndLoadField) { |
| 175 Node* object = Parameter(Type::Any(), 0); |
| 176 Node* value = Parameter(Type::Any(), 1); |
| 177 Node* index = Parameter(Type::UnsignedSmall(), 2); |
| 178 Node* effect = graph()->start(); |
| 179 Node* control = graph()->start(); |
| 180 FieldAccess access = {kTaggedBase, |
| 181 kPointerSize, |
| 182 MaybeHandle<Name>(), |
| 183 Type::Any(), |
| 184 MachineType::AnyTagged(), |
| 185 kNoWriteBarrier}; |
74 | 186 |
75 EXPECT_THAT(graph()->end(), IsEnd(IsReturn(value, store, graph()->start()))); | 187 StrictMock<MockAdvancedReducerEditor> editor; |
| 188 LoadElimination load_elimination(&editor, zone()); |
| 189 |
| 190 load_elimination.Reduce(graph()->start()); |
| 191 |
| 192 Node* store1 = effect = graph()->NewNode(simplified()->StoreField(access), |
| 193 object, value, effect, control); |
| 194 load_elimination.Reduce(store1); |
| 195 |
| 196 Node* store2 = effect = graph()->NewNode( |
| 197 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), object, |
| 198 index, object, effect, control); |
| 199 load_elimination.Reduce(store2); |
| 200 |
| 201 Node* load = effect = graph()->NewNode(simplified()->LoadField(access), |
| 202 object, effect, control); |
| 203 EXPECT_CALL(editor, ReplaceWithValue(load, value, store2, _)); |
| 204 Reduction r = load_elimination.Reduce(load); |
| 205 ASSERT_TRUE(r.Changed()); |
| 206 EXPECT_EQ(value, r.replacement()); |
76 } | 207 } |
77 | 208 |
78 } // namespace compiler | 209 } // namespace compiler |
79 } // namespace internal | 210 } // namespace internal |
80 } // namespace v8 | 211 } // namespace v8 |
OLD | NEW |