# HG changeset patch # User Thomas Wuerthinger # Date 1426608964 -3600 # Node ID d15769a7e444435782f4eaeded9c8204cbb59e6c # Parent d66d53b6b73c882d84fb0af4722f9a0ac8b48fb2# Parent 706252994ee6a432ce0265c8755f2a1baa30f9a3 Merge. diff -r 706252994ee6 -r d15769a7e444 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Tue Mar 17 15:52:41 2015 +0100 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Tue Mar 17 17:16:04 2015 +0100 @@ -282,9 +282,42 @@ } /** + * 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() { + SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES); + assertDeepEquals(18, schedule.getCFG().getBlocks().size()); + assertReadWithinStartBlock(schedule, false); + assertReadWithinAllReturnBlocks(schedule, false); + } + + /** * Here the read should not float to the end. */ - public static int testLoop7Snippet(int a, int b) { + public static int testLoop8Snippet(int a, int b) { int result = container.a; for (int i = 0; i < a; i++) { if (b < 0) { @@ -301,8 +334,8 @@ } @Test - public void testLoop7() { - SchedulePhase schedule = getFinalSchedule("testLoop7Snippet", TestMode.WITHOUT_FRAMESTATES); + public void testLoop8() { + SchedulePhase schedule = getFinalSchedule("testLoop8Snippet", TestMode.WITHOUT_FRAMESTATES); assertDeepEquals(10, schedule.getCFG().getBlocks().size()); assertReadWithinStartBlock(schedule, true); assertReadWithinAllReturnBlocks(schedule, false); diff -r 706252994ee6 -r d15769a7e444 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest2.java Tue Mar 17 17:16:04 2015 +0100 @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2015, 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 com.oracle.graal.compiler.test; + +import java.util.*; + +import org.junit.*; + +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.DeoptimizingNode.DeoptDuring; +import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.nodes.calc.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.spi.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.schedule.*; +import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy; +import com.oracle.graal.phases.tiers.*; + +public class SchedulingTest2 extends GraphScheduleTest { + + public static int testSnippet() { + return test() + 2; + } + + public static int test() { + return 40; + } + + @Test + public void testValueProxyInputs() { + StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES); + ReturnNode returnNode = graph.getNodes(ReturnNode.TYPE).first(); + BeginNode beginNode = graph.add(new BeginNode()); + returnNode.replaceAtPredecessor(beginNode); + beginNode.setNext(returnNode); + Debug.dump(graph, "Graph"); + SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); + schedule.apply(graph); + BlockMap> blockToNodesMap = schedule.getBlockToNodesMap(); + NodeMap nodeToBlock = schedule.getNodeToBlockMap(); + assertDeepEquals(2, schedule.getCFG().getBlocks().size()); + for (BinaryArithmeticNode node : graph.getNodes().filter(BinaryArithmeticNode.class)) { + if (node instanceof AddNode) { + assertTrue(node.toString() + " expected: " + nodeToBlock.get(beginNode) + " but was: " + nodeToBlock.get(node), nodeToBlock.get(node) == nodeToBlock.get(beginNode)); + } + } + + for (FrameState fs : graph.getNodes(FrameState.TYPE)) { + Block block = nodeToBlock.get(fs); + assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock()); + for (Node usage : fs.usages()) { + if (usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) { + assertTrue(usage.toString(), nodeToBlock.get(usage) == block); + if (usage != block.getBeginNode()) { + List map = blockToNodesMap.get(block); + assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage)); + } + } + } + } + + PhaseContext context = new PhaseContext(getProviders()); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context); + new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, context); + MidTierContext midContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null); + + new GuardLoweringPhase().apply(graph, midContext); + FrameStateAssignmentPhase phase = new FrameStateAssignmentPhase(); + phase.apply(graph); + + schedule = new SchedulePhase(SchedulingStrategy.EARLIEST); + schedule.apply(graph); + blockToNodesMap = schedule.getBlockToNodesMap(); + nodeToBlock = schedule.getNodeToBlockMap(); + for (FrameState fs : graph.getNodes(FrameState.TYPE)) { + Block block = nodeToBlock.get(fs); + assertTrue(fs.toString(), block == schedule.getCFG().getStartBlock()); + for (Node usage : fs.usages()) { + if ((usage instanceof StateSplit && ((StateSplit) usage).stateAfter() == fs) || (usage instanceof DeoptDuring && ((DeoptDuring) usage).stateDuring() == fs)) { + assertTrue(usage.toString(), nodeToBlock.get(usage) == block); + if (usage != block.getBeginNode()) { + List map = blockToNodesMap.get(block); + assertTrue(map.indexOf(fs) + " < " + map.indexOf(usage), map.indexOf(fs) < map.indexOf(usage)); + } + } + } + } + } +} diff -r 706252994ee6 -r d15769a7e444 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Mar 17 15:52:41 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Mar 17 17:16:04 2015 +0100 @@ -237,15 +237,21 @@ if (this.killLocationsBetweenThisAndDominator == null) { LocationSet dominatorResult = new LocationSet(); Block stopBlock = getDominator(); - for (Block b : this.getPredecessors()) { - if (b != stopBlock && (!this.isLoopHeader() || b.getLoopDepth() < this.getLoopDepth())) { - dominatorResult.addAll(b.getKillLocations()); - if (dominatorResult.isAny()) { - break; - } - b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock); - if (dominatorResult.isAny()) { - break; + if (this.isLoopHeader()) { + assert stopBlock.getLoopDepth() < this.getLoopDepth(); + dominatorResult.addAll(((HIRLoop) this.getLoop()).getKillLocations()); + } else { + for (Block b : this.getPredecessors()) { + assert !this.isLoopHeader(); + if (b != stopBlock) { + dominatorResult.addAll(b.getKillLocations()); + if (dominatorResult.isAny()) { + break; + } + b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock); + if (dominatorResult.isAny()) { + break; + } } } } diff -r 706252994ee6 -r d15769a7e444 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java Tue Mar 17 15:52:41 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java Tue Mar 17 17:16:04 2015 +0100 @@ -39,7 +39,7 @@ return ((LoopBeginNode) getHeader().getBeginNode()).loopEnds().count(); } - private LocationSet getKillLocations() { + public LocationSet getKillLocations() { if (killLocations == null) { killLocations = new LocationSet(); for (Block b : this.getBlocks()) { diff -r 706252994ee6 -r d15769a7e444 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java Tue Mar 17 17:16:04 2015 +0100 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2015, 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 com.oracle.graal.phases.schedule; + +import java.util.*; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.graph.Node; +import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.cfg.*; +import com.oracle.graal.nodes.extended.*; +import com.oracle.graal.phases.graph.*; +import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure; + +public final class MemoryScheduleVerification extends BlockIteratorClosure> { + + private final BlockMap> blockToNodesMap; + + public static boolean check(Block startBlock, BlockMap> blockToNodesMap) { + ReentrantBlockIterator.apply(new MemoryScheduleVerification(blockToNodesMap), startBlock); + return true; + } + + private MemoryScheduleVerification(BlockMap> blockToNodesMap) { + this.blockToNodesMap = blockToNodesMap; + } + + @Override + protected Set getInitialState() { + return CollectionsFactory.newSet(); + } + + @Override + protected Set processBlock(Block block, Set currentState) { + for (Node n : blockToNodesMap.get(block)) { + if (n instanceof AbstractMergeNode) { + AbstractMergeNode abstractMergeNode = (AbstractMergeNode) n; + for (PhiNode phi : abstractMergeNode.phis()) { + if (phi instanceof MemoryPhiNode) { + MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi; + addFloatingReadUsages(currentState, memoryPhiNode); + } + } + + } + + if (n instanceof MemoryCheckpoint) { + if (n instanceof MemoryCheckpoint.Single) { + MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n; + processLocation(n, single.getLocationIdentity(), currentState); + } else if (n instanceof MemoryCheckpoint.Multi) { + MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n; + for (LocationIdentity location : multi.getLocationIdentities()) { + processLocation(n, location, currentState); + } + } + + addFloatingReadUsages(currentState, n); + } else if (n instanceof FloatingReadNode) { + FloatingReadNode floatingReadNode = (FloatingReadNode) n; + if (floatingReadNode.getLastLocationAccess() != null && floatingReadNode.getLocationIdentity().isMutable()) { + if (currentState.contains(floatingReadNode)) { + // Floating read was found in the state. + currentState.remove(floatingReadNode); + } else { + throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule"); + } + } + + } + } + return currentState; + } + + private static void addFloatingReadUsages(Set currentState, Node n) { + for (FloatingReadNode read : n.usages().filter(FloatingReadNode.class)) { + if (read.getLastLocationAccess() == n && read.getLocationIdentity().isMutable()) { + currentState.add(read); + } + } + } + + private void processLocation(Node n, LocationIdentity location, Set currentState) { + assert n != null; + if (location.isImmutable()) { + return; + } + + for (FloatingReadNode r : cloneState(currentState)) { + if (r.getLocationIdentity().overlaps(location)) { + // This read is killed by this location. + currentState.remove(r); + } + } + } + + @Override + protected Set merge(Block merge, List> states) { + Set result = states.get(0); + for (int i = 1; i < states.size(); ++i) { + result.retainAll(states.get(i)); + } + return result; + } + + @Override + protected Set cloneState(Set oldState) { + Set result = CollectionsFactory.newSet(); + result.addAll(oldState); + return result; + } + + @Override + protected List> processLoop(Loop loop, Set initialState) { + HIRLoop l = (HIRLoop) loop; + for (MemoryPhiNode memoryPhi : ((LoopBeginNode) l.getHeader().getBeginNode()).phis().filter(MemoryPhiNode.class)) { + for (FloatingReadNode r : cloneState(initialState)) { + if (r.getLocationIdentity().overlaps(memoryPhi.getLocationIdentity())) { + initialState.remove(r); + } + } + } + return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates; + } +} diff -r 706252994ee6 -r d15769a7e444 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Mar 17 15:52:41 2015 +0100 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Mar 17 17:16:04 2015 +0100 @@ -94,6 +94,7 @@ cfg = ControlFlowGraph.compute(graph, true, true, true, false); if (selectedStrategy == SchedulingStrategy.EARLIEST) { + // Assign early so we are getting a context in case of an exception. this.nodeToBlockMap = graph.createNodeMap(); this.blockToNodesMap = new BlockMap<>(cfg); NodeBitMap visited = graph.createNodeBitMap(); @@ -105,6 +106,11 @@ NodeMap currentNodeMap = graph.createNodeMap(); BlockMap> earliestBlockToNodesMap = new BlockMap<>(cfg); NodeBitMap visited = graph.createNodeBitMap(); + + // Assign early so we are getting a context in case of an exception. + this.blockToNodesMap = earliestBlockToNodesMap; + this.nodeToBlockMap = currentNodeMap; + scheduleEarliestIterative(cfg, earliestBlockToNodesMap, currentNodeMap, visited, graph); BlockMap> latestBlockToNodesMap = new BlockMap<>(cfg); @@ -115,10 +121,12 @@ BlockMap> watchListMap = calcLatestBlocks(isOutOfLoops, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap); sortNodesLatestWithinBlock(cfg, earliestBlockToNodesMap, latestBlockToNodesMap, currentNodeMap, watchListMap, visited); + assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap); + assert MemoryScheduleVerification.check(cfg.getStartBlock(), latestBlockToNodesMap); + this.blockToNodesMap = latestBlockToNodesMap; this.nodeToBlockMap = currentNodeMap; - assert verifySchedule(cfg, latestBlockToNodesMap, currentNodeMap); cfg.setNodeToBlock(currentNodeMap); } } @@ -165,7 +173,7 @@ // We are not constraint within currentBlock. Check if // we are contraint while walking down the dominator // line. - Block newLatestBlock = adjustLatestForRead(currentBlock, latestBlock, location); + Block newLatestBlock = adjustLatestForRead(floatingReadNode, currentBlock, latestBlock, location); assert dominates(newLatestBlock, latestBlock); assert dominates(currentBlock, newLatestBlock); latestBlock = newLatestBlock; @@ -203,7 +211,7 @@ return true; } - private static Block adjustLatestForRead(Block earliestBlock, Block latestBlock, LocationIdentity location) { + private static Block adjustLatestForRead(FloatingReadNode floatingReadNode, Block earliestBlock, Block latestBlock, LocationIdentity location) { assert strictlyDominates(earliestBlock, latestBlock); Block current = latestBlock.getDominator(); @@ -218,6 +226,7 @@ } dominatorChain.add(current); current = current.getDominator(); + assert current != null : floatingReadNode; } // The first element of dominatorChain now contains the latest possible block. @@ -537,6 +546,8 @@ } } } + + assert MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes); } private static void resortEarliestWithinBlock(Block b, BlockMap> blockToNodes, NodeMap nodeToBlock, NodeBitMap unprocessed) { @@ -550,7 +561,7 @@ MemoryNode lastLocationAccess = floatingReadNode.getLastLocationAccess(); if (locationIdentity.isMutable() && lastLocationAccess != null) { ValueNode lastAccessLocation = lastLocationAccess.asNode(); - if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode) { + if (nodeToBlock.get(lastAccessLocation) == b && lastAccessLocation != beginNode && !(lastAccessLocation instanceof MemoryPhiNode)) { // This node's last access location is within this block. Add to watch list // when processing the last access location. } else { @@ -650,16 +661,22 @@ assert current.predecessor() == null && !(current instanceof FixedNode) : "The assignment of blocks to fixed nodes is already done when constructing the cfg."; Block earliest = startBlock; for (Node input : current.inputs()) { - Block inputEarliest; - if (input instanceof ControlSplitNode) { - inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor()); - } else { - inputEarliest = nodeToBlock.get(input); - } + Block inputEarliest = nodeToBlock.get(input); if (inputEarliest == null) { assert current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current; } else { assert inputEarliest != null; + if (inputEarliest.getEndNode() == input) { + // This is the last node of the block. + if (current instanceof FrameState && input instanceof StateSplit && ((StateSplit) input).stateAfter() == current) { + // Keep regular inputEarliest. + } else if (input instanceof ControlSplitNode) { + inputEarliest = nodeToBlock.get(((ControlSplitNode) input).getPrimarySuccessor()); + } else { + assert inputEarliest.getSuccessorCount() == 1; + inputEarliest = inputEarliest.getSuccessors().get(0); + } + } if (earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) { earliest = inputEarliest; } diff -r 706252994ee6 -r d15769a7e444 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Tue Mar 17 15:52:41 2015 +0100 +++ b/src/share/vm/compiler/compileBroker.cpp Tue Mar 17 17:16:04 2015 +0100 @@ -801,12 +801,6 @@ GraalCompiler* graal = new GraalCompiler(); #endif -#ifdef COMPILER1 - if (c1_count > 0) { - _compilers[0] = new Compiler(); - } -#endif // COMPILER1 - #if defined(COMPILERGRAAL) _compilers[1] = graal; if (FLAG_IS_DEFAULT(GraalThreads)) { @@ -817,8 +811,18 @@ } else { c2_count = GraalThreads; } + if (FLAG_IS_DEFAULT(GraalHostThreads)) { + } else { + c1_count = GraalHostThreads; + } #endif // COMPILERGRAAL +#ifdef COMPILER1 + if (c1_count > 0) { + _compilers[0] = new Compiler(); + } +#endif // COMPILER1 + #ifdef COMPILER2 if (c2_count > 0) { _compilers[1] = new C2Compiler(); diff -r 706252994ee6 -r d15769a7e444 src/share/vm/graal/graalGlobals.hpp --- a/src/share/vm/graal/graalGlobals.hpp Tue Mar 17 15:52:41 2015 +0100 +++ b/src/share/vm/graal/graalGlobals.hpp Tue Mar 17 17:16:04 2015 +0100 @@ -61,6 +61,9 @@ COMPILERGRAAL_PRESENT(product(intx, GraalThreads, 1, \ "Force number of Graal compiler threads to use")) \ \ + COMPILERGRAAL_PRESENT(product(intx, GraalHostThreads, 1, \ + "Force number of compiler threads for Graal host compiler")) \ + \ GRAAL_ONLY(product(bool, CodeInstallSafepointChecks, true, \ "Perform explicit safepoint checks while installing code")) \ \