# HG changeset patch # User Doug Simon # Date 1397581628 -7200 # Node ID bd5471cdc3e1ef60db1aeea61e904651cbe505b0 # Parent e3491381c424d5e456311059b45af4c428e978e6# Parent 2082889fc8f6e78ecbb463d7edf95788ee4163b8 Merge. diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java --- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Tue Apr 15 19:07:08 2014 +0200 @@ -34,12 +34,12 @@ * with the most likely path that was left out during this process. The process iteratively * continues until all blocks are scheduled. Additionally, it is guaranteed that all blocks of a * loop are scheduled before any block following the loop is scheduled. - * + * * The machine code generator order includes reordering of loop headers such that the backward jump * is a conditional jump if there is only one loop end block. Additionally, the target of loop * backward jumps are always marked as aligned. Aligning the target of conditional jumps does not * bring a measurable benefit and is therefore avoided to keep the code size small. - * + * * The linear scan register allocator order has an additional mechanism that prevents merge nodes * from being scheduled if there is at least one highly likely predecessor still unscheduled. This * increases the probability that the merge node and the corresponding predecessor are more closely @@ -63,7 +63,7 @@ /** * Computes the block order used for the linear scan register allocator. - * + * * @return sorted list of blocks */ public static > List computeLinearScanOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) { @@ -77,7 +77,7 @@ /** * Computes the block order used for code emission. - * + * * @return sorted list of blocks */ public static > List computeCodeEmittingOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) { @@ -151,7 +151,6 @@ /** * Add a linear path to the code emission order greedily following the most likely successor. */ - @SuppressWarnings("unchecked") private static > void addPathToCodeEmittingOrder(T initialBlock, List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) { T block = initialBlock; while (block != null) { @@ -166,17 +165,17 @@ addBlock(block, order); } - Loop loop = block.getLoop(); + Loop loop = block.getLoop(); if (block.isLoopEnd() && skipLoopHeader(loop.header)) { // This is the only loop end of a skipped loop header. // Add the header immediately afterwards. - addBlock((T) loop.header, order); + addBlock(loop.header, order); // Make sure the loop successors of the loop header are aligned // as they are the target // of the backward jump. - for (Block successor : loop.header.getSuccessors()) { + for (T successor : loop.header.getSuccessors()) { if (successor.getLoopDepth() == block.getLoopDepth()) { successor.setAlign(true); } @@ -230,8 +229,8 @@ * Skip the loop header block if the loop consists of more than one block and it has only a * single loop end block. */ - private static boolean skipLoopHeader(AbstractBlock block) { - return (block.isLoopHeader() && !block.isLoopEnd() && block.getLoop().loopBegin().loopEnds().count() == 1); + private static > boolean skipLoopHeader(AbstractBlock block) { + return (block.isLoopHeader() && !block.isLoopEnd() && block.getLoop().numBackedges() == 1); } /** diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Tue Apr 15 19:07:08 2014 +0200 @@ -121,7 +121,7 @@ // add loops ? how do we add looks when we haven't parsed the bytecode? // create the control flow graph - LIRControlFlowGraph cfg = new LIRControlFlowGraph(blockMap.blocks.toArray(new BciBlock[0]), new Loop[0]); + LIRControlFlowGraph cfg = new LIRControlFlowGraph(blockMap); BlocksToDoubles blockProbabilities = new BlocksToDoubles(blockMap.blocks.size()); for (BciBlock b : blockMap.blocks) { @@ -261,8 +261,7 @@ @Override protected Value genIntegerMul(Kind kind, Value x, Value y) { - // TODO Auto-generated method stub - throw GraalInternalError.unimplemented("Auto-generated method stub"); + return gen.emitMul(x, y); } @Override @@ -584,9 +583,9 @@ return v; } - private void createTarget(BciBlock block, LIRFrameStateBuilder state) { - assert block != null && state != null; - assert !block.isExceptionEntry || state.stackSize() == 1; + private void createTarget(BciBlock block) { + assert block != null && frameState != null; + assert !block.isExceptionEntry || frameState.stackSize() == 1; if (!blockVisited.get(block)) { /* @@ -594,7 +593,14 @@ * placeholder that later can be replaced with a MergeNode when we see this block again. */ blockVisited.set(block); - block.entryState = state.copy(); + if (block.getPredecessorCount() > 1) { + /* + * If there are more than one predecessors we have to ensure that we are not passing + * constants to the new framestate otherwise we will get interfacing problems. + */ + moveConstantsToVariables(); + } + block.entryState = frameState.copy(); block.entryState.clearNonLiveLocals(block, liveness, true); Debug.log("createTarget %s: first visit", block); @@ -602,12 +608,17 @@ } // We already saw this block before, so we have to merge states. - if (!((LIRFrameStateBuilder) block.entryState).isCompatibleWith(state)) { + if (!((LIRFrameStateBuilder) block.entryState).isCompatibleWith(frameState)) { throw new BailoutException("stacks do not match; bytecodes would not verify"); } if (block.isLoopHeader) { - assert currentBlock.getId() >= block.getId() : "must be backward branch"; + assert currentBlock == null || currentBlock.getId() >= block.getId() : "must be backward branch"; + if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) { + // this is the only successor of the current block so we can adjust + adaptFramestate((LIRFrameStateBuilder) block.entryState); + return; + } GraalInternalError.unimplemented("Loops not yet supported"); } assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch"; @@ -629,6 +640,29 @@ Debug.log("createTarget %s: merging state", block); } + private void moveConstantsToVariables() { + Debug.log("moveConstantsToVariables: framestate before: %s", frameState); + for (int i = 0; i < frameState.stackSize(); i++) { + Value src = frameState.stackAt(i); + if (src instanceof Constant) { + AllocatableValue dst = gen.newVariable(src.getPlatformKind()); + gen.emitMove(dst, src); + frameState.storeStack(i, dst); + Debug.log("introduce new variabe %s for stackslot %d (end of block %s", dst, i, currentBlock); + } + } + for (int i = 0; i < frameState.localsSize(); i++) { + Value src = frameState.localAt(i); + if (src instanceof Constant) { + AllocatableValue dst = gen.newVariable(src.getPlatformKind()); + gen.emitMove(dst, src); + frameState.storeLocal(i, dst); + Debug.log("introduce new variabe %s for local %d (end of block %s", dst, i, currentBlock); + } + } + Debug.log("moveConstantsToVariables: framestate after: %s", frameState); + } + private void adaptValues(Value dst, Value src) { if (dst == null) { return; @@ -636,7 +670,7 @@ assert src != null : "Source is null but Destination is not!"; if (!dst.equals(src)) { - assert dst instanceof AllocatableValue; + assert dst instanceof AllocatableValue : "Not an AllocatableValue: " + dst; gen.emitMove((AllocatableValue) dst, src); } } @@ -725,7 +759,7 @@ } LabelRef getSuccessor(int index) { - createTarget(currentBlock.getSuccessor(index), frameState); + createTarget(currentBlock.getSuccessor(index)); return LabelRef.forSuccessor(lirGenRes.getLIR(), currentBlock, index); } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRBlock.java Tue Apr 15 19:07:08 2014 +0200 @@ -34,7 +34,7 @@ successors = Collections.emptyList(); } - public Loop getLoop() { + public Loop getLoop() { // TODO Auto-generated method stub return null; } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRControlFlowGraph.java Tue Apr 15 19:07:08 2014 +0200 @@ -22,24 +22,30 @@ */ package com.oracle.graal.baseline; +import java.util.*; + +import com.oracle.graal.graph.*; +import com.oracle.graal.java.*; import com.oracle.graal.java.BciBlockMapping.BciBlock; import com.oracle.graal.nodes.cfg.*; public class LIRControlFlowGraph implements AbstractControlFlowGraph { private BciBlock[] blocks; - private Loop[] loops; + private Collection> loops; + private BitSet visited; - public LIRControlFlowGraph(BciBlock[] blocks, Loop[] loops) { - this.blocks = blocks; - this.loops = loops; + public LIRControlFlowGraph(BciBlockMapping blockMap) { + blocks = blockMap.blocks.toArray(new BciBlock[0]); + loops = new ArrayList<>(); + computeLoopInformation(); } public BciBlock[] getBlocks() { return blocks; } - public Loop[] getLoops() { + public Collection> getLoops() { return loops; } @@ -50,4 +56,44 @@ return null; } + private void computeLoopInformation() { + visited = new BitSet(blocks.length); + Deque stack = new ArrayDeque<>(); + for (int i = blocks.length - 1; i >= 0; i--) { + BciBlock block = blocks[i]; + calcLoop(block, stack); + } + } + + private void calcLoop(BciBlock block, Deque stack) { + if (visited.get(block.getId())) { + return; + } + visited.set(block.getId()); + if (block.isLoopEnd()) { + BciBlock loopHeader = getLoopHeader(block); + LIRLoop l = new LIRLoop(stack.peek(), loops.size(), loopHeader); + loops.add(l); + stack.push(l); + } + block.loop = stack.peek(); + if (block.isLoopHeader()) { + assert block.loop.header.equals(block); + stack.pop(); + } + for (BciBlock pred : block.getPredecessors()) { + calcLoop(pred, stack); + } + } + + private static BciBlock getLoopHeader(BciBlock block) { + assert block.isLoopEnd(); + for (BciBlock sux : block.getSuccessors()) { + if (sux.isLoopHeader() && sux.getId() <= block.getId() && block.loops == sux.loops) { + return sux; + } + } + throw GraalInternalError.shouldNotReachHere("No loop header found for " + block); + } + } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRLoop.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/LIRLoop.java Tue Apr 15 19:07:08 2014 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014, 2014, 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.baseline; + +import com.oracle.graal.java.BciBlockMapping.BciBlock; +import com.oracle.graal.nodes.cfg.*; + +public class LIRLoop extends Loop { + + protected LIRLoop(Loop parent, int index, BciBlock header) { + super(parent, index, header); + } + + @Override + public long numBackedges() { + // currently only loops with one backedge are supported + return 1; + } + +} diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java Tue Apr 15 19:07:08 2014 +0200 @@ -148,10 +148,10 @@ Debug.dump(graph, "Graph"); ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); - Assert.assertTrue(cfg.getLoops().length == 3); - Loop rootLoop = cfg.getLoops()[0]; - Loop nestedLoop = cfg.getLoops()[1]; - Loop innerMostLoop = cfg.getLoops()[2]; + Assert.assertTrue(cfg.getLoops().size() == 3); + Loop rootLoop = cfg.getLoops().get(0); + Loop nestedLoop = cfg.getLoops().get(1); + Loop innerMostLoop = cfg.getLoops().get(2); Invoke a = getInvoke("a", graph); Invoke b = getInvoke("b", graph); Invoke c = getInvoke("c", graph); @@ -168,14 +168,14 @@ Debug.dump(graph, "Graph"); } - private static boolean contains(Loop loop, Invoke node, ControlFlowGraph cfg) { + private static boolean contains(Loop loop, Invoke node, ControlFlowGraph cfg) { Block block = cfg.blockFor((Node) node); Assert.assertNotNull(block); return loop.blocks.contains(block); } - private static boolean containsDirect(Loop loop, Invoke node, ControlFlowGraph cfg) { - for (Loop child : loop.children) { + private static boolean containsDirect(Loop loop, Invoke node, ControlFlowGraph cfg) { + for (Loop child : loop.children) { if (contains(child, node, cfg)) { return false; } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Tue Apr 15 19:07:08 2014 +0200 @@ -335,7 +335,7 @@ } int numLoops() { - return ir.getControlFlowGraph().getLoops().length; + return ir.getControlFlowGraph().getLoops().size(); } boolean isIntervalInLoop(int interval, int loop) { diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java --- a/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java Tue Apr 15 19:07:08 2014 +0200 @@ -46,7 +46,7 @@ cfgBlocks.remove(0); if (firstBlock.isLoopHeader()) { DecompilerLoopBlock loopBlock = new DecompilerLoopBlock(firstBlock, decompiler, decompiler.getSchedule(), infoStream); - Loop loop = firstBlock.getLoop(); + Loop loop = firstBlock.getLoop(); for (int i = 0; i < cfgBlocks.size(); i++) { if (loop.blocks.contains(cfgBlocks.get(i)) && cfgBlocks.get(i) != firstBlock) { diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Tue Apr 15 19:07:08 2014 +0200 @@ -82,6 +82,12 @@ public boolean isLoopHeader; public int loopId; + /** + * XXX to be removed - currently only used by baseline compiler + */ + public Loop loop; + public boolean isLoopEnd; + public FixedWithNextNode firstInstruction; public AbstractFrameStateBuilder entryState; @@ -144,14 +150,12 @@ return sb.toString(); } - public Loop getLoop() { - // TODO Auto-generated method stub - return null; + public Loop getLoop() { + return loop; } public int getLoopDepth() { - // TODO Auto-generated method stub - return 0; + return Long.bitCount(loops); } public boolean isLoopHeader() { @@ -159,13 +163,11 @@ } public boolean isLoopEnd() { - // TODO Auto-generated method stub - return false; + return isLoopEnd; } public boolean isExceptionEntry() { - // TODO Auto-generated method stub - return false; + return isExceptionEntry; } public BciBlock getSuccessor(int index) { @@ -716,6 +718,10 @@ for (BciBlock successor : block.getSuccessors()) { // Recursively process successors. loops |= computeBlockOrder(successor); + if (block.visited && successor.active) { + // Reached block via backward branch. + block.isLoopEnd = true; + } } block.loops = loops; diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java Tue Apr 15 19:07:08 2014 +0200 @@ -36,19 +36,19 @@ public class LoopEx { - private final Loop lirLoop; + private final Loop lirLoop; private LoopFragmentInside inside; private LoopFragmentWhole whole; private CountedLoopInfo counted; // TODO (gd) detect private LoopsData data; private InductionVariables ivs; - LoopEx(Loop lirLoop, LoopsData data) { + LoopEx(Loop lirLoop, LoopsData data) { this.lirLoop = lirLoop; this.data = data; } - public Loop lirLoop() { + public Loop lirLoop() { return lirLoop; } @@ -88,7 +88,7 @@ } public LoopBeginNode loopBegin() { - return lirLoop().loopBegin(); + return (LoopBeginNode) lirLoop().header.getBeginNode(); } public FixedNode predecessor() { diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentWhole.java Tue Apr 15 19:07:08 2014 +0200 @@ -56,7 +56,7 @@ @Override public NodeIterable nodes() { if (nodes == null) { - Loop lirLoop = loop().lirLoop(); + Loop lirLoop = loop().lirLoop(); nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(lirLoop.blocks), LoopFragment.toHirBlocks(lirLoop.exits)); } return nodes; diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java --- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java Tue Apr 15 19:07:08 2014 +0200 @@ -31,7 +31,7 @@ public class LoopsData { - private Map lirLoopToEx = new IdentityHashMap<>(); + private Map, LoopEx> lirLoopToEx = new IdentityHashMap<>(); private Map loopBeginToEx = new IdentityHashMap<>(); private ControlFlowGraph cfg; @@ -42,14 +42,14 @@ throw Debug.handle(e); } - for (Loop lirLoop : cfg.getLoops()) { + for (Loop lirLoop : cfg.getLoops()) { LoopEx ex = new LoopEx(lirLoop, this); lirLoopToEx.put(lirLoop, ex); loopBeginToEx.put(ex.loopBegin(), ex); } } - public LoopEx loop(Loop lirLoop) { + public LoopEx loop(Loop lirLoop) { return lirLoopToEx.get(lirLoop); } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractBlock.java Tue Apr 15 19:07:08 2014 +0200 @@ -24,11 +24,11 @@ import java.util.*; -public interface AbstractBlock> { +public interface AbstractBlock> { int getId(); - Loop getLoop(); + Loop getLoop(); int getLoopDepth(); diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractControlFlowGraph.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/AbstractControlFlowGraph.java Tue Apr 15 19:07:08 2014 +0200 @@ -22,11 +22,13 @@ */ package com.oracle.graal.nodes.cfg; +import java.util.*; + public interface AbstractControlFlowGraph> { T[] getBlocks(); - Loop[] getLoops(); + Collection> getLoops(); T getStartBlock(); } diff -r e3491381c424 -r bd5471cdc3e1 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 Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Tue Apr 15 19:07:08 2014 +0200 @@ -32,7 +32,7 @@ protected final AbstractBeginNode beginNode; protected FixedNode endNode; - protected Loop loop; + protected Loop loop; protected List dominated; protected Block postdominator; @@ -49,7 +49,7 @@ return endNode; } - public Loop getLoop() { + public Loop getLoop() { return loop; } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/CFGVerifier.java Tue Apr 15 19:07:08 2014 +0200 @@ -84,13 +84,13 @@ } if (cfg.getLoops() != null) { - for (Loop loop : cfg.getLoops()) { + for (Loop loop : cfg.getLoops()) { assert loop.header.isLoopHeader(); for (Block block : loop.blocks) { assert block.getId() >= loop.header.getId(); - Loop blockLoop = block.getLoop(); + Loop blockLoop = block.getLoop(); while (blockLoop != loop) { assert blockLoop != null; blockLoop = blockLoop.parent; @@ -109,7 +109,7 @@ for (Block block : loop.exits) { assert block.getId() >= loop.header.getId(); - Loop blockLoop = block.getLoop(); + Loop blockLoop = block.getLoop(); while (blockLoop != null) { blockLoop = blockLoop.parent; assert blockLoop != loop; diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Tue Apr 15 19:07:08 2014 +0200 @@ -34,7 +34,7 @@ private final NodeMap nodeToBlock; private Block[] reversePostOrder; - private Loop[] loops; + private List> loops; public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { ControlFlowGraph cfg = new ControlFlowGraph(graph); @@ -106,7 +106,7 @@ return nodeToBlock.get(node); } - public Loop[] getLoops() { + public List> getLoops() { return loops; } @@ -233,12 +233,12 @@ } private void computeLoopInformation() { - ArrayList loopsList = new ArrayList<>(); + loops = new ArrayList<>(); for (Block block : reversePostOrder) { Node beginNode = block.getBeginNode(); if (beginNode instanceof LoopBeginNode) { - Loop loop = new Loop(block.getLoop(), loopsList.size(), block); - loopsList.add(loop); + Loop loop = new HIRLoop(block.getLoop(), loops.size(), block); + loops.add(loop); LoopBeginNode loopBegin = (LoopBeginNode) beginNode; for (LoopEndNode end : loopBegin.loopEnds()) { @@ -269,10 +269,9 @@ } } } - loops = loopsList.toArray(new Loop[loopsList.size()]); } - private static void addBranchToLoop(Loop l, Block b) { + private static void addBranchToLoop(Loop l, Block b) { if (l.blocks.contains(b)) { return; } @@ -283,7 +282,7 @@ } } - private static void computeLoopBlocks(Block block, Loop loop) { + private static void computeLoopBlocks(Block block, Loop loop) { if (block.getLoop() == loop) { return; } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/HIRLoop.java Tue Apr 15 19:07:08 2014 +0200 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, 2014, 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.nodes.cfg; + +import com.oracle.graal.nodes.*; + +public class HIRLoop extends Loop { + + protected HIRLoop(Loop parent, int index, Block header) { + super(parent, index, header); + } + + @Override + public long numBackedges() { + return ((LoopBeginNode) header.getBeginNode()).loopEnds().count(); + } +} diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Loop.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Loop.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Loop.java Tue Apr 15 19:07:08 2014 +0200 @@ -24,20 +24,18 @@ import java.util.*; -import com.oracle.graal.nodes.*; +public abstract class Loop> { -public class Loop { - - public final Loop parent; - public final List children; + public final Loop parent; + public final List> children; public final int depth; public final int index; - public final Block header; - public final List blocks; - public final List exits; + public final T header; + public final List blocks; + public final List exits; - protected Loop(Loop parent, int index, Block header) { + protected Loop(Loop parent, int index, T header) { this.parent = parent; if (parent != null) { this.depth = parent.depth + 1; @@ -52,12 +50,10 @@ this.exits = new ArrayList<>(); } + public abstract long numBackedges(); + @Override public String toString() { return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : ""); } - - public LoopBeginNode loopBegin() { - return (LoopBeginNode) header.getBeginNode(); - } } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java Tue Apr 15 19:07:08 2014 +0200 @@ -92,9 +92,9 @@ private static void exitLoops(AbstractDeoptimizeNode deopt, EndNode end, ControlFlowGraph cfg) { Block block = cfg.blockFor(deopt); - Loop loop = block.getLoop(); + Loop loop = block.getLoop(); while (loop != null) { - end.graph().addBeforeFixed(end, end.graph().add(new LoopExitNode(loop.loopBegin()))); + end.graph().addBeforeFixed(end, end.graph().add(new LoopExitNode((LoopBeginNode) loop.header.getBeginNode()))); loop = loop.parent; } } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java Tue Apr 15 19:07:08 2014 +0200 @@ -174,10 +174,10 @@ } private void insertLoopExits(DeoptimizeNode deopt) { - Loop loop = block.getLoop(); + Loop loop = block.getLoop(); StructuredGraph graph = deopt.graph(); while (loop != null) { - LoopExitNode exit = graph.add(new LoopExitNode(loop.loopBegin())); + LoopExitNode exit = graph.add(new LoopExitNode((LoopBeginNode) loop.header.getBeginNode())); graph.addBeforeFixed(deopt, exit); loop = loop.parent; } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Tue Apr 15 19:07:08 2014 +0200 @@ -43,11 +43,11 @@ * for each node would be too costly, so this phase takes the compromise that it trusts split * probabilities, but not loop frequencies. This means that it will insert counters at the start of * a method and at each loop header. - * + * * A schedule is created so that floating nodes can also be taken into account. The weight of a node * is determined heuristically in the * {@link ProfileCompiledMethodsPhase#getNodeWeight(ScheduledNode)} method. - * + * * Additionally, there's a second counter that's only increased for code sections without invokes. */ public class ProfileCompiledMethodsPhase extends Phase { @@ -65,18 +65,18 @@ schedule.apply(graph, false); ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); - for (Loop loop : cfg.getLoops()) { - double loopProbability = probabilities.get(loop.loopBegin()); + for (Loop loop : cfg.getLoops()) { + double loopProbability = probabilities.get(loop.header.getBeginNode()); if (loopProbability > (1D / Integer.MAX_VALUE)) { - addSectionCounters(loop.loopBegin(), loop.blocks, loop.children, schedule, probabilities); + addSectionCounters(loop.header.getBeginNode(), loop.blocks, loop.children, schedule, probabilities); } } - addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), Arrays.asList(cfg.getLoops()), schedule, probabilities); + addSectionCounters(graph.start(), Arrays.asList(cfg.getBlocks()), cfg.getLoops(), schedule, probabilities); } - private static void addSectionCounters(FixedWithNextNode start, Collection sectionBlocks, Collection childLoops, SchedulePhase schedule, NodesToDoubles probabilities) { + private static void addSectionCounters(FixedWithNextNode start, Collection sectionBlocks, Collection> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) { HashSet blocks = new HashSet<>(sectionBlocks); - for (Loop loop : childLoops) { + for (Loop loop : childLoops) { blocks.removeAll(loop.blocks); } double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start); diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java Tue Apr 15 19:07:08 2014 +0200 @@ -105,26 +105,26 @@ private Scope[] computeScopes() { ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); - Loop[] loops = cfg.getLoops(); - HashMap processedScopes = new HashMap<>(); - Scope[] result = new Scope[loops.length + 1]; + List> loops = cfg.getLoops(); + HashMap, Scope> processedScopes = new HashMap<>(); + Scope[] result = new Scope[loops.size() + 1]; Scope methodScope = new Scope(graph.start(), null); processedScopes.put(null, methodScope); result[0] = methodScope; - for (int i = 0; i < loops.length; i++) { - result[i + 1] = createScope(loops[i], processedScopes); + for (int i = 0; i < loops.size(); i++) { + result[i + 1] = createScope(loops.get(i), processedScopes); } return result; } - private Scope createScope(Loop loop, HashMap processedLoops) { + private Scope createScope(Loop loop, HashMap, Scope> processedLoops) { Scope parent = processedLoops.get(loop.parent); if (parent == null) { parent = createScope(loop.parent, processedLoops); } - Scope result = new Scope(loop.loopBegin(), parent); + Scope result = new Scope(loop.header.getBeginNode(), parent); processedLoops.put(loop, result); return result; } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java Tue Apr 15 19:07:08 2014 +0200 @@ -45,14 +45,14 @@ protected abstract StateT cloneState(StateT oldState); - protected abstract List processLoop(Loop loop, StateT initialState); + protected abstract List processLoop(Loop loop, StateT initialState); } private ReentrantBlockIterator() { // no instances allowed } - public static LoopInfo processLoop(BlockIteratorClosure closure, Loop loop, StateT initialState) { + public static LoopInfo processLoop(BlockIteratorClosure closure, Loop loop, StateT initialState) { IdentityHashMap blockEndStates = apply(closure, loop.header, initialState, new HashSet<>(loop.blocks)); LoopInfo info = new LoopInfo<>(); @@ -101,8 +101,8 @@ states.put(current.getEndNode(), state); } else { // recurse into the loop - Loop loop = successor.getLoop(); - LoopBeginNode loopBegin = loop.loopBegin(); + Loop loop = successor.getLoop(); + LoopBeginNode loopBegin = (LoopBeginNode) loop.header.getBeginNode(); assert successor.getBeginNode() == loopBegin; List exitStates = closure.processLoop(loop, state); diff -r e3491381c424 -r bd5471cdc3e1 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 Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java Tue Apr 15 19:07:08 2014 +0200 @@ -152,7 +152,7 @@ } @Override - protected List processLoop(Loop loop, KillSet state) { + protected List processLoop(Loop loop, KillSet state) { LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, cloneState(state)); assert loop.header.getBeginNode() instanceof LoopBeginNode; @@ -649,7 +649,7 @@ * implies that the inputs' blocks have a total ordering via their dominance relation. So in * order to find the earliest block placement for this node we need to find the input block * that is dominated by all other input blocks. - * + * * While iterating over the inputs a set of dominator blocks of the current earliest * placement is maintained. When the block of an input is not within this set, it becomes * the current earliest placement and the list of dominator blocks is updated. diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java Tue Apr 15 19:07:08 2014 +0200 @@ -140,7 +140,7 @@ BlockIteratorClosure closure = new BlockIteratorClosure() { @Override - protected List processLoop(Loop loop, NodeBitMap initialState) { + protected List processLoop(Loop loop, NodeBitMap initialState) { return ReentrantBlockIterator.processLoop(this, loop, initialState).exitStates; } diff -r e3491381c424 -r bd5471cdc3e1 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Tue Apr 15 19:06:49 2014 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java Tue Apr 15 19:07:08 2014 +0200 @@ -43,7 +43,7 @@ protected final NodeMap aliases; protected final BlockMap blockEffects; - private final IdentityHashMap loopMergeEffects = new IdentityHashMap<>(); + private final IdentityHashMap, GraphEffectList> loopMergeEffects = new IdentityHashMap<>(); private final IdentityHashMap loopEntryStates = new IdentityHashMap<>(); private boolean changed; @@ -105,7 +105,7 @@ } @Override - protected List processLoop(Loop loop, Void initialState) { + protected List processLoop(Loop loop, Void initialState) { LoopInfo info = ReentrantBlockIterator.processLoop(this, loop, initialState); apply(loopMergeEffects.get(loop), loop); return info.exitStates; @@ -150,7 +150,7 @@ } @Override - protected final List processLoop(Loop loop, BlockT initialState) { + protected final List processLoop(Loop loop, BlockT initialState) { BlockT loopEntryState = initialState; BlockT lastMergedState = cloneState(initialState); MergeProcessor mergeProcessor = createMergeProcessor(loop.header); @@ -174,7 +174,7 @@ loopMergeEffects.put(loop, mergeProcessor.afterMergeEffects); assert info.exitStates.size() == loop.exits.size(); - loopEntryStates.put(loop.loopBegin(), loopEntryState); + loopEntryStates.put((LoopBeginNode) loop.header.getBeginNode(), loopEntryState); for (int i = 0; i < loop.exits.size(); i++) { assert info.exitStates.get(i) != null : "no loop exit state at " + loop.exits.get(i) + " / " + loop.header; } diff -r e3491381c424 -r bd5471cdc3e1 mx/mx_graal.py --- a/mx/mx_graal.py Tue Apr 15 19:06:49 2014 +0200 +++ b/mx/mx_graal.py Tue Apr 15 19:07:08 2014 +0200 @@ -28,7 +28,7 @@ import os, sys, shutil, zipfile, tempfile, re, time, datetime, platform, subprocess, multiprocessing, StringIO from os.path import join, exists, dirname, basename, getmtime -from argparse import ArgumentParser, REMAINDER +from argparse import ArgumentParser, RawDescriptionHelpFormatter, REMAINDER from outputparser import OutputParser, ValuesMatcher import mx import xml.dom.minidom @@ -828,7 +828,7 @@ else: return [], args -def _run_tests(args, harness, annotations, testfile): +def _run_tests(args, harness, annotations, testfile, whitelist): vmArgs, tests = _extract_VM_args(args) @@ -860,6 +860,9 @@ mx.log('warning: no tests matched by substring "' + t) projectscp = mx.classpath(projs) + if whitelist: + classes = list(set(classes) & set(whitelist)) + if len(classes) != 0: f_testfile = open(testfile, 'w') for c in classes: @@ -867,7 +870,7 @@ f_testfile.close() harness(projectscp, vmArgs) -def _unittest(args, annotations, prefixcp=""): +def _unittest(args, annotations, prefixcp="", whitelist=None): mxdir = dirname(__file__) name = 'JUnitWrapper' javaSource = join(mxdir, name + '.java') @@ -894,12 +897,20 @@ vm(prefixArgs + vmArgs + ['-cp', prefixcp + projectscp + os.pathsep + mxdir, name] + [testfile]) try: - _run_tests(args, harness, annotations, testfile) + _run_tests(args, harness, annotations, testfile, whitelist) finally: if os.environ.get('MX_TESTFILE') is None: os.remove(testfile) _unittestHelpSuffix = """ + Unittest options: + + --short-only run short testcases only + --long-only run long testcases only + --baseline-whitelist run only testcases which are known to + work with the baseline compiler + + To avoid conflicts with VM options '--' can be used as delimiter. If filters are supplied, only tests whose fully qualified name includes a filter as a substring are run. @@ -928,17 +939,64 @@ def unittest(args): """run the JUnit tests (all testcases){0}""" - _unittest(args, ['@Test', '@LongTest', '@Parameters']) + parser = ArgumentParser(prog='mx unittest', + description='run the JUnit tests', + add_help=False, + formatter_class=RawDescriptionHelpFormatter, + epilog=_unittestHelpSuffix, + ) + group = parser.add_mutually_exclusive_group() + group.add_argument('--short-only', action='store_true', help='run short testcases only') + group.add_argument('--long-only', action='store_true', help='run long testcases only') + parser.add_argument('--baseline-whitelist', action='store_true', help='run baseline testcases only') + + ut_args = [] + delimiter = False + # check for delimiter + while len(args) > 0: + arg = args.pop(0) + if arg == '--': + delimiter = True + break + ut_args.append(arg) + + if delimiter: + # all arguments before '--' must be recognized + parsed_args = parser.parse_args(ut_args) + else: + # parse all know arguments + parsed_args, remaining_args = parser.parse_known_args(ut_args) + args = remaining_args + args + + whitelist = None + if parsed_args.baseline_whitelist: + baseline_whitelist_file = 'test/baseline_whitelist.txt' + try: + with open(join(_graal_home, baseline_whitelist_file)) as fp: + whitelist = [l.rstrip() for l in fp.readlines()] + except IOError: + mx.log('warning: could not read baseline whitelist: ' + baseline_whitelist_file) + + if parsed_args.long_only: + annotations = ['@LongTest', '@Parameters'] + elif parsed_args.short_only: + annotations = ['@Test'] + else: + annotations = ['@Test', '@LongTest', '@Parameters'] + + _unittest(args, annotations, whitelist=whitelist) def shortunittest(args): - """run the JUnit tests (short testcases only){0}""" + """alias for 'unittest --short-only'{0}""" - _unittest(args, ['@Test']) + args.insert(0, '--short-only') + unittest(args) def longunittest(args): - """run the JUnit tests (long testcases only){0}""" + """alias for 'unittest --long-only'{0}""" - _unittest(args, ['@LongTest', '@Parameters']) + args.insert(0, '--long-only') + unittest(args) def buildvms(args): """build one or more VMs in various configurations""" @@ -1784,9 +1842,9 @@ 'specjbb2005': [specjbb2005, '[VM options] [-- [SPECjbb2005 options]]'], 'gate' : [gate, '[-options]'], 'bench' : [bench, '[-resultfile file] [all(default)|dacapo|specjvm2008|bootstrap]'], - 'unittest' : [unittest, '[VM options] [filters...]', _unittestHelpSuffix], - 'longunittest' : [longunittest, '[VM options] [filters...]', _unittestHelpSuffix], - 'shortunittest' : [shortunittest, '[VM options] [filters...]', _unittestHelpSuffix], + 'unittest' : [unittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix], + 'longunittest' : [longunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix], + 'shortunittest' : [shortunittest, '[unittest options] [--] [VM options] [filters...]', _unittestHelpSuffix], 'jacocoreport' : [jacocoreport, '[output directory]'], 'site' : [site, '[-options]'], 'vm': [vm, '[-options] class [args...]'], diff -r e3491381c424 -r bd5471cdc3e1 test/baseline_whitelist.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/baseline_whitelist.txt Tue Apr 15 19:07:08 2014 +0200 @@ -0,0 +1,7 @@ +com.oracle.graal.jtt.loop.Loop03 +com.oracle.graal.jtt.bytecode.BC_iadd +com.oracle.graal.jtt.bytecode.BC_iadd2 +com.oracle.graal.jtt.bytecode.BC_iadd3 +com.oracle.graal.jtt.bytecode.BC_ifeq_2 +com.oracle.graal.jtt.bytecode.BC_ifeq_3 +com.oracle.graal.jtt.bytecode.BC_ifeq