# HG changeset patch # User Thomas Wuerthinger # Date 1423189490 -3600 # Node ID 3b2e98f9e47c745a48c07c672692eea873fc82f2 # Parent f41186c896cdfa5ec7ed14e0413711042772c74e Initial prototype for loop explosion during graph building. diff -r f41186c896cd -r 3b2e98f9e47c 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 Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Fri Feb 06 03:24:50 2015 +0100 @@ -112,7 +112,7 @@ frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true); currentBlock = blockMap.startBlock; - blockMap.startBlock.entryState = frameState; + blockMap.startBlock.setEntryState(0, frameState); if (blockMap.startBlock.isLoopHeader) { throw GraalInternalError.unimplemented("Handle start block as loop header"); } @@ -624,15 +624,15 @@ */ moveConstantsToVariables(); } - block.entryState = frameState.copy(); - block.entryState.clearNonLiveLocals(block, liveness, true); + block.setEntryState(0, frameState.copy()); + block.getEntryState(0).clearNonLiveLocals(block, liveness, true); Debug.log("createTarget %s: first visit", block); return; } // We already saw this block before, so we have to merge states. - if (!((BaselineFrameStateBuilder) block.entryState).isCompatibleWith(frameState)) { + if (!((BaselineFrameStateBuilder) block.getEntryState(0)).isCompatibleWith(frameState)) { throw new BailoutException("stacks do not match; bytecodes would not verify"); } @@ -640,7 +640,7 @@ 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((BaselineFrameStateBuilder) block.entryState); + adaptFramestate((BaselineFrameStateBuilder) block.getEntryState(0)); return; } GraalInternalError.unimplemented("Loops not yet supported"); @@ -654,7 +654,7 @@ */ if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) { // this is the only successor of the current block so we can adjust - adaptFramestate((BaselineFrameStateBuilder) block.entryState); + adaptFramestate((BaselineFrameStateBuilder) block.getEntryState(0)); return; } GraalInternalError.unimplemented("second block visit not yet implemented"); @@ -715,7 +715,7 @@ } protected void processBlock(BciBlock block) { - frameState = (BaselineFrameStateBuilder) block.entryState; + frameState = (BaselineFrameStateBuilder) block.getEntryState(0); setCurrentFrameState(frameState); currentBlock = block; iterateBytecodesForBlock(block); @@ -745,7 +745,7 @@ * We need to preserve the frame state builder of the loop header so that we can merge * values for phi functions, so make a copy of it. */ - block.entryState = frameState.copy(); + block.setEntryState(0, frameState.copy()); } int endBCI = stream.endBCI(); diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java --- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java Fri Feb 06 03:24:50 2015 +0100 @@ -343,6 +343,9 @@ public static final OptionValue ImplicitStableValues = new OptionValue<>(true); + @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug) + public static final OptionValue MaximumLoopExplosionCount = new OptionValue<>(10000); + /** * Counts the various paths taken through snippets. */ diff -r f41186c896cd -r 3b2e98f9e47c 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 Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Fri Feb 06 03:24:50 2015 +0100 @@ -81,8 +81,8 @@ public int endBci; public boolean isExceptionEntry; public boolean isLoopHeader; - public boolean isLastLoopEnd; public int loopId; + public int loopEnd; /** * XXX to be removed - currently only used by baseline compiler. @@ -90,8 +90,10 @@ public Loop loop; public boolean isLoopEnd; - public FixedWithNextNode firstInstruction; - public AbstractFrameStateBuilder entryState; + private FixedWithNextNode firstInstruction; + private AbstractFrameStateBuilder entryState; + private FixedWithNextNode[] firstInstructionArray; + private AbstractFrameStateBuilder[] entryStateArray; private boolean visited; private boolean active; @@ -330,6 +332,66 @@ public void setJsrReturnBci(int bci) { this.getOrCreateJSRData().jsrReturnBci = bci; } + + public FixedWithNextNode getFirstInstruction(int dimension) { + if (dimension == 0) { + return firstInstruction; + } else { + if (firstInstructionArray != null && dimension - 1 < firstInstructionArray.length) { + return firstInstructionArray[dimension - 1]; + } else { + return null; + } + } + } + + public void setFirstInstruction(int dimension, FixedWithNextNode firstInstruction) { + if (dimension == 0) { + this.firstInstruction = firstInstruction; + } else { + if (firstInstructionArray == null) { + firstInstructionArray = new FixedWithNextNode[4]; + } + if (dimension - 1 < firstInstructionArray.length) { + // We are within bounds. + } else { + // We are out of bounds. + firstInstructionArray = Arrays.copyOf(firstInstructionArray, Math.max(firstInstructionArray.length * 2, dimension)); + } + + firstInstructionArray[dimension - 1] = firstInstruction; + } + } + + public AbstractFrameStateBuilder getEntryState(int dimension) { + if (dimension == 0) { + return entryState; + } else { + if (entryStateArray != null && dimension - 1 < entryStateArray.length) { + return entryStateArray[dimension - 1]; + } else { + return null; + } + } + } + + public void setEntryState(int dimension, AbstractFrameStateBuilder entryState) { + if (dimension == 0) { + this.entryState = entryState; + } else { + if (entryStateArray == null) { + entryStateArray = new AbstractFrameStateBuilder[4]; + } + if (dimension - 1 < entryStateArray.length) { + // We are within bounds. + } else { + // We are out of bounds. + entryStateArray = Arrays.copyOf(entryStateArray, Math.max(entryStateArray.length * 2, dimension)); + } + + entryStateArray[dimension - 1] = entryState; + } + } } public static class ExceptionDispatchBlock extends BciBlock { @@ -783,7 +845,7 @@ for (BciBlock succBlock : blocks[i].getSuccessors()) { succ += succBlock.getId() + " "; } - System.out.printf("%3s %10s %s %s succ=[%s]\n", blocks[i].getId(), Long.toBinaryString(blocks[i].loops), blocks[i].isLoopHeader, blocks[i].isLastLoopEnd, succ); + System.out.printf("%3s %10s %s succ=[%s]\n", blocks[i].getId(), Long.toBinaryString(blocks[i].loops), blocks[i].isLoopHeader, succ); } System.out.println(); } @@ -791,20 +853,20 @@ private int handleLoopHeader(BciBlock[] newBlocks, int nextStart, int i, BciBlock loopHeader) { int next = nextStart; - BciBlock last = loopHeader; + int endOfLoop = nextStart - 1; for (int j = i + 1; j < blocks.length; ++j) { BciBlock other = blocks[j]; if (other != null && (other.loops & (1L << loopHeader.loopId)) != 0) { other.setId(next); + endOfLoop = next; newBlocks[next++] = other; - last = other; blocks[j] = null; if (other.isLoopHeader) { next = handleLoopHeader(newBlocks, next, j, other); } } } - last.isLastLoopEnd = true; + loopHeader.loopEnd = endOfLoop; return next; } diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Feb 06 03:24:50 2015 +0100 @@ -170,6 +170,12 @@ } } + private static class ExplodedLoopContext { + private BciBlock header; + private int targetPeelIteration; + private int peelIteration; + } + public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext { private BciBlock[] loopHeaders; @@ -192,6 +198,8 @@ private FixedWithNextNode lastInstr; // the last instruction added private final boolean explodeLoops; + private Stack explodeLoopsContext; + private int nextPeelIteration = 1; public BytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI) { super(metaAccess, method, graphBuilderConfig, optimisticOpts); @@ -268,15 +276,18 @@ } currentBlock = blockMap.startBlock; - blockMap.startBlock.entryState = frameState; - if (blockMap.startBlock.isLoopHeader) { + blockMap.startBlock.setEntryState(0, frameState); + if (blockMap.startBlock.isLoopHeader && !explodeLoops) { appendGoto(createTarget(blockMap.startBlock, frameState)); } else { - blockMap.startBlock.firstInstruction = lastInstr; + blockMap.startBlock.setFirstInstruction(0, lastInstr); } - for (BciBlock block : blockMap.getBlocks()) { - processBlock(this, block); + int index = 0; + BciBlock[] blocks = blockMap.getBlocks(); + while (index < blocks.length) { + BciBlock block = blocks[index]; + index = iterateBlock(blocks, block); } processBlock(this, returnBlock); processBlock(this, unwindBlock); @@ -286,6 +297,50 @@ } } + private int iterateBlock(BciBlock[] blocks, BciBlock block) { + if (block.isLoopHeader && this.explodeLoops) { + return iterateExplodedLoopHeader(blocks, block); + } else { + processBlock(this, block); + return block.getId() + 1; + } + } + + private int iterateExplodedLoopHeader(BciBlock[] blocks, BciBlock header) { + if (explodeLoopsContext == null) { + explodeLoopsContext = new Stack<>(); + } + + ExplodedLoopContext context = new ExplodedLoopContext(); + context.header = header; + context.peelIteration = this.getCurrentDimension(); + context.targetPeelIteration = -1; + explodeLoopsContext.push(context); + Debug.dump(currentGraph, "before loop explosion " + context.peelIteration); + + while (true) { + + processBlock(this, header); + for (int j = header.getId() + 1; j <= header.loopEnd; ++j) { + BciBlock block = blocks[j]; + iterateBlock(blocks, block); + } + + if (context.targetPeelIteration != -1) { + // We were reaching the backedge during explosion. Explode further. + Debug.dump(currentGraph, "Before loop explosion " + context.targetPeelIteration); + context.peelIteration = context.targetPeelIteration; + context.targetPeelIteration = -1; + } else { + // We did not reach the backedge. Exit. + Debug.dump(currentGraph, "after loop explosion " + context.peelIteration); + break; + } + } + explodeLoopsContext.pop(); + return header.loopEnd + 1; + } + private BciBlock returnBlock(int bci) { if (returnBlock == null) { returnBlock = new BciBlock(); @@ -448,7 +503,7 @@ @Override protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, Kind kind) { - return new LoadIndexedNode(array, index, kind); + return LoadIndexedNode.create(array, index, kind, metaAccess, constantReflectionProvider); } @Override @@ -458,7 +513,7 @@ @Override protected ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y) { - return new AddNode(x, y); + return AddNode.create(x, y); } @Override @@ -584,7 +639,7 @@ @Override protected ValueNode genIntegerLessThan(ValueNode x, ValueNode y) { - return new IntegerLessThanNode(x, y); + return IntegerLessThanNode.create(x, y, constantReflectionProvider); } @Override @@ -656,7 +711,7 @@ protected void emitBoundsCheck(ValueNode index, ValueNode length) { AbstractBeginNode trueSucc = currentGraph.add(new BeginNode()); BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); - append(new IfNode(currentGraph.unique(new IntegerBelowNode(index, length)), trueSucc, exception, 0.99)); + append(new IfNode(currentGraph.unique(IntegerBelowNode.create(index, length, constantReflectionProvider)), trueSucc, exception, 0.99)); lastInstr = trueSucc; exception.setStateAfter(frameState.create(bci())); @@ -665,7 +720,7 @@ @Override protected ValueNode genArrayLength(ValueNode x) { - return new ArrayLengthNode(x); + return ArrayLengthNode.create(x, constantReflectionProvider); } @Override @@ -1030,7 +1085,7 @@ } private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) { - if (currentBlock != null) { + if (currentBlock != null && !explodeLoops) { long exits = currentBlock.loops & ~targetBlock.loops; if (exits != 0) { LoopExitNode firstLoopExit = null; @@ -1061,7 +1116,7 @@ } HIRFrameStateBuilder newState = state.copy(); for (BciBlock loop : exitLoops) { - LoopBeginNode loopBegin = (LoopBeginNode) loop.firstInstruction; + LoopBeginNode loopBegin = (LoopBeginNode) loop.getFirstInstruction(this.getCurrentDimension()); LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin)); if (lastLoopExit != null) { lastLoopExit.setNext(loopExit); @@ -1071,7 +1126,7 @@ } lastLoopExit = loopExit; Debug.log("Target %s (%s) Exits %s, scanning framestates...", targetBlock, target, loop); - newState.insertLoopProxies(loopExit, (HIRFrameStateBuilder) loop.entryState); + newState.insertLoopProxies(loopExit, (HIRFrameStateBuilder) loop.getEntryState(this.getCurrentDimension())); loopExit.setStateAfter(newState.create(bci)); } @@ -1096,53 +1151,88 @@ assert block != null && state != null; assert !block.isExceptionEntry || state.stackSize() == 1; - if (block.firstInstruction == null) { + int operatingDimension = this.getCurrentDimension(); + if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) { + int i; + for (i = explodeLoopsContext.size() - 1; i >= 0; --i) { + ExplodedLoopContext context = explodeLoopsContext.elementAt(i); + if (context.header == block) { + + // We have a hit on our current explosion context loop begin. + if (context.targetPeelIteration == -1) { + // This is the first hit => allocate a new dimension and at the same + // time mark the context loop begin as hit during the current + // iteration. + context.targetPeelIteration = nextPeelIteration++; + if (nextPeelIteration > GraalOptions.MaximumLoopExplosionCount.getValue()) { + throw new BailoutException("too many loop explosion interations - does the explosion not terminate?"); + } + } + + // Operate on the target dimension. + operatingDimension = context.targetPeelIteration; + break; + } else if (block.getId() > context.header.getId() && block.getId() <= context.header.loopEnd) { + // We hit the range of this context. + operatingDimension = context.peelIteration; + break; + } + } + + if (i == -1) { + // I did not find a dimension. + operatingDimension = 0; + } + } + + if (block.getFirstInstruction(operatingDimension) == null) { /* * This is the first time we see this block as a branch target. Create and * return a placeholder that later can be replaced with a MergeNode when we see * this block again. */ FixedNode targetNode; - block.firstInstruction = currentGraph.add(new BeginNode()); - targetNode = block.firstInstruction; + block.setFirstInstruction(operatingDimension, currentGraph.add(new BeginNode())); + targetNode = block.getFirstInstruction(operatingDimension); Target target = checkLoopExit(targetNode, block, state); FixedNode result = target.fixed; - block.entryState = target.state == state ? state.copy() : target.state; - block.entryState.clearNonLiveLocals(block, liveness, true); + AbstractFrameStateBuilder entryState = target.state == state ? state.copy() : target.state; + block.setEntryState(operatingDimension, entryState); + entryState.clearNonLiveLocals(block, liveness, true); Debug.log("createTarget %s: first visit, result: %s", block, targetNode); return result; } // We already saw this block before, so we have to merge states. - if (!((HIRFrameStateBuilder) block.entryState).isCompatibleWith(state)) { + if (!((HIRFrameStateBuilder) block.getEntryState(operatingDimension)).isCompatibleWith(state)) { throw new BailoutException("stacks do not match; bytecodes would not verify"); } - if (block.firstInstruction instanceof LoopBeginNode) { - assert block.isLoopHeader && currentBlock.getId() >= block.getId() : "must be backward branch"; + if (block.getFirstInstruction(operatingDimension) instanceof LoopBeginNode) { + assert this.explodeLoops || (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch"; /* * Backward loop edge. We need to create a special LoopEndNode and merge with * the loop begin node created before. */ - LoopBeginNode loopBegin = (LoopBeginNode) block.firstInstruction; + LoopBeginNode loopBegin = (LoopBeginNode) block.getFirstInstruction(operatingDimension); Target target = checkLoopExit(currentGraph.add(new LoopEndNode(loopBegin)), block, state); FixedNode result = target.fixed; - ((HIRFrameStateBuilder) block.entryState).merge(loopBegin, target.state); + ((HIRFrameStateBuilder) block.getEntryState(operatingDimension)).merge(loopBegin, target.state); Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result); return result; } assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch"; - assert block.firstInstruction.next() == null : "bytecodes already parsed for block"; + assert block.getFirstInstruction(operatingDimension).next() == null : "bytecodes already parsed for block"; - if (block.firstInstruction instanceof AbstractBeginNode && !(block.firstInstruction instanceof AbstractMergeNode)) { + if (block.getFirstInstruction(operatingDimension) instanceof AbstractBeginNode && !(block.getFirstInstruction(operatingDimension) instanceof AbstractMergeNode)) { /* * This is the second time we see this block. Create the actual MergeNode and * the End Node for the already existing edge. For simplicity, we leave the * placeholder in the graph and just append the new nodes after the placeholder. */ - AbstractBeginNode placeholder = (AbstractBeginNode) block.firstInstruction; + AbstractBeginNode placeholder = (AbstractBeginNode) block.getFirstInstruction(operatingDimension); // The EndNode for the already existing edge. AbstractEndNode end = currentGraph.add(new EndNode()); @@ -1160,16 +1250,16 @@ mergeNode.addForwardEnd(end); mergeNode.setNext(next); - block.firstInstruction = mergeNode; + block.setFirstInstruction(operatingDimension, mergeNode); } - AbstractMergeNode mergeNode = (AbstractMergeNode) block.firstInstruction; + AbstractMergeNode mergeNode = (AbstractMergeNode) block.getFirstInstruction(operatingDimension); // The EndNode for the newly merged edge. AbstractEndNode newEnd = currentGraph.add(new EndNode()); Target target = checkLoopExit(newEnd, block, state); FixedNode result = target.fixed; - ((HIRFrameStateBuilder) block.entryState).merge(mergeNode, target.state); + ((HIRFrameStateBuilder) block.getEntryState(operatingDimension)).merge(mergeNode, target.state); mergeNode.addForwardEnd(newEnd); Debug.log("createTarget %s: merging state, result: %s", block, result); @@ -1199,14 +1289,14 @@ protected void processBlock(BytecodeParser parser, BciBlock block) { // Ignore blocks that have no predecessors by the time their bytecodes are parsed - if (block == null || block.firstInstruction == null) { + if (block == null || block.getFirstInstruction(this.getCurrentDimension()) == null) { Debug.log("Ignoring block %s", block); return; } - try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader)) { + try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.getFirstInstruction(this.getCurrentDimension()), block.isLoopHeader)) { - lastInstr = block.firstInstruction; - frameState = (HIRFrameStateBuilder) block.entryState; + lastInstr = block.getFirstInstruction(this.getCurrentDimension()); + frameState = (HIRFrameStateBuilder) block.getEntryState(this.getCurrentDimension()); parser.setCurrentFrameState(frameState); currentBlock = block; @@ -1341,7 +1431,7 @@ @Override protected void iterateBytecodesForBlock(BciBlock block) { - if (block.isLoopHeader) { + if (block.isLoopHeader && !explodeLoops) { // Create the loop header block, which later will merge the backward branches of // the loop. AbstractEndNode preLoopEnd = currentGraph.add(new EndNode()); @@ -1360,12 +1450,12 @@ * merge to the loop header. This ensures that the loop header has exactly one * non-loop predecessor. */ - block.firstInstruction = loopBegin; + block.setFirstInstruction(this.getCurrentDimension(), loopBegin); /* * We need to preserve the frame state builder of the loop header so that we can * merge values for phi functions, so make a copy of it. */ - block.entryState = frameState.copy(); + block.setEntryState(this.getCurrentDimension(), frameState.copy()); Debug.log(" created loop header %s", loopBegin); } @@ -1544,6 +1634,13 @@ frameState.push(kind, value); } + private int getCurrentDimension() { + if (this.explodeLoopsContext == null || this.explodeLoopsContext.isEmpty()) { + return 0; + } else { + return this.explodeLoopsContext.peek().peelIteration; + } + } } } } diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java Fri Feb 06 03:24:50 2015 +0100 @@ -39,6 +39,17 @@ super(ArithmeticOpTable::getAdd, x, y); } + public static ValueNode create(ValueNode x, ValueNode y) { + BinaryOp op = ArithmeticOpTable.forStamp(x.stamp()).getAdd(); + Stamp stamp = op.foldStamp(x.stamp(), y.stamp()); + ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); + if (tryConstantFold != null) { + return tryConstantFold; + } else { + return new AddNode(x, y); + } + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { ValueNode ret = super.canonical(tool, forX, forY); diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java Fri Feb 06 03:24:50 2015 +0100 @@ -61,13 +61,21 @@ @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - if (forX.isConstant() && forY.isConstant()) { - Constant ret = getOp(forX, forY).foldConstant(forX.asConstant(), forY.asConstant()); - return ConstantNode.forPrimitive(stamp(), ret); + ValueNode result = tryConstantFold(getOp(forX, forY), forX, forY, stamp()); + if (result != null) { + return result; } return this; } + public static ConstantNode tryConstantFold(BinaryOp op, ValueNode forX, ValueNode forY, Stamp stamp) { + if (forX.isConstant() && forY.isConstant()) { + Constant ret = op.foldConstant(forX.asConstant(), forY.asConstant()); + return ConstantNode.forPrimitive(stamp, ret); + } + return null; + } + @Override public boolean inferStamp() { return updateStamp(getOp(getX(), getY()).foldStamp(getX().stamp(), getY().stamp())); diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java Fri Feb 06 03:24:50 2015 +0100 @@ -22,6 +22,7 @@ */ package com.oracle.graal.nodes.calc; +import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.common.calc.*; import com.oracle.graal.compiler.common.type.*; import com.oracle.graal.graph.spi.*; @@ -38,12 +39,33 @@ assert y.stamp() instanceof IntegerStamp; } + public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { + LogicNode result = CompareNode.tryConstantFold(Condition.BT, x, y, constantReflection, false); + if (result != null) { + return result; + } else { + result = findSynonym(x, y); + if (result != null) { + return result; + } + return new IntegerBelowNode(x, y); + } + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { ValueNode result = super.canonical(tool, forX, forY); if (result != this) { return result; } + LogicNode synonym = findSynonym(forX, forY); + if (synonym != null) { + return synonym; + } + return this; + } + + private static LogicNode findSynonym(ValueNode forX, ValueNode forY) { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { return LogicConstantNode.contradiction(); } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { @@ -61,7 +83,7 @@ // 0 |<| y is the same as 0 != y return new LogicNegationNode(CompareNode.createCompareNode(Condition.EQ, forX, forY)); } - return this; + return null; } @Override diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java Fri Feb 06 03:24:50 2015 +0100 @@ -40,6 +40,19 @@ assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object; } + public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { + LogicNode result = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, false); + if (result != null) { + return result; + } else { + result = findSynonym(x, y); + if (result != null) { + return result; + } + return new IntegerLessThanNode(x, y); + } + } + @Override protected ValueNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) { PrimitiveConstant primitive = (PrimitiveConstant) constant; @@ -63,6 +76,19 @@ if (result != this) { return result; } + ValueNode synonym = findSynonym(forX, forY); + if (synonym != null) { + return synonym; + } + if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { + if (IntegerStamp.sameSign((IntegerStamp) forX.stamp(), (IntegerStamp) forY.stamp())) { + return new IntegerBelowNode(forX, forY); + } + } + return this; + } + + private static LogicNode findSynonym(ValueNode forX, ValueNode forY) { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { return LogicConstantNode.contradiction(); } else if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { @@ -74,12 +100,7 @@ return LogicConstantNode.contradiction(); } } - if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { - if (IntegerStamp.sameSign((IntegerStamp) forX.stamp(), (IntegerStamp) forY.stamp())) { - return new IntegerBelowNode(forX, forY); - } - } - return this; + return null; } @Override diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java Fri Feb 06 03:24:50 2015 +0100 @@ -51,6 +51,14 @@ this.array = array; } + public static ValueNode create(ValueNode forValue, ConstantReflectionProvider constantReflection) { + ValueNode length = readArrayLength(forValue, constantReflection); + if (length != null) { + return length; + } + return new ArrayLengthNode(forValue); + } + public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { ValueNode length = readArrayLength(forValue, tool.getConstantReflection()); if (length != null) { diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java Fri Feb 06 03:24:50 2015 +0100 @@ -48,6 +48,14 @@ this(createStamp(array, elementKind), array, index, elementKind); } + public static ValueNode create(ValueNode array, ValueNode index, Kind elementKind, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { + ValueNode constant = tryConstantFold(array, index, metaAccess, constantReflection); + if (constant != null) { + return constant; + } + return new LoadIndexedNode(array, index, elementKind); + } + protected LoadIndexedNode(Stamp stamp, ValueNode array, ValueNode index, Kind elementKind) { super(stamp, array, index, elementKind); } @@ -79,15 +87,23 @@ } public Node canonical(CanonicalizerTool tool) { - if (array().isConstant() && !array().isNullConstant() && index().isConstant()) { - JavaConstant arrayConstant = array().asJavaConstant(); + ValueNode constant = tryConstantFold(array(), index(), tool.getMetaAccess(), tool.getConstantReflection()); + if (constant != null) { + return constant; + } + return this; + } + + private static ValueNode tryConstantFold(ValueNode array, ValueNode index, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) { + if (array.isConstant() && !array.isNullConstant() && index.isConstant()) { + JavaConstant arrayConstant = array.asJavaConstant(); if (arrayConstant != null) { - JavaConstant constant = tool.getConstantReflection().readConstantArrayElement(arrayConstant, index().asJavaConstant().asInt()); + JavaConstant constant = constantReflection.readConstantArrayElement(arrayConstant, index.asJavaConstant().asInt()); if (constant != null) { - return ConstantNode.forConstant(constant, tool.getMetaAccess()); + return ConstantNode.forConstant(constant, metaAccess); } } } - return this; + return null; } } diff -r f41186c896cd -r 3b2e98f9e47c graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Thu Feb 05 04:16:48 2015 +0100 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri Feb 06 03:24:50 2015 +0100 @@ -148,12 +148,17 @@ public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) { if (receiver.isConstant()) { JavaConstant asJavaConstant = receiver.asJavaConstant(); - JavaConstant result = providers.getConstantReflection().readConstantFieldValue(field, asJavaConstant); - if (result != null) { - ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, providers.getMetaAccess())); - builder.push(constantNode.getKind().getStackKind(), constantNode); - return true; - } + return tryConstantFold(builder, field, asJavaConstant); + } + return false; + } + + private boolean tryConstantFold(GraphBuilderContext builder, ResolvedJavaField field, JavaConstant asJavaConstant) { + JavaConstant result = providers.getConstantReflection().readConstantFieldValue(field, asJavaConstant); + if (result != null) { + ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, providers.getMetaAccess())); + builder.push(constantNode.getKind().getStackKind(), constantNode); + return true; } return false; } @@ -164,7 +169,7 @@ builder.push(trueNode.getKind().getStackKind(), trueNode); return true; } - return false; + return tryConstantFold(builder, staticField, null); } }