OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 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 | 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/v8.h" | 5 #include "src/v8.h" |
6 #include "test/cctest/cctest.h" | 6 #include "test/cctest/cctest.h" |
7 | 7 |
| 8 #include "src/base/bits.h" |
8 #include "src/compiler/common-operator.h" | 9 #include "src/compiler/common-operator.h" |
9 #include "src/compiler/control-reducer.h" | 10 #include "src/compiler/control-reducer.h" |
10 #include "src/compiler/graph-inl.h" | 11 #include "src/compiler/graph-inl.h" |
11 #include "src/compiler/js-graph.h" | 12 #include "src/compiler/js-graph.h" |
| 13 #include "src/compiler/node-properties-inl.h" |
12 | 14 |
13 using namespace v8::internal; | 15 using namespace v8::internal; |
14 using namespace v8::internal::compiler; | 16 using namespace v8::internal::compiler; |
15 | 17 |
16 class CTrimTester : HandleAndZoneScope { | 18 static const size_t kNumLeafs = 4; |
| 19 |
| 20 // A helper for all tests dealing with ControlTester. |
| 21 class ControlReducerTester : HandleAndZoneScope { |
17 public: | 22 public: |
18 CTrimTester() | 23 ControlReducerTester() |
19 : isolate(main_isolate()), | 24 : isolate(main_isolate()), |
20 common(main_zone()), | 25 common(main_zone()), |
21 graph(main_zone()), | 26 graph(main_zone()), |
22 jsgraph(&graph, &common, NULL, NULL), | 27 jsgraph(&graph, &common, NULL, NULL), |
23 start(graph.NewNode(common.Start(1))), | 28 start(graph.NewNode(common.Start(1))), |
| 29 end(graph.NewNode(common.End(), start)), |
24 p0(graph.NewNode(common.Parameter(0), start)), | 30 p0(graph.NewNode(common.Parameter(0), start)), |
| 31 zero(jsgraph.Int32Constant(0)), |
25 one(jsgraph.OneConstant()), | 32 one(jsgraph.OneConstant()), |
26 half(jsgraph.Constant(0.5)) { | 33 half(jsgraph.Constant(0.5)), |
27 graph.SetEnd(start); | 34 self(graph.NewNode(common.Int32Constant(0xaabbccdd))), |
| 35 dead(graph.NewNode(common.Dead())) { |
| 36 graph.SetEnd(end); |
28 graph.SetStart(start); | 37 graph.SetStart(start); |
| 38 leaf[0] = zero; |
| 39 leaf[1] = one; |
| 40 leaf[2] = half; |
| 41 leaf[3] = p0; |
29 } | 42 } |
30 | 43 |
31 Isolate* isolate; | 44 Isolate* isolate; |
32 CommonOperatorBuilder common; | 45 CommonOperatorBuilder common; |
33 Graph graph; | 46 Graph graph; |
34 JSGraph jsgraph; | 47 JSGraph jsgraph; |
35 Node* start; | 48 Node* start; |
| 49 Node* end; |
36 Node* p0; | 50 Node* p0; |
| 51 Node* zero; |
37 Node* one; | 52 Node* one; |
38 Node* half; | 53 Node* half; |
| 54 Node* self; |
| 55 Node* dead; |
| 56 Node* leaf[kNumLeafs]; |
| 57 |
| 58 Node* Phi(Node* a) { |
| 59 return SetSelfReferences(graph.NewNode(op(1, false), a, start)); |
| 60 } |
| 61 |
| 62 Node* Phi(Node* a, Node* b) { |
| 63 return SetSelfReferences(graph.NewNode(op(2, false), a, b, start)); |
| 64 } |
| 65 |
| 66 Node* Phi(Node* a, Node* b, Node* c) { |
| 67 return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start)); |
| 68 } |
| 69 |
| 70 Node* Phi(Node* a, Node* b, Node* c, Node* d) { |
| 71 return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start)); |
| 72 } |
| 73 |
| 74 Node* EffectPhi(Node* a) { |
| 75 return SetSelfReferences(graph.NewNode(op(1, true), a, start)); |
| 76 } |
| 77 |
| 78 Node* EffectPhi(Node* a, Node* b) { |
| 79 return SetSelfReferences(graph.NewNode(op(2, true), a, b, start)); |
| 80 } |
| 81 |
| 82 Node* EffectPhi(Node* a, Node* b, Node* c) { |
| 83 return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start)); |
| 84 } |
| 85 |
| 86 Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) { |
| 87 return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start)); |
| 88 } |
| 89 |
| 90 Node* SetSelfReferences(Node* node) { |
| 91 Node::Inputs inputs = node->inputs(); |
| 92 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); |
| 93 ++iter) { |
| 94 Node* input = *iter; |
| 95 if (input == self) node->ReplaceInput(iter.index(), node); |
| 96 } |
| 97 return node; |
| 98 } |
| 99 |
| 100 const Operator* op(int count, bool effect) { |
| 101 return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count); |
| 102 } |
39 | 103 |
40 void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); } | 104 void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); } |
| 105 |
| 106 // Checks one-step reduction of a phi. |
| 107 void ReducePhi(Node* expect, Node* phi) { |
| 108 Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi); |
| 109 CHECK_EQ(expect, result); |
| 110 ReducePhiIterative(expect, phi); // iterative should give the same result. |
| 111 } |
| 112 |
| 113 void ReducePhiIterative(Node* expect, Node* phi) { |
| 114 p0->ReplaceInput(0, start); // hack: parameters may be trimmed. |
| 115 Node* ret = graph.NewNode(common.Return(), phi, start); |
| 116 Node* end = graph.NewNode(common.End(), ret); |
| 117 graph.SetEnd(end); |
| 118 ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common); |
| 119 CHECK_EQ(expect, ret->InputAt(0)); |
| 120 } |
| 121 |
| 122 void ReduceMerge(Node* expect, Node* merge) { |
| 123 Node* result = |
| 124 ControlReducer::ReduceMergeForTesting(&jsgraph, &common, merge); |
| 125 CHECK_EQ(expect, result); |
| 126 } |
| 127 |
| 128 void ReduceMergeIterative(Node* expect, Node* merge) { |
| 129 p0->ReplaceInput(0, start); // hack: parameters may be trimmed. |
| 130 Node* end = graph.NewNode(common.End(), merge); |
| 131 graph.SetEnd(end); |
| 132 ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common); |
| 133 CHECK_EQ(expect, end->InputAt(0)); |
| 134 } |
| 135 |
| 136 void ReduceBranch(Node* expect, Node* branch) { |
| 137 Node* result = |
| 138 ControlReducer::ReduceBranchForTesting(&jsgraph, &common, branch); |
| 139 CHECK_EQ(expect, result); |
| 140 } |
41 }; | 141 }; |
42 | 142 |
43 | 143 |
44 bool IsUsedBy(Node* a, Node* b) { | 144 bool IsUsedBy(Node* a, Node* b) { |
45 for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) { | 145 for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) { |
46 if (b == *i) return true; | 146 if (b == *i) return true; |
47 } | 147 } |
48 return false; | 148 return false; |
49 } | 149 } |
50 | 150 |
51 | 151 |
52 TEST(Trim1_live) { | 152 TEST(Trim1_live) { |
53 CTrimTester T; | 153 ControlReducerTester T; |
54 CHECK(IsUsedBy(T.start, T.p0)); | 154 CHECK(IsUsedBy(T.start, T.p0)); |
55 T.graph.SetEnd(T.p0); | 155 T.graph.SetEnd(T.p0); |
56 T.Trim(); | 156 T.Trim(); |
57 CHECK(IsUsedBy(T.start, T.p0)); | 157 CHECK(IsUsedBy(T.start, T.p0)); |
58 CHECK_EQ(T.start, T.p0->InputAt(0)); | 158 CHECK_EQ(T.start, T.p0->InputAt(0)); |
59 } | 159 } |
60 | 160 |
61 | 161 |
62 TEST(Trim1_dead) { | 162 TEST(Trim1_dead) { |
63 CTrimTester T; | 163 ControlReducerTester T; |
64 CHECK(IsUsedBy(T.start, T.p0)); | 164 CHECK(IsUsedBy(T.start, T.p0)); |
65 T.Trim(); | 165 T.Trim(); |
66 CHECK(!IsUsedBy(T.start, T.p0)); | 166 CHECK(!IsUsedBy(T.start, T.p0)); |
67 CHECK_EQ(NULL, T.p0->InputAt(0)); | 167 CHECK_EQ(NULL, T.p0->InputAt(0)); |
68 } | 168 } |
69 | 169 |
70 | 170 |
71 TEST(Trim2_live) { | 171 TEST(Trim2_live) { |
72 CTrimTester T; | 172 ControlReducerTester T; |
73 Node* phi = | 173 Node* phi = |
74 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); | 174 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); |
75 CHECK(IsUsedBy(T.one, phi)); | 175 CHECK(IsUsedBy(T.one, phi)); |
76 CHECK(IsUsedBy(T.half, phi)); | 176 CHECK(IsUsedBy(T.half, phi)); |
77 CHECK(IsUsedBy(T.start, phi)); | 177 CHECK(IsUsedBy(T.start, phi)); |
78 T.graph.SetEnd(phi); | 178 T.graph.SetEnd(phi); |
79 T.Trim(); | 179 T.Trim(); |
80 CHECK(IsUsedBy(T.one, phi)); | 180 CHECK(IsUsedBy(T.one, phi)); |
81 CHECK(IsUsedBy(T.half, phi)); | 181 CHECK(IsUsedBy(T.half, phi)); |
82 CHECK(IsUsedBy(T.start, phi)); | 182 CHECK(IsUsedBy(T.start, phi)); |
83 CHECK_EQ(T.one, phi->InputAt(0)); | 183 CHECK_EQ(T.one, phi->InputAt(0)); |
84 CHECK_EQ(T.half, phi->InputAt(1)); | 184 CHECK_EQ(T.half, phi->InputAt(1)); |
85 CHECK_EQ(T.start, phi->InputAt(2)); | 185 CHECK_EQ(T.start, phi->InputAt(2)); |
86 } | 186 } |
87 | 187 |
88 | 188 |
89 TEST(Trim2_dead) { | 189 TEST(Trim2_dead) { |
90 CTrimTester T; | 190 ControlReducerTester T; |
91 Node* phi = | 191 Node* phi = |
92 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); | 192 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); |
93 CHECK(IsUsedBy(T.one, phi)); | 193 CHECK(IsUsedBy(T.one, phi)); |
94 CHECK(IsUsedBy(T.half, phi)); | 194 CHECK(IsUsedBy(T.half, phi)); |
95 CHECK(IsUsedBy(T.start, phi)); | 195 CHECK(IsUsedBy(T.start, phi)); |
96 T.Trim(); | 196 T.Trim(); |
97 CHECK(!IsUsedBy(T.one, phi)); | 197 CHECK(!IsUsedBy(T.one, phi)); |
98 CHECK(!IsUsedBy(T.half, phi)); | 198 CHECK(!IsUsedBy(T.half, phi)); |
99 CHECK(!IsUsedBy(T.start, phi)); | 199 CHECK(!IsUsedBy(T.start, phi)); |
100 CHECK_EQ(NULL, phi->InputAt(0)); | 200 CHECK_EQ(NULL, phi->InputAt(0)); |
101 CHECK_EQ(NULL, phi->InputAt(1)); | 201 CHECK_EQ(NULL, phi->InputAt(1)); |
102 CHECK_EQ(NULL, phi->InputAt(2)); | 202 CHECK_EQ(NULL, phi->InputAt(2)); |
103 } | 203 } |
104 | 204 |
105 | 205 |
106 TEST(Trim_chain1) { | 206 TEST(Trim_chain1) { |
107 CTrimTester T; | 207 ControlReducerTester T; |
108 const int kDepth = 15; | 208 const int kDepth = 15; |
109 Node* live[kDepth]; | 209 Node* live[kDepth]; |
110 Node* dead[kDepth]; | 210 Node* dead[kDepth]; |
111 Node* end = T.start; | 211 Node* end = T.start; |
112 for (int i = 0; i < kDepth; i++) { | 212 for (int i = 0; i < kDepth; i++) { |
113 live[i] = end = T.graph.NewNode(T.common.Merge(1), end); | 213 live[i] = end = T.graph.NewNode(T.common.Merge(1), end); |
114 dead[i] = T.graph.NewNode(T.common.Merge(1), end); | 214 dead[i] = T.graph.NewNode(T.common.Merge(1), end); |
115 } | 215 } |
116 // end -> live[last] -> live[last-1] -> ... -> start | 216 // end -> live[last] -> live[last-1] -> ... -> start |
117 // dead[last] ^ dead[last-1] ^ ... ^ | 217 // dead[last] ^ dead[last-1] ^ ... ^ |
118 T.graph.SetEnd(end); | 218 T.graph.SetEnd(end); |
119 T.Trim(); | 219 T.Trim(); |
120 for (int i = 0; i < kDepth; i++) { | 220 for (int i = 0; i < kDepth; i++) { |
121 CHECK(!IsUsedBy(live[i], dead[i])); | 221 CHECK(!IsUsedBy(live[i], dead[i])); |
122 CHECK_EQ(NULL, dead[i]->InputAt(0)); | 222 CHECK_EQ(NULL, dead[i]->InputAt(0)); |
123 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); | 223 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); |
124 } | 224 } |
125 } | 225 } |
126 | 226 |
127 | 227 |
128 TEST(Trim_chain2) { | 228 TEST(Trim_chain2) { |
129 CTrimTester T; | 229 ControlReducerTester T; |
130 const int kDepth = 15; | 230 const int kDepth = 15; |
131 Node* live[kDepth]; | 231 Node* live[kDepth]; |
132 Node* dead[kDepth]; | 232 Node* dead[kDepth]; |
133 Node* l = T.start; | 233 Node* l = T.start; |
134 Node* d = T.start; | 234 Node* d = T.start; |
135 for (int i = 0; i < kDepth; i++) { | 235 for (int i = 0; i < kDepth; i++) { |
136 live[i] = l = T.graph.NewNode(T.common.Merge(1), l); | 236 live[i] = l = T.graph.NewNode(T.common.Merge(1), l); |
137 dead[i] = d = T.graph.NewNode(T.common.Merge(1), d); | 237 dead[i] = d = T.graph.NewNode(T.common.Merge(1), d); |
138 } | 238 } |
139 // end -> live[last] -> live[last-1] -> ... -> start | 239 // end -> live[last] -> live[last-1] -> ... -> start |
140 // dead[last] -> dead[last-1] -> ... -> start | 240 // dead[last] -> dead[last-1] -> ... -> start |
141 T.graph.SetEnd(l); | 241 T.graph.SetEnd(l); |
142 T.Trim(); | 242 T.Trim(); |
143 CHECK(!IsUsedBy(T.start, dead[0])); | 243 CHECK(!IsUsedBy(T.start, dead[0])); |
144 for (int i = 0; i < kDepth; i++) { | 244 for (int i = 0; i < kDepth; i++) { |
145 CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0)); | 245 CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0)); |
146 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); | 246 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); |
147 } | 247 } |
148 } | 248 } |
149 | 249 |
150 | 250 |
151 TEST(Trim_cycle1) { | 251 TEST(Trim_cycle1) { |
152 CTrimTester T; | 252 ControlReducerTester T; |
153 Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start); | 253 Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start); |
154 loop->ReplaceInput(1, loop); | 254 loop->ReplaceInput(1, loop); |
155 Node* end = T.graph.NewNode(T.common.End(), loop); | 255 Node* end = T.graph.NewNode(T.common.End(), loop); |
156 T.graph.SetEnd(end); | 256 T.graph.SetEnd(end); |
157 | 257 |
158 CHECK(IsUsedBy(T.start, loop)); | 258 CHECK(IsUsedBy(T.start, loop)); |
159 CHECK(IsUsedBy(loop, end)); | 259 CHECK(IsUsedBy(loop, end)); |
160 CHECK(IsUsedBy(loop, loop)); | 260 CHECK(IsUsedBy(loop, loop)); |
161 | 261 |
162 T.Trim(); | 262 T.Trim(); |
163 | 263 |
164 // nothing should have happened to the loop itself. | 264 // nothing should have happened to the loop itself. |
165 CHECK(IsUsedBy(T.start, loop)); | 265 CHECK(IsUsedBy(T.start, loop)); |
166 CHECK(IsUsedBy(loop, end)); | 266 CHECK(IsUsedBy(loop, end)); |
167 CHECK(IsUsedBy(loop, loop)); | 267 CHECK(IsUsedBy(loop, loop)); |
168 CHECK_EQ(T.start, loop->InputAt(0)); | 268 CHECK_EQ(T.start, loop->InputAt(0)); |
169 CHECK_EQ(loop, loop->InputAt(1)); | 269 CHECK_EQ(loop, loop->InputAt(1)); |
170 CHECK_EQ(loop, end->InputAt(0)); | 270 CHECK_EQ(loop, end->InputAt(0)); |
171 } | 271 } |
172 | 272 |
173 | 273 |
174 TEST(Trim_cycle2) { | 274 TEST(Trim_cycle2) { |
175 CTrimTester T; | 275 ControlReducerTester T; |
176 Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start); | 276 Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start); |
177 loop->ReplaceInput(1, loop); | 277 loop->ReplaceInput(1, loop); |
178 Node* end = T.graph.NewNode(T.common.End(), loop); | 278 Node* end = T.graph.NewNode(T.common.End(), loop); |
179 Node* phi = | 279 Node* phi = |
180 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop); | 280 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop); |
181 T.graph.SetEnd(end); | 281 T.graph.SetEnd(end); |
182 | 282 |
183 CHECK(IsUsedBy(T.start, loop)); | 283 CHECK(IsUsedBy(T.start, loop)); |
184 CHECK(IsUsedBy(loop, end)); | 284 CHECK(IsUsedBy(loop, end)); |
185 CHECK(IsUsedBy(loop, loop)); | 285 CHECK(IsUsedBy(loop, loop)); |
(...skipping 14 matching lines...) Expand all Loading... |
200 // phi should have been trimmed away. | 300 // phi should have been trimmed away. |
201 CHECK(!IsUsedBy(loop, phi)); | 301 CHECK(!IsUsedBy(loop, phi)); |
202 CHECK(!IsUsedBy(T.one, phi)); | 302 CHECK(!IsUsedBy(T.one, phi)); |
203 CHECK(!IsUsedBy(T.half, phi)); | 303 CHECK(!IsUsedBy(T.half, phi)); |
204 CHECK_EQ(NULL, phi->InputAt(0)); | 304 CHECK_EQ(NULL, phi->InputAt(0)); |
205 CHECK_EQ(NULL, phi->InputAt(1)); | 305 CHECK_EQ(NULL, phi->InputAt(1)); |
206 CHECK_EQ(NULL, phi->InputAt(2)); | 306 CHECK_EQ(NULL, phi->InputAt(2)); |
207 } | 307 } |
208 | 308 |
209 | 309 |
210 void CheckTrimConstant(CTrimTester* T, Node* k) { | 310 void CheckTrimConstant(ControlReducerTester* T, Node* k) { |
211 Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start); | 311 Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start); |
212 CHECK(IsUsedBy(k, phi)); | 312 CHECK(IsUsedBy(k, phi)); |
213 T->Trim(); | 313 T->Trim(); |
214 CHECK(!IsUsedBy(k, phi)); | 314 CHECK(!IsUsedBy(k, phi)); |
215 CHECK_EQ(NULL, phi->InputAt(0)); | 315 CHECK_EQ(NULL, phi->InputAt(0)); |
216 CHECK_EQ(NULL, phi->InputAt(1)); | 316 CHECK_EQ(NULL, phi->InputAt(1)); |
217 } | 317 } |
218 | 318 |
219 | 319 |
220 TEST(Trim_constants) { | 320 TEST(Trim_constants) { |
221 CTrimTester T; | 321 ControlReducerTester T; |
222 int32_t int32_constants[] = { | 322 int32_t int32_constants[] = { |
223 0, -1, -2, 2, 2, 3, 3, 4, 4, 5, 5, 4, 5, 6, 6, 7, 8, 7, 8, 9, | 323 0, -1, -2, 2, 2, 3, 3, 4, 4, 5, 5, 4, 5, 6, 6, 7, 8, 7, 8, 9, |
224 0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9}; | 324 0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9}; |
225 | 325 |
226 for (size_t i = 0; i < arraysize(int32_constants); i++) { | 326 for (size_t i = 0; i < arraysize(int32_constants); i++) { |
227 CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i])); | 327 CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i])); |
228 CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i])); | 328 CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i])); |
229 CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i])); | 329 CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i])); |
230 } | 330 } |
231 | 331 |
232 Node* other_constants[] = { | 332 Node* other_constants[] = { |
233 T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(), | 333 T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(), |
234 T.jsgraph.TrueConstant(), T.jsgraph.FalseConstant(), | 334 T.jsgraph.TrueConstant(), T.jsgraph.FalseConstant(), |
235 T.jsgraph.NullConstant(), T.jsgraph.ZeroConstant(), | 335 T.jsgraph.NullConstant(), T.jsgraph.ZeroConstant(), |
236 T.jsgraph.OneConstant(), T.jsgraph.NaNConstant(), | 336 T.jsgraph.OneConstant(), T.jsgraph.NaNConstant(), |
237 T.jsgraph.Constant(21), T.jsgraph.Constant(22.2)}; | 337 T.jsgraph.Constant(21), T.jsgraph.Constant(22.2)}; |
238 | 338 |
239 for (size_t i = 0; i < arraysize(other_constants); i++) { | 339 for (size_t i = 0; i < arraysize(other_constants); i++) { |
240 CheckTrimConstant(&T, other_constants[i]); | 340 CheckTrimConstant(&T, other_constants[i]); |
241 } | 341 } |
242 } | 342 } |
| 343 |
| 344 |
| 345 TEST(CReducePhi1) { |
| 346 ControlReducerTester R; |
| 347 |
| 348 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0])); |
| 349 R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1])); |
| 350 R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2])); |
| 351 R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3])); |
| 352 } |
| 353 |
| 354 |
| 355 TEST(CReducePhi1_dead) { |
| 356 ControlReducerTester R; |
| 357 |
| 358 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead)); |
| 359 R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1], R.dead)); |
| 360 R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2], R.dead)); |
| 361 R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3], R.dead)); |
| 362 |
| 363 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0])); |
| 364 R.ReducePhi(R.leaf[1], R.Phi(R.dead, R.leaf[1])); |
| 365 R.ReducePhi(R.leaf[2], R.Phi(R.dead, R.leaf[2])); |
| 366 R.ReducePhi(R.leaf[3], R.Phi(R.dead, R.leaf[3])); |
| 367 } |
| 368 |
| 369 |
| 370 TEST(CReducePhi1_dead2) { |
| 371 ControlReducerTester R; |
| 372 |
| 373 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead, R.dead)); |
| 374 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0], R.dead)); |
| 375 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.dead, R.leaf[0])); |
| 376 } |
| 377 |
| 378 |
| 379 TEST(CReducePhi2a) { |
| 380 ControlReducerTester R; |
| 381 |
| 382 for (size_t i = 0; i < kNumLeafs; i++) { |
| 383 Node* a = R.leaf[i]; |
| 384 R.ReducePhi(a, R.Phi(a, a)); |
| 385 } |
| 386 } |
| 387 |
| 388 |
| 389 TEST(CReducePhi2b) { |
| 390 ControlReducerTester R; |
| 391 |
| 392 for (size_t i = 0; i < kNumLeafs; i++) { |
| 393 Node* a = R.leaf[i]; |
| 394 R.ReducePhi(a, R.Phi(R.self, a)); |
| 395 R.ReducePhi(a, R.Phi(a, R.self)); |
| 396 } |
| 397 } |
| 398 |
| 399 |
| 400 TEST(CReducePhi2c) { |
| 401 ControlReducerTester R; |
| 402 |
| 403 for (size_t i = 1; i < kNumLeafs; i++) { |
| 404 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 405 Node* phi1 = R.Phi(b, a); |
| 406 R.ReducePhi(phi1, phi1); |
| 407 |
| 408 Node* phi2 = R.Phi(a, b); |
| 409 R.ReducePhi(phi2, phi2); |
| 410 } |
| 411 } |
| 412 |
| 413 |
| 414 TEST(CReducePhi2_dead) { |
| 415 ControlReducerTester R; |
| 416 |
| 417 for (size_t i = 0; i < kNumLeafs; i++) { |
| 418 Node* a = R.leaf[i]; |
| 419 R.ReducePhi(a, R.Phi(a, a, R.dead)); |
| 420 R.ReducePhi(a, R.Phi(a, R.dead, a)); |
| 421 R.ReducePhi(a, R.Phi(R.dead, a, a)); |
| 422 } |
| 423 |
| 424 for (size_t i = 0; i < kNumLeafs; i++) { |
| 425 Node* a = R.leaf[i]; |
| 426 R.ReducePhi(a, R.Phi(R.self, a)); |
| 427 R.ReducePhi(a, R.Phi(a, R.self)); |
| 428 R.ReducePhi(a, R.Phi(R.self, a, R.dead)); |
| 429 R.ReducePhi(a, R.Phi(a, R.self, R.dead)); |
| 430 } |
| 431 |
| 432 for (size_t i = 1; i < kNumLeafs; i++) { |
| 433 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 434 Node* phi1 = R.Phi(b, a, R.dead); |
| 435 R.ReducePhi(phi1, phi1); |
| 436 |
| 437 Node* phi2 = R.Phi(a, b, R.dead); |
| 438 R.ReducePhi(phi2, phi2); |
| 439 } |
| 440 } |
| 441 |
| 442 |
| 443 TEST(CReducePhi3) { |
| 444 ControlReducerTester R; |
| 445 |
| 446 for (size_t i = 0; i < kNumLeafs; i++) { |
| 447 Node* a = R.leaf[i]; |
| 448 R.ReducePhi(a, R.Phi(a, a, a)); |
| 449 } |
| 450 |
| 451 for (size_t i = 0; i < kNumLeafs; i++) { |
| 452 Node* a = R.leaf[i]; |
| 453 R.ReducePhi(a, R.Phi(R.self, a, a)); |
| 454 R.ReducePhi(a, R.Phi(a, R.self, a)); |
| 455 R.ReducePhi(a, R.Phi(a, a, R.self)); |
| 456 } |
| 457 |
| 458 for (size_t i = 1; i < kNumLeafs; i++) { |
| 459 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 460 Node* phi1 = R.Phi(b, a, a); |
| 461 R.ReducePhi(phi1, phi1); |
| 462 |
| 463 Node* phi2 = R.Phi(a, b, a); |
| 464 R.ReducePhi(phi2, phi2); |
| 465 |
| 466 Node* phi3 = R.Phi(a, a, b); |
| 467 R.ReducePhi(phi3, phi3); |
| 468 } |
| 469 } |
| 470 |
| 471 |
| 472 TEST(CReducePhi4) { |
| 473 ControlReducerTester R; |
| 474 |
| 475 for (size_t i = 0; i < kNumLeafs; i++) { |
| 476 Node* a = R.leaf[i]; |
| 477 R.ReducePhi(a, R.Phi(a, a, a, a)); |
| 478 } |
| 479 |
| 480 for (size_t i = 0; i < kNumLeafs; i++) { |
| 481 Node* a = R.leaf[i]; |
| 482 R.ReducePhi(a, R.Phi(R.self, a, a, a)); |
| 483 R.ReducePhi(a, R.Phi(a, R.self, a, a)); |
| 484 R.ReducePhi(a, R.Phi(a, a, R.self, a)); |
| 485 R.ReducePhi(a, R.Phi(a, a, a, R.self)); |
| 486 |
| 487 R.ReducePhi(a, R.Phi(R.self, R.self, a, a)); |
| 488 R.ReducePhi(a, R.Phi(a, R.self, R.self, a)); |
| 489 R.ReducePhi(a, R.Phi(a, a, R.self, R.self)); |
| 490 R.ReducePhi(a, R.Phi(R.self, a, a, R.self)); |
| 491 } |
| 492 |
| 493 for (size_t i = 1; i < kNumLeafs; i++) { |
| 494 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 495 Node* phi1 = R.Phi(b, a, a, a); |
| 496 R.ReducePhi(phi1, phi1); |
| 497 |
| 498 Node* phi2 = R.Phi(a, b, a, a); |
| 499 R.ReducePhi(phi2, phi2); |
| 500 |
| 501 Node* phi3 = R.Phi(a, a, b, a); |
| 502 R.ReducePhi(phi3, phi3); |
| 503 |
| 504 Node* phi4 = R.Phi(a, a, a, b); |
| 505 R.ReducePhi(phi4, phi4); |
| 506 } |
| 507 } |
| 508 |
| 509 |
| 510 TEST(CReducePhi_iterative1) { |
| 511 ControlReducerTester R; |
| 512 |
| 513 R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0]))); |
| 514 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.leaf[0])); |
| 515 } |
| 516 |
| 517 |
| 518 TEST(CReducePhi_iterative2) { |
| 519 ControlReducerTester R; |
| 520 |
| 521 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.Phi(R.leaf[0]))); |
| 522 } |
| 523 |
| 524 |
| 525 TEST(CReducePhi_iterative3) { |
| 526 ControlReducerTester R; |
| 527 |
| 528 R.ReducePhiIterative(R.leaf[0], |
| 529 R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.leaf[0]))); |
| 530 R.ReducePhiIterative(R.leaf[0], |
| 531 R.Phi(R.Phi(R.leaf[0], R.leaf[0]), R.leaf[0])); |
| 532 } |
| 533 |
| 534 |
| 535 TEST(CReducePhi_iterative4) { |
| 536 ControlReducerTester R; |
| 537 |
| 538 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.leaf[0]), |
| 539 R.Phi(R.leaf[0], R.leaf[0]))); |
| 540 |
| 541 Node* p1 = R.Phi(R.leaf[0], R.leaf[0]); |
| 542 R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1)); |
| 543 |
| 544 Node* p2 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]); |
| 545 R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2, p2)); |
| 546 |
| 547 Node* p3 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]); |
| 548 R.ReducePhiIterative(R.leaf[0], R.Phi(p3, p3, R.leaf[0])); |
| 549 } |
| 550 |
| 551 |
| 552 TEST(CReducePhi_iterative_self1) { |
| 553 ControlReducerTester R; |
| 554 |
| 555 R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.self))); |
| 556 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.leaf[0])); |
| 557 } |
| 558 |
| 559 |
| 560 TEST(CReducePhi_iterative_self2) { |
| 561 ControlReducerTester R; |
| 562 |
| 563 R.ReducePhiIterative( |
| 564 R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.Phi(R.leaf[0], R.self))); |
| 565 R.ReducePhiIterative( |
| 566 R.leaf[0], R.Phi(R.Phi(R.self, R.leaf[0]), R.Phi(R.self, R.leaf[0]))); |
| 567 |
| 568 Node* p1 = R.Phi(R.leaf[0], R.self); |
| 569 R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1)); |
| 570 |
| 571 Node* p2 = R.Phi(R.self, R.leaf[0]); |
| 572 R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2)); |
| 573 } |
| 574 |
| 575 |
| 576 TEST(EReducePhi1) { |
| 577 ControlReducerTester R; |
| 578 |
| 579 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0])); |
| 580 R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1])); |
| 581 R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2])); |
| 582 R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3])); |
| 583 } |
| 584 |
| 585 |
| 586 TEST(EReducePhi1_dead) { |
| 587 ControlReducerTester R; |
| 588 |
| 589 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead)); |
| 590 R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1], R.dead)); |
| 591 R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2], R.dead)); |
| 592 R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3], R.dead)); |
| 593 |
| 594 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0])); |
| 595 R.ReducePhi(R.leaf[1], R.EffectPhi(R.dead, R.leaf[1])); |
| 596 R.ReducePhi(R.leaf[2], R.EffectPhi(R.dead, R.leaf[2])); |
| 597 R.ReducePhi(R.leaf[3], R.EffectPhi(R.dead, R.leaf[3])); |
| 598 } |
| 599 |
| 600 |
| 601 TEST(EReducePhi1_dead2) { |
| 602 ControlReducerTester R; |
| 603 |
| 604 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead, R.dead)); |
| 605 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0], R.dead)); |
| 606 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.dead, R.leaf[0])); |
| 607 } |
| 608 |
| 609 |
| 610 TEST(CMergeReduce_simple1) { |
| 611 ControlReducerTester R; |
| 612 |
| 613 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); |
| 614 R.ReduceMerge(R.start, merge); |
| 615 } |
| 616 |
| 617 |
| 618 TEST(CMergeReduce_simple2) { |
| 619 ControlReducerTester R; |
| 620 |
| 621 Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start); |
| 622 Node* merge2 = R.graph.NewNode(R.common.Merge(1), merge1); |
| 623 R.ReduceMerge(merge1, merge2); |
| 624 R.ReduceMergeIterative(R.start, merge2); |
| 625 } |
| 626 |
| 627 |
| 628 TEST(CMergeReduce_none1) { |
| 629 ControlReducerTester R; |
| 630 |
| 631 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.start); |
| 632 R.ReduceMerge(merge, merge); |
| 633 } |
| 634 |
| 635 |
| 636 TEST(CMergeReduce_none2) { |
| 637 ControlReducerTester R; |
| 638 |
| 639 Node* t = R.graph.NewNode(R.common.IfTrue(), R.start); |
| 640 Node* f = R.graph.NewNode(R.common.IfFalse(), R.start); |
| 641 Node* merge = R.graph.NewNode(R.common.Merge(2), t, f); |
| 642 R.ReduceMerge(merge, merge); |
| 643 } |
| 644 |
| 645 |
| 646 TEST(CMergeReduce_self3) { |
| 647 ControlReducerTester R; |
| 648 |
| 649 Node* merge = |
| 650 R.SetSelfReferences(R.graph.NewNode(R.common.Merge(2), R.start, R.self)); |
| 651 R.ReduceMerge(merge, merge); |
| 652 } |
| 653 |
| 654 |
| 655 TEST(CMergeReduce_dead1) { |
| 656 ControlReducerTester R; |
| 657 |
| 658 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.dead); |
| 659 R.ReduceMerge(R.start, merge); |
| 660 } |
| 661 |
| 662 |
| 663 TEST(CMergeReduce_dead2) { |
| 664 ControlReducerTester R; |
| 665 |
| 666 Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start); |
| 667 Node* merge2 = R.graph.NewNode(R.common.Merge(2), merge1, R.dead); |
| 668 R.ReduceMerge(merge1, merge2); |
| 669 R.ReduceMergeIterative(R.start, merge2); |
| 670 } |
| 671 |
| 672 |
| 673 TEST(CMergeReduce_dead_rm1a) { |
| 674 ControlReducerTester R; |
| 675 |
| 676 for (int i = 0; i < 3; i++) { |
| 677 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 678 merge->ReplaceInput(i, R.dead); |
| 679 R.ReduceMerge(merge, merge); |
| 680 CHECK_EQ(IrOpcode::kMerge, merge->opcode()); |
| 681 CHECK_EQ(2, OpParameter<int32_t>(merge->op())); |
| 682 CHECK_EQ(2, merge->InputCount()); |
| 683 CHECK_EQ(R.start, merge->InputAt(0)); |
| 684 CHECK_EQ(R.start, merge->InputAt(1)); |
| 685 } |
| 686 } |
| 687 |
| 688 |
| 689 TEST(CMergeReduce_dead_rm1b) { |
| 690 ControlReducerTester R; |
| 691 |
| 692 Node* t = R.graph.NewNode(R.common.IfTrue(), R.start); |
| 693 Node* f = R.graph.NewNode(R.common.IfFalse(), R.start); |
| 694 for (int i = 0; i < 2; i++) { |
| 695 Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead); |
| 696 for (int j = i + 1; j < 3; j++) { |
| 697 merge->ReplaceInput(i, t); |
| 698 merge->ReplaceInput(j, f); |
| 699 R.ReduceMerge(merge, merge); |
| 700 CHECK_EQ(IrOpcode::kMerge, merge->opcode()); |
| 701 CHECK_EQ(2, OpParameter<int32_t>(merge->op())); |
| 702 CHECK_EQ(2, merge->InputCount()); |
| 703 CHECK_EQ(t, merge->InputAt(0)); |
| 704 CHECK_EQ(f, merge->InputAt(1)); |
| 705 } |
| 706 } |
| 707 } |
| 708 |
| 709 |
| 710 TEST(CMergeReduce_dead_rm2) { |
| 711 ControlReducerTester R; |
| 712 |
| 713 for (int i = 0; i < 3; i++) { |
| 714 Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead); |
| 715 merge->ReplaceInput(i, R.start); |
| 716 R.ReduceMerge(R.start, merge); |
| 717 } |
| 718 } |
| 719 |
| 720 |
| 721 TEST(CLoopReduce_dead_rm1) { |
| 722 ControlReducerTester R; |
| 723 |
| 724 for (int i = 0; i < 3; i++) { |
| 725 Node* loop = R.graph.NewNode(R.common.Loop(3), R.dead, R.start, R.start); |
| 726 R.ReduceMerge(loop, loop); |
| 727 CHECK_EQ(IrOpcode::kLoop, loop->opcode()); |
| 728 CHECK_EQ(2, OpParameter<int32_t>(loop->op())); |
| 729 CHECK_EQ(2, loop->InputCount()); |
| 730 CHECK_EQ(R.start, loop->InputAt(0)); |
| 731 CHECK_EQ(R.start, loop->InputAt(1)); |
| 732 } |
| 733 } |
| 734 |
| 735 |
| 736 TEST(CMergeReduce_edit_phi1) { |
| 737 ControlReducerTester R; |
| 738 |
| 739 for (int i = 0; i < 3; i++) { |
| 740 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 741 merge->ReplaceInput(i, R.dead); |
| 742 Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0], |
| 743 R.leaf[1], R.leaf[2], merge); |
| 744 R.ReduceMerge(merge, merge); |
| 745 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); |
| 746 CHECK_EQ(2, phi->op()->InputCount()); |
| 747 CHECK_EQ(3, phi->InputCount()); |
| 748 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); |
| 749 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); |
| 750 CHECK_EQ(merge, phi->InputAt(2)); |
| 751 } |
| 752 } |
| 753 |
| 754 |
| 755 TEST(CMergeReduce_edit_effect_phi1) { |
| 756 ControlReducerTester R; |
| 757 |
| 758 for (int i = 0; i < 3; i++) { |
| 759 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 760 merge->ReplaceInput(i, R.dead); |
| 761 Node* phi = R.graph.NewNode(R.common.EffectPhi(3), R.leaf[0], R.leaf[1], |
| 762 R.leaf[2], merge); |
| 763 R.ReduceMerge(merge, merge); |
| 764 CHECK_EQ(IrOpcode::kEffectPhi, phi->opcode()); |
| 765 CHECK_EQ(0, phi->op()->InputCount()); |
| 766 CHECK_EQ(2, OperatorProperties::GetEffectInputCount(phi->op())); |
| 767 CHECK_EQ(3, phi->InputCount()); |
| 768 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); |
| 769 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); |
| 770 CHECK_EQ(merge, phi->InputAt(2)); |
| 771 } |
| 772 } |
| 773 |
| 774 |
| 775 TEST(CMergeReduce_exhaustive_4) { |
| 776 ControlReducerTester R; |
| 777 Node* control[] = { |
| 778 R.graph.NewNode(R.common.Start(1)), R.graph.NewNode(R.common.Start(2)), |
| 779 R.graph.NewNode(R.common.Start(3)), R.graph.NewNode(R.common.Start(4))}; |
| 780 Node* values[] = {R.jsgraph.Int32Constant(11), R.jsgraph.Int32Constant(22), |
| 781 R.jsgraph.Int32Constant(33), R.jsgraph.Int32Constant(44)}; |
| 782 Node* effects[] = { |
| 783 R.graph.NewNode(R.common.Start(5)), R.graph.NewNode(R.common.Start(6)), |
| 784 R.graph.NewNode(R.common.Start(7)), R.graph.NewNode(R.common.Start(8))}; |
| 785 |
| 786 for (int p = 0; p < 16; p++) { |
| 787 int a = p & 1, b = p & 2, c = p & 4, d = p & 8; |
| 788 Node* merge = R.graph.NewNode(R.common.Merge(4), control[0], control[1], |
| 789 control[2], control[3]); |
| 790 |
| 791 if (!a) merge->ReplaceInput(0, R.dead); |
| 792 if (!b) merge->ReplaceInput(1, R.dead); |
| 793 if (!c) merge->ReplaceInput(2, R.dead); |
| 794 if (!d) merge->ReplaceInput(3, R.dead); |
| 795 Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 4), values[0], |
| 796 values[1], values[2], values[3], merge); |
| 797 Node* effect = R.graph.NewNode(R.common.EffectPhi(4), effects[0], |
| 798 effects[1], effects[2], effects[3], merge); |
| 799 |
| 800 int count = v8::base::bits::CountPopulation32(p); |
| 801 if (count == 0) { |
| 802 // result should be dead. |
| 803 Node* r = |
| 804 ControlReducer::ReduceMergeForTesting(&R.jsgraph, &R.common, merge); |
| 805 CHECK_EQ(IrOpcode::kDead, r->opcode()); |
| 806 } else if (count == 1) { |
| 807 // result should be one of the controls. |
| 808 Node* expect = control[WhichPowerOf2(p)]; |
| 809 R.ReduceMerge(expect, merge); |
| 810 } else { |
| 811 // merge should be edited. |
| 812 R.ReduceMerge(merge, merge); |
| 813 CHECK_EQ(count, merge->InputCount()); |
| 814 CHECK_EQ(count, OperatorProperties::GetControlInputCount(merge->op())); |
| 815 |
| 816 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); |
| 817 CHECK_EQ(count, phi->op()->InputCount()); |
| 818 CHECK_EQ(count + 1, phi->InputCount()); |
| 819 |
| 820 CHECK_EQ(IrOpcode::kEffectPhi, effect->opcode()); |
| 821 CHECK_EQ(0, effect->op()->InputCount()); |
| 822 CHECK_EQ(count, OperatorProperties::GetEffectInputCount(effect->op())); |
| 823 CHECK_EQ(count + 1, effect->InputCount()); |
| 824 } |
| 825 } |
| 826 } |
| 827 |
| 828 |
| 829 TEST(CMergeReduce_edit_many_phis1) { |
| 830 ControlReducerTester R; |
| 831 |
| 832 const int kPhiCount = 10; |
| 833 Node* phis[kPhiCount]; |
| 834 |
| 835 for (int i = 0; i < 3; i++) { |
| 836 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 837 merge->ReplaceInput(i, R.dead); |
| 838 for (int j = 0; j < kPhiCount; j++) { |
| 839 phis[j] = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0], |
| 840 R.leaf[1], R.leaf[2], merge); |
| 841 } |
| 842 R.ReduceMerge(merge, merge); |
| 843 for (int j = 0; j < kPhiCount; j++) { |
| 844 Node* phi = phis[j]; |
| 845 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); |
| 846 CHECK_EQ(2, phi->op()->InputCount()); |
| 847 CHECK_EQ(3, phi->InputCount()); |
| 848 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); |
| 849 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); |
| 850 CHECK_EQ(merge, phi->InputAt(2)); |
| 851 } |
| 852 } |
| 853 } |
| 854 |
| 855 |
| 856 TEST(CMergeReduce_simple_chain1) { |
| 857 ControlReducerTester R; |
| 858 for (int i = 0; i < 5; i++) { |
| 859 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); |
| 860 for (int j = 0; j < i; j++) { |
| 861 merge = R.graph.NewNode(R.common.Merge(1), merge); |
| 862 } |
| 863 R.ReduceMergeIterative(R.start, merge); |
| 864 } |
| 865 } |
| 866 |
| 867 |
| 868 TEST(CMergeReduce_dead_chain1) { |
| 869 ControlReducerTester R; |
| 870 for (int i = 0; i < 5; i++) { |
| 871 Node* merge = R.graph.NewNode(R.common.Merge(1), R.dead); |
| 872 for (int j = 0; j < i; j++) { |
| 873 merge = R.graph.NewNode(R.common.Merge(1), merge); |
| 874 } |
| 875 // TODO(titzer): the NULL is because end gets killed. Check for dead |
| 876 // properly. |
| 877 R.ReduceMergeIterative(NULL, merge); |
| 878 } |
| 879 } |
| 880 |
| 881 |
| 882 TEST(CMergeReduce_dead_chain2) { |
| 883 ControlReducerTester R; |
| 884 for (int i = 0; i < 5; i++) { |
| 885 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); |
| 886 for (int j = 0; j < i; j++) { |
| 887 merge = R.graph.NewNode(R.common.Merge(2), merge, R.dead); |
| 888 } |
| 889 R.ReduceMergeIterative(R.start, merge); |
| 890 } |
| 891 } |
| 892 |
| 893 |
| 894 struct Diamond { |
| 895 Node* branch; |
| 896 Node* if_true; |
| 897 Node* if_false; |
| 898 Node* merge; |
| 899 Node* phi; |
| 900 |
| 901 Diamond(ControlReducerTester& R, Node* cond) { |
| 902 branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
| 903 if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 904 if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
| 905 merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
| 906 phi = NULL; |
| 907 } |
| 908 |
| 909 Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) { |
| 910 branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
| 911 if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 912 if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
| 913 merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
| 914 phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge); |
| 915 } |
| 916 |
| 917 void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); } |
| 918 |
| 919 void nest(Diamond& that, bool if_true) { |
| 920 if (if_true) { |
| 921 branch->ReplaceInput(1, that.if_true); |
| 922 that.merge->ReplaceInput(0, merge); |
| 923 } else { |
| 924 branch->ReplaceInput(1, that.if_false); |
| 925 that.merge->ReplaceInput(1, merge); |
| 926 } |
| 927 } |
| 928 }; |
| 929 |
| 930 |
| 931 struct While { |
| 932 Node* branch; |
| 933 Node* if_true; |
| 934 Node* exit; |
| 935 Node* loop; |
| 936 |
| 937 While(ControlReducerTester& R, Node* cond) { |
| 938 loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); |
| 939 branch = R.graph.NewNode(R.common.Branch(), cond, loop); |
| 940 if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 941 exit = R.graph.NewNode(R.common.IfFalse(), branch); |
| 942 loop->ReplaceInput(1, if_true); |
| 943 } |
| 944 |
| 945 void chain(Node* control) { loop->ReplaceInput(0, control); } |
| 946 }; |
| 947 |
| 948 |
| 949 TEST(CBranchReduce_none1) { |
| 950 ControlReducerTester R; |
| 951 Diamond d(R, R.p0); |
| 952 R.ReduceBranch(d.branch, d.branch); |
| 953 } |
| 954 |
| 955 |
| 956 TEST(CBranchReduce_none2) { |
| 957 ControlReducerTester R; |
| 958 Diamond d1(R, R.p0); |
| 959 Diamond d2(R, R.p0); |
| 960 d2.chain(d1); |
| 961 R.ReduceBranch(d2.branch, d2.branch); |
| 962 } |
| 963 |
| 964 |
| 965 TEST(CBranchReduce_true) { |
| 966 ControlReducerTester R; |
| 967 Node* true_values[] = { |
| 968 R.one, R.jsgraph.Int32Constant(2), |
| 969 R.jsgraph.Int32Constant(0x7fffffff), R.jsgraph.Constant(1.0), |
| 970 R.jsgraph.Constant(22.1), R.jsgraph.TrueConstant()}; |
| 971 |
| 972 for (size_t i = 0; i < arraysize(true_values); i++) { |
| 973 Diamond d(R, true_values[i]); |
| 974 Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true); |
| 975 Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false); |
| 976 R.ReduceBranch(R.start, d.branch); |
| 977 CHECK_EQ(R.start, true_use->InputAt(0)); |
| 978 CHECK_EQ(IrOpcode::kDead, false_use->InputAt(0)->opcode()); |
| 979 CHECK(d.if_true->IsDead()); // replaced |
| 980 CHECK(d.if_false->IsDead()); // replaced |
| 981 } |
| 982 } |
| 983 |
| 984 |
| 985 TEST(CBranchReduce_false) { |
| 986 ControlReducerTester R; |
| 987 Node* false_values[] = {R.zero, R.jsgraph.Constant(0.0), |
| 988 R.jsgraph.Constant(-0.0), R.jsgraph.FalseConstant()}; |
| 989 |
| 990 for (size_t i = 0; i < arraysize(false_values); i++) { |
| 991 Diamond d(R, false_values[i]); |
| 992 Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true); |
| 993 Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false); |
| 994 R.ReduceBranch(R.start, d.branch); |
| 995 CHECK_EQ(R.start, false_use->InputAt(0)); |
| 996 CHECK_EQ(IrOpcode::kDead, true_use->InputAt(0)->opcode()); |
| 997 CHECK(d.if_true->IsDead()); // replaced |
| 998 CHECK(d.if_false->IsDead()); // replaced |
| 999 } |
| 1000 } |
| 1001 |
| 1002 |
| 1003 TEST(CDiamondReduce_true) { |
| 1004 ControlReducerTester R; |
| 1005 Diamond d1(R, R.one); |
| 1006 R.ReduceMergeIterative(R.start, d1.merge); |
| 1007 } |
| 1008 |
| 1009 |
| 1010 TEST(CDiamondReduce_false) { |
| 1011 ControlReducerTester R; |
| 1012 Diamond d2(R, R.zero); |
| 1013 R.ReduceMergeIterative(R.start, d2.merge); |
| 1014 } |
| 1015 |
| 1016 |
| 1017 TEST(CChainedDiamondsReduce_true_false) { |
| 1018 ControlReducerTester R; |
| 1019 Diamond d1(R, R.one); |
| 1020 Diamond d2(R, R.zero); |
| 1021 d2.chain(d1); |
| 1022 |
| 1023 R.ReduceMergeIterative(R.start, d2.merge); |
| 1024 } |
| 1025 |
| 1026 |
| 1027 TEST(CChainedDiamondsReduce_x_false) { |
| 1028 ControlReducerTester R; |
| 1029 Diamond d1(R, R.p0); |
| 1030 Diamond d2(R, R.zero); |
| 1031 d2.chain(d1); |
| 1032 |
| 1033 R.ReduceMergeIterative(d1.merge, d2.merge); |
| 1034 } |
| 1035 |
| 1036 |
| 1037 TEST(CChainedDiamondsReduce_false_x) { |
| 1038 ControlReducerTester R; |
| 1039 Diamond d1(R, R.zero); |
| 1040 Diamond d2(R, R.p0); |
| 1041 d2.chain(d1); |
| 1042 |
| 1043 R.ReduceMergeIterative(d2.merge, d2.merge); |
| 1044 CHECK_EQ(R.start, d2.branch->InputAt(1)); |
| 1045 } |
| 1046 |
| 1047 |
| 1048 TEST(CChainedDiamondsReduce_phi1) { |
| 1049 ControlReducerTester R; |
| 1050 Diamond d1(R, R.zero, R.one, R.zero); // foldable branch, phi. |
| 1051 Diamond d2(R, d1.phi); |
| 1052 d2.chain(d1); |
| 1053 |
| 1054 R.ReduceMergeIterative(R.start, d2.merge); |
| 1055 } |
| 1056 |
| 1057 |
| 1058 TEST(CChainedDiamondsReduce_phi2) { |
| 1059 ControlReducerTester R; |
| 1060 Diamond d1(R, R.p0, R.one, R.one); // redundant phi. |
| 1061 Diamond d2(R, d1.phi); |
| 1062 d2.chain(d1); |
| 1063 |
| 1064 R.ReduceMergeIterative(d1.merge, d2.merge); |
| 1065 } |
| 1066 |
| 1067 |
| 1068 TEST(CNestedDiamondsReduce_true_true_false) { |
| 1069 ControlReducerTester R; |
| 1070 Diamond d1(R, R.one); |
| 1071 Diamond d2(R, R.zero); |
| 1072 d2.nest(d1, true); |
| 1073 |
| 1074 R.ReduceMergeIterative(R.start, d1.merge); |
| 1075 } |
| 1076 |
| 1077 |
| 1078 TEST(CNestedDiamondsReduce_false_true_false) { |
| 1079 ControlReducerTester R; |
| 1080 Diamond d1(R, R.one); |
| 1081 Diamond d2(R, R.zero); |
| 1082 d2.nest(d1, false); |
| 1083 |
| 1084 R.ReduceMergeIterative(R.start, d1.merge); |
| 1085 } |
| 1086 |
| 1087 |
| 1088 TEST(CNestedDiamonds_xyz) { |
| 1089 ControlReducerTester R; |
| 1090 |
| 1091 for (int a = 0; a < 2; a++) { |
| 1092 for (int b = 0; b < 2; b++) { |
| 1093 for (int c = 0; c < 2; c++) { |
| 1094 Diamond d1(R, R.jsgraph.Int32Constant(a)); |
| 1095 Diamond d2(R, R.jsgraph.Int32Constant(b)); |
| 1096 d2.nest(d1, c); |
| 1097 |
| 1098 R.ReduceMergeIterative(R.start, d1.merge); |
| 1099 } |
| 1100 } |
| 1101 } |
| 1102 } |
| 1103 |
| 1104 |
| 1105 TEST(CDeadLoop1) { |
| 1106 ControlReducerTester R; |
| 1107 |
| 1108 Node* loop = R.graph.NewNode(R.common.Loop(1), R.start); |
| 1109 Node* branch = R.graph.NewNode(R.common.Branch(), R.p0, loop); |
| 1110 Node* if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 1111 Node* if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
| 1112 loop->ReplaceInput(0, if_true); // loop is not connected to start (i.e. dead) |
| 1113 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, if_false); |
| 1114 R.ReduceMergeIterative(R.start, merge); |
| 1115 CHECK_EQ(NULL, if_true->InputAt(0)); |
| 1116 CHECK_EQ(NULL, if_false->InputAt(0)); |
| 1117 } |
| 1118 |
| 1119 |
| 1120 TEST(CDeadLoop2) { |
| 1121 ControlReducerTester R; |
| 1122 |
| 1123 While w(R, R.p0); |
| 1124 Diamond d(R, R.zero); |
| 1125 // if (0) { while (p0) ; } else { } |
| 1126 w.branch->ReplaceInput(1, d.if_true); |
| 1127 d.merge->ReplaceInput(0, w.exit); |
| 1128 |
| 1129 R.ReduceMergeIterative(R.start, d.merge); |
| 1130 CHECK_EQ(NULL, d.if_true->InputAt(0)); |
| 1131 CHECK_EQ(NULL, d.if_false->InputAt(0)); |
| 1132 } |
| 1133 |
| 1134 |
| 1135 TEST(CNonTermLoop1) { |
| 1136 ControlReducerTester R; |
| 1137 Node* loop = |
| 1138 R.SetSelfReferences(R.graph.NewNode(R.common.Loop(1), R.start, R.self)); |
| 1139 ControlReducer::ReduceGraph(R.graph.zone(), &R.jsgraph, &R.common); |
| 1140 Node* end = R.graph.end(); |
| 1141 CHECK_EQ(R.start, loop->InputAt(0)); |
| 1142 CHECK_EQ(loop, loop->InputAt(1)); |
| 1143 Node* merge = end->InputAt(0); |
| 1144 CHECK_EQ(IrOpcode::kMerge, merge->opcode()); |
| 1145 CHECK_EQ(2, merge->InputCount()); |
| 1146 CHECK_EQ(2, OperatorProperties::GetControlInputCount(merge->op())); |
| 1147 CHECK_EQ(R.start, merge->InputAt(0)); |
| 1148 CHECK_EQ(loop, merge->InputAt(1)); |
| 1149 } |
| 1150 |
| 1151 |
| 1152 TEST(CNonTermLoop2) {} |
OLD | NEW |