# HG changeset patch # User Chris Seaton # Date 1386944823 0 # Node ID e585ac5a385d9a07722f78e1aa18faf4888ba9b5 # Parent 093353894575e6f88557d399b6f0b1cc2495d553# Parent da085171251983ec2952de0edd070451563cdf56 Merge. diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java --- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java Fri Dec 13 14:27:03 2013 +0000 @@ -1446,6 +1446,14 @@ emitByte(0x50 | encode); } + public void pushfq() { + emitByte(0x9c); + } + + public void popfq() { + emitByte(0x9D); + } + public final void ret(int imm16) { if (imm16 == 0) { emitByte(0xC3); @@ -2279,7 +2287,11 @@ subq(dst, imm32, false); } - public final void subq(Register dst, int imm32, boolean force32Imm) { + public final void subqWide(Register dst, int imm32) { + subq(dst, imm32, true); + } + + private void subq(Register dst, int imm32, boolean force32Imm) { prefixqAndEncode(dst.encoding); emitArith(0x81, 0xE8, dst, imm32, force32Imm); } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CommonedConstantsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CommonedConstantsTest.java Fri Dec 13 14:27:03 2013 +0000 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2012, 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.lang.reflect.*; + +import org.junit.*; + +import com.oracle.graal.api.meta.*; + +/** + * Tests any optimization that commons loads of non-inlineable constants. + */ +public class CommonedConstantsTest extends GraalCompilerTest { + + public static final String[] array = {"1", "2", null}; + + // A method where a constant is used on the normal and exception edge of a non-inlined call. + // The dominating block of both usages is the block containing the call. + public static Object testSnippet(String[] arr, int i) { + Object result = null; + try { + result = Array.get(arr, i); + } catch (ArrayIndexOutOfBoundsException e) { + result = array[0]; + } + if (result == null) { + result = array[2]; + } + return result; + } + + @Test + public void test0() { + // Ensure the exception path is profiled + ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(getMethod("testSnippet")); + javaMethod.reprofile(); + testSnippet(array, array.length); + + test("testSnippet", array, 0); + test("testSnippet", array, 2); + test("testSnippet", array, 3); + test("testSnippet", array, 1); + } +} diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Fri Dec 13 14:27:03 2013 +0000 @@ -262,14 +262,13 @@ for (Block b : lir.linearScanOrder()) { emitBlock(lirGen, b); } + lirGen.beforeRegisterAllocation(); Debug.dump(lir, "After LIR generation"); } catch (Throwable e) { throw Debug.handle(e); } - lirGen.beforeRegisterAllocation(); - try (Scope s = Debug.scope("Allocator")) { if (backend.shouldAllocateRegisters()) { new LinearScan(target, lir, lirGen, frameMap).allocate(); diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java Fri Dec 13 14:27:03 2013 +0000 @@ -42,6 +42,7 @@ import com.oracle.graal.lir.StandardOp.BlockEndOp; import com.oracle.graal.lir.StandardOp.JumpOp; import com.oracle.graal.lir.StandardOp.LabelOp; +import com.oracle.graal.lir.StandardOp.NoOp; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.PhiNode.PhiType; import com.oracle.graal.nodes.calc.*; @@ -82,11 +83,69 @@ private final boolean printIRWithLIR; /** - * Maps constants the variables within the scope of a single block to avoid loading a constant + * Maps constants to variables within the scope of a single block to avoid loading a constant * more than once per block. */ private Map constantsLoadedInCurrentBlock; + /** + * Handle for an operation that loads a constant into a variable. The operation starts in the + * first block where the constant is used but will eventually be + * {@linkplain LIRGenerator#insertConstantLoads() moved} to a block dominating all usages of the + * constant. + */ + public static class LoadConstant implements Comparable { + /** + * The index of {@link #op} within {@link #block}'s instruction list or -1 if {@code op} is + * to be moved to a dominator block. + */ + int index; + + /** + * The operation that loads the constant. + */ + private final LIRInstruction op; + + /** + * The block that does or will contain {@link #op}. This is initially the block where the + * first usage of the constant is seen during LIR generation. + */ + private Block block; + + /** + * The variable into which the constant is loaded. + */ + private final Variable variable; + + public LoadConstant(Variable variable, Block block, int index, LIRInstruction op) { + this.variable = variable; + this.block = block; + this.index = index; + this.op = op; + } + + /** + * Sorts {@link LoadConstant} objects according to their enclosing blocks. This is used to + * group loads per block in {@link LIRGenerator#insertConstantLoads()}. + */ + public int compareTo(LoadConstant o) { + if (block.getId() < o.block.getId()) { + return -1; + } + if (block.getId() > o.block.getId()) { + return 1; + } + return 0; + } + + @Override + public String toString() { + return block + "#" + op; + } + } + + private Map constantLoads; + private ValueNode currentInstruction; private ValueNode lastInstructionPrinted; // Debugging only @@ -181,6 +240,12 @@ return operand; } + /** + * Controls whether commoning is performed on {@linkplain #canInlineConstant(Constant) + * non-inlinable} constants. + */ + private static final boolean CommonConstantLoads = Boolean.parseBoolean(System.getProperty("graal.commonConstantLoads", "true")); + private Value getConstantOperand(ValueNode node) { if (!ConstantNodeRecordsUsages) { Constant value = node.asConstant(); @@ -189,15 +254,42 @@ return !node.isExternal() ? setResult(node, value) : value; } else { Variable loadedValue; - if (constantsLoadedInCurrentBlock == null) { - constantsLoadedInCurrentBlock = new HashMap<>(); - loadedValue = null; + if (CommonConstantLoads) { + if (constantLoads == null) { + constantLoads = new HashMap<>(); + } + LoadConstant load = constantLoads.get(value); + if (load == null) { + int index = lir.lir(currentBlock).size(); + // loadedValue = newVariable(value.getPlatformKind()); + loadedValue = emitMove(value); + LIRInstruction op = lir.lir(currentBlock).get(index); + constantLoads.put(value, new LoadConstant(loadedValue, currentBlock, index, op)); + } else { + Block dominator = ControlFlowGraph.commonDominator(load.block, currentBlock); + loadedValue = load.variable; + if (dominator != load.block) { + if (load.index >= 0) { + List instructions = lir.lir(load.block); + instructions.set(load.index, new NoOp(null, -1)); + load.index = -1; + } + } else { + assert load.block != currentBlock || load.index < lir.lir(currentBlock).size(); + } + load.block = dominator; + } } else { - loadedValue = constantsLoadedInCurrentBlock.get(value); - } - if (loadedValue == null) { - loadedValue = emitMove(value); - constantsLoadedInCurrentBlock.put(value, loadedValue); + if (constantsLoadedInCurrentBlock == null) { + constantsLoadedInCurrentBlock = new HashMap<>(); + loadedValue = null; + } else { + loadedValue = constantsLoadedInCurrentBlock.get(value); + } + if (loadedValue == null) { + loadedValue = emitMove(value); + constantsLoadedInCurrentBlock.put(value, loadedValue); + } } return loadedValue; } @@ -795,10 +887,74 @@ @Override public void beforeRegisterAllocation() { + insertConstantLoads(); } /** - * Gets an garbage vale for a given kind. + * Moves deferred {@linkplain LoadConstant loads} of constants into blocks dominating all usages + * of the constant. Any operations inserted into a block are guaranteed to be immediately prior + * to the first control flow instruction near the end of the block. + */ + private void insertConstantLoads() { + if (constantLoads != null) { + // Remove loads where all usages are in the same block. + for (Iterator> iter = constantLoads.entrySet().iterator(); iter.hasNext();) { + LoadConstant lc = iter.next().getValue(); + if (lc.index != -1) { + assert lir.lir(lc.block).get(lc.index) == lc.op; + iter.remove(); + } + } + if (constantLoads.isEmpty()) { + return; + } + + // Sorting groups the loads per block. + LoadConstant[] groupedByBlock = constantLoads.values().toArray(new LoadConstant[constantLoads.size()]); + Arrays.sort(groupedByBlock); + + int groupBegin = 0; + while (true) { + int groupEnd = groupBegin + 1; + Block block = groupedByBlock[groupBegin].block; + while (groupEnd < groupedByBlock.length && groupedByBlock[groupEnd].block == block) { + groupEnd++; + } + int groupSize = groupEnd - groupBegin; + + List ops = lir.lir(block); + int lastIndex = ops.size() - 1; + assert ops.get(lastIndex) instanceof BlockEndOp; + int insertionIndex = lastIndex; + for (int i = Math.max(0, lastIndex - MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END); i < lastIndex; i++) { + if (getExceptionEdge(ops.get(i)) != null) { + insertionIndex = i; + break; + } + } + + if (groupSize == 1) { + ops.add(insertionIndex, groupedByBlock[groupBegin].op); + } else { + assert groupSize > 1; + List moves = new ArrayList<>(groupSize); + for (int i = groupBegin; i < groupEnd; i++) { + moves.add(groupedByBlock[i].op); + } + ops.addAll(insertionIndex, moves); + } + + if (groupEnd == groupedByBlock.length) { + break; + } + groupBegin = groupEnd; + } + constantLoads = null; + } + } + + /** + * Gets a garbage value for a given kind. */ protected Constant zapValueForKind(PlatformKind kind) { long dead = 0xDEADDEADDEADDEADL; diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java Fri Dec 13 14:27:03 2013 +0000 @@ -83,8 +83,8 @@ * @param isVerifiedEntryPoint specifies if the code buffer is currently at the verified entry * point */ - protected static void emitStackOverflowCheck(CompilationResultBuilder crb, int stackShadowPages, boolean afterFrameInit, boolean isVerifiedEntryPoint) { - if (stackShadowPages > 0) { + protected static void emitStackOverflowCheck(CompilationResultBuilder crb, int pagesToBang, boolean afterFrameInit, boolean isVerifiedEntryPoint) { + if (pagesToBang > 0) { AMD64MacroAssembler asm = (AMD64MacroAssembler) crb.asm; int frameSize = crb.frameMap.frameSize(); @@ -92,7 +92,7 @@ int lastFramePage = frameSize / unsafe.pageSize(); // emit multiple stack bangs for methods with frames larger than a page for (int i = 0; i <= lastFramePage; i++) { - int disp = (i + stackShadowPages) * unsafe.pageSize(); + int disp = (i + pagesToBang) * unsafe.pageSize(); if (afterFrameInit) { disp -= frameSize; } @@ -141,12 +141,12 @@ } } else { int verifiedEntryPointOffset = asm.codeBuffer.position(); - if (!isStub && stackShadowPages > 0) { - emitStackOverflowCheck(crb, stackShadowPages, false, true); + if (!isStub && pagesToBang > 0) { + emitStackOverflowCheck(crb, pagesToBang, false, true); assert asm.codeBuffer.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; } if (!isStub && asm.codeBuffer.position() == verifiedEntryPointOffset) { - asm.subq(rsp, frameSize, true); + asm.subqWide(rsp, frameSize); assert asm.codeBuffer.position() - verifiedEntryPointOffset >= PATCHED_VERIFIED_ENTRY_POINT_INSTRUCTION_SIZE; } else { asm.decrementq(rsp, frameSize); @@ -278,7 +278,7 @@ * @param installedCodeOwner see {@link Backend#emitCode} */ public void emitCodeBody(ResolvedJavaMethod installedCodeOwner, CompilationResultBuilder crb, LIRGenerator lirGen) { - lirGen.lir.emitCode(crb); + crb.emit(lirGen.lir); } /** diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java Fri Dec 13 14:27:03 2013 +0000 @@ -48,7 +48,7 @@ import com.oracle.graal.hotspot.nodes.*; import com.oracle.graal.hotspot.stubs.*; import com.oracle.graal.lir.*; -import com.oracle.graal.lir.StandardOp.PlaceholderOp; +import com.oracle.graal.lir.StandardOp.NoOp; import com.oracle.graal.lir.StandardOp.SaveRegistersOp; import com.oracle.graal.lir.amd64.*; import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; @@ -93,14 +93,14 @@ */ class SaveRbp { - final PlaceholderOp placeholder; + final NoOp placeholder; /** * The slot reserved for saving RBP. */ final StackSlot reservedSlot; - public SaveRbp(PlaceholderOp placeholder) { + public SaveRbp(NoOp placeholder) { this.placeholder = placeholder; this.reservedSlot = frameMap.allocateSpillSlot(Kind.Long); assert reservedSlot.getRawOffset() == -16 : reservedSlot.getRawOffset(); @@ -172,7 +172,7 @@ emitIncomingValues(params); - saveRbp = new SaveRbp(new PlaceholderOp(currentBlock, lir.lir(currentBlock).size())); + saveRbp = new SaveRbp(new NoOp(currentBlock, lir.lir(currentBlock).size())); append(saveRbp.placeholder); for (LocalNode local : graph.getNodes(LocalNode.class)) { @@ -433,6 +433,7 @@ @Override public void beforeRegisterAllocation() { + super.beforeRegisterAllocation(); boolean hasDebugInfo = lir.hasDebugInfo(); AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo); if (hasDebugInfo) { diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Fri Dec 13 14:27:03 2013 +0000 @@ -297,7 +297,7 @@ } } // Prologue done, Emit code for the LIR. - lirGen.lir.emitCode(crb); + crb.emit(lirGen.lir); // Now that code is emitted go back and figure out what the upper Bound stack size was. long maxStackSize = ((HSAILAssembler) crb.asm).upperBoundStackSize(); String spillsegStringFinal; diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackend.java Fri Dec 13 14:27:03 2013 +0000 @@ -284,7 +284,7 @@ } // Emit code for the LIR try { - lirGen.lir.emitCode(crb); + crb.emit(lirGen.lir); } catch (GraalInternalError e) { e.printStackTrace(); // TODO : Better error handling needs to be done once diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java --- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java Fri Dec 13 14:27:03 2013 +0000 @@ -81,15 +81,15 @@ * @param afterFrameInit specifies if the stack pointer has already been adjusted to allocate * the current frame */ - protected static void emitStackOverflowCheck(CompilationResultBuilder crb, int stackShadowPages, boolean afterFrameInit) { - if (stackShadowPages > 0) { + protected static void emitStackOverflowCheck(CompilationResultBuilder crb, int pagesToBang, boolean afterFrameInit) { + if (pagesToBang > 0) { SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; final int frameSize = crb.frameMap.totalFrameSize(); if (frameSize > 0) { int lastFramePage = frameSize / unsafe.pageSize(); // emit multiple stack bangs for methods with frames larger than a page for (int i = 0; i <= lastFramePage; i++) { - int disp = (i + stackShadowPages) * unsafe.pageSize(); + int disp = (i + pagesToBang) * unsafe.pageSize(); if (afterFrameInit) { disp -= frameSize; } @@ -124,8 +124,8 @@ final int frameSize = crb.frameMap.totalFrameSize(); SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; - if (!isStub && stackShadowPages > 0) { - emitStackOverflowCheck(crb, stackShadowPages, false); + if (!isStub && pagesToBang > 0) { + emitStackOverflowCheck(crb, pagesToBang, false); } new Save(sp, -frameSize, sp).emit(masm); @@ -207,7 +207,7 @@ crb.recordMark(Marks.MARK_VERIFIED_ENTRY); // Emit code for the LIR - lirGen.lir.emitCode(crb); + crb.emit(lirGen.lir); HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls(); diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java Fri Dec 13 14:27:03 2013 +0000 @@ -40,11 +40,11 @@ /** * This will be 0 if stack banging is disabled. */ - protected final int stackShadowPages; + protected final int pagesToBang; public HotSpotHostBackend(HotSpotGraalRuntime runtime, HotSpotProviders providers) { super(runtime, providers); - this.stackShadowPages = runtime.getConfig().useStackBanging ? runtime.getConfig().stackShadowPages : 0; + this.pagesToBang = runtime.getConfig().useStackBanging ? runtime.getConfig().stackShadowPages : 0; } @Override diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodData.java Fri Dec 13 14:27:03 2013 +0000 @@ -397,7 +397,7 @@ @Override public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { - return sb.append(format("count(%d)", getCounterValue(data, pos))); + return sb.append(format("count(%d) null_seen(%s) exception_seen(%s)", getCounterValue(data, pos), getNullSeen(data, pos), getExceptionSeen(data, pos))); } } @@ -524,7 +524,9 @@ public StringBuilder appendTo(StringBuilder sb, HotSpotMethodData data, int pos) { RawItemProfile profile = getRawTypeProfile(data, pos); TriState nullSeen = getNullSeen(data, pos); - sb.append(format("count(%d) null_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, getTypesNotRecordedExecutionCount(data, pos), profile.entries)); + TriState exceptionSeen = getExceptionSeen(data, pos); + sb.append(format("count(%d) null_seen(%s) exception_seen(%s) nonprofiled_count(%d) entries(%d)", getCounterValue(data, pos), nullSeen, exceptionSeen, + getTypesNotRecordedExecutionCount(data, pos), profile.entries)); for (int i = 0; i < profile.entries; i++) { long count = profile.counts[i]; sb.append(format("%n %s (%d, %4.2f)", MetaUtil.toJavaName(profile.items[i]), count, (double) count / profile.totalCount)); diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java Fri Dec 13 14:27:03 2013 +0000 @@ -73,12 +73,11 @@ @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - int sourceIndex = crb.getCurrentBlockIndex(); - if (trueDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex)) { + if (crb.isSuccessorEdge(trueDestination)) { jcc(masm, true, falseDestination); } else { jcc(masm, false, trueDestination); - if (!falseDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex)) { + if (!crb.isSuccessorEdge(falseDestination)) { masm.jmp(falseDestination.label()); } } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java --- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Fri Dec 13 14:27:03 2013 +0000 @@ -188,14 +188,13 @@ @Override public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) { - int sourceIndex = crb.getCurrentBlockIndex(); - if (trueDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex)) { + if (crb.isSuccessorEdge(trueDestination)) { HSAILCompare.emit(crb, masm, condition.negate(), x, y, z, !unordered); masm.cbr(masm.nameOf(falseDestination.label())); } else { HSAILCompare.emit(crb, masm, condition, x, y, z, unordered); masm.cbr(masm.nameOf(trueDestination.label())); - if (!falseDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex)) { + if (!crb.isSuccessorEdge(falseDestination)) { masm.jmp(falseDestination.label()); } } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java --- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXControlFlow.java Fri Dec 13 14:27:03 2013 +0000 @@ -85,12 +85,11 @@ @Override public void emitCode(CompilationResultBuilder crb, PTXMacroAssembler masm) { - int sourceIndex = crb.getCurrentBlockIndex(); - if (trueDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex)) { + if (crb.isSuccessorEdge(trueDestination)) { masm.bra(masm.nameOf(falseDestination.label()), predRegNum); } else { masm.bra(masm.nameOf(trueDestination.label())); - if (!falseDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex)) { + if (!crb.isSuccessorEdge(falseDestination)) { masm.jmp(falseDestination.label()); } } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java --- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java Fri Dec 13 14:27:03 2013 +0000 @@ -73,18 +73,17 @@ @Override public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { - int sourceIndex = crb.getCurrentBlockIndex(); Label actualTarget; Condition actualCondition; boolean needJump; - if (trueDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex)) { + if (crb.isSuccessorEdge(trueDestination)) { actualCondition = condition.negate(); actualTarget = falseDestination.label(); needJump = false; } else { actualCondition = condition; actualTarget = trueDestination.label(); - needJump = !falseDestination.isCodeEmittingOrderSuccessorEdge(sourceIndex); + needJump = !crb.isSuccessorEdge(falseDestination); } assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object; CC cc = kind == Kind.Int ? CC.Icc : CC.Xcc; diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java Fri Dec 13 14:27:03 2013 +0000 @@ -25,10 +25,8 @@ import java.util.*; import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -import com.oracle.graal.graph.*; +import com.oracle.graal.lir.LIRInstruction.StateProcedure; import com.oracle.graal.lir.StandardOp.BlockEndOp; -import com.oracle.graal.lir.asm.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.cfg.*; @@ -137,46 +135,6 @@ firstVariableNumber = num; } - public void emitCode(CompilationResultBuilder crb) { - crb.frameContext.enter(crb); - - // notifyBlocksOfSuccessors(); - - int index = 0; - for (Block b : codeEmittingOrder) { - crb.setCurrentBlockIndex(index++); - emitBlock(crb, b); - } - } - - private void emitBlock(CompilationResultBuilder crb, Block block) { - if (Debug.isDumpEnabled()) { - crb.blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); - } - - for (LIRInstruction op : lir(block)) { - if (Debug.isDumpEnabled()) { - crb.blockComment(String.format("%d %s", op.id(), op)); - } - - try { - emitOp(crb, op); - } catch (GraalInternalError e) { - throw e.addContext("lir instruction", block + "@" + op.id() + " " + op + "\n" + codeEmittingOrder); - } - } - } - - private static void emitOp(CompilationResultBuilder crb, LIRInstruction op) { - try { - op.emitCode(crb); - } catch (AssertionError t) { - throw new GraalInternalError(t); - } catch (RuntimeException t) { - throw new GraalInternalError(t); - } - } - public void setHasArgInCallerFrame() { hasArgInCallerFrame = true; } @@ -189,15 +147,55 @@ return hasArgInCallerFrame; } + /** + * Gets the exception edge (if any) originating at a given operation. + */ + public static LabelRef getExceptionEdge(LIRInstruction op) { + final LabelRef[] exceptionEdge = {null}; + op.forEachState(new StateProcedure() { + @Override + protected void doState(LIRFrameState state) { + if (state.exceptionEdge != null) { + assert exceptionEdge[0] == null; + exceptionEdge[0] = state.exceptionEdge; + } + } + }); + return exceptionEdge[0]; + } + + /** + * The maximum distance an operation with an {@linkplain #getExceptionEdge(LIRInstruction) + * exception edge} can be from the last instruction of a LIR block. The value of 2 is based on a + * non-void call operation that has an exception edge. Such a call op will have a move op after + * it to put the return value into the result variable. + *

+ * The rationale for such a constant is to limit the search for an insertion point when adding + * move operations at the end of a block. Such moves must be inserted before all control flow + * instructions. + */ + public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 2; + public static boolean verifyBlock(LIR lir, Block block) { List ops = lir.lir(block); if (ops.size() == 0) { - return true; + return false; } - for (LIRInstruction op : ops.subList(0, ops.size() - 1)) { + LIRInstruction opWithExceptionEdge = null; + int index = 0; + int lastIndex = ops.size() - 1; + for (LIRInstruction op : ops.subList(0, lastIndex)) { assert !(op instanceof BlockEndOp) : op.getClass(); + LabelRef exceptionEdge = getExceptionEdge(op); + if (exceptionEdge != null) { + assert opWithExceptionEdge == null : "multiple ops with an exception edge not allowed"; + opWithExceptionEdge = op; + int distanceFromEnd = lastIndex - index; + assert distanceFromEnd <= MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END; + } + index++; } - LIRInstruction end = ops.get(ops.size() - 1); + LIRInstruction end = ops.get(lastIndex); assert end instanceof BlockEndOp : end.getClass(); return true; } @@ -210,7 +208,9 @@ for (Block pred : block.getPredecessors()) { assert blocks.contains(pred) : "missing predecessor from: " + block + "to: " + pred; } - verifyBlock(lir, block); + if (!verifyBlock(lir, block)) { + return false; + } } return true; } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java Fri Dec 13 14:27:03 2013 +0000 @@ -22,8 +22,6 @@ */ package com.oracle.graal.lir; -import java.util.*; - import com.oracle.graal.asm.*; import com.oracle.graal.lir.StandardOp.BranchOp; import com.oracle.graal.lir.StandardOp.JumpOp; @@ -78,21 +76,8 @@ return ((StandardOp.LabelOp) lir.lir(getTargetBlock()).get(0)).getLabel(); } - /** - * Determines if the edge represented by this object is from a block to its lexical successor in - * the code emitting order of blocks. - * - * @param sourceIndex the index of this edge's {@linkplain #getSourceBlock() source} in the code - * emitting order - */ - public boolean isCodeEmittingOrderSuccessorEdge(int sourceIndex) { - List order = lir.codeEmittingOrder(); - assert order.get(sourceIndex) == block; - return sourceIndex < order.size() - 1 && order.get(sourceIndex + 1) == getTargetBlock(); - } - @Override public String toString() { - return suxIndex < block.getSuccessorCount() ? getTargetBlock().toString() : "?" + block + ":" + suxIndex + "?"; + return getSourceBlock() + " -> " + (suxIndex < block.getSuccessors().size() ? getTargetBlock() : "?"); } } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java Fri Dec 13 14:27:03 2013 +0000 @@ -113,7 +113,7 @@ @Override public void emitCode(CompilationResultBuilder crb) { - if (!destination.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { + if (!crb.isSuccessorEdge(destination)) { crb.asm.jmp(destination.label()); } } @@ -174,9 +174,10 @@ } /** - * Placeholder for a LIR instruction that will be subsequently replaced. + * A LIR operation that does nothing. If the operation records its position, it can be + * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}. */ - public static class PlaceholderOp extends LIRInstruction { + public static class NoOp extends LIRInstruction { /** * The block in which this instruction is located. @@ -188,7 +189,7 @@ */ final int index; - public PlaceholderOp(Block block, int index) { + public NoOp(Block block, int index) { this.block = block; this.index = index; } @@ -199,7 +200,9 @@ @Override public void emitCode(CompilationResultBuilder crb) { - throw new GraalInternalError(this + " should have been replaced"); + if (block != null) { + throw new GraalInternalError(this + " should have been replaced"); + } } } } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java Fri Dec 13 14:27:03 2013 +0000 @@ -116,9 +116,9 @@ } public void conditionalJumpOrDefault(int index, Condition condition, boolean canFallThrough) { - if (canFallThrough && defaultTarget.isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { + if (canFallThrough && crb.isSuccessorEdge(defaultTarget)) { conditionalJump(index, condition, keyTargets[index].label()); - } else if (canFallThrough && keyTargets[index].isCodeEmittingOrderSuccessorEdge(crb.getCurrentBlockIndex())) { + } else if (canFallThrough && crb.isSuccessorEdge(keyTargets[index])) { conditionalJump(index, condition.negate(), defaultTarget.label()); } else { conditionalJump(index, condition, keyTargets[index].label()); diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java Fri Dec 13 14:27:03 2013 +0000 @@ -32,6 +32,7 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.lir.*; +import com.oracle.graal.nodes.cfg.*; /** * Fills in a {@link CompilationResult} as its code is being assembled. @@ -59,7 +60,12 @@ public final FrameMap frameMap; /** - * The index of the block currently being processed in the code emitting block order. + * The LIR for which code is being generated. + */ + private LIR lir; + + /** + * The index of the block currently being emitted. */ private int currentBlockIndex; @@ -285,16 +291,58 @@ } /** - * Gets the index of the block currently being processed in the code emitting block order. + * Determines if a given edge from the block currently being emitted goes to its lexical + * successor. */ - public int getCurrentBlockIndex() { - return currentBlockIndex; + public boolean isSuccessorEdge(LabelRef edge) { + assert lir != null; + List order = lir.codeEmittingOrder(); + assert order.get(currentBlockIndex) == edge.getSourceBlock(); + return currentBlockIndex < order.size() - 1 && order.get(currentBlockIndex + 1) == edge.getTargetBlock(); } /** - * Sets the index of the block currently being processed in the code emitting block order. + * Emits code for {@code lir} in its {@linkplain LIR#codeEmittingOrder() code emitting order}. */ - public void setCurrentBlockIndex(int index) { - this.currentBlockIndex = index; + public void emit(@SuppressWarnings("hiding") LIR lir) { + assert this.lir == null; + assert currentBlockIndex == 0; + this.lir = lir; + this.currentBlockIndex = 0; + frameContext.enter(this); + for (Block b : lir.codeEmittingOrder()) { + emitBlock(b); + currentBlockIndex++; + } + this.lir = null; + this.currentBlockIndex = 0; + } + + private void emitBlock(Block block) { + if (Debug.isDumpEnabled()) { + blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); + } + + for (LIRInstruction op : lir.lir(block)) { + if (Debug.isDumpEnabled()) { + blockComment(String.format("%d %s", op.id(), op)); + } + + try { + emitOp(this, op); + } catch (GraalInternalError e) { + throw e.addContext("lir instruction", block + "@" + op.id() + " " + op + "\n" + lir.codeEmittingOrder()); + } + } + } + + private static void emitOp(CompilationResultBuilder crb, LIRInstruction op) { + try { + op.emitCode(crb); + } catch (AssertionError t) { + throw new GraalInternalError(t); + } catch (RuntimeException t) { + throw new GraalInternalError(t); + } } } diff -r 093353894575 -r e585ac5a385d graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Fri Dec 13 14:26:39 2013 +0000 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java Fri Dec 13 14:27:03 2013 +0000 @@ -102,6 +102,7 @@ /** * Called just before register allocation is performed on the LIR owned by this generator. + * Overriding implementations of this method must call the overridden method. */ void beforeRegisterAllocation();