@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().size()); 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]); } }
@Test public void testIfRead3() { ScheduleResult schedule = getFinalSchedule("testIfRead3Snippet", TestMode.WITHOUT_FRAMESTATES); assertDeepEquals(4, schedule.getCFG().getBlocks().size()); assertReadWithinStartBlock(schedule, false); assertReadWithinAllReturnBlocks(schedule, true); }
@Test public void testAntiDependency() { ScheduleResult schedule = getFinalSchedule("testAntiDependencySnippet", TestMode.WITHOUT_FRAMESTATES); assertDeepEquals(4, schedule.getCFG().getBlocks().size()); assertReadBeforeAllWritesInStartBlock(schedule); }
@Test public void testIfRead1() { ScheduleResult schedule = getFinalSchedule("testIfRead1Snippet", TestMode.WITHOUT_FRAMESTATES); assertDeepEquals(3, schedule.getCFG().getBlocks().size()); assertReadWithinStartBlock(schedule, true); assertReadAndWriteInSameBlock(schedule, false); }
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); }
@Test public void testIfRead2() { ScheduleResult schedule = getFinalSchedule("testIfRead2Snippet", TestMode.WITHOUT_FRAMESTATES); assertDeepEquals(3, schedule.getCFG().getBlocks().size()); assertDeepEquals(1, schedule.getCFG().graph.getNodes().filter(FloatingReadNode.class).count()); assertReadWithinStartBlock(schedule, false); assertReadWithinAllReturnBlocks(schedule, false); assertReadAndWriteInSameBlock(schedule, false); }
@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()); }
@Override public void run(StructuredGraph graph) { schedulePhase.apply(graph, false); schedule = graph.getLastSchedule(); schedule.getCFG().computePostdominators(); Block startBlock = schedule.getCFG().getStartBlock(); ProcessFrame rootFrame = new ProcessFrame(startBlock, graph.createNodeBitMap(), startBlock.getBeginNode(), null); LoweringPhase.processBlock(rootFrame); }
@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); }
@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()); } }
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); }
/** * Gets all usages of a floating, lowerable node that are unscheduled. * * <p>Given that the lowering of such nodes may introduce fixed nodes, they must be lowered in * the context of a usage that dominates all other usages. The fixed nodes resulting from * lowering are attached to the fixed node context of the dominating usage. This ensures the * post-lowering graph still has a valid schedule. * * @param node a {@link Lowerable} node */ private Collection<Node> getUnscheduledUsages(Node node) { List<Node> unscheduledUsages = new ArrayList<>(); if (node instanceof FloatingNode) { for (Node usage : node.usages()) { if (usage instanceof ValueNode) { if (schedule.getCFG().getNodeToBlock().isNew(usage) || schedule.getCFG().blockFor(usage) == null) { unscheduledUsages.add(usage); } } } } return unscheduledUsages; }
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); }
@Test public void testValueProxyInputs() { StructuredGraph graph = parseEager("testValueProxyInputsSnippet", AllowAssumptions.YES); for (FrameState fs : graph.getNodes().filter(FrameState.class).snapshot()) { fs.replaceAtUsages(null); GraphUtil.killWithUnusedFloatingInputs(fs); } SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST); schedulePhase.apply(graph); ScheduleResult schedule = graph.getLastSchedule(); NodeMap<Block> nodeToBlock = schedule.getCFG().getNodeToBlock(); assertTrue(graph.getNodes().filter(LoopExitNode.class).count() == 1); LoopExitNode loopExit = graph.getNodes().filter(LoopExitNode.class).first(); List<Node> list = schedule.nodesFor(nodeToBlock.get(loopExit)); for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) { if (!(node instanceof AddNode)) { assertTrue(node.toString(), nodeToBlock.get(node) == nodeToBlock.get(loopExit)); assertTrue( list.indexOf(node) + " < " + list.indexOf(loopExit) + ", " + node + ", " + loopExit, list.indexOf(node) < list.indexOf(loopExit)); } } }
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))); }
@SuppressWarnings("try") private AnchoringNode process( final Block b, final NodeBitMap activeGuards, final AnchoringNode startAnchor) { final LoweringToolImpl loweringTool = new LoweringToolImpl(context, startAnchor, activeGuards, b.getBeginNode()); // Lower the instructions of this block. List<Node> nodes = schedule.nodesFor(b); for (Node node : nodes) { if (node.isDeleted()) { // This case can happen when previous lowerings deleted nodes. continue; } // Cache the next node to be able to reconstruct the previous of the next node // after lowering. FixedNode nextNode = null; if (node instanceof FixedWithNextNode) { nextNode = ((FixedWithNextNode) node).next(); } else { nextNode = loweringTool.lastFixedNode().next(); } if (node instanceof Lowerable) { Collection<Node> unscheduledUsages = null; assert (unscheduledUsages = getUnscheduledUsages(node)) != null; Mark preLoweringMark = node.graph().getMark(); try (DebugCloseable s = node.graph().withNodeContext(node)) { ((Lowerable) node).lower(loweringTool); } if (loweringTool.guardAnchor.asNode().isDeleted()) { // TODO nextNode could be deleted but this is not currently supported assert nextNode.isAlive(); loweringTool.guardAnchor = AbstractBeginNode.prevBegin(nextNode); } assert checkPostNodeLowering(node, loweringTool, preLoweringMark, unscheduledUsages); } if (!nextNode.isAlive()) { // can happen when the rest of the block is killed by lowering // (e.g. by an unconditional deopt) break; } else { Node nextLastFixed = nextNode.predecessor(); if (!(nextLastFixed instanceof FixedWithNextNode)) { // insert begin node, to have a valid last fixed for next lowerable node. // This is about lowering a FixedWithNextNode to a control split while this // FixedWithNextNode is followed by some kind of BeginNode. // For example the when a FixedGuard followed by a loop exit is lowered to a // control-split + deopt. AbstractBeginNode begin = node.graph().add(new BeginNode()); nextLastFixed.replaceFirstSuccessor(nextNode, begin); begin.setNext(nextNode); nextLastFixed = begin; } loweringTool.setLastFixedNode((FixedWithNextNode) nextLastFixed); } } return loweringTool.getCurrentGuardAnchor(); }