1 /* 2 * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.core.test; 24 25 import static org.graalvm.compiler.core.common.GraalOptions.OptImplicitNullChecks; 26 import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops; 27 import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount; 28 import static org.hamcrest.core.IsInstanceOf.instanceOf; 29 import static org.junit.Assert.assertThat; 30 31 import java.util.ArrayList; 32 import java.util.List; 33 34 import org.junit.Assert; 35 import org.junit.Test; 36 37 import org.graalvm.compiler.api.directives.GraalDirectives; 38 import org.graalvm.compiler.debug.Debug; 39 import org.graalvm.compiler.debug.Debug.Scope; 40 import org.graalvm.compiler.graph.Node; 41 import org.graalvm.compiler.graph.iterators.NodeIterable; 42 import org.graalvm.compiler.nodes.ReturnNode; 43 import org.graalvm.compiler.nodes.StartNode; 44 import org.graalvm.compiler.nodes.StructuredGraph; 45 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 46 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 47 import org.graalvm.compiler.nodes.cfg.Block; 48 import org.graalvm.compiler.nodes.memory.FloatingReadNode; 49 import org.graalvm.compiler.nodes.memory.WriteNode; 50 import org.graalvm.compiler.nodes.spi.LoweringTool; 51 import org.graalvm.compiler.options.OptionValues; 52 import org.graalvm.compiler.phases.OptimisticOptimizations; 53 import org.graalvm.compiler.phases.common.CanonicalizerPhase; 54 import org.graalvm.compiler.phases.common.FloatingReadPhase; 55 import org.graalvm.compiler.phases.common.GuardLoweringPhase; 56 import org.graalvm.compiler.phases.common.LoweringPhase; 57 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; 58 import org.graalvm.compiler.phases.common.inlining.InliningPhase; 59 import org.graalvm.compiler.phases.schedule.SchedulePhase; 60 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; 61 import org.graalvm.compiler.phases.tiers.HighTierContext; 62 import org.graalvm.compiler.phases.tiers.MidTierContext; 63 64 /** 65 * In these test the FrameStates are explicitly cleared out, so that the scheduling of 66 * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the 67 * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the 68 * right thing. 69 * 70 * The scheduling shouldn't depend on FrameStates, which is tested by this class. 71 */ 72 public class MemoryScheduleTest extends GraphScheduleTest { 73 74 private enum TestMode { 75 WITH_FRAMESTATES, 76 WITHOUT_FRAMESTATES, 77 INLINED_WITHOUT_FRAMESTATES 78 } 79 80 public static class Container { 81 82 public int a; 83 public int b; 84 public int c; 85 86 public Object obj; 87 } 88 89 private static final Container container = new Container(); 90 private static final List<Container> containerList = new ArrayList<>(); 91 private static final double LOOP_ENTRY_PROBABILITY = 0.9; 92 93 /** 94 * In this test the read should be scheduled before the write. 95 */ 96 public static int testSimpleSnippet() { 97 try { 98 return container.a; 99 } finally { 100 container.a = 15; 101 } 102 } 103 104 @Test 105 public void testSimple() { 106 for (TestMode mode : TestMode.values()) { 107 ScheduleResult schedule = getFinalSchedule("testSimpleSnippet", mode); 108 StructuredGraph graph = schedule.getCFG().graph; 109 assertReadAndWriteInSameBlock(schedule, true); 110 assertOrderedAfterSchedule(schedule, graph.getNodes().filter(FloatingReadNode.class).first(), graph.getNodes().filter(WriteNode.class).first()); 111 } 112 } 113 114 /** 115 * In this case the read should be scheduled in the first block. 116 */ 117 public static int testSplit1Snippet(int a) { 118 try { 119 return container.a; 120 } finally { 121 if (a < 0) { 122 container.a = 15; 123 } else { 124 container.b = 15; 125 } 126 } 127 } 128 129 @Test 130 public void testSplit1() { 131 for (TestMode mode : TestMode.values()) { 132 ScheduleResult schedule = getFinalSchedule("testSplit1Snippet", mode); 133 assertReadWithinStartBlock(schedule, true); 134 assertReadWithinAllReturnBlocks(schedule, false); 135 } 136 } 137 138 /** 139 * Here the read should float to the end. 140 */ 141 public static int testSplit2Snippet(int a) { 142 try { 143 return container.a; 144 } finally { 145 if (a < 0) { 146 container.c = 15; 147 } else { 148 container.b = 15; 149 } 150 container.obj = null; 151 } 152 } 153 154 @Test 155 public void testSplit2() { 156 ScheduleResult schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES); 157 assertReadWithinStartBlock(schedule, false); 158 assertReadWithinAllReturnBlocks(schedule, true); 159 } 160 161 /** 162 * Here the read should not float to the end. 163 */ 164 public static int testLoop1Snippet(int a, int b) { 165 try { 166 return container.a; 167 } finally { 168 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a); i++) { 169 if (b < 0) { 170 container.b = 10; 171 } else { 172 container.a = 15; 173 } 174 } 175 } 176 } 177 178 @Test 179 public void testLoop1() { 180 ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); 181 assertDeepEquals(6, schedule.getCFG().getBlocks().length); 182 assertReadWithinStartBlock(schedule, true); 183 assertReadWithinAllReturnBlocks(schedule, false); 184 } 185 186 /** 187 * Here the read should float to the end. 188 */ 189 public static int testLoop2Snippet(int a, int b) { 190 try { 191 return container.a; 192 } finally { 193 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a); i++) { 194 if (b < 0) { 195 container.b = 10; 196 } else { 197 container.c = 15; 198 } 199 } 200 } 201 } 202 203 @Test 204 public void testLoop2() { 205 ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); 206 assertDeepEquals(6, schedule.getCFG().getBlocks().length); 207 assertReadWithinStartBlock(schedule, false); 208 assertReadWithinAllReturnBlocks(schedule, true); 209 } 210 211 /** 212 * Here the read should float out of the loop. 213 */ 214 public static int testLoop3Snippet(int a) { 215 int j = 0; 216 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a); i++) { 217 if (i - container.a == 0) { 218 break; 219 } 220 j++; 221 } 222 return j; 223 } 224 225 @Test 226 public void testLoop3() { 227 ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES); 228 assertDeepEquals(6, schedule.getCFG().getBlocks().length); 229 assertReadWithinStartBlock(schedule, true); 230 assertReadWithinAllReturnBlocks(schedule, false); 231 } 232 233 public String testStringReplaceSnippet(String input) { 234 return input.replace('a', 'b'); 235 } 236 237 @Test 238 public void testStringReplace() { 239 getFinalSchedule("testStringReplaceSnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); 240 test("testStringReplaceSnippet", "acbaaa"); 241 } 242 243 /** 244 * Here the read should float out of the loop. 245 */ 246 public static int testLoop5Snippet(int a, int b, MemoryScheduleTest obj) { 247 int ret = 0; 248 int bb = b; 249 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a); i++) { 250 ret = obj.hash; 251 if (a > 10) { 252 bb++; 253 } else { 254 bb--; 255 } 256 ret = ret / 10; 257 } 258 return ret + bb; 259 } 260 261 @Test 262 public void testLoop5() { 263 ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES); 264 assertDeepEquals(10, schedule.getCFG().getBlocks().length); 265 assertReadWithinStartBlock(schedule, false); 266 assertReadWithinAllReturnBlocks(schedule, false); 267 } 268 269 /** 270 * Here the read should not float out of the loop. 271 */ 272 public static int testLoop6Snippet(int a, int b, MemoryScheduleTest obj) { 273 int ret = 0; 274 int bb = b; 275 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a); i++) { 276 ret = obj.hash; 277 if (a > 10) { 278 bb++; 279 } else { 280 bb--; 281 for (int j = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, j < b); ++j) { 282 obj.hash = 3; 283 } 284 } 285 ret = ret / 10; 286 } 287 return ret + bb; 288 } 289 290 @Test 291 public void testLoop6() { 292 ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES); 293 assertDeepEquals(13, schedule.getCFG().getBlocks().length); 294 assertReadWithinStartBlock(schedule, false); 295 assertReadWithinAllReturnBlocks(schedule, false); 296 } 297 298 /** 299 * Here the read should not float out of the loop. 300 */ 301 public static int testLoop7Snippet(int a, int b, MemoryScheduleTest obj) { 302 int ret = 0; 303 int bb = b; 304 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a); i++) { 305 ret = obj.hash; 306 if (a > 10) { 307 bb++; 308 } else { 309 bb--; 310 for (int k = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, k < a); ++k) { 311 if (k % 2 == 1) { 312 for (int j = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, j < b); ++j) { 313 obj.hash = 3; 314 } 315 } 316 } 317 } 318 ret = ret / 10; 319 } 320 return ret + bb; 321 } 322 323 @Test 324 public void testLoop7() { 325 ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES); 326 assertDeepEquals(18, schedule.getCFG().getBlocks().length); 327 assertReadWithinStartBlock(schedule, false); 328 assertReadWithinAllReturnBlocks(schedule, false); 329 } 330 331 /** 332 * Here the read should not float to the end. 333 */ 334 public static int testLoop8Snippet(int a, int b) { 335 int result = container.a; 336 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a); i++) { 337 if (b < 0) { 338 container.b = 10; 339 break; 340 } else { 341 for (int j = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, j < b); j++) { 342 container.a = 0; 343 } 344 } 345 } 346 GraalDirectives.controlFlowAnchor(); 347 return result; 348 } 349 350 @Test 351 public void testLoop8() { 352 ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES); 353 assertDeepEquals(10, schedule.getCFG().getBlocks().length); 354 assertReadWithinStartBlock(schedule, true); 355 assertReadWithinAllReturnBlocks(schedule, false); 356 } 357 358 /** 359 * Here the read should float after the loop. 360 */ 361 public static int testLoop9Snippet(int a, int b) { 362 container.a = b; 363 for (int i = 0; i < a; i++) { 364 container.a = i; 365 } 366 GraalDirectives.controlFlowAnchor(); 367 return container.a; 368 } 369 370 @Test 371 public void testLoop9() { 372 ScheduleResult schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES); 373 StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); 374 assertThat(graph.getNodes(ReturnNode.TYPE), hasCount(1)); 375 ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first(); 376 assertThat(ret.result(), instanceOf(FloatingReadNode.class)); 377 Block readBlock = schedule.getNodeToBlockMap().get(ret.result()); 378 Assert.assertEquals(0, readBlock.getLoopDepth()); 379 } 380 381 /** 382 * Here the read should not float to the end. 383 */ 384 public static int testIfRead1Snippet(int a) { 385 int res = container.a; 386 if (a < 0) { 387 container.a = 10; 388 } 389 return res; 390 } 391 392 @Test 393 public void testIfRead1() { 394 ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES); 395 assertDeepEquals(3, schedule.getCFG().getBlocks().length); 396 assertReadWithinStartBlock(schedule, true); 397 assertReadAndWriteInSameBlock(schedule, false); 398 } 399 400 /** 401 * Here the read should float in the else block. 402 */ 403 public static int testIfRead2Snippet(int a) { 404 int res = 0; 405 if (a < 0) { 406 container.a = 10; 407 } else { 408 res = container.a; 409 } 410 return res; 411 } 412 413 @Test 414 public void testIfRead2() { 415 ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES); 416 assertDeepEquals(3, schedule.getCFG().getBlocks().length); 417 assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count()); 418 assertReadWithinStartBlock(schedule, false); 419 assertReadWithinAllReturnBlocks(schedule, false); 420 assertReadAndWriteInSameBlock(schedule, false); 421 } 422 423 /** 424 * Here the read should float to the end, right before the write. 425 */ 426 public static int testIfRead3Snippet(int a) { 427 if (a < 0) { 428 container.a = 10; 429 } 430 int res = container.a; 431 container.a = 20; 432 return res; 433 } 434 435 @Test 436 public void testIfRead3() { 437 ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES); 438 assertDeepEquals(4, schedule.getCFG().getBlocks().length); 439 assertReadWithinStartBlock(schedule, false); 440 assertReadWithinAllReturnBlocks(schedule, true); 441 } 442 443 /** 444 * Here the read should be just in the if branch (with the write). 445 */ 446 public static int testIfRead4Snippet(int a) { 447 if (a > 0) { 448 int res = container.a; 449 container.a = 0x20; 450 return res; 451 } else { 452 return 0x10; 453 } 454 } 455 456 @Test 457 public void testIfRead4() { 458 ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES); 459 assertDeepEquals(3, schedule.getCFG().getBlocks().length); 460 assertReadWithinStartBlock(schedule, false); 461 assertReadWithinAllReturnBlocks(schedule, false); 462 assertReadAndWriteInSameBlock(schedule, true); 463 } 464 465 /** 466 * Here the read should float to the end. 467 */ 468 public static int testIfRead5Snippet(int a) { 469 if (a < 0) { 470 container.a = 10; 471 } 472 return container.a; 473 } 474 475 @Test 476 public void testIfRead5() { 477 ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES); 478 assertDeepEquals(4, schedule.getCFG().getBlocks().length); 479 assertReadWithinStartBlock(schedule, false); 480 assertReadWithinAllReturnBlocks(schedule, true); 481 assertReadAndWriteInSameBlock(schedule, false); 482 } 483 484 public static int testAntiDependencySnippet(int a) { 485 /* 486 * This read must not be scheduled after the following write. 487 */ 488 int res = container.a; 489 container.a = 10; 490 491 /* 492 * Add some more basic blocks. 493 */ 494 if (a < 0) { 495 container.b = 20; 496 } 497 container.c = 30; 498 return res; 499 } 500 501 @Test 502 public void testAntiDependency() { 503 ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES); 504 assertDeepEquals(4, schedule.getCFG().getBlocks().length); 505 assertReadBeforeAllWritesInStartBlock(schedule); 506 } 507 508 /** 509 * testing scheduling within a block. 510 */ 511 public static int testBlockScheduleSnippet() { 512 int res = 0; 513 container.a = 0x00; 514 container.a = 0x10; 515 container.a = 0x20; 516 container.a = 0x30; 517 container.a = 0x40; 518 res = container.a; 519 container.a = 0x50; 520 container.a = 0x60; 521 container.a = 0x70; 522 return res; 523 } 524 525 @Test 526 public void testBlockSchedule() { 527 ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES); 528 StructuredGraph graph = schedule.getCFG().graph; 529 NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class); 530 531 assertDeepEquals(1, schedule.getCFG().getBlocks().length); 532 assertDeepEquals(8, writeNodes.count()); 533 assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count()); 534 535 FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); 536 537 WriteNode[] writes = new WriteNode[8]; 538 int i = 0; 539 for (WriteNode n : writeNodes) { 540 writes[i] = n; 541 i++; 542 } 543 assertOrderedAfterSchedule(schedule, writes[4], read); 544 assertOrderedAfterSchedule(schedule, read, writes[5]); 545 for (int j = 0; j < 7; j++) { 546 assertOrderedAfterSchedule(schedule, writes[j], writes[j + 1]); 547 } 548 } 549 550 /** 551 * read should move inside the loop (out of loop is disabled). 552 */ 553 public static int testBlockSchedule2Snippet(int value) { 554 int res = 0; 555 556 container.a = value; 557 for (int i = 0; i < 100; i++) { 558 if (i == 10) { 559 return container.a; 560 } 561 res += i; 562 } 563 return res; 564 } 565 566 @Test 567 public void testBlockSchedule2() { 568 ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST); 569 assertReadWithinStartBlock(schedule, false); 570 assertReadWithinAllReturnBlocks(schedule, false); 571 assertReadAndWriteInSameBlock(schedule, false); 572 } 573 574 public static void testProxySnippet() { 575 while (container.a < container.b) { 576 List<Container> list = new ArrayList<>(containerList); 577 while (container.c < list.size()) { 578 if (container.obj != null) { 579 return; 580 } 581 container.c++; 582 } 583 container.a = 0; 584 container.b--; 585 } 586 container.b++; 587 } 588 589 @Test 590 public void testProxy() { 591 ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES); 592 assertReadWithinStartBlock(schedule, false); 593 assertReadWithinAllReturnBlocks(schedule, false); 594 } 595 596 private int hash = 0; 597 private final char[] value = new char[3]; 598 599 public int testStringHashCodeSnippet() { 600 int h = hash; 601 if (h == 0 && value.length > 0) { 602 char[] val = value; 603 604 for (int i = 0; i < value.length; i++) { 605 h = 31 * h + val[i]; 606 } 607 hash = h; 608 } 609 return h; 610 } 611 612 @Test 613 public void testStringHashCode() { 614 ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES); 615 assertReadWithinStartBlock(schedule, true); 616 assertReadWithinAllReturnBlocks(schedule, false); 617 618 hash = 0x1337; 619 value[0] = 'a'; 620 value[1] = 'b'; 621 value[2] = 'c'; 622 test("testStringHashCodeSnippet"); 623 } 624 625 public static int testLoop4Snippet(int count) { 626 int[] a = new int[count]; 627 628 for (int i = 0; GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < a.length); i++) { 629 a[i] = i; 630 } 631 632 int i = 0; 633 int iwrap = count - 1; 634 int sum = 0; 635 636 while (GraalDirectives.injectBranchProbability(LOOP_ENTRY_PROBABILITY, i < count)) { 637 sum += (a[i] + a[iwrap]) / 2; 638 iwrap = i; 639 i++; 640 } 641 return sum; 642 } 643 644 @Test 645 public void testLoop4() { 646 ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES); 647 assertReadWithinStartBlock(schedule, false); 648 assertReadWithinAllReturnBlocks(schedule, false); 649 } 650 651 private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) { 652 StructuredGraph graph = schedule.getCFG().graph; 653 assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty()); 654 655 int withRead = 0; 656 int returnBlocks = 0; 657 for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) { 658 Block block = schedule.getCFG().getNodeToBlock().get(returnNode); 659 for (Node node : schedule.getBlockToNodesMap().get(block)) { 660 if (node instanceof FloatingReadNode) { 661 withRead++; 662 break; 663 } 664 } 665 returnBlocks++; 666 } 667 assertDeepEquals(withRead == returnBlocks, withinReturnBlock); 668 } 669 670 private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) { 671 boolean readEncountered = false; 672 for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { 673 if (node instanceof FloatingReadNode) { 674 readEncountered = true; 675 } 676 } 677 assertDeepEquals(withinStartBlock, readEncountered); 678 } 679 680 private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) { 681 StructuredGraph graph = schedule.getCFG().graph; 682 FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); 683 WriteNode write = graph.getNodes().filter(WriteNode.class).first(); 684 assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write))); 685 } 686 687 private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) { 688 boolean writeNodeFound = false; 689 boolean readNodeFound = false; 690 for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) { 691 if (node instanceof FloatingReadNode) { 692 assertTrue(!writeNodeFound); 693 readNodeFound = true; 694 } else if (node instanceof WriteNode) { 695 writeNodeFound = true; 696 } 697 } 698 assertTrue(readNodeFound); 699 } 700 701 private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) { 702 return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS); 703 } 704 705 @SuppressWarnings("try") 706 private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) { 707 OptionValues options = new OptionValues(getInitialOptions(), OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false); 708 final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO, options); 709 try (Scope d = Debug.scope("FloatingReadTest", graph)) { 710 HighTierContext context = getDefaultHighTierContext(); 711 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); 712 canonicalizer.apply(graph, context); 713 if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { 714 new InliningPhase(canonicalizer).apply(graph, context); 715 } 716 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); 717 if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { 718 graph.clearAllStateAfter(); 719 } 720 Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates"); 721 722 new FloatingReadPhase().apply(graph); 723 new RemoveValueProxyPhase().apply(graph); 724 725 MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); 726 new GuardLoweringPhase().apply(graph, midContext); 727 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext); 728 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext); 729 730 SchedulePhase schedule = new SchedulePhase(schedulingStrategy); 731 schedule.apply(graph); 732 assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count()); 733 return graph.getLastSchedule(); 734 } catch (Throwable e) { 735 throw Debug.handle(e); 736 } 737 } 738 }