| /* |
| * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package org.graalvm.compiler.core.test; |
| |
| import static org.graalvm.compiler.core.common.GraalOptions.OptImplicitNullChecks; |
| import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops; |
| import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount; |
| import static org.hamcrest.core.IsInstanceOf.instanceOf; |
| import static org.junit.Assert.assertThat; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.junit.Assert; |
| import org.junit.Test; |
| |
| import org.graalvm.compiler.api.directives.GraalDirectives; |
| import org.graalvm.compiler.debug.Debug; |
| import org.graalvm.compiler.debug.Debug.Scope; |
| import org.graalvm.compiler.graph.Node; |
| import org.graalvm.compiler.graph.iterators.NodeIterable; |
| import org.graalvm.compiler.nodes.ReturnNode; |
| import org.graalvm.compiler.nodes.StartNode; |
| import org.graalvm.compiler.nodes.StructuredGraph; |
| import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; |
| import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; |
| import org.graalvm.compiler.nodes.cfg.Block; |
| import org.graalvm.compiler.nodes.memory.FloatingReadNode; |
| import org.graalvm.compiler.nodes.memory.WriteNode; |
| import org.graalvm.compiler.nodes.spi.LoweringTool; |
| import org.graalvm.compiler.options.OptionValue; |
| import org.graalvm.compiler.options.OptionValue.OverrideScope; |
| import org.graalvm.compiler.phases.OptimisticOptimizations; |
| import org.graalvm.compiler.phases.common.CanonicalizerPhase; |
| import org.graalvm.compiler.phases.common.FloatingReadPhase; |
| import org.graalvm.compiler.phases.common.GuardLoweringPhase; |
| import org.graalvm.compiler.phases.common.LoweringPhase; |
| import org.graalvm.compiler.phases.common.RemoveValueProxyPhase; |
| import org.graalvm.compiler.phases.common.inlining.InliningPhase; |
| import org.graalvm.compiler.phases.schedule.SchedulePhase; |
| import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; |
| import org.graalvm.compiler.phases.tiers.HighTierContext; |
| import org.graalvm.compiler.phases.tiers.MidTierContext; |
| |
| /** |
| * In these test the FrameStates are explicitly cleared out, so that the scheduling of |
| * FloatingReadNodes depends solely on the scheduling algorithm. The FrameStates normally keep the |
| * FloatingReadNodes above a certain point, so that they (most of the time...) magically do the |
| * right thing. |
| * |
| * The scheduling shouldn't depend on FrameStates, which is tested by this class. |
| */ |
| public class MemoryScheduleTest extends GraphScheduleTest { |
| |
| private enum TestMode { |
| WITH_FRAMESTATES, |
| WITHOUT_FRAMESTATES, |
| INLINED_WITHOUT_FRAMESTATES |
| } |
| |
| public static class Container { |
| |
| public int a; |
| public int b; |
| public int c; |
| |
| public Object obj; |
| } |
| |
| private static final Container container = new Container(); |
| private static final List<Container> containerList = new ArrayList<>(); |
| |
| /** |
| * In this test the read should be scheduled before the write. |
| */ |
| public static int testSimpleSnippet() { |
| try { |
| return container.a; |
| } finally { |
| container.a = 15; |
| } |
| } |
| |
| @Test |
| public void testSimple() { |
| for (TestMode mode : TestMode.values()) { |
| ScheduleResult schedule = getFinalSchedule("testSimpleSnippet", mode); |
| StructuredGraph graph = schedule.getCFG().graph; |
| assertReadAndWriteInSameBlock(schedule, true); |
| assertOrderedAfterSchedule(schedule, graph.getNodes().filter(FloatingReadNode.class).first(), graph.getNodes().filter(WriteNode.class).first()); |
| } |
| } |
| |
| /** |
| * In this case the read should be scheduled in the first block. |
| */ |
| public static int testSplit1Snippet(int a) { |
| try { |
| return container.a; |
| } finally { |
| if (a < 0) { |
| container.a = 15; |
| } else { |
| container.b = 15; |
| } |
| } |
| } |
| |
| @Test |
| public void testSplit1() { |
| for (TestMode mode : TestMode.values()) { |
| ScheduleResult schedule = getFinalSchedule("testSplit1Snippet", mode); |
| assertReadWithinStartBlock(schedule, true); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| } |
| |
| /** |
| * Here the read should float to the end. |
| */ |
| public static int testSplit2Snippet(int a) { |
| try { |
| return container.a; |
| } finally { |
| if (a < 0) { |
| container.c = 15; |
| } else { |
| container.b = 15; |
| } |
| container.obj = null; |
| } |
| } |
| |
| @Test |
| public void testSplit2() { |
| ScheduleResult schedule = getFinalSchedule("testSplit2Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, true); |
| } |
| |
| /** |
| * Here the read should not float to the end. |
| */ |
| public static int testLoop1Snippet(int a, int b) { |
| try { |
| return container.a; |
| } finally { |
| for (int i = 0; i < a; i++) { |
| if (b < 0) { |
| container.b = 10; |
| } else { |
| container.a = 15; |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testLoop1() { |
| ScheduleResult schedule = getFinalSchedule("testLoop1Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(6, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, true); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| /** |
| * Here the read should float to the end. |
| */ |
| public static int testLoop2Snippet(int a, int b) { |
| try { |
| return container.a; |
| } finally { |
| for (int i = 0; i < a; i++) { |
| if (b < 0) { |
| container.b = 10; |
| } else { |
| container.c = 15; |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testLoop2() { |
| ScheduleResult schedule = getFinalSchedule("testLoop2Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(6, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, true); |
| } |
| |
| /** |
| * Here the read should float out of the loop. |
| */ |
| public static int testLoop3Snippet(int a) { |
| int j = 0; |
| for (int i = 0; i < a; i++) { |
| if (i - container.a == 0) { |
| break; |
| } |
| j++; |
| } |
| return j; |
| } |
| |
| @Test |
| public void testLoop3() { |
| ScheduleResult schedule = getFinalSchedule("testLoop3Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(6, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, true); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| public String testStringReplaceSnippet(String input) { |
| return input.replace('a', 'b'); |
| } |
| |
| @Test |
| public void testStringReplace() { |
| getFinalSchedule("testStringReplaceSnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); |
| test("testStringReplaceSnippet", "acbaaa"); |
| } |
| |
| /** |
| * Here the read should float out of the loop. |
| */ |
| public static int testLoop5Snippet(int a, int b, MemoryScheduleTest obj) { |
| int ret = 0; |
| int bb = b; |
| for (int i = 0; i < a; i++) { |
| ret = obj.hash; |
| if (a > 10) { |
| bb++; |
| } else { |
| bb--; |
| } |
| ret = ret / 10; |
| } |
| return ret + bb; |
| } |
| |
| @Test |
| public void testLoop5() { |
| ScheduleResult schedule = getFinalSchedule("testLoop5Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(10, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| /** |
| * Here the read should not float out of the loop. |
| */ |
| public static int testLoop6Snippet(int a, int b, MemoryScheduleTest obj) { |
| int ret = 0; |
| int bb = b; |
| for (int i = 0; i < a; i++) { |
| ret = obj.hash; |
| if (a > 10) { |
| bb++; |
| } else { |
| bb--; |
| for (int j = 0; j < b; ++j) { |
| obj.hash = 3; |
| } |
| } |
| ret = ret / 10; |
| } |
| return ret + bb; |
| } |
| |
| @Test |
| public void testLoop6() { |
| ScheduleResult schedule = getFinalSchedule("testLoop6Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(13, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| /** |
| * Here the read should not float out of the loop. |
| */ |
| public static int testLoop7Snippet(int a, int b, MemoryScheduleTest obj) { |
| int ret = 0; |
| int bb = b; |
| for (int i = 0; i < a; i++) { |
| ret = obj.hash; |
| if (a > 10) { |
| bb++; |
| } else { |
| bb--; |
| for (int k = 0; k < a; ++k) { |
| if (k % 2 == 1) { |
| for (int j = 0; j < b; ++j) { |
| obj.hash = 3; |
| } |
| } |
| } |
| } |
| ret = ret / 10; |
| } |
| return ret + bb; |
| } |
| |
| @Test |
| public void testLoop7() { |
| ScheduleResult schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(18, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| /** |
| * Here the read should not float to the end. |
| */ |
| public static int testLoop8Snippet(int a, int b) { |
| int result = container.a; |
| for (int i = 0; i < a; i++) { |
| if (b < 0) { |
| container.b = 10; |
| break; |
| } else { |
| for (int j = 0; j < b; j++) { |
| container.a = 0; |
| } |
| } |
| } |
| GraalDirectives.controlFlowAnchor(); |
| return result; |
| } |
| |
| @Test |
| public void testLoop8() { |
| ScheduleResult schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(10, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, true); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| /** |
| * Here the read should float after the loop. |
| */ |
| public static int testLoop9Snippet(int a, int b) { |
| container.a = b; |
| for (int i = 0; i < a; i++) { |
| container.a = i; |
| } |
| GraalDirectives.controlFlowAnchor(); |
| return container.a; |
| } |
| |
| @Test |
| public void testLoop9() { |
| ScheduleResult schedule = getFinalSchedule("testLoop9Snippet", TestMode.WITHOUT_FRAMESTATES); |
| StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); |
| assertThat(graph.getNodes(ReturnNode.TYPE), hasCount(1)); |
| ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first(); |
| assertThat(ret.result(), instanceOf(FloatingReadNode.class)); |
| Block readBlock = schedule.getNodeToBlockMap().get(ret.result()); |
| Assert.assertEquals(0, readBlock.getLoopDepth()); |
| } |
| |
| /** |
| * Here the read should float to the end (into the same block as the return). |
| */ |
| public static int testArrayCopySnippet(Integer intValue, char[] a, char[] b, int len) { |
| System.arraycopy(a, 0, b, 0, len); |
| return intValue.intValue(); |
| } |
| |
| @Test |
| public void testArrayCopy() { |
| ScheduleResult schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES); |
| StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph(); |
| assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); |
| ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first(); |
| assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode); |
| assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result())); |
| assertReadWithinAllReturnBlocks(schedule, true); |
| } |
| |
| /** |
| * Here the read should not float to the end. |
| */ |
| public static int testIfRead1Snippet(int a) { |
| int res = container.a; |
| if (a < 0) { |
| container.a = 10; |
| } |
| return res; |
| } |
| |
| @Test |
| public void testIfRead1() { |
| ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(3, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, true); |
| assertReadAndWriteInSameBlock(schedule, false); |
| } |
| |
| /** |
| * Here the read should float in the else block. |
| */ |
| public static int testIfRead2Snippet(int a) { |
| int res = 0; |
| if (a < 0) { |
| container.a = 10; |
| } else { |
| res = container.a; |
| } |
| return res; |
| } |
| |
| @Test |
| public void testIfRead2() { |
| ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(3, schedule.getCFG().getBlocks().length); |
| assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count()); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| assertReadAndWriteInSameBlock(schedule, false); |
| } |
| |
| /** |
| * Here the read should float to the end, right before the write. |
| */ |
| public static int testIfRead3Snippet(int a) { |
| if (a < 0) { |
| container.a = 10; |
| } |
| int res = container.a; |
| container.a = 20; |
| return res; |
| } |
| |
| @Test |
| public void testIfRead3() { |
| ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(4, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, true); |
| } |
| |
| /** |
| * Here the read should be just in the if branch (with the write). |
| */ |
| public static int testIfRead4Snippet(int a) { |
| if (a > 0) { |
| int res = container.a; |
| container.a = 0x20; |
| return res; |
| } else { |
| return 0x10; |
| } |
| } |
| |
| @Test |
| public void testIfRead4() { |
| ScheduleResult schedule = getFinalSchedule("testIfRead4Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(3, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| assertReadAndWriteInSameBlock(schedule, true); |
| } |
| |
| /** |
| * Here the read should float to the end. |
| */ |
| public static int testIfRead5Snippet(int a) { |
| if (a < 0) { |
| container.a = 10; |
| } |
| return container.a; |
| } |
| |
| @Test |
| public void testIfRead5() { |
| ScheduleResult schedule = getFinalSchedule("testIfRead5Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(4, schedule.getCFG().getBlocks().length); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, true); |
| assertReadAndWriteInSameBlock(schedule, false); |
| } |
| |
| public static int testAntiDependencySnippet(int a) { |
| /* |
| * This read must not be scheduled after the following write. |
| */ |
| int res = container.a; |
| container.a = 10; |
| |
| /* |
| * Add some more basic blocks. |
| */ |
| if (a < 0) { |
| container.b = 20; |
| } |
| container.c = 30; |
| return res; |
| } |
| |
| @Test |
| public void testAntiDependency() { |
| ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES); |
| assertDeepEquals(4, schedule.getCFG().getBlocks().length); |
| assertReadBeforeAllWritesInStartBlock(schedule); |
| } |
| |
| /** |
| * testing scheduling within a block. |
| */ |
| public static int testBlockScheduleSnippet() { |
| int res = 0; |
| container.a = 0x00; |
| container.a = 0x10; |
| container.a = 0x20; |
| container.a = 0x30; |
| container.a = 0x40; |
| res = container.a; |
| container.a = 0x50; |
| container.a = 0x60; |
| container.a = 0x70; |
| return res; |
| } |
| |
| @Test |
| public void testBlockSchedule() { |
| ScheduleResult schedule = getFinalSchedule("testBlockScheduleSnippet", TestMode.WITHOUT_FRAMESTATES); |
| StructuredGraph graph = schedule.getCFG().graph; |
| NodeIterable<WriteNode> writeNodes = graph.getNodes().filter(WriteNode.class); |
| |
| assertDeepEquals(1, schedule.getCFG().getBlocks().length); |
| assertDeepEquals(8, writeNodes.count()); |
| assertDeepEquals(1, graph.getNodes().filter(FloatingReadNode.class).count()); |
| |
| FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); |
| |
| WriteNode[] writes = new WriteNode[8]; |
| int i = 0; |
| for (WriteNode n : writeNodes) { |
| writes[i] = n; |
| i++; |
| } |
| assertOrderedAfterSchedule(schedule, writes[4], read); |
| assertOrderedAfterSchedule(schedule, read, writes[5]); |
| for (int j = 0; j < 7; j++) { |
| assertOrderedAfterSchedule(schedule, writes[j], writes[j + 1]); |
| } |
| } |
| |
| /** |
| * read should move inside the loop (out of loop is disabled). |
| */ |
| public static int testBlockSchedule2Snippet(int value) { |
| int res = 0; |
| |
| container.a = value; |
| for (int i = 0; i < 100; i++) { |
| if (i == 10) { |
| return container.a; |
| } |
| res += i; |
| } |
| return res; |
| } |
| |
| @Test |
| public void testBlockSchedule2() { |
| ScheduleResult schedule = getFinalSchedule("testBlockSchedule2Snippet", TestMode.WITHOUT_FRAMESTATES, SchedulingStrategy.LATEST); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| assertReadAndWriteInSameBlock(schedule, false); |
| } |
| |
| public static void testProxySnippet() { |
| while (container.a < container.b) { |
| List<Container> list = new ArrayList<>(containerList); |
| while (container.c < list.size()) { |
| if (container.obj != null) { |
| return; |
| } |
| container.c++; |
| } |
| container.a = 0; |
| container.b--; |
| } |
| container.b++; |
| } |
| |
| @Test |
| public void testProxy() { |
| ScheduleResult schedule = getFinalSchedule("testProxySnippet", TestMode.WITHOUT_FRAMESTATES); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| private int hash = 0; |
| private final char[] value = new char[3]; |
| |
| public int testStringHashCodeSnippet() { |
| int h = hash; |
| if (h == 0 && value.length > 0) { |
| char[] val = value; |
| |
| for (int i = 0; i < value.length; i++) { |
| h = 31 * h + val[i]; |
| } |
| hash = h; |
| } |
| return h; |
| } |
| |
| @Test |
| public void testStringHashCode() { |
| ScheduleResult schedule = getFinalSchedule("testStringHashCodeSnippet", TestMode.WITHOUT_FRAMESTATES); |
| assertReadWithinStartBlock(schedule, true); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| |
| hash = 0x1337; |
| value[0] = 'a'; |
| value[1] = 'b'; |
| value[2] = 'c'; |
| test("testStringHashCodeSnippet"); |
| } |
| |
| public static int testLoop4Snippet(int count) { |
| int[] a = new int[count]; |
| |
| for (int i = 0; i < a.length; i++) { |
| a[i] = i; |
| } |
| |
| int i = 0; |
| int iwrap = count - 1; |
| int sum = 0; |
| |
| while (i < count) { |
| sum += (a[i] + a[iwrap]) / 2; |
| iwrap = i; |
| i++; |
| } |
| return sum; |
| } |
| |
| @Test |
| public void testLoop4() { |
| ScheduleResult schedule = getFinalSchedule("testLoop4Snippet", TestMode.WITHOUT_FRAMESTATES); |
| assertReadWithinStartBlock(schedule, false); |
| assertReadWithinAllReturnBlocks(schedule, false); |
| } |
| |
| private void assertReadWithinAllReturnBlocks(ScheduleResult schedule, boolean withinReturnBlock) { |
| StructuredGraph graph = schedule.getCFG().graph; |
| assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty()); |
| |
| int withRead = 0; |
| int returnBlocks = 0; |
| for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) { |
| Block block = schedule.getCFG().getNodeToBlock().get(returnNode); |
| for (Node node : schedule.getBlockToNodesMap().get(block)) { |
| if (node instanceof FloatingReadNode) { |
| withRead++; |
| break; |
| } |
| } |
| returnBlocks++; |
| } |
| assertDeepEquals(withRead == returnBlocks, withinReturnBlock); |
| } |
| |
| private void assertReadWithinStartBlock(ScheduleResult schedule, boolean withinStartBlock) { |
| boolean readEncountered = false; |
| for (Node node : schedule.getBlockToNodesMap().get(schedule.getCFG().getStartBlock())) { |
| if (node instanceof FloatingReadNode) { |
| readEncountered = true; |
| } |
| } |
| assertDeepEquals(withinStartBlock, readEncountered); |
| } |
| |
| private static void assertReadAndWriteInSameBlock(ScheduleResult schedule, boolean inSame) { |
| StructuredGraph graph = schedule.getCFG().graph; |
| FloatingReadNode read = graph.getNodes().filter(FloatingReadNode.class).first(); |
| WriteNode write = graph.getNodes().filter(WriteNode.class).first(); |
| assertTrue(!(inSame ^ schedule.getCFG().blockFor(read) == schedule.getCFG().blockFor(write))); |
| } |
| |
| private static void assertReadBeforeAllWritesInStartBlock(ScheduleResult schedule) { |
| boolean writeNodeFound = false; |
| boolean readNodeFound = false; |
| for (Node node : schedule.nodesFor(schedule.getCFG().getStartBlock())) { |
| if (node instanceof FloatingReadNode) { |
| assertTrue(!writeNodeFound); |
| readNodeFound = true; |
| } else if (node instanceof WriteNode) { |
| writeNodeFound = true; |
| } |
| } |
| assertTrue(readNodeFound); |
| } |
| |
| private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode) { |
| return getFinalSchedule(snippet, mode, SchedulingStrategy.LATEST_OUT_OF_LOOPS); |
| } |
| |
| @SuppressWarnings("try") |
| private ScheduleResult getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) { |
| final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); |
| try (Scope d = Debug.scope("FloatingReadTest", graph)) { |
| try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) { |
| HighTierContext context = getDefaultHighTierContext(); |
| CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); |
| canonicalizer.apply(graph, context); |
| if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { |
| new InliningPhase(canonicalizer).apply(graph, context); |
| } |
| new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); |
| if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { |
| graph.clearAllStateAfter(); |
| } |
| Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates"); |
| |
| new FloatingReadPhase().apply(graph); |
| new RemoveValueProxyPhase().apply(graph); |
| |
| MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo()); |
| new GuardLoweringPhase().apply(graph, midContext); |
| new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext); |
| new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext); |
| |
| SchedulePhase schedule = new SchedulePhase(schedulingStrategy); |
| schedule.apply(graph); |
| assertDeepEquals(1, graph.getNodes().filter(StartNode.class).count()); |
| return graph.getLastSchedule(); |
| } |
| } catch (Throwable e) { |
| throw Debug.handle(e); |
| } |
| } |
| } |