1 /*
   2  * Copyright (c) 2011, 2015, 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.OptionValue;
  52 import org.graalvm.compiler.options.OptionValue.OverrideScope;
  53 import org.graalvm.compiler.phases.OptimisticOptimizations;
  54 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
  55 import org.graalvm.compiler.phases.common.FloatingReadPhase;
  56 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
  57 import org.graalvm.compiler.phases.common.LoweringPhase;
  58 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
  59 import org.graalvm.compiler.phases.common.inlining.InliningPhase;
  60 import org.graalvm.compiler.phases.schedule.SchedulePhase;
  61 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
  62 import org.graalvm.compiler.phases.tiers.HighTierContext;
  63 import org.graalvm.compiler.phases.tiers.MidTierContext;
  64 
  65 /**
  66  * In these test the FrameStates are explicitly cleared out, so that the scheduling of
  67  * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the
  68  * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the
  69  * right thing.
  70  *
  71  * The scheduling shouldn't depend on FrameStates, which is tested by this class.
  72  */
  73 public class MemoryScheduleTest extends GraphScheduleTest {
  74 
  75     private enum TestMode {
  76         WITH_FRAMESTATES,
  77         WITHOUT_FRAMESTATES,
  78         INLINED_WITHOUT_FRAMESTATES
  79     }
  80 
  81     public static class Container {
  82 
  83         public int a;
  84         public int b;
  85         public int c;
  86 
  87         public Object obj;
  88     }
  89 
  90     private static final Container container = new Container();
  91     private static final List<Container> containerList = new ArrayList<>();
  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; 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; 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; 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; 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; i < a; i++) {
 276             ret = obj.hash;
 277             if (a > 10) {
 278                 bb++;
 279             } else {
 280                 bb--;
 281                 for (int j = 0; 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; i < a; i++) {
 305             ret = obj.hash;
 306             if (a > 10) {
 307                 bb++;
 308             } else {
 309                 bb--;
 310                 for (int k = 0; k < a; ++k) {
 311                     if (k % 2 == 1) {
 312                         for (int j = 0; 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; i < a; i++) {
 337             if (b < 0) {
 338                 container.b = 10;
 339                 break;
 340             } else {
 341                 for (int j = 0; 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 float to the end (into the same block as the return).
 383      */
 384     public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) {
 385         System.arraycopy(a, 0, b, 0, len);
 386         return intValue.intValue();
 387     }
 388 
 389     @Test
 390     public void testArrayCopy() {
 391         ScheduleResult schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
 392         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
 393         assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
 394         ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
 395         assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode);
 396         assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
 397         assertReadWithinAllReturnBlocks(schedule, true);
 398     }
 399 
 400     /**
 401      * Here the read should not float to the end.
 402      */
 403     public static int testIfRead1Snippet(int a) {
 404         int res = container.a;
 405         if (a < 0) {
 406             container.a = 10;
 407         }
 408         return res;
 409     }
 410 
 411     @Test
 412     public void testIfRead1() {
 413         ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES);
 414         assertDeepEquals(3, schedule.getCFG().getBlocks().length);
 415         assertReadWithinStartBlock(schedule, true);
 416         assertReadAndWriteInSameBlock(schedule, false);
 417     }
 418 
 419     /**
 420      * Here the read should float in the else block.
 421      */
 422     public static int testIfRead2Snippet(int a) {
 423         int res = 0;
 424         if (a < 0) {
 425             container.a = 10;
 426         } else {
 427             res = container.a;
 428         }
 429         return res;
 430     }
 431 
 432     @Test
 433     public void testIfRead2() {
 434         ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES);
 435         assertDeepEquals(3, schedule.getCFG().getBlocks().length);
 436         assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count());
 437         assertReadWithinStartBlock(schedule, false);
 438         assertReadWithinAllReturnBlocks(schedule, false);
 439         assertReadAndWriteInSameBlock(schedule, false);
 440     }
 441 
 442     /**
 443      * Here the read should float to the end, right before the write.
 444      */
 445     public static int testIfRead3Snippet(int a) {
 446         if (a < 0) {
 447             container.a = 10;
 448         }
 449         int res = container.a;
 450         container.a = 20;
 451         return res;
 452     }
 453 
 454     @Test
 455     public void testIfRead3() {
 456         ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES);
 457         assertDeepEquals(4, schedule.getCFG().getBlocks().length);
 458         assertReadWithinStartBlock(schedule, false);
 459         assertReadWithinAllReturnBlocks(schedule, true);
 460     }
 461 
 462     /**
 463      * Here the read should be just in the if branch (with the write).
 464      */
 465     public static int testIfRead4Snippet(int a) {
 466         if (a > 0) {
 467             int res = container.a;
 468             container.a = 0x20;
 469             return res;
 470         } else {
 471             return 0x10;
 472         }
 473     }
 474 
 475     @Test
 476     public void testIfRead4() {
 477         ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES);
 478         assertDeepEquals(3, schedule.getCFG().getBlocks().length);
 479         assertReadWithinStartBlock(schedule, false);
 480         assertReadWithinAllReturnBlocks(schedule, false);
 481         assertReadAndWriteInSameBlock(schedule, true);
 482     }
 483 
 484     /**
 485      * Here the read should float to the end.
 486      */
 487     public static int testIfRead5Snippet(int a) {
 488         if (a < 0) {
 489             container.a = 10;
 490         }
 491         return container.a;
 492     }
 493 
 494     @Test
 495     public void testIfRead5() {
 496         ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES);
 497         assertDeepEquals(4, schedule.getCFG().getBlocks().length);
 498         assertReadWithinStartBlock(schedule, false);
 499         assertReadWithinAllReturnBlocks(schedule, true);
 500         assertReadAndWriteInSameBlock(schedule, false);
 501     }
 502 
 503     public static int testAntiDependencySnippet(int a) {
 504         /*
 505          * This read must not be scheduled after the following write.
 506          */
 507         int res = container.a;
 508         container.a = 10;
 509 
 510         /*
 511          * Add some more basic blocks.
 512          */
 513         if (a < 0) {
 514             container.b = 20;
 515         }
 516         container.c = 30;
 517         return res;
 518     }
 519 
 520     @Test
 521     public void testAntiDependency() {
 522         ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES);
 523         assertDeepEquals(4, schedule.getCFG().getBlocks().length);
 524         assertReadBeforeAllWritesInStartBlock(schedule);
 525     }
 526 
 527     /**
 528      * testing scheduling within a block.
 529      */
 530     public static int testBlockScheduleSnippet() {
 531         int res = 0;
 532         container.a = 0x00;
 533         container.a = 0x10;
 534         container.a = 0x20;
 535         container.a = 0x30;
 536         container.a = 0x40;
 537         res = container.a;
 538         container.a = 0x50;
 539         container.a = 0x60;
 540         container.a = 0x70;
 541         return res;
 542     }
 543 
 544     @Test
 545     public void testBlockSchedule() {
 546         ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES);
 547         StructuredGraph graph = schedule.getCFG().graph;
 548         NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class);
 549 
 550         assertDeepEquals(1, schedule.getCFG().getBlocks().length);
 551         assertDeepEquals(8, writeNodes.count());
 552         assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count());
 553 
 554         FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
 555 
 556         WriteNode[] writes = new WriteNode[8];
 557         int i = 0;
 558         for (WriteNode n : writeNodes) {
 559             writes[i] = n;
 560             i++;
 561         }
 562         assertOrderedAfterSchedule(schedule, writes[4], read);
 563         assertOrderedAfterSchedule(schedule, read, writes[5]);
 564         for (int j = 0; j < 7; j++) {
 565             assertOrderedAfterSchedule(schedule, writes[j], writes[j + 1]);
 566         }
 567     }
 568 
 569     /**
 570      * read should move inside the loop (out of loop is disabled).
 571      */
 572     public static int testBlockSchedule2Snippet(int value) {
 573         int res = 0;
 574 
 575         container.a = value;
 576         for (int i = 0; i < 100; i++) {
 577             if (i == 10) {
 578                 return container.a;
 579             }
 580             res += i;
 581         }
 582         return res;
 583     }
 584 
 585     @Test
 586     public void testBlockSchedule2() {
 587         ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST);
 588         assertReadWithinStartBlock(schedule, false);
 589         assertReadWithinAllReturnBlocks(schedule, false);
 590         assertReadAndWriteInSameBlock(schedule, false);
 591     }
 592 
 593     public static void testProxySnippet() {
 594         while (container.a < container.b) {
 595             List<Container> list = new ArrayList<>(containerList);
 596             while (container.c < list.size()) {
 597                 if (container.obj != null) {
 598                     return;
 599                 }
 600                 container.c++;
 601             }
 602             container.a = 0;
 603             container.b--;
 604         }
 605         container.b++;
 606     }
 607 
 608     @Test
 609     public void testProxy() {
 610         ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES);
 611         assertReadWithinStartBlock(schedule, false);
 612         assertReadWithinAllReturnBlocks(schedule, false);
 613     }
 614 
 615     private int hash = 0;
 616     private final char[] value = new char[3];
 617 
 618     public int testStringHashCodeSnippet() {
 619         int h = hash;
 620         if (h == 0 && value.length > 0) {
 621             char[] val = value;
 622 
 623             for (int i = 0; i < value.length; i++) {
 624                 h = 31 * h + val[i];
 625             }
 626             hash = h;
 627         }
 628         return h;
 629     }
 630 
 631     @Test
 632     public void testStringHashCode() {
 633         ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES);
 634         assertReadWithinStartBlock(schedule, true);
 635         assertReadWithinAllReturnBlocks(schedule, false);
 636 
 637         hash = 0x1337;
 638         value[0] = 'a';
 639         value[1] = 'b';
 640         value[2] = 'c';
 641         test("testStringHashCodeSnippet");
 642     }
 643 
 644     public static int testLoop4Snippet(int count) {
 645         int[] a = new int[count];
 646 
 647         for (int i = 0; i < a.length; i++) {
 648             a[i] = i;
 649         }
 650 
 651         int i = 0;
 652         int iwrap = count - 1;
 653         int sum = 0;
 654 
 655         while (i < count) {
 656             sum += (a[i] + a[iwrap]) / 2;
 657             iwrap = i;
 658             i++;
 659         }
 660         return sum;
 661     }
 662 
 663     @Test
 664     public void testLoop4() {
 665         ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES);
 666         assertReadWithinStartBlock(schedule, false);
 667         assertReadWithinAllReturnBlocks(schedule, false);
 668     }
 669 
 670     private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) {
 671         StructuredGraph graph = schedule.getCFG().graph;
 672         assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty());
 673 
 674         int withRead = 0;
 675         int returnBlocks = 0;
 676         for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
 677             Block block = schedule.getCFG().getNodeToBlock().get(returnNode);
 678             for (Node node : schedule.getBlockToNodesMap().get(block)) {
 679                 if (node instanceof FloatingReadNode) {
 680                     withRead++;
 681                     break;
 682                 }
 683             }
 684             returnBlocks++;
 685         }
 686         assertDeepEquals(withRead == returnBlocks, withinReturnBlock);
 687     }
 688 
 689     private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) {
 690         boolean readEncountered = false;
 691         for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) {
 692             if (node instanceof FloatingReadNode) {
 693                 readEncountered = true;
 694             }
 695         }
 696         assertDeepEquals(withinStartBlock, readEncountered);
 697     }
 698 
 699     private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) {
 700         StructuredGraph graph = schedule.getCFG().graph;
 701         FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first();
 702         WriteNode write = graph.getNodes().filter(WriteNode.class).first();
 703         assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write)));
 704     }
 705 
 706     private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) {
 707         boolean writeNodeFound = false;
 708         boolean readNodeFound = false;
 709         for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) {
 710             if (node instanceof FloatingReadNode) {
 711                 assertTrue(!writeNodeFound);
 712                 readNodeFound = true;
 713             } else if (node instanceof WriteNode) {
 714                 writeNodeFound = true;
 715             }
 716         }
 717         assertTrue(readNodeFound);
 718     }
 719 
 720     private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) {
 721         return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS);
 722     }
 723 
 724     @SuppressWarnings("try")
 725     private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
 726         final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
 727         try (Scope d = Debug.scope("FloatingReadTest", graph)) {
 728             try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
 729                 HighTierContext context = getDefaultHighTierContext();
 730                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
 731                 canonicalizer.apply(graph, context);
 732                 if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
 733                     new InliningPhase(canonicalizer).apply(graph, context);
 734                 }
 735                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
 736                 if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
 737                     graph.clearAllStateAfter();
 738                 }
 739                 Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates");
 740 
 741                 new FloatingReadPhase().apply(graph);
 742                 new RemoveValueProxyPhase().apply(graph);
 743 
 744                 MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
 745                 new GuardLoweringPhase().apply(graph, midContext);
 746                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
 747                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext);
 748 
 749                 SchedulePhase schedule = new SchedulePhase(schedulingStrategy);
 750                 schedule.apply(graph);
 751                 assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count());
 752                 return graph.getLastSchedule();
 753             }
 754         } catch (Throwable e) {
 755             throw Debug.handle(e);
 756         }
 757     }
 758 }