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 // TODO(titzer): convert this whole file into unit tests. |
| 21 |
| 22 static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL, |
| 23 Node* i2 = NULL) { |
| 24 int count = 3; |
| 25 if (i2 == NULL) count = 2; |
| 26 if (i1 == NULL) count = 1; |
| 27 if (i0 == NULL) count = 0; |
| 28 CHECK_EQ(count, node->InputCount()); |
| 29 if (i0 != NULL) CHECK_EQ(i0, node->InputAt(0)); |
| 30 if (i1 != NULL) CHECK_EQ(i1, node->InputAt(1)); |
| 31 if (i2 != NULL) CHECK_EQ(i2, node->InputAt(2)); |
| 32 return count; |
| 33 } |
| 34 |
| 35 |
| 36 static int CheckMerge(Node* node, Node* i0 = NULL, Node* i1 = NULL, |
| 37 Node* i2 = NULL) { |
| 38 CHECK_EQ(IrOpcode::kMerge, node->opcode()); |
| 39 int count = CheckInputs(node, i0, i1, i2); |
| 40 CHECK_EQ(count, OperatorProperties::GetControlInputCount(node->op())); |
| 41 return count; |
| 42 } |
| 43 |
| 44 |
| 45 static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL, |
| 46 Node* i2 = NULL) { |
| 47 CHECK_EQ(IrOpcode::kLoop, node->opcode()); |
| 48 int count = CheckInputs(node, i0, i1, i2); |
| 49 CHECK_EQ(count, OperatorProperties::GetControlInputCount(node->op())); |
| 50 return count; |
| 51 } |
| 52 |
| 53 |
| 54 bool IsUsedBy(Node* a, Node* b) { |
| 55 for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) { |
| 56 if (b == *i) return true; |
| 57 } |
| 58 return false; |
| 59 } |
| 60 |
| 61 |
| 62 // A helper for all tests dealing with ControlTester. |
| 63 class ControlReducerTester : HandleAndZoneScope { |
17 public: | 64 public: |
18 CTrimTester() | 65 ControlReducerTester() |
19 : isolate(main_isolate()), | 66 : isolate(main_isolate()), |
20 common(main_zone()), | 67 common(main_zone()), |
21 graph(main_zone()), | 68 graph(main_zone()), |
22 jsgraph(&graph, &common, NULL, NULL), | 69 jsgraph(&graph, &common, NULL, NULL), |
23 start(graph.NewNode(common.Start(1))), | 70 start(graph.NewNode(common.Start(1))), |
| 71 end(graph.NewNode(common.End(), start)), |
24 p0(graph.NewNode(common.Parameter(0), start)), | 72 p0(graph.NewNode(common.Parameter(0), start)), |
| 73 zero(jsgraph.Int32Constant(0)), |
25 one(jsgraph.OneConstant()), | 74 one(jsgraph.OneConstant()), |
26 half(jsgraph.Constant(0.5)) { | 75 half(jsgraph.Constant(0.5)), |
27 graph.SetEnd(start); | 76 self(graph.NewNode(common.Int32Constant(0xaabbccdd))), |
| 77 dead(graph.NewNode(common.Dead())) { |
| 78 graph.SetEnd(end); |
28 graph.SetStart(start); | 79 graph.SetStart(start); |
| 80 leaf[0] = zero; |
| 81 leaf[1] = one; |
| 82 leaf[2] = half; |
| 83 leaf[3] = p0; |
29 } | 84 } |
30 | 85 |
31 Isolate* isolate; | 86 Isolate* isolate; |
32 CommonOperatorBuilder common; | 87 CommonOperatorBuilder common; |
33 Graph graph; | 88 Graph graph; |
34 JSGraph jsgraph; | 89 JSGraph jsgraph; |
35 Node* start; | 90 Node* start; |
| 91 Node* end; |
36 Node* p0; | 92 Node* p0; |
| 93 Node* zero; |
37 Node* one; | 94 Node* one; |
38 Node* half; | 95 Node* half; |
| 96 Node* self; |
| 97 Node* dead; |
| 98 Node* leaf[kNumLeafs]; |
| 99 |
| 100 Node* Phi(Node* a) { |
| 101 return SetSelfReferences(graph.NewNode(op(1, false), a, start)); |
| 102 } |
| 103 |
| 104 Node* Phi(Node* a, Node* b) { |
| 105 return SetSelfReferences(graph.NewNode(op(2, false), a, b, start)); |
| 106 } |
| 107 |
| 108 Node* Phi(Node* a, Node* b, Node* c) { |
| 109 return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start)); |
| 110 } |
| 111 |
| 112 Node* Phi(Node* a, Node* b, Node* c, Node* d) { |
| 113 return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start)); |
| 114 } |
| 115 |
| 116 Node* EffectPhi(Node* a) { |
| 117 return SetSelfReferences(graph.NewNode(op(1, true), a, start)); |
| 118 } |
| 119 |
| 120 Node* EffectPhi(Node* a, Node* b) { |
| 121 return SetSelfReferences(graph.NewNode(op(2, true), a, b, start)); |
| 122 } |
| 123 |
| 124 Node* EffectPhi(Node* a, Node* b, Node* c) { |
| 125 return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start)); |
| 126 } |
| 127 |
| 128 Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) { |
| 129 return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start)); |
| 130 } |
| 131 |
| 132 Node* SetSelfReferences(Node* node) { |
| 133 Node::Inputs inputs = node->inputs(); |
| 134 for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end(); |
| 135 ++iter) { |
| 136 Node* input = *iter; |
| 137 if (input == self) node->ReplaceInput(iter.index(), node); |
| 138 } |
| 139 return node; |
| 140 } |
| 141 |
| 142 const Operator* op(int count, bool effect) { |
| 143 return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count); |
| 144 } |
39 | 145 |
40 void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); } | 146 void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); } |
| 147 |
| 148 void ReduceGraph() { |
| 149 ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common); |
| 150 } |
| 151 |
| 152 // Checks one-step reduction of a phi. |
| 153 void ReducePhi(Node* expect, Node* phi) { |
| 154 Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi); |
| 155 CHECK_EQ(expect, result); |
| 156 ReducePhiIterative(expect, phi); // iterative should give the same result. |
| 157 } |
| 158 |
| 159 void ReducePhiIterative(Node* expect, Node* phi) { |
| 160 p0->ReplaceInput(0, start); // hack: parameters may be trimmed. |
| 161 Node* ret = graph.NewNode(common.Return(), phi, start, start); |
| 162 Node* end = graph.NewNode(common.End(), ret); |
| 163 graph.SetEnd(end); |
| 164 ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common); |
| 165 CheckInputs(end, ret); |
| 166 CheckInputs(ret, expect, start, start); |
| 167 } |
| 168 |
| 169 void ReduceMerge(Node* expect, Node* merge) { |
| 170 Node* result = |
| 171 ControlReducer::ReduceMergeForTesting(&jsgraph, &common, merge); |
| 172 CHECK_EQ(expect, result); |
| 173 } |
| 174 |
| 175 void ReduceMergeIterative(Node* expect, Node* merge) { |
| 176 p0->ReplaceInput(0, start); // hack: parameters may be trimmed. |
| 177 Node* end = graph.NewNode(common.End(), merge); |
| 178 graph.SetEnd(end); |
| 179 ReduceGraph(); |
| 180 CheckInputs(end, expect); |
| 181 } |
| 182 |
| 183 void ReduceBranch(Node* expect, Node* branch) { |
| 184 Node* result = |
| 185 ControlReducer::ReduceBranchForTesting(&jsgraph, &common, branch); |
| 186 CHECK_EQ(expect, result); |
| 187 } |
| 188 |
| 189 Node* Return(Node* val, Node* effect, Node* control) { |
| 190 Node* ret = graph.NewNode(common.Return(), val, effect, control); |
| 191 end->ReplaceInput(0, ret); |
| 192 return ret; |
| 193 } |
41 }; | 194 }; |
42 | 195 |
43 | 196 |
44 bool IsUsedBy(Node* a, Node* b) { | |
45 for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) { | |
46 if (b == *i) return true; | |
47 } | |
48 return false; | |
49 } | |
50 | |
51 | |
52 TEST(Trim1_live) { | 197 TEST(Trim1_live) { |
53 CTrimTester T; | 198 ControlReducerTester T; |
54 CHECK(IsUsedBy(T.start, T.p0)); | 199 CHECK(IsUsedBy(T.start, T.p0)); |
55 T.graph.SetEnd(T.p0); | 200 T.graph.SetEnd(T.p0); |
56 T.Trim(); | 201 T.Trim(); |
57 CHECK(IsUsedBy(T.start, T.p0)); | 202 CHECK(IsUsedBy(T.start, T.p0)); |
58 CHECK_EQ(T.start, T.p0->InputAt(0)); | 203 CheckInputs(T.p0, T.start); |
59 } | 204 } |
60 | 205 |
61 | 206 |
62 TEST(Trim1_dead) { | 207 TEST(Trim1_dead) { |
63 CTrimTester T; | 208 ControlReducerTester T; |
64 CHECK(IsUsedBy(T.start, T.p0)); | 209 CHECK(IsUsedBy(T.start, T.p0)); |
65 T.Trim(); | 210 T.Trim(); |
66 CHECK(!IsUsedBy(T.start, T.p0)); | 211 CHECK(!IsUsedBy(T.start, T.p0)); |
67 CHECK_EQ(NULL, T.p0->InputAt(0)); | 212 CHECK_EQ(NULL, T.p0->InputAt(0)); |
68 } | 213 } |
69 | 214 |
70 | 215 |
71 TEST(Trim2_live) { | 216 TEST(Trim2_live) { |
72 CTrimTester T; | 217 ControlReducerTester T; |
73 Node* phi = | 218 Node* phi = |
74 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); | 219 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); |
75 CHECK(IsUsedBy(T.one, phi)); | 220 CHECK(IsUsedBy(T.one, phi)); |
76 CHECK(IsUsedBy(T.half, phi)); | 221 CHECK(IsUsedBy(T.half, phi)); |
77 CHECK(IsUsedBy(T.start, phi)); | 222 CHECK(IsUsedBy(T.start, phi)); |
78 T.graph.SetEnd(phi); | 223 T.graph.SetEnd(phi); |
79 T.Trim(); | 224 T.Trim(); |
80 CHECK(IsUsedBy(T.one, phi)); | 225 CHECK(IsUsedBy(T.one, phi)); |
81 CHECK(IsUsedBy(T.half, phi)); | 226 CHECK(IsUsedBy(T.half, phi)); |
82 CHECK(IsUsedBy(T.start, phi)); | 227 CHECK(IsUsedBy(T.start, phi)); |
83 CHECK_EQ(T.one, phi->InputAt(0)); | 228 CheckInputs(phi, T.one, T.half, T.start); |
84 CHECK_EQ(T.half, phi->InputAt(1)); | |
85 CHECK_EQ(T.start, phi->InputAt(2)); | |
86 } | 229 } |
87 | 230 |
88 | 231 |
89 TEST(Trim2_dead) { | 232 TEST(Trim2_dead) { |
90 CTrimTester T; | 233 ControlReducerTester T; |
91 Node* phi = | 234 Node* phi = |
92 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); | 235 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start); |
93 CHECK(IsUsedBy(T.one, phi)); | 236 CHECK(IsUsedBy(T.one, phi)); |
94 CHECK(IsUsedBy(T.half, phi)); | 237 CHECK(IsUsedBy(T.half, phi)); |
95 CHECK(IsUsedBy(T.start, phi)); | 238 CHECK(IsUsedBy(T.start, phi)); |
96 T.Trim(); | 239 T.Trim(); |
97 CHECK(!IsUsedBy(T.one, phi)); | 240 CHECK(!IsUsedBy(T.one, phi)); |
98 CHECK(!IsUsedBy(T.half, phi)); | 241 CHECK(!IsUsedBy(T.half, phi)); |
99 CHECK(!IsUsedBy(T.start, phi)); | 242 CHECK(!IsUsedBy(T.start, phi)); |
100 CHECK_EQ(NULL, phi->InputAt(0)); | 243 CHECK_EQ(NULL, phi->InputAt(0)); |
101 CHECK_EQ(NULL, phi->InputAt(1)); | 244 CHECK_EQ(NULL, phi->InputAt(1)); |
102 CHECK_EQ(NULL, phi->InputAt(2)); | 245 CHECK_EQ(NULL, phi->InputAt(2)); |
103 } | 246 } |
104 | 247 |
105 | 248 |
106 TEST(Trim_chain1) { | 249 TEST(Trim_chain1) { |
107 CTrimTester T; | 250 ControlReducerTester T; |
108 const int kDepth = 15; | 251 const int kDepth = 15; |
109 Node* live[kDepth]; | 252 Node* live[kDepth]; |
110 Node* dead[kDepth]; | 253 Node* dead[kDepth]; |
111 Node* end = T.start; | 254 Node* end = T.start; |
112 for (int i = 0; i < kDepth; i++) { | 255 for (int i = 0; i < kDepth; i++) { |
113 live[i] = end = T.graph.NewNode(T.common.Merge(1), end); | 256 live[i] = end = T.graph.NewNode(T.common.Merge(1), end); |
114 dead[i] = T.graph.NewNode(T.common.Merge(1), end); | 257 dead[i] = T.graph.NewNode(T.common.Merge(1), end); |
115 } | 258 } |
116 // end -> live[last] -> live[last-1] -> ... -> start | 259 // end -> live[last] -> live[last-1] -> ... -> start |
117 // dead[last] ^ dead[last-1] ^ ... ^ | 260 // dead[last] ^ dead[last-1] ^ ... ^ |
118 T.graph.SetEnd(end); | 261 T.graph.SetEnd(end); |
119 T.Trim(); | 262 T.Trim(); |
120 for (int i = 0; i < kDepth; i++) { | 263 for (int i = 0; i < kDepth; i++) { |
121 CHECK(!IsUsedBy(live[i], dead[i])); | 264 CHECK(!IsUsedBy(live[i], dead[i])); |
122 CHECK_EQ(NULL, dead[i]->InputAt(0)); | 265 CHECK_EQ(NULL, dead[i]->InputAt(0)); |
123 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); | 266 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); |
124 } | 267 } |
125 } | 268 } |
126 | 269 |
127 | 270 |
128 TEST(Trim_chain2) { | 271 TEST(Trim_chain2) { |
129 CTrimTester T; | 272 ControlReducerTester T; |
130 const int kDepth = 15; | 273 const int kDepth = 15; |
131 Node* live[kDepth]; | 274 Node* live[kDepth]; |
132 Node* dead[kDepth]; | 275 Node* dead[kDepth]; |
133 Node* l = T.start; | 276 Node* l = T.start; |
134 Node* d = T.start; | 277 Node* d = T.start; |
135 for (int i = 0; i < kDepth; i++) { | 278 for (int i = 0; i < kDepth; i++) { |
136 live[i] = l = T.graph.NewNode(T.common.Merge(1), l); | 279 live[i] = l = T.graph.NewNode(T.common.Merge(1), l); |
137 dead[i] = d = T.graph.NewNode(T.common.Merge(1), d); | 280 dead[i] = d = T.graph.NewNode(T.common.Merge(1), d); |
138 } | 281 } |
139 // end -> live[last] -> live[last-1] -> ... -> start | 282 // end -> live[last] -> live[last-1] -> ... -> start |
140 // dead[last] -> dead[last-1] -> ... -> start | 283 // dead[last] -> dead[last-1] -> ... -> start |
141 T.graph.SetEnd(l); | 284 T.graph.SetEnd(l); |
142 T.Trim(); | 285 T.Trim(); |
143 CHECK(!IsUsedBy(T.start, dead[0])); | 286 CHECK(!IsUsedBy(T.start, dead[0])); |
144 for (int i = 0; i < kDepth; i++) { | 287 for (int i = 0; i < kDepth; i++) { |
145 CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0)); | 288 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)); | 289 CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0)); |
147 } | 290 } |
148 } | 291 } |
149 | 292 |
150 | 293 |
151 TEST(Trim_cycle1) { | 294 TEST(Trim_cycle1) { |
152 CTrimTester T; | 295 ControlReducerTester T; |
153 Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start); | 296 Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start); |
154 loop->ReplaceInput(1, loop); | 297 loop->ReplaceInput(1, loop); |
155 Node* end = T.graph.NewNode(T.common.End(), loop); | 298 Node* end = T.graph.NewNode(T.common.End(), loop); |
156 T.graph.SetEnd(end); | 299 T.graph.SetEnd(end); |
157 | 300 |
158 CHECK(IsUsedBy(T.start, loop)); | 301 CHECK(IsUsedBy(T.start, loop)); |
159 CHECK(IsUsedBy(loop, end)); | 302 CHECK(IsUsedBy(loop, end)); |
160 CHECK(IsUsedBy(loop, loop)); | 303 CHECK(IsUsedBy(loop, loop)); |
161 | 304 |
162 T.Trim(); | 305 T.Trim(); |
163 | 306 |
164 // nothing should have happened to the loop itself. | 307 // nothing should have happened to the loop itself. |
165 CHECK(IsUsedBy(T.start, loop)); | 308 CHECK(IsUsedBy(T.start, loop)); |
166 CHECK(IsUsedBy(loop, end)); | 309 CHECK(IsUsedBy(loop, end)); |
167 CHECK(IsUsedBy(loop, loop)); | 310 CHECK(IsUsedBy(loop, loop)); |
168 CHECK_EQ(T.start, loop->InputAt(0)); | 311 CheckInputs(loop, T.start, loop); |
169 CHECK_EQ(loop, loop->InputAt(1)); | 312 CheckInputs(end, loop); |
170 CHECK_EQ(loop, end->InputAt(0)); | |
171 } | 313 } |
172 | 314 |
173 | 315 |
174 TEST(Trim_cycle2) { | 316 TEST(Trim_cycle2) { |
175 CTrimTester T; | 317 ControlReducerTester T; |
176 Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start); | 318 Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start); |
177 loop->ReplaceInput(1, loop); | 319 loop->ReplaceInput(1, loop); |
178 Node* end = T.graph.NewNode(T.common.End(), loop); | 320 Node* end = T.graph.NewNode(T.common.End(), loop); |
179 Node* phi = | 321 Node* phi = |
180 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop); | 322 T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop); |
181 T.graph.SetEnd(end); | 323 T.graph.SetEnd(end); |
182 | 324 |
183 CHECK(IsUsedBy(T.start, loop)); | 325 CHECK(IsUsedBy(T.start, loop)); |
184 CHECK(IsUsedBy(loop, end)); | 326 CHECK(IsUsedBy(loop, end)); |
185 CHECK(IsUsedBy(loop, loop)); | 327 CHECK(IsUsedBy(loop, loop)); |
186 CHECK(IsUsedBy(loop, phi)); | 328 CHECK(IsUsedBy(loop, phi)); |
187 CHECK(IsUsedBy(T.one, phi)); | 329 CHECK(IsUsedBy(T.one, phi)); |
188 CHECK(IsUsedBy(T.half, phi)); | 330 CHECK(IsUsedBy(T.half, phi)); |
189 | 331 |
190 T.Trim(); | 332 T.Trim(); |
191 | 333 |
192 // nothing should have happened to the loop itself. | 334 // nothing should have happened to the loop itself. |
193 CHECK(IsUsedBy(T.start, loop)); | 335 CHECK(IsUsedBy(T.start, loop)); |
194 CHECK(IsUsedBy(loop, end)); | 336 CHECK(IsUsedBy(loop, end)); |
195 CHECK(IsUsedBy(loop, loop)); | 337 CHECK(IsUsedBy(loop, loop)); |
196 CHECK_EQ(T.start, loop->InputAt(0)); | 338 CheckInputs(loop, T.start, loop); |
197 CHECK_EQ(loop, loop->InputAt(1)); | 339 CheckInputs(end, loop); |
198 CHECK_EQ(loop, end->InputAt(0)); | |
199 | 340 |
200 // phi should have been trimmed away. | 341 // phi should have been trimmed away. |
201 CHECK(!IsUsedBy(loop, phi)); | 342 CHECK(!IsUsedBy(loop, phi)); |
202 CHECK(!IsUsedBy(T.one, phi)); | 343 CHECK(!IsUsedBy(T.one, phi)); |
203 CHECK(!IsUsedBy(T.half, phi)); | 344 CHECK(!IsUsedBy(T.half, phi)); |
204 CHECK_EQ(NULL, phi->InputAt(0)); | 345 CHECK_EQ(NULL, phi->InputAt(0)); |
205 CHECK_EQ(NULL, phi->InputAt(1)); | 346 CHECK_EQ(NULL, phi->InputAt(1)); |
206 CHECK_EQ(NULL, phi->InputAt(2)); | 347 CHECK_EQ(NULL, phi->InputAt(2)); |
207 } | 348 } |
208 | 349 |
209 | 350 |
210 void CheckTrimConstant(CTrimTester* T, Node* k) { | 351 void CheckTrimConstant(ControlReducerTester* T, Node* k) { |
211 Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start); | 352 Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start); |
212 CHECK(IsUsedBy(k, phi)); | 353 CHECK(IsUsedBy(k, phi)); |
213 T->Trim(); | 354 T->Trim(); |
214 CHECK(!IsUsedBy(k, phi)); | 355 CHECK(!IsUsedBy(k, phi)); |
215 CHECK_EQ(NULL, phi->InputAt(0)); | 356 CHECK_EQ(NULL, phi->InputAt(0)); |
216 CHECK_EQ(NULL, phi->InputAt(1)); | 357 CHECK_EQ(NULL, phi->InputAt(1)); |
217 } | 358 } |
218 | 359 |
219 | 360 |
220 TEST(Trim_constants) { | 361 TEST(Trim_constants) { |
221 CTrimTester T; | 362 ControlReducerTester T; |
222 int32_t int32_constants[] = { | 363 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, | 364 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}; | 365 0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9}; |
225 | 366 |
226 for (size_t i = 0; i < arraysize(int32_constants); i++) { | 367 for (size_t i = 0; i < arraysize(int32_constants); i++) { |
227 CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i])); | 368 CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i])); |
228 CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i])); | 369 CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i])); |
229 CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i])); | 370 CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i])); |
230 } | 371 } |
231 | 372 |
232 Node* other_constants[] = { | 373 Node* other_constants[] = { |
233 T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(), | 374 T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(), |
234 T.jsgraph.TrueConstant(), T.jsgraph.FalseConstant(), | 375 T.jsgraph.TrueConstant(), T.jsgraph.FalseConstant(), |
235 T.jsgraph.NullConstant(), T.jsgraph.ZeroConstant(), | 376 T.jsgraph.NullConstant(), T.jsgraph.ZeroConstant(), |
236 T.jsgraph.OneConstant(), T.jsgraph.NaNConstant(), | 377 T.jsgraph.OneConstant(), T.jsgraph.NaNConstant(), |
237 T.jsgraph.Constant(21), T.jsgraph.Constant(22.2)}; | 378 T.jsgraph.Constant(21), T.jsgraph.Constant(22.2)}; |
238 | 379 |
239 for (size_t i = 0; i < arraysize(other_constants); i++) { | 380 for (size_t i = 0; i < arraysize(other_constants); i++) { |
240 CheckTrimConstant(&T, other_constants[i]); | 381 CheckTrimConstant(&T, other_constants[i]); |
241 } | 382 } |
242 } | 383 } |
| 384 |
| 385 |
| 386 TEST(CReducePhi1) { |
| 387 ControlReducerTester R; |
| 388 |
| 389 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0])); |
| 390 R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1])); |
| 391 R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2])); |
| 392 R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3])); |
| 393 } |
| 394 |
| 395 |
| 396 TEST(CReducePhi1_dead) { |
| 397 ControlReducerTester R; |
| 398 |
| 399 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead)); |
| 400 R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1], R.dead)); |
| 401 R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2], R.dead)); |
| 402 R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3], R.dead)); |
| 403 |
| 404 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0])); |
| 405 R.ReducePhi(R.leaf[1], R.Phi(R.dead, R.leaf[1])); |
| 406 R.ReducePhi(R.leaf[2], R.Phi(R.dead, R.leaf[2])); |
| 407 R.ReducePhi(R.leaf[3], R.Phi(R.dead, R.leaf[3])); |
| 408 } |
| 409 |
| 410 |
| 411 TEST(CReducePhi1_dead2) { |
| 412 ControlReducerTester R; |
| 413 |
| 414 R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead, R.dead)); |
| 415 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0], R.dead)); |
| 416 R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.dead, R.leaf[0])); |
| 417 } |
| 418 |
| 419 |
| 420 TEST(CReducePhi2a) { |
| 421 ControlReducerTester R; |
| 422 |
| 423 for (size_t i = 0; i < kNumLeafs; i++) { |
| 424 Node* a = R.leaf[i]; |
| 425 R.ReducePhi(a, R.Phi(a, a)); |
| 426 } |
| 427 } |
| 428 |
| 429 |
| 430 TEST(CReducePhi2b) { |
| 431 ControlReducerTester R; |
| 432 |
| 433 for (size_t i = 0; i < kNumLeafs; i++) { |
| 434 Node* a = R.leaf[i]; |
| 435 R.ReducePhi(a, R.Phi(R.self, a)); |
| 436 R.ReducePhi(a, R.Phi(a, R.self)); |
| 437 } |
| 438 } |
| 439 |
| 440 |
| 441 TEST(CReducePhi2c) { |
| 442 ControlReducerTester R; |
| 443 |
| 444 for (size_t i = 1; i < kNumLeafs; i++) { |
| 445 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 446 Node* phi1 = R.Phi(b, a); |
| 447 R.ReducePhi(phi1, phi1); |
| 448 |
| 449 Node* phi2 = R.Phi(a, b); |
| 450 R.ReducePhi(phi2, phi2); |
| 451 } |
| 452 } |
| 453 |
| 454 |
| 455 TEST(CReducePhi2_dead) { |
| 456 ControlReducerTester R; |
| 457 |
| 458 for (size_t i = 0; i < kNumLeafs; i++) { |
| 459 Node* a = R.leaf[i]; |
| 460 R.ReducePhi(a, R.Phi(a, a, R.dead)); |
| 461 R.ReducePhi(a, R.Phi(a, R.dead, a)); |
| 462 R.ReducePhi(a, R.Phi(R.dead, a, a)); |
| 463 } |
| 464 |
| 465 for (size_t i = 0; i < kNumLeafs; i++) { |
| 466 Node* a = R.leaf[i]; |
| 467 R.ReducePhi(a, R.Phi(R.self, a)); |
| 468 R.ReducePhi(a, R.Phi(a, R.self)); |
| 469 R.ReducePhi(a, R.Phi(R.self, a, R.dead)); |
| 470 R.ReducePhi(a, R.Phi(a, R.self, R.dead)); |
| 471 } |
| 472 |
| 473 for (size_t i = 1; i < kNumLeafs; i++) { |
| 474 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 475 Node* phi1 = R.Phi(b, a, R.dead); |
| 476 R.ReducePhi(phi1, phi1); |
| 477 |
| 478 Node* phi2 = R.Phi(a, b, R.dead); |
| 479 R.ReducePhi(phi2, phi2); |
| 480 } |
| 481 } |
| 482 |
| 483 |
| 484 TEST(CReducePhi3) { |
| 485 ControlReducerTester R; |
| 486 |
| 487 for (size_t i = 0; i < kNumLeafs; i++) { |
| 488 Node* a = R.leaf[i]; |
| 489 R.ReducePhi(a, R.Phi(a, a, a)); |
| 490 } |
| 491 |
| 492 for (size_t i = 0; i < kNumLeafs; i++) { |
| 493 Node* a = R.leaf[i]; |
| 494 R.ReducePhi(a, R.Phi(R.self, a, a)); |
| 495 R.ReducePhi(a, R.Phi(a, R.self, a)); |
| 496 R.ReducePhi(a, R.Phi(a, a, R.self)); |
| 497 } |
| 498 |
| 499 for (size_t i = 1; i < kNumLeafs; i++) { |
| 500 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 501 Node* phi1 = R.Phi(b, a, a); |
| 502 R.ReducePhi(phi1, phi1); |
| 503 |
| 504 Node* phi2 = R.Phi(a, b, a); |
| 505 R.ReducePhi(phi2, phi2); |
| 506 |
| 507 Node* phi3 = R.Phi(a, a, b); |
| 508 R.ReducePhi(phi3, phi3); |
| 509 } |
| 510 } |
| 511 |
| 512 |
| 513 TEST(CReducePhi4) { |
| 514 ControlReducerTester R; |
| 515 |
| 516 for (size_t i = 0; i < kNumLeafs; i++) { |
| 517 Node* a = R.leaf[i]; |
| 518 R.ReducePhi(a, R.Phi(a, a, a, a)); |
| 519 } |
| 520 |
| 521 for (size_t i = 0; i < kNumLeafs; i++) { |
| 522 Node* a = R.leaf[i]; |
| 523 R.ReducePhi(a, R.Phi(R.self, a, a, a)); |
| 524 R.ReducePhi(a, R.Phi(a, R.self, a, a)); |
| 525 R.ReducePhi(a, R.Phi(a, a, R.self, a)); |
| 526 R.ReducePhi(a, R.Phi(a, a, a, R.self)); |
| 527 |
| 528 R.ReducePhi(a, R.Phi(R.self, R.self, a, a)); |
| 529 R.ReducePhi(a, R.Phi(a, R.self, R.self, a)); |
| 530 R.ReducePhi(a, R.Phi(a, a, R.self, R.self)); |
| 531 R.ReducePhi(a, R.Phi(R.self, a, a, R.self)); |
| 532 } |
| 533 |
| 534 for (size_t i = 1; i < kNumLeafs; i++) { |
| 535 Node* a = R.leaf[i], *b = R.leaf[0]; |
| 536 Node* phi1 = R.Phi(b, a, a, a); |
| 537 R.ReducePhi(phi1, phi1); |
| 538 |
| 539 Node* phi2 = R.Phi(a, b, a, a); |
| 540 R.ReducePhi(phi2, phi2); |
| 541 |
| 542 Node* phi3 = R.Phi(a, a, b, a); |
| 543 R.ReducePhi(phi3, phi3); |
| 544 |
| 545 Node* phi4 = R.Phi(a, a, a, b); |
| 546 R.ReducePhi(phi4, phi4); |
| 547 } |
| 548 } |
| 549 |
| 550 |
| 551 TEST(CReducePhi_iterative1) { |
| 552 ControlReducerTester R; |
| 553 |
| 554 R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0]))); |
| 555 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.leaf[0])); |
| 556 } |
| 557 |
| 558 |
| 559 TEST(CReducePhi_iterative2) { |
| 560 ControlReducerTester R; |
| 561 |
| 562 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.Phi(R.leaf[0]))); |
| 563 } |
| 564 |
| 565 |
| 566 TEST(CReducePhi_iterative3) { |
| 567 ControlReducerTester R; |
| 568 |
| 569 R.ReducePhiIterative(R.leaf[0], |
| 570 R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.leaf[0]))); |
| 571 R.ReducePhiIterative(R.leaf[0], |
| 572 R.Phi(R.Phi(R.leaf[0], R.leaf[0]), R.leaf[0])); |
| 573 } |
| 574 |
| 575 |
| 576 TEST(CReducePhi_iterative4) { |
| 577 ControlReducerTester R; |
| 578 |
| 579 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.leaf[0]), |
| 580 R.Phi(R.leaf[0], R.leaf[0]))); |
| 581 |
| 582 Node* p1 = R.Phi(R.leaf[0], R.leaf[0]); |
| 583 R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1)); |
| 584 |
| 585 Node* p2 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]); |
| 586 R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2, p2)); |
| 587 |
| 588 Node* p3 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]); |
| 589 R.ReducePhiIterative(R.leaf[0], R.Phi(p3, p3, R.leaf[0])); |
| 590 } |
| 591 |
| 592 |
| 593 TEST(CReducePhi_iterative_self1) { |
| 594 ControlReducerTester R; |
| 595 |
| 596 R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.self))); |
| 597 R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.leaf[0])); |
| 598 } |
| 599 |
| 600 |
| 601 TEST(CReducePhi_iterative_self2) { |
| 602 ControlReducerTester R; |
| 603 |
| 604 R.ReducePhiIterative( |
| 605 R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.Phi(R.leaf[0], R.self))); |
| 606 R.ReducePhiIterative( |
| 607 R.leaf[0], R.Phi(R.Phi(R.self, R.leaf[0]), R.Phi(R.self, R.leaf[0]))); |
| 608 |
| 609 Node* p1 = R.Phi(R.leaf[0], R.self); |
| 610 R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1)); |
| 611 |
| 612 Node* p2 = R.Phi(R.self, R.leaf[0]); |
| 613 R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2)); |
| 614 } |
| 615 |
| 616 |
| 617 TEST(EReducePhi1) { |
| 618 ControlReducerTester R; |
| 619 |
| 620 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0])); |
| 621 R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1])); |
| 622 R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2])); |
| 623 R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3])); |
| 624 } |
| 625 |
| 626 |
| 627 TEST(EReducePhi1_dead) { |
| 628 ControlReducerTester R; |
| 629 |
| 630 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead)); |
| 631 R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1], R.dead)); |
| 632 R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2], R.dead)); |
| 633 R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3], R.dead)); |
| 634 |
| 635 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0])); |
| 636 R.ReducePhi(R.leaf[1], R.EffectPhi(R.dead, R.leaf[1])); |
| 637 R.ReducePhi(R.leaf[2], R.EffectPhi(R.dead, R.leaf[2])); |
| 638 R.ReducePhi(R.leaf[3], R.EffectPhi(R.dead, R.leaf[3])); |
| 639 } |
| 640 |
| 641 |
| 642 TEST(EReducePhi1_dead2) { |
| 643 ControlReducerTester R; |
| 644 |
| 645 R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead, R.dead)); |
| 646 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0], R.dead)); |
| 647 R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.dead, R.leaf[0])); |
| 648 } |
| 649 |
| 650 |
| 651 TEST(CMergeReduce_simple1) { |
| 652 ControlReducerTester R; |
| 653 |
| 654 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); |
| 655 R.ReduceMerge(R.start, merge); |
| 656 } |
| 657 |
| 658 |
| 659 TEST(CMergeReduce_simple2) { |
| 660 ControlReducerTester R; |
| 661 |
| 662 Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start); |
| 663 Node* merge2 = R.graph.NewNode(R.common.Merge(1), merge1); |
| 664 R.ReduceMerge(merge1, merge2); |
| 665 R.ReduceMergeIterative(R.start, merge2); |
| 666 } |
| 667 |
| 668 |
| 669 TEST(CMergeReduce_none1) { |
| 670 ControlReducerTester R; |
| 671 |
| 672 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.start); |
| 673 R.ReduceMerge(merge, merge); |
| 674 } |
| 675 |
| 676 |
| 677 TEST(CMergeReduce_none2) { |
| 678 ControlReducerTester R; |
| 679 |
| 680 Node* t = R.graph.NewNode(R.common.IfTrue(), R.start); |
| 681 Node* f = R.graph.NewNode(R.common.IfFalse(), R.start); |
| 682 Node* merge = R.graph.NewNode(R.common.Merge(2), t, f); |
| 683 R.ReduceMerge(merge, merge); |
| 684 } |
| 685 |
| 686 |
| 687 TEST(CMergeReduce_self3) { |
| 688 ControlReducerTester R; |
| 689 |
| 690 Node* merge = |
| 691 R.SetSelfReferences(R.graph.NewNode(R.common.Merge(2), R.start, R.self)); |
| 692 R.ReduceMerge(merge, merge); |
| 693 } |
| 694 |
| 695 |
| 696 TEST(CMergeReduce_dead1) { |
| 697 ControlReducerTester R; |
| 698 |
| 699 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.dead); |
| 700 R.ReduceMerge(R.start, merge); |
| 701 } |
| 702 |
| 703 |
| 704 TEST(CMergeReduce_dead2) { |
| 705 ControlReducerTester R; |
| 706 |
| 707 Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start); |
| 708 Node* merge2 = R.graph.NewNode(R.common.Merge(2), merge1, R.dead); |
| 709 R.ReduceMerge(merge1, merge2); |
| 710 R.ReduceMergeIterative(R.start, merge2); |
| 711 } |
| 712 |
| 713 |
| 714 TEST(CMergeReduce_dead_rm1a) { |
| 715 ControlReducerTester R; |
| 716 |
| 717 for (int i = 0; i < 3; i++) { |
| 718 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 719 merge->ReplaceInput(i, R.dead); |
| 720 R.ReduceMerge(merge, merge); |
| 721 CheckMerge(merge, R.start, R.start); |
| 722 } |
| 723 } |
| 724 |
| 725 |
| 726 TEST(CMergeReduce_dead_rm1b) { |
| 727 ControlReducerTester R; |
| 728 |
| 729 Node* t = R.graph.NewNode(R.common.IfTrue(), R.start); |
| 730 Node* f = R.graph.NewNode(R.common.IfFalse(), R.start); |
| 731 for (int i = 0; i < 2; i++) { |
| 732 Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead); |
| 733 for (int j = i + 1; j < 3; j++) { |
| 734 merge->ReplaceInput(i, t); |
| 735 merge->ReplaceInput(j, f); |
| 736 R.ReduceMerge(merge, merge); |
| 737 CheckMerge(merge, t, f); |
| 738 } |
| 739 } |
| 740 } |
| 741 |
| 742 |
| 743 TEST(CMergeReduce_dead_rm2) { |
| 744 ControlReducerTester R; |
| 745 |
| 746 for (int i = 0; i < 3; i++) { |
| 747 Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead); |
| 748 merge->ReplaceInput(i, R.start); |
| 749 R.ReduceMerge(R.start, merge); |
| 750 } |
| 751 } |
| 752 |
| 753 |
| 754 TEST(CLoopReduce_dead_rm1) { |
| 755 ControlReducerTester R; |
| 756 |
| 757 for (int i = 0; i < 3; i++) { |
| 758 Node* loop = R.graph.NewNode(R.common.Loop(3), R.dead, R.start, R.start); |
| 759 R.ReduceMerge(loop, loop); |
| 760 CheckLoop(loop, R.start, R.start); |
| 761 } |
| 762 } |
| 763 |
| 764 |
| 765 TEST(CMergeReduce_edit_phi1) { |
| 766 ControlReducerTester R; |
| 767 |
| 768 for (int i = 0; i < 3; i++) { |
| 769 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 770 merge->ReplaceInput(i, R.dead); |
| 771 Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0], |
| 772 R.leaf[1], R.leaf[2], merge); |
| 773 R.ReduceMerge(merge, merge); |
| 774 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); |
| 775 CHECK_EQ(2, phi->op()->InputCount()); |
| 776 CHECK_EQ(3, phi->InputCount()); |
| 777 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); |
| 778 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); |
| 779 CHECK_EQ(merge, phi->InputAt(2)); |
| 780 } |
| 781 } |
| 782 |
| 783 |
| 784 TEST(CMergeReduce_edit_effect_phi1) { |
| 785 ControlReducerTester R; |
| 786 |
| 787 for (int i = 0; i < 3; i++) { |
| 788 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 789 merge->ReplaceInput(i, R.dead); |
| 790 Node* phi = R.graph.NewNode(R.common.EffectPhi(3), R.leaf[0], R.leaf[1], |
| 791 R.leaf[2], merge); |
| 792 R.ReduceMerge(merge, merge); |
| 793 CHECK_EQ(IrOpcode::kEffectPhi, phi->opcode()); |
| 794 CHECK_EQ(0, phi->op()->InputCount()); |
| 795 CHECK_EQ(2, OperatorProperties::GetEffectInputCount(phi->op())); |
| 796 CHECK_EQ(3, phi->InputCount()); |
| 797 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); |
| 798 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); |
| 799 CHECK_EQ(merge, phi->InputAt(2)); |
| 800 } |
| 801 } |
| 802 |
| 803 |
| 804 static const int kSelectorSize = 4; |
| 805 |
| 806 // Helper to select K of N nodes according to a mask, useful for the test below. |
| 807 struct Selector { |
| 808 int mask; |
| 809 int count; |
| 810 explicit Selector(int m) { |
| 811 mask = m; |
| 812 count = v8::base::bits::CountPopulation32(m); |
| 813 } |
| 814 bool is_selected(int i) { return (mask & (1 << i)) != 0; } |
| 815 void CheckNode(Node* node, IrOpcode::Value opcode, Node** inputs, |
| 816 Node* control) { |
| 817 CHECK_EQ(opcode, node->opcode()); |
| 818 CHECK_EQ(count + (control != NULL ? 1 : 0), node->InputCount()); |
| 819 int index = 0; |
| 820 for (int i = 0; i < kSelectorSize; i++) { |
| 821 if (mask & (1 << i)) { |
| 822 CHECK_EQ(inputs[i], node->InputAt(index++)); |
| 823 } |
| 824 } |
| 825 CHECK_EQ(count, index); |
| 826 if (control != NULL) CHECK_EQ(control, node->InputAt(index++)); |
| 827 } |
| 828 int single_index() { |
| 829 CHECK_EQ(1, count); |
| 830 return WhichPowerOf2(mask); |
| 831 } |
| 832 }; |
| 833 |
| 834 |
| 835 TEST(CMergeReduce_exhaustive_4) { |
| 836 ControlReducerTester R; |
| 837 Node* controls[] = { |
| 838 R.graph.NewNode(R.common.Start(1)), R.graph.NewNode(R.common.Start(2)), |
| 839 R.graph.NewNode(R.common.Start(3)), R.graph.NewNode(R.common.Start(4))}; |
| 840 Node* values[] = {R.jsgraph.Int32Constant(11), R.jsgraph.Int32Constant(22), |
| 841 R.jsgraph.Int32Constant(33), R.jsgraph.Int32Constant(44)}; |
| 842 Node* effects[] = { |
| 843 R.jsgraph.Float64Constant(123.4), R.jsgraph.Float64Constant(223.4), |
| 844 R.jsgraph.Float64Constant(323.4), R.jsgraph.Float64Constant(423.4)}; |
| 845 |
| 846 for (int mask = 0; mask < (1 << (kSelectorSize - 1)); mask++) { |
| 847 // Reduce a single merge with a given mask. |
| 848 Node* merge = R.graph.NewNode(R.common.Merge(4), controls[0], controls[1], |
| 849 controls[2], controls[3]); |
| 850 Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 4), values[0], |
| 851 values[1], values[2], values[3], merge); |
| 852 Node* ephi = R.graph.NewNode(R.common.EffectPhi(4), effects[0], effects[1], |
| 853 effects[2], effects[3], merge); |
| 854 |
| 855 Node* phi_use = |
| 856 R.graph.NewNode(R.common.Phi(kMachAnyTagged, 1), phi, R.start); |
| 857 Node* ephi_use = R.graph.NewNode(R.common.EffectPhi(1), ephi, R.start); |
| 858 |
| 859 Selector selector(mask); |
| 860 |
| 861 for (int i = 0; i < kSelectorSize; i++) { // set up dead merge inputs. |
| 862 if (!selector.is_selected(i)) merge->ReplaceInput(i, R.dead); |
| 863 } |
| 864 |
| 865 Node* result = |
| 866 ControlReducer::ReduceMergeForTesting(&R.jsgraph, &R.common, merge); |
| 867 |
| 868 int count = selector.count; |
| 869 if (count == 0) { |
| 870 // result should be dead. |
| 871 CHECK_EQ(IrOpcode::kDead, result->opcode()); |
| 872 } else if (count == 1) { |
| 873 // merge should be replaced with one of the controls. |
| 874 CHECK_EQ(controls[selector.single_index()], result); |
| 875 // Phis should have been directly replaced. |
| 876 CHECK_EQ(values[selector.single_index()], phi_use->InputAt(0)); |
| 877 CHECK_EQ(effects[selector.single_index()], ephi_use->InputAt(0)); |
| 878 } else { |
| 879 // Otherwise, nodes should be edited in place. |
| 880 CHECK_EQ(merge, result); |
| 881 selector.CheckNode(merge, IrOpcode::kMerge, controls, NULL); |
| 882 selector.CheckNode(phi, IrOpcode::kPhi, values, merge); |
| 883 selector.CheckNode(ephi, IrOpcode::kEffectPhi, effects, merge); |
| 884 CHECK_EQ(phi, phi_use->InputAt(0)); |
| 885 CHECK_EQ(ephi, ephi_use->InputAt(0)); |
| 886 CHECK_EQ(count, phi->op()->InputCount()); |
| 887 CHECK_EQ(count + 1, phi->InputCount()); |
| 888 CHECK_EQ(count, OperatorProperties::GetEffectInputCount(ephi->op())); |
| 889 CHECK_EQ(count + 1, ephi->InputCount()); |
| 890 } |
| 891 } |
| 892 } |
| 893 |
| 894 |
| 895 TEST(CMergeReduce_edit_many_phis1) { |
| 896 ControlReducerTester R; |
| 897 |
| 898 const int kPhiCount = 10; |
| 899 Node* phis[kPhiCount]; |
| 900 |
| 901 for (int i = 0; i < 3; i++) { |
| 902 Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start); |
| 903 merge->ReplaceInput(i, R.dead); |
| 904 for (int j = 0; j < kPhiCount; j++) { |
| 905 phis[j] = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0], |
| 906 R.leaf[1], R.leaf[2], merge); |
| 907 } |
| 908 R.ReduceMerge(merge, merge); |
| 909 for (int j = 0; j < kPhiCount; j++) { |
| 910 Node* phi = phis[j]; |
| 911 CHECK_EQ(IrOpcode::kPhi, phi->opcode()); |
| 912 CHECK_EQ(2, phi->op()->InputCount()); |
| 913 CHECK_EQ(3, phi->InputCount()); |
| 914 CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0)); |
| 915 CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1)); |
| 916 CHECK_EQ(merge, phi->InputAt(2)); |
| 917 } |
| 918 } |
| 919 } |
| 920 |
| 921 |
| 922 TEST(CMergeReduce_simple_chain1) { |
| 923 ControlReducerTester R; |
| 924 for (int i = 0; i < 5; i++) { |
| 925 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); |
| 926 for (int j = 0; j < i; j++) { |
| 927 merge = R.graph.NewNode(R.common.Merge(1), merge); |
| 928 } |
| 929 R.ReduceMergeIterative(R.start, merge); |
| 930 } |
| 931 } |
| 932 |
| 933 |
| 934 TEST(CMergeReduce_dead_chain1) { |
| 935 ControlReducerTester R; |
| 936 for (int i = 0; i < 5; i++) { |
| 937 Node* merge = R.graph.NewNode(R.common.Merge(1), R.dead); |
| 938 for (int j = 0; j < i; j++) { |
| 939 merge = R.graph.NewNode(R.common.Merge(1), merge); |
| 940 } |
| 941 Node* end = R.graph.NewNode(R.common.End(), merge); |
| 942 R.graph.SetEnd(end); |
| 943 R.ReduceGraph(); |
| 944 CHECK(merge->IsDead()); |
| 945 CHECK_EQ(NULL, end->InputAt(0)); // end dies. |
| 946 } |
| 947 } |
| 948 |
| 949 |
| 950 TEST(CMergeReduce_dead_chain2) { |
| 951 ControlReducerTester R; |
| 952 for (int i = 0; i < 5; i++) { |
| 953 Node* merge = R.graph.NewNode(R.common.Merge(1), R.start); |
| 954 for (int j = 0; j < i; j++) { |
| 955 merge = R.graph.NewNode(R.common.Merge(2), merge, R.dead); |
| 956 } |
| 957 R.ReduceMergeIterative(R.start, merge); |
| 958 } |
| 959 } |
| 960 |
| 961 |
| 962 struct Branch { |
| 963 Node* branch; |
| 964 Node* if_true; |
| 965 Node* if_false; |
| 966 |
| 967 Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) { |
| 968 if (control == NULL) control = R.start; |
| 969 branch = R.graph.NewNode(R.common.Branch(), cond, control); |
| 970 if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 971 if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
| 972 } |
| 973 }; |
| 974 |
| 975 |
| 976 struct Diamond { |
| 977 Node* branch; |
| 978 Node* if_true; |
| 979 Node* if_false; |
| 980 Node* merge; |
| 981 Node* phi; |
| 982 |
| 983 Diamond(ControlReducerTester& R, Node* cond) { |
| 984 branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
| 985 if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 986 if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
| 987 merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
| 988 phi = NULL; |
| 989 } |
| 990 |
| 991 Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) { |
| 992 branch = R.graph.NewNode(R.common.Branch(), cond, R.start); |
| 993 if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 994 if_false = R.graph.NewNode(R.common.IfFalse(), branch); |
| 995 merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false); |
| 996 phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge); |
| 997 } |
| 998 |
| 999 void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); } |
| 1000 |
| 1001 // Nest {this} into either the if_true or if_false branch of {that}. |
| 1002 void nest(Diamond& that, bool if_true) { |
| 1003 if (if_true) { |
| 1004 branch->ReplaceInput(1, that.if_true); |
| 1005 that.merge->ReplaceInput(0, merge); |
| 1006 } else { |
| 1007 branch->ReplaceInput(1, that.if_false); |
| 1008 that.merge->ReplaceInput(1, merge); |
| 1009 } |
| 1010 } |
| 1011 }; |
| 1012 |
| 1013 |
| 1014 struct While { |
| 1015 Node* branch; |
| 1016 Node* if_true; |
| 1017 Node* exit; |
| 1018 Node* loop; |
| 1019 |
| 1020 While(ControlReducerTester& R, Node* cond) { |
| 1021 loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); |
| 1022 branch = R.graph.NewNode(R.common.Branch(), cond, loop); |
| 1023 if_true = R.graph.NewNode(R.common.IfTrue(), branch); |
| 1024 exit = R.graph.NewNode(R.common.IfFalse(), branch); |
| 1025 loop->ReplaceInput(1, if_true); |
| 1026 } |
| 1027 |
| 1028 void chain(Node* control) { loop->ReplaceInput(0, control); } |
| 1029 }; |
| 1030 |
| 1031 |
| 1032 TEST(CBranchReduce_none1) { |
| 1033 ControlReducerTester R; |
| 1034 Diamond d(R, R.p0); |
| 1035 R.ReduceBranch(d.branch, d.branch); |
| 1036 } |
| 1037 |
| 1038 |
| 1039 TEST(CBranchReduce_none2) { |
| 1040 ControlReducerTester R; |
| 1041 Diamond d1(R, R.p0); |
| 1042 Diamond d2(R, R.p0); |
| 1043 d2.chain(d1); |
| 1044 R.ReduceBranch(d2.branch, d2.branch); |
| 1045 } |
| 1046 |
| 1047 |
| 1048 TEST(CBranchReduce_true) { |
| 1049 ControlReducerTester R; |
| 1050 Node* true_values[] = { |
| 1051 R.one, R.jsgraph.Int32Constant(2), |
| 1052 R.jsgraph.Int32Constant(0x7fffffff), R.jsgraph.Constant(1.0), |
| 1053 R.jsgraph.Constant(22.1), R.jsgraph.TrueConstant()}; |
| 1054 |
| 1055 for (size_t i = 0; i < arraysize(true_values); i++) { |
| 1056 Diamond d(R, true_values[i]); |
| 1057 Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true); |
| 1058 Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false); |
| 1059 R.ReduceBranch(R.start, d.branch); |
| 1060 CHECK_EQ(R.start, true_use->InputAt(0)); |
| 1061 CHECK_EQ(IrOpcode::kDead, false_use->InputAt(0)->opcode()); |
| 1062 CHECK(d.if_true->IsDead()); // replaced |
| 1063 CHECK(d.if_false->IsDead()); // replaced |
| 1064 } |
| 1065 } |
| 1066 |
| 1067 |
| 1068 TEST(CBranchReduce_false) { |
| 1069 ControlReducerTester R; |
| 1070 Node* false_values[] = {R.zero, R.jsgraph.Constant(0.0), |
| 1071 R.jsgraph.Constant(-0.0), R.jsgraph.FalseConstant()}; |
| 1072 |
| 1073 for (size_t i = 0; i < arraysize(false_values); i++) { |
| 1074 Diamond d(R, false_values[i]); |
| 1075 Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true); |
| 1076 Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false); |
| 1077 R.ReduceBranch(R.start, d.branch); |
| 1078 CHECK_EQ(R.start, false_use->InputAt(0)); |
| 1079 CHECK_EQ(IrOpcode::kDead, true_use->InputAt(0)->opcode()); |
| 1080 CHECK(d.if_true->IsDead()); // replaced |
| 1081 CHECK(d.if_false->IsDead()); // replaced |
| 1082 } |
| 1083 } |
| 1084 |
| 1085 |
| 1086 TEST(CDiamondReduce_true) { |
| 1087 ControlReducerTester R; |
| 1088 Diamond d1(R, R.one); |
| 1089 R.ReduceMergeIterative(R.start, d1.merge); |
| 1090 } |
| 1091 |
| 1092 |
| 1093 TEST(CDiamondReduce_false) { |
| 1094 ControlReducerTester R; |
| 1095 Diamond d2(R, R.zero); |
| 1096 R.ReduceMergeIterative(R.start, d2.merge); |
| 1097 } |
| 1098 |
| 1099 |
| 1100 TEST(CChainedDiamondsReduce_true_false) { |
| 1101 ControlReducerTester R; |
| 1102 Diamond d1(R, R.one); |
| 1103 Diamond d2(R, R.zero); |
| 1104 d2.chain(d1); |
| 1105 |
| 1106 R.ReduceMergeIterative(R.start, d2.merge); |
| 1107 } |
| 1108 |
| 1109 |
| 1110 TEST(CChainedDiamondsReduce_x_false) { |
| 1111 ControlReducerTester R; |
| 1112 Diamond d1(R, R.p0); |
| 1113 Diamond d2(R, R.zero); |
| 1114 d2.chain(d1); |
| 1115 |
| 1116 R.ReduceMergeIterative(d1.merge, d2.merge); |
| 1117 } |
| 1118 |
| 1119 |
| 1120 TEST(CChainedDiamondsReduce_false_x) { |
| 1121 ControlReducerTester R; |
| 1122 Diamond d1(R, R.zero); |
| 1123 Diamond d2(R, R.p0); |
| 1124 d2.chain(d1); |
| 1125 |
| 1126 R.ReduceMergeIterative(d2.merge, d2.merge); |
| 1127 CheckInputs(d2.branch, R.p0, R.start); |
| 1128 } |
| 1129 |
| 1130 |
| 1131 TEST(CChainedDiamondsReduce_phi1) { |
| 1132 ControlReducerTester R; |
| 1133 Diamond d1(R, R.zero, R.one, R.zero); // foldable branch, phi. |
| 1134 Diamond d2(R, d1.phi); |
| 1135 d2.chain(d1); |
| 1136 |
| 1137 R.ReduceMergeIterative(R.start, d2.merge); |
| 1138 } |
| 1139 |
| 1140 |
| 1141 TEST(CChainedDiamondsReduce_phi2) { |
| 1142 ControlReducerTester R; |
| 1143 Diamond d1(R, R.p0, R.one, R.one); // redundant phi. |
| 1144 Diamond d2(R, d1.phi); |
| 1145 d2.chain(d1); |
| 1146 |
| 1147 R.ReduceMergeIterative(d1.merge, d2.merge); |
| 1148 } |
| 1149 |
| 1150 |
| 1151 TEST(CNestedDiamondsReduce_true_true_false) { |
| 1152 ControlReducerTester R; |
| 1153 Diamond d1(R, R.one); |
| 1154 Diamond d2(R, R.zero); |
| 1155 d2.nest(d1, true); |
| 1156 |
| 1157 R.ReduceMergeIterative(R.start, d1.merge); |
| 1158 } |
| 1159 |
| 1160 |
| 1161 TEST(CNestedDiamondsReduce_false_true_false) { |
| 1162 ControlReducerTester R; |
| 1163 Diamond d1(R, R.one); |
| 1164 Diamond d2(R, R.zero); |
| 1165 d2.nest(d1, false); |
| 1166 |
| 1167 R.ReduceMergeIterative(R.start, d1.merge); |
| 1168 } |
| 1169 |
| 1170 |
| 1171 TEST(CNestedDiamonds_xyz) { |
| 1172 ControlReducerTester R; |
| 1173 |
| 1174 for (int a = 0; a < 2; a++) { |
| 1175 for (int b = 0; b < 2; b++) { |
| 1176 for (int c = 0; c < 2; c++) { |
| 1177 Diamond d1(R, R.jsgraph.Int32Constant(a)); |
| 1178 Diamond d2(R, R.jsgraph.Int32Constant(b)); |
| 1179 d2.nest(d1, c); |
| 1180 |
| 1181 R.ReduceMergeIterative(R.start, d1.merge); |
| 1182 } |
| 1183 } |
| 1184 } |
| 1185 } |
| 1186 |
| 1187 |
| 1188 TEST(CDeadLoop1) { |
| 1189 ControlReducerTester R; |
| 1190 |
| 1191 Node* loop = R.graph.NewNode(R.common.Loop(1), R.start); |
| 1192 Branch b(R, R.p0, loop); |
| 1193 loop->ReplaceInput(0, b.if_true); // loop is not connected to start. |
| 1194 Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, b.if_false); |
| 1195 R.ReduceMergeIterative(R.start, merge); |
| 1196 CHECK(b.if_true->IsDead()); |
| 1197 CHECK(b.if_false->IsDead()); |
| 1198 } |
| 1199 |
| 1200 |
| 1201 TEST(CDeadLoop2) { |
| 1202 ControlReducerTester R; |
| 1203 |
| 1204 While w(R, R.p0); |
| 1205 Diamond d(R, R.zero); |
| 1206 // if (0) { while (p0) ; } else { } |
| 1207 w.branch->ReplaceInput(1, d.if_true); |
| 1208 d.merge->ReplaceInput(0, w.exit); |
| 1209 |
| 1210 R.ReduceMergeIterative(R.start, d.merge); |
| 1211 CHECK(d.if_true->IsDead()); |
| 1212 CHECK(d.if_false->IsDead()); |
| 1213 } |
| 1214 |
| 1215 |
| 1216 TEST(CNonTermLoop1) { |
| 1217 ControlReducerTester R; |
| 1218 Node* loop = |
| 1219 R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self)); |
| 1220 R.ReduceGraph(); |
| 1221 Node* end = R.graph.end(); |
| 1222 CheckLoop(loop, R.start, loop); |
| 1223 Node* merge = end->InputAt(0); |
| 1224 CheckMerge(merge, R.start, loop); |
| 1225 } |
| 1226 |
| 1227 |
| 1228 TEST(CNonTermLoop2) { |
| 1229 ControlReducerTester R; |
| 1230 Diamond d(R, R.p0); |
| 1231 Node* loop = R.SetSelfReferences( |
| 1232 R.graph.NewNode(R.common.Loop(2), d.if_false, R.self)); |
| 1233 d.merge->ReplaceInput(1, R.dead); |
| 1234 Node* end = R.graph.end(); |
| 1235 end->ReplaceInput(0, d.merge); |
| 1236 R.ReduceGraph(); |
| 1237 CHECK_EQ(end, R.graph.end()); |
| 1238 CheckLoop(loop, d.if_false, loop); |
| 1239 Node* merge = end->InputAt(0); |
| 1240 CheckMerge(merge, d.if_true, loop); |
| 1241 } |
| 1242 |
| 1243 |
| 1244 TEST(NonTermLoop3) { |
| 1245 ControlReducerTester R; |
| 1246 Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); |
| 1247 Branch b(R, R.one, loop); |
| 1248 loop->ReplaceInput(1, b.if_true); |
| 1249 Node* end = R.graph.end(); |
| 1250 end->ReplaceInput(0, b.if_false); |
| 1251 |
| 1252 R.ReduceGraph(); |
| 1253 |
| 1254 CHECK_EQ(end, R.graph.end()); |
| 1255 CheckInputs(end, loop); |
| 1256 CheckInputs(loop, R.start, loop); |
| 1257 } |
| 1258 |
| 1259 |
| 1260 TEST(CNonTermLoop_terminate1) { |
| 1261 ControlReducerTester R; |
| 1262 Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); |
| 1263 Node* effect = R.SetSelfReferences( |
| 1264 R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop)); |
| 1265 Branch b(R, R.one, loop); |
| 1266 loop->ReplaceInput(1, b.if_true); |
| 1267 Node* end = R.graph.end(); |
| 1268 end->ReplaceInput(0, b.if_false); |
| 1269 |
| 1270 R.ReduceGraph(); |
| 1271 |
| 1272 CHECK_EQ(end, R.graph.end()); |
| 1273 CheckLoop(loop, R.start, loop); |
| 1274 Node* terminate = end->InputAt(0); |
| 1275 CHECK_EQ(IrOpcode::kTerminate, terminate->opcode()); |
| 1276 CHECK_EQ(2, terminate->InputCount()); |
| 1277 CHECK_EQ(1, OperatorProperties::GetEffectInputCount(terminate->op())); |
| 1278 CHECK_EQ(1, OperatorProperties::GetControlInputCount(terminate->op())); |
| 1279 CheckInputs(terminate, effect, loop); |
| 1280 } |
| 1281 |
| 1282 |
| 1283 TEST(CNonTermLoop_terminate2) { |
| 1284 ControlReducerTester R; |
| 1285 Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start); |
| 1286 Node* effect1 = R.SetSelfReferences( |
| 1287 R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop)); |
| 1288 Node* effect2 = R.SetSelfReferences( |
| 1289 R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop)); |
| 1290 Branch b(R, R.one, loop); |
| 1291 loop->ReplaceInput(1, b.if_true); |
| 1292 Node* end = R.graph.end(); |
| 1293 end->ReplaceInput(0, b.if_false); |
| 1294 |
| 1295 R.ReduceGraph(); |
| 1296 |
| 1297 CheckLoop(loop, R.start, loop); |
| 1298 CHECK_EQ(end, R.graph.end()); |
| 1299 Node* terminate = end->InputAt(0); |
| 1300 CHECK_EQ(IrOpcode::kTerminate, terminate->opcode()); |
| 1301 CHECK_EQ(3, terminate->InputCount()); |
| 1302 CHECK_EQ(2, OperatorProperties::GetEffectInputCount(terminate->op())); |
| 1303 CHECK_EQ(1, OperatorProperties::GetControlInputCount(terminate->op())); |
| 1304 Node* e0 = terminate->InputAt(0); |
| 1305 Node* e1 = terminate->InputAt(1); |
| 1306 CHECK(e0 == effect1 || e1 == effect1); |
| 1307 CHECK(e0 == effect2 || e1 == effect2); |
| 1308 CHECK_EQ(loop, terminate->InputAt(2)); |
| 1309 } |
| 1310 |
| 1311 |
| 1312 TEST(CNonTermLoop_terminate_m1) { |
| 1313 ControlReducerTester R; |
| 1314 Node* loop = |
| 1315 R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self)); |
| 1316 Node* effect = R.SetSelfReferences( |
| 1317 R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop)); |
| 1318 R.ReduceGraph(); |
| 1319 Node* end = R.graph.end(); |
| 1320 CHECK_EQ(R.start, loop->InputAt(0)); |
| 1321 CHECK_EQ(loop, loop->InputAt(1)); |
| 1322 Node* merge = end->InputAt(0); |
| 1323 CHECK_EQ(IrOpcode::kMerge, merge->opcode()); |
| 1324 CHECK_EQ(2, merge->InputCount()); |
| 1325 CHECK_EQ(2, OperatorProperties::GetControlInputCount(merge->op())); |
| 1326 CHECK_EQ(R.start, merge->InputAt(0)); |
| 1327 |
| 1328 Node* terminate = merge->InputAt(1); |
| 1329 CHECK_EQ(IrOpcode::kTerminate, terminate->opcode()); |
| 1330 CHECK_EQ(2, terminate->InputCount()); |
| 1331 CHECK_EQ(1, OperatorProperties::GetEffectInputCount(terminate->op())); |
| 1332 CHECK_EQ(1, OperatorProperties::GetControlInputCount(terminate->op())); |
| 1333 CHECK_EQ(effect, terminate->InputAt(0)); |
| 1334 CHECK_EQ(loop, terminate->InputAt(1)); |
| 1335 } |
| 1336 |
| 1337 |
| 1338 TEST(CNonTermLoop_big1) { |
| 1339 ControlReducerTester R; |
| 1340 Branch b1(R, R.p0); |
| 1341 Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true); |
| 1342 |
| 1343 Branch b2(R, R.p0, b1.if_false); |
| 1344 Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true); |
| 1345 Node* loop = R.SetSelfReferences( |
| 1346 R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self)); |
| 1347 Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf); |
| 1348 R.end->ReplaceInput(0, merge); |
| 1349 |
| 1350 R.ReduceGraph(); |
| 1351 |
| 1352 CheckInputs(R.end, merge); |
| 1353 CheckInputs(merge, rt, rf, loop); |
| 1354 CheckInputs(loop, b2.if_false, loop); |
| 1355 } |
| 1356 |
| 1357 |
| 1358 TEST(CNonTermLoop_big2) { |
| 1359 ControlReducerTester R; |
| 1360 Branch b1(R, R.p0); |
| 1361 Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true); |
| 1362 |
| 1363 Branch b2(R, R.zero, b1.if_false); |
| 1364 Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true); |
| 1365 Node* loop = R.SetSelfReferences( |
| 1366 R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self)); |
| 1367 Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf); |
| 1368 R.end->ReplaceInput(0, merge); |
| 1369 |
| 1370 R.ReduceGraph(); |
| 1371 |
| 1372 Node* new_merge = R.end->InputAt(0); // old merge was reduced. |
| 1373 CHECK_NE(merge, new_merge); |
| 1374 CheckInputs(new_merge, rt, loop); |
| 1375 CheckInputs(loop, b1.if_false, loop); |
| 1376 CHECK(merge->IsDead()); |
| 1377 CHECK(rf->IsDead()); |
| 1378 CHECK(b2.if_true->IsDead()); |
| 1379 } |
| 1380 |
| 1381 |
| 1382 TEST(Return1) { |
| 1383 ControlReducerTester R; |
| 1384 Node* ret = R.Return(R.one, R.start, R.start); |
| 1385 R.ReduceGraph(); |
| 1386 CheckInputs(R.graph.end(), ret); |
| 1387 CheckInputs(ret, R.one, R.start, R.start); |
| 1388 } |
| 1389 |
| 1390 |
| 1391 TEST(Return2) { |
| 1392 ControlReducerTester R; |
| 1393 Diamond d(R, R.one); |
| 1394 Node* ret = R.Return(R.half, R.start, d.merge); |
| 1395 R.ReduceGraph(); |
| 1396 CHECK(d.branch->IsDead()); |
| 1397 CHECK(d.if_true->IsDead()); |
| 1398 CHECK(d.if_false->IsDead()); |
| 1399 CHECK(d.merge->IsDead()); |
| 1400 |
| 1401 CheckInputs(R.graph.end(), ret); |
| 1402 CheckInputs(ret, R.half, R.start, R.start); |
| 1403 } |
| 1404 |
| 1405 |
| 1406 TEST(Return_true1) { |
| 1407 ControlReducerTester R; |
| 1408 Diamond d(R, R.one, R.half, R.zero); |
| 1409 Node* ret = R.Return(d.phi, R.start, d.merge); |
| 1410 R.ReduceGraph(); |
| 1411 CHECK(d.branch->IsDead()); |
| 1412 CHECK(d.if_true->IsDead()); |
| 1413 CHECK(d.if_false->IsDead()); |
| 1414 CHECK(d.merge->IsDead()); |
| 1415 CHECK(d.phi->IsDead()); |
| 1416 |
| 1417 CheckInputs(R.graph.end(), ret); |
| 1418 CheckInputs(ret, R.half, R.start, R.start); |
| 1419 } |
| 1420 |
| 1421 |
| 1422 TEST(Return_false1) { |
| 1423 ControlReducerTester R; |
| 1424 Diamond d(R, R.zero, R.one, R.half); |
| 1425 Node* ret = R.Return(d.phi, R.start, d.merge); |
| 1426 R.ReduceGraph(); |
| 1427 CHECK(d.branch->IsDead()); |
| 1428 CHECK(d.if_true->IsDead()); |
| 1429 CHECK(d.if_false->IsDead()); |
| 1430 CHECK(d.merge->IsDead()); |
| 1431 CHECK(d.phi->IsDead()); |
| 1432 |
| 1433 CheckInputs(R.graph.end(), ret); |
| 1434 CheckInputs(ret, R.half, R.start, R.start); |
| 1435 } |
| 1436 |
| 1437 |
| 1438 void CheckDeadDiamond(Diamond& d) { |
| 1439 CHECK(d.branch->IsDead()); |
| 1440 CHECK(d.if_true->IsDead()); |
| 1441 CHECK(d.if_false->IsDead()); |
| 1442 CHECK(d.merge->IsDead()); |
| 1443 if (d.phi != NULL) CHECK(d.phi->IsDead()); |
| 1444 } |
| 1445 |
| 1446 |
| 1447 void CheckLiveDiamond(Diamond& d, bool live_phi = true) { |
| 1448 CheckInputs(d.merge, d.if_true, d.if_false); |
| 1449 CheckInputs(d.if_true, d.branch); |
| 1450 CheckInputs(d.if_false, d.branch); |
| 1451 if (d.phi != NULL) { |
| 1452 if (live_phi) { |
| 1453 CHECK_EQ(3, d.phi->InputCount()); |
| 1454 CHECK_EQ(d.merge, d.phi->InputAt(2)); |
| 1455 } else { |
| 1456 CHECK(d.phi->IsDead()); |
| 1457 } |
| 1458 } |
| 1459 } |
| 1460 |
| 1461 |
| 1462 TEST(Return_effect1) { |
| 1463 ControlReducerTester R; |
| 1464 Diamond d(R, R.one); |
| 1465 Node* e1 = R.jsgraph.Float64Constant(-100.1); |
| 1466 Node* e2 = R.jsgraph.Float64Constant(+100.1); |
| 1467 Node* effect = R.graph.NewNode(R.common.EffectPhi(2), e1, e2, d.merge); |
| 1468 Node* ret = R.Return(R.p0, effect, d.merge); |
| 1469 R.ReduceGraph(); |
| 1470 CheckDeadDiamond(d); |
| 1471 CHECK(effect->IsDead()); |
| 1472 |
| 1473 CheckInputs(R.graph.end(), ret); |
| 1474 CheckInputs(ret, R.p0, e1, R.start); |
| 1475 } |
| 1476 |
| 1477 |
| 1478 TEST(Return_nested_diamonds1) { |
| 1479 ControlReducerTester R; |
| 1480 Diamond d1(R, R.p0, R.one, R.zero); |
| 1481 Diamond d2(R, R.p0); |
| 1482 Diamond d3(R, R.p0); |
| 1483 |
| 1484 d2.nest(d1, true); |
| 1485 d3.nest(d1, false); |
| 1486 |
| 1487 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1488 |
| 1489 R.ReduceGraph(); // nothing should happen. |
| 1490 |
| 1491 CheckInputs(ret, d1.phi, R.start, d1.merge); |
| 1492 CheckInputs(d1.phi, R.one, R.zero, d1.merge); |
| 1493 CheckInputs(d1.merge, d2.merge, d3.merge); |
| 1494 CheckLiveDiamond(d2); |
| 1495 CheckLiveDiamond(d3); |
| 1496 } |
| 1497 |
| 1498 |
| 1499 TEST(Return_nested_diamonds_true1) { |
| 1500 ControlReducerTester R; |
| 1501 Diamond d1(R, R.one, R.one, R.zero); |
| 1502 Diamond d2(R, R.p0); |
| 1503 Diamond d3(R, R.p0); |
| 1504 |
| 1505 d2.nest(d1, true); |
| 1506 d3.nest(d1, false); |
| 1507 |
| 1508 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1509 |
| 1510 R.ReduceGraph(); // d1 gets folded true. |
| 1511 |
| 1512 CheckInputs(ret, R.one, R.start, d2.merge); |
| 1513 CheckInputs(d2.branch, R.p0, R.start); |
| 1514 CheckDeadDiamond(d1); |
| 1515 CheckLiveDiamond(d2); |
| 1516 CheckDeadDiamond(d3); |
| 1517 } |
| 1518 |
| 1519 |
| 1520 TEST(Return_nested_diamonds_false1) { |
| 1521 ControlReducerTester R; |
| 1522 Diamond d1(R, R.zero, R.one, R.zero); |
| 1523 Diamond d2(R, R.p0); |
| 1524 Diamond d3(R, R.p0); |
| 1525 |
| 1526 d2.nest(d1, true); |
| 1527 d3.nest(d1, false); |
| 1528 |
| 1529 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1530 |
| 1531 R.ReduceGraph(); // d1 gets folded false. |
| 1532 |
| 1533 CheckInputs(ret, R.zero, R.start, d3.merge); |
| 1534 CheckInputs(d3.branch, R.p0, R.start); |
| 1535 CheckDeadDiamond(d1); |
| 1536 CheckDeadDiamond(d2); |
| 1537 CheckLiveDiamond(d3); |
| 1538 } |
| 1539 |
| 1540 |
| 1541 TEST(Return_nested_diamonds_true_true1) { |
| 1542 ControlReducerTester R; |
| 1543 Diamond d1(R, R.one, R.one, R.zero); |
| 1544 Diamond d2(R, R.one); |
| 1545 Diamond d3(R, R.p0); |
| 1546 |
| 1547 d2.nest(d1, true); |
| 1548 d3.nest(d1, false); |
| 1549 |
| 1550 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1551 |
| 1552 R.ReduceGraph(); // d1 and d2 both get folded true. |
| 1553 |
| 1554 CheckInputs(ret, R.one, R.start, R.start); |
| 1555 CheckDeadDiamond(d1); |
| 1556 CheckDeadDiamond(d2); |
| 1557 CheckDeadDiamond(d3); |
| 1558 } |
| 1559 |
| 1560 |
| 1561 TEST(Return_nested_diamonds_true_false1) { |
| 1562 ControlReducerTester R; |
| 1563 Diamond d1(R, R.one, R.one, R.zero); |
| 1564 Diamond d2(R, R.zero); |
| 1565 Diamond d3(R, R.p0); |
| 1566 |
| 1567 d2.nest(d1, true); |
| 1568 d3.nest(d1, false); |
| 1569 |
| 1570 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1571 |
| 1572 R.ReduceGraph(); // d1 gets folded true and d2 gets folded false. |
| 1573 |
| 1574 CheckInputs(ret, R.one, R.start, R.start); |
| 1575 CheckDeadDiamond(d1); |
| 1576 CheckDeadDiamond(d2); |
| 1577 CheckDeadDiamond(d3); |
| 1578 } |
| 1579 |
| 1580 |
| 1581 TEST(Return_nested_diamonds2) { |
| 1582 ControlReducerTester R; |
| 1583 Node* x2 = R.jsgraph.Float64Constant(11.1); |
| 1584 Node* y2 = R.jsgraph.Float64Constant(22.2); |
| 1585 Node* x3 = R.jsgraph.Float64Constant(33.3); |
| 1586 Node* y3 = R.jsgraph.Float64Constant(44.4); |
| 1587 |
| 1588 Diamond d2(R, R.p0, x2, y2); |
| 1589 Diamond d3(R, R.p0, x3, y3); |
| 1590 Diamond d1(R, R.p0, d2.phi, d3.phi); |
| 1591 |
| 1592 d2.nest(d1, true); |
| 1593 d3.nest(d1, false); |
| 1594 |
| 1595 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1596 |
| 1597 R.ReduceGraph(); // nothing should happen. |
| 1598 |
| 1599 CheckInputs(ret, d1.phi, R.start, d1.merge); |
| 1600 CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge); |
| 1601 CheckInputs(d1.merge, d2.merge, d3.merge); |
| 1602 CheckLiveDiamond(d2); |
| 1603 CheckLiveDiamond(d3); |
| 1604 } |
| 1605 |
| 1606 |
| 1607 TEST(Return_nested_diamonds_true2) { |
| 1608 ControlReducerTester R; |
| 1609 Node* x2 = R.jsgraph.Float64Constant(11.1); |
| 1610 Node* y2 = R.jsgraph.Float64Constant(22.2); |
| 1611 Node* x3 = R.jsgraph.Float64Constant(33.3); |
| 1612 Node* y3 = R.jsgraph.Float64Constant(44.4); |
| 1613 |
| 1614 Diamond d2(R, R.p0, x2, y2); |
| 1615 Diamond d3(R, R.p0, x3, y3); |
| 1616 Diamond d1(R, R.one, d2.phi, d3.phi); |
| 1617 |
| 1618 d2.nest(d1, true); |
| 1619 d3.nest(d1, false); |
| 1620 |
| 1621 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1622 |
| 1623 R.ReduceGraph(); // d1 gets folded true. |
| 1624 |
| 1625 CheckInputs(ret, d2.phi, R.start, d2.merge); |
| 1626 CheckInputs(d2.branch, R.p0, R.start); |
| 1627 CheckDeadDiamond(d1); |
| 1628 CheckLiveDiamond(d2); |
| 1629 CheckDeadDiamond(d3); |
| 1630 } |
| 1631 |
| 1632 |
| 1633 TEST(Return_nested_diamonds_true_true2) { |
| 1634 ControlReducerTester R; |
| 1635 Node* x2 = R.jsgraph.Float64Constant(11.1); |
| 1636 Node* y2 = R.jsgraph.Float64Constant(22.2); |
| 1637 Node* x3 = R.jsgraph.Float64Constant(33.3); |
| 1638 Node* y3 = R.jsgraph.Float64Constant(44.4); |
| 1639 |
| 1640 Diamond d2(R, R.one, x2, y2); |
| 1641 Diamond d3(R, R.p0, x3, y3); |
| 1642 Diamond d1(R, R.one, d2.phi, d3.phi); |
| 1643 |
| 1644 d2.nest(d1, true); |
| 1645 d3.nest(d1, false); |
| 1646 |
| 1647 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1648 |
| 1649 R.ReduceGraph(); // d1 gets folded true. |
| 1650 |
| 1651 CheckInputs(ret, x2, R.start, R.start); |
| 1652 CheckDeadDiamond(d1); |
| 1653 CheckDeadDiamond(d2); |
| 1654 CheckDeadDiamond(d3); |
| 1655 } |
| 1656 |
| 1657 |
| 1658 TEST(Return_nested_diamonds_true_false2) { |
| 1659 ControlReducerTester R; |
| 1660 Node* x2 = R.jsgraph.Float64Constant(11.1); |
| 1661 Node* y2 = R.jsgraph.Float64Constant(22.2); |
| 1662 Node* x3 = R.jsgraph.Float64Constant(33.3); |
| 1663 Node* y3 = R.jsgraph.Float64Constant(44.4); |
| 1664 |
| 1665 Diamond d2(R, R.zero, x2, y2); |
| 1666 Diamond d3(R, R.p0, x3, y3); |
| 1667 Diamond d1(R, R.one, d2.phi, d3.phi); |
| 1668 |
| 1669 d2.nest(d1, true); |
| 1670 d3.nest(d1, false); |
| 1671 |
| 1672 Node* ret = R.Return(d1.phi, R.start, d1.merge); |
| 1673 |
| 1674 R.ReduceGraph(); // d1 gets folded true. |
| 1675 |
| 1676 CheckInputs(ret, y2, R.start, R.start); |
| 1677 CheckDeadDiamond(d1); |
| 1678 CheckDeadDiamond(d2); |
| 1679 CheckDeadDiamond(d3); |
| 1680 } |
OLD | NEW |