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