# HG changeset patch # User Thomas Wuerthinger # Date 1328778201 -3600 # Node ID 6dda62bf5be4fb05c9753497e92a1845903c14eb # Parent 818757f088d3d288c3352e27204f6d7ceb4c5b9d# Parent 3a309467fc8e747cbb9e35924b5e76103ca3f7eb Merge. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java --- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java Thu Feb 09 10:03:21 2012 +0100 @@ -48,6 +48,10 @@ l.patchInstructions(this); } + public abstract void align(int modulus); + + public abstract void jmp(Label l); + protected abstract void patchJumpTarget(int branch, int jumpTarget); protected final void emitByte(int x) { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.asm/src/com/oracle/max/asm/NumUtil.java --- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/NumUtil.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/NumUtil.java Thu Feb 09 10:03:21 2012 +0100 @@ -98,4 +98,8 @@ assert isShort(v); return (short) v; } + + public static int roundUp(int number, int mod) { + return ((number + mod - 1) / mod) * mod; + } } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java --- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java Thu Feb 09 10:03:21 2012 +0100 @@ -759,6 +759,7 @@ } } + @Override public final void jmp(Label l) { if (l.isBound()) { jmp(l.position(), false); @@ -2876,6 +2877,7 @@ testl(AMD64.rax, new CiAddress(Word, r.asValue(Word), 0)); } + @Override public void align(int modulus) { if (codeBuffer.position() % modulus != 0) { nop(modulus - (codeBuffer.position() % modulus)); diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiExceptionSeen.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiExceptionSeen.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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.max.cri.ri; + + +/** + * Represents the three possibilities that an exception was seen at a specific BCI. + */ +public enum RiExceptionSeen { + TRUE, + FALSE, + UNKNOWN; + + public static RiExceptionSeen get(boolean value) { + return value ? TRUE : FALSE; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiProfilingInfo.java Thu Feb 09 10:03:21 2012 +0100 @@ -50,10 +50,12 @@ RiTypeProfile getTypeProfile(int bci); /** - * Returns true if the instruction at least once an exception was thrown at the given BCI. - * @return true if an exception was encountered during profiling, false otherwise. + * Returns information if the given BCI did ever throw an exception. + * @return @link{RiExceptionSeen.TRUE} if the instruction has thrown an exception at least once, + * @link{RiExceptionSeen.FALSE} if it never threw an exception, and @link{RiExceptionSeen.UNKNOWN} + * if this information was not recorded. */ - boolean getExceptionSeen(int bci); + RiExceptionSeen getExceptionSeen(int bci); /** * Returns an estimate how often the current BCI was executed. Avoid comparing execution counts to each other, diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java --- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiResolvedMethod.java Thu Feb 09 10:03:21 2012 +0100 @@ -49,6 +49,12 @@ int codeSize(); /** + * Gets the size of the compiled machine code. + * @return the size of the compiled machine code in bytes, or 0 if no compiled code exists. + */ + int compiledCodeSize(); + + /** * Gets the symbol used to link this method if it is native, otherwise {@code null}. */ String jniSymbol(); @@ -211,4 +217,9 @@ * @return {@code true} if this method can be inlined */ boolean canBeInlined(); + + /** + * Dumps the recorded profiling information to TTY. + */ + void dumpProfile(); } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/AssignRegisters.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/AssignRegisters.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.simple; + +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.alloc.util.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; + +public abstract class AssignRegisters { + public final LIR lir; + public final FrameMap frameMap; + + public AssignRegisters(LIR lir, FrameMap frameMap) { + this.lir = lir; + this.frameMap = frameMap; + } + + private CiBitMap curRegisterRefMap; + private CiBitMap curFrameRefMap; + + public void execute() { + ValueProcedure useProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value); } }; + ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value); } }; + ValueProcedure setReferenceProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return setReference(value); } }; + + Debug.log("==== start assign registers ===="); + for (int i = lir.linearScanOrder().size() - 1; i >= 0; i--) { + Block block = lir.linearScanOrder().get(i); + Debug.log("start block %s", block); + + curRegisterRefMap = frameMap.initRegisterRefMap(); + curFrameRefMap = frameMap.initFrameRefMap(); + + // Put all values live at the end of the block into the reference map. + locationsForBlockEnd(block).forEachLocation(setReferenceProc); + + for (int j = block.lir.size() - 1; j >= 0; j--) { + LIRInstruction op = block.lir.get(j); + Debug.log(" op %d %s", op.id(), op); + + op.forEachOutput(defProc); + op.forEachTemp(defProc); + op.forEachState(useProc); + op.forEachAlive(useProc); + + if (op.info != null) { + Debug.log(" registerRefMap: %s frameRefMap: %s", curRegisterRefMap, curFrameRefMap); + op.info.finish(new CiBitMap(curRegisterRefMap), new CiBitMap(curFrameRefMap), frameMap); + + if (op instanceof LIRXirInstruction) { + LIRXirInstruction xir = (LIRXirInstruction) op; + if (xir.infoAfter != null) { + xir.infoAfter.finish(new CiBitMap(curRegisterRefMap), new CiBitMap(curFrameRefMap), frameMap); + } + } + } + + // Process input operands after assigning the reference map, so that input operands that are used + // for the last time at this instruction are not part of the reference map. + op.forEachInput(useProc); + } + Debug.log("end block %s", block); + } + Debug.log("==== end assign registers ===="); + } + + private CiValue use(CiValue value) { + Debug.log(" use %s", value); + if (isLocation(value)) { + CiValue location = asLocation(value).location; + frameMap.setReference(location, curRegisterRefMap, curFrameRefMap); + return location; + } else { + frameMap.setReference(value, curRegisterRefMap, curFrameRefMap); + return value; + } + } + + private CiValue def(CiValue value) { + Debug.log(" def %s", value); + if (isLocation(value)) { + CiValue location = asLocation(value).location; + frameMap.clearReference(location, curRegisterRefMap, curFrameRefMap); + return location; + } else { + frameMap.clearReference(value, curRegisterRefMap, curFrameRefMap); + return value; + } + } + + private CiValue setReference(CiValue value) { + Debug.log(" setReference %s", value); + frameMap.setReference(asLocation(value).location, curRegisterRefMap, curFrameRefMap); + return value; + } + + protected abstract LocationMap locationsForBlockEnd(Block block); +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.simple; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static com.oracle.max.graal.lir.ValueUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; + +public class DataFlowAnalysis { + private final LIR lir; + private final RiRegisterConfig registerConfig; + + public DataFlowAnalysis(LIR lir, RiRegisterConfig registerConfig) { + this.lir = lir; + this.registerConfig = registerConfig; + } + + public void execute() { + numberInstructions(); + backwardDataFlow(); + } + + + private List blocks() { + return lir.linearScanOrder(); + } + + private int numVariables() { + return lir.numVariables(); + } + + private boolean isAllocatableRegister(CiValue value) { + return isRegister(value) && registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; + } + + + private int[] definitions; + private BitSet[] blockLiveIn; + private Block[] opIdBlock; + private Object[] opIdKilledValues; + + + public BitSet liveIn(Block block) { + return blockLiveIn[block.getId()]; + } + private void setLiveIn(Block block, BitSet liveIn) { + blockLiveIn[block.getId()] = liveIn; + } + + private Block blockOf(int opId) { + return opIdBlock[opId >> 1]; + } + private void setBlockOf(int opId, Block block) { + opIdBlock[opId >> 1] = block; + } + + private Object killedValues(int opId) { + return opIdKilledValues[opId]; + } + private void setKilledValues(int opId, Object killedValues) { + opIdKilledValues[opId] = killedValues; + } + + public void forEachKilled(LIRInstruction op, boolean end, ValueProcedure proc) { + Object entry = killedValues(op.id() + (end ? 1 : 0)); + if (entry == null) { + // Nothing to do + } else if (entry instanceof CiValue) { + CiValue newValue = proc.doValue((CiValue) entry, null, null); + assert newValue == entry : "procedure does not allow to change values"; + } else { + CiValue[] values = (CiValue[]) entry; + for (int i = 0; i < values.length; i++) { + if (values[i] != null) { + CiValue newValue = proc.doValue(values[i], null, null); + assert newValue == values[i] : "procedure does not allow to change values"; + } + } + } + } + + public int definition(Variable value) { + return definitions[value.index]; + } + + /** + * Numbers all instructions in all blocks. The numbering follows the {@linkplain ComputeLinearScanOrder linear scan order}. + */ + private void numberInstructions() { + ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return setDef(value); } }; + + int numInstructions = 0; + for (Block block : blocks()) { + numInstructions += block.lir.size(); + } + opIdBlock = new Block[numInstructions]; + opIdKilledValues = new Object[numInstructions << 1]; + definitions = new int[numVariables()]; + + curOpId = 0; + for (Block block : blocks()) { + for (LIRInstruction op : block.lir) { + op.setId(curOpId); + setBlockOf(curOpId, block); + + op.forEachTemp(defProc); + op.forEachOutput(defProc); + + curOpId += 2; // numbering of lirOps by two + } + } + assert curOpId == numInstructions << 1; + } + + private CiValue setDef(CiValue value) { + if (isVariable(value)) { + assert definitions[asVariable(value).index] == 0 : "Variable defined twice"; + definitions[asVariable(value).index] = curOpId; + } + return value; + } + + + private BitSet variableLive; + private BitSet registerLive; + private int curOpId; + + private void backwardDataFlow() { + ValueProcedure inputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId); } }; + ValueProcedure aliveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId + 1); } }; + ValueProcedure tempProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, true); } }; + ValueProcedure outputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, false); } }; + + blockLiveIn = new BitSet[blocks().size()]; + registerLive = new BitSet(); + + Debug.log("==== start backward data flow analysis ===="); + for (int i = blocks().size() - 1; i >= 0; i--) { + Block block = blocks().get(i); + Debug.log("start block %s loop %s", block, block.getLoop()); + + variableLive = new BitSet(); + for (Block sux : block.getSuccessors()) { + BitSet suxLive = liveIn(sux); + if (suxLive != null) { + Debug.log(" sux %s suxLive: %s", sux, suxLive); + variableLive.or(suxLive); + } + } + + assert registerLive.isEmpty() : "no fixed register must be alive before processing a block"; + + for (int j = block.lir.size() - 1; j >= 0; j--) { + LIRInstruction op = block.lir.get(j); + curOpId = op.id(); + Debug.log(" op %d %s variableLive: %s registerLive: %s", curOpId, op, variableLive, registerLive); + + op.forEachOutput(outputProc); + op.forEachTemp(tempProc); + op.forEachState(aliveProc); + op.forEachAlive(aliveProc); + op.forEachInput(inputProc); + } + + assert registerLive.isEmpty() : "no fixed register must be alive after processing a block"; + assert liveIn(block) == null; + setLiveIn(block, variableLive); + + if (block.isLoopHeader()) { + Debug.log(" loop header, propagating live set to loop blocks variableLive: %s", variableLive); + // All variables that are live at the beginning of a loop are also live the whole loop. + // This is guaranteed by the SSA form. + for (Block loop : block.getLoop().blocks) { + BitSet loopLiveIn = liveIn(loop); + assert loopLiveIn != null : "All loop blocks must have been processed before the loop header"; + loopLiveIn.or(variableLive); + Debug.log(" block %s loopLiveIn %s", loop, loopLiveIn); + } + } + + Debug.log("end block %s variableLive: %s", block, variableLive); + } + Debug.log("==== end backward data flow analysis ===="); + } + + private CiValue use(CiValue value, int killOpId) { + Debug.log(" use %s", value); + if (isVariable(value)) { + int variableIdx = asVariable(value).index; + assert definitions[variableIdx] < curOpId; + if (!variableLive.get(variableIdx)) { + Debug.log(" set live variable %d", variableIdx); + variableLive.set(variableIdx); + kill(value, killOpId); + } + + } else if (isAllocatableRegister(value)) { + int regNum = asRegister(value).number; + if (!registerLive.get(regNum)) { + Debug.log(" set live register %d", regNum); + registerLive.set(regNum); + kill(value, killOpId); + } + } + return value; + } + + private CiValue def(CiValue value, boolean isTemp) { + Debug.log(" def %s", value); + if (isVariable(value)) { + int variableIdx = asVariable(value).index; + assert definitions[variableIdx] == curOpId; + if (variableLive.get(variableIdx)) { + Debug.log(" clear live variable %d", variableIdx); + assert !isTemp : "temp variable cannot be used after the operation"; + variableLive.clear(variableIdx); + } else { + // Variable has never been used, so kill it immediately after the definition. + kill(value, curOpId + 1); + } + + } else if (isAllocatableRegister(value)) { + int regNum = asRegister(value).number; + if (registerLive.get(regNum)) { + Debug.log(" clear live register %d", regNum); + assert !isTemp : "temp variable cannot be used after the operation"; + registerLive.clear(regNum); + } else { + // Register has never been used, so kill it immediately after the definition. + kill(value, curOpId + 1); + } + } + return value; + } + + private void kill(CiValue value, int opId) { + if (opId < 0) { + return; + } + if (isVariable(value)) { + int defOpId = definitions[asVariable(value).index]; + assert defOpId > 0 && defOpId <= opId; + + Block defBlock = blockOf(defOpId); + Block useBlock = blockOf(opId); + + if (useBlock.getLoop() != null && useBlock.getLoop() != defBlock.getLoop()) { + // This is a value defined outside of the loop it is currently used in. Therefore, it is live the whole loop + // and is not killed by the current instruction. + Debug.log(" no kill because use in %s, definition in %s", useBlock.getLoop(), defBlock.getLoop()); + return; + } + } + Debug.log(" kill %s at %d", value, opId); + + Object entry = killedValues(opId); + if (entry == null) { + setKilledValues(opId, value); + } else if (entry instanceof CiValue) { + setKilledValues(opId, new CiValue[] {(CiValue) entry, value}); + } else { + CiValue[] killed = (CiValue[]) entry; + for (int i = 0; i < killed.length; i++) { + if (killed[i] == null) { + killed[i] = value; + return; + } + } + int oldLen = killed.length; + killed = Arrays.copyOf(killed, oldLen * 2); + setKilledValues(opId, killed); + killed[oldLen] = value; + } + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/LinearScanAllocator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/LinearScanAllocator.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.simple; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiRegister.RegisterFlag; +import com.oracle.max.graal.alloc.util.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; + +public class LinearScanAllocator { + private final LIR lir; + private final FrameMap frameMap; + + private final DataFlowAnalysis dataFlow; + + public LinearScanAllocator(LIR lir, FrameMap frameMap) { + this.lir = lir; + this.frameMap = frameMap; + + this.dataFlow = new DataFlowAnalysis(lir, frameMap.registerConfig); + this.blockBeginLocations = new LocationMap[lir.linearScanOrder().size()]; + this.blockEndLocations = new LocationMap[lir.linearScanOrder().size()]; + this.moveResolver = new MoveResolverImpl(lir, frameMap); + + this.variableLastUse = new int[lir.numVariables()]; + } + + private class MoveResolverImpl extends MoveResolver { + public MoveResolverImpl(LIR lir, FrameMap frameMap) { + super(lir, frameMap); + } + + @Override + protected CiValue scratchRegister(Variable spilled) { + GraalInternalError.shouldNotReachHere("needs working implementation"); + + EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); + CiRegister[] availableRegs = categorizedRegs.get(spilled.flag); + for (CiRegister reg : availableRegs) { + if (curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null) { + return reg.asValue(spilled.kind); + } + } + throw new CiBailout("No register found"); + } + } + + private class ResolveDataFlowImpl extends ResolveDataFlow { + public ResolveDataFlowImpl(LIR lir, MoveResolver moveResolver, DataFlowAnalysis dataFlow) { + super(lir, moveResolver, dataFlow); + } + + @Override + protected LocationMap locationsForBlockBegin(Block block) { + return beginLocationsFor(block); + } + + @Override + protected LocationMap locationsForBlockEnd(Block block) { + return endLocationsFor(block); + } + } + + private class AssignRegistersImpl extends AssignRegisters { + public AssignRegistersImpl(LIR lir, FrameMap frameMap) { + super(lir, frameMap); + } + + @Override + protected LocationMap locationsForBlockEnd(Block block) { + return endLocationsFor(block); + } + } + + + private int maxRegisterNum() { + return frameMap.target.arch.registers.length; + } + + private boolean isAllocatableRegister(CiValue value) { + return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; + } + + + private final LocationMap[] blockBeginLocations; + + private LocationMap beginLocationsFor(Block block) { + return blockBeginLocations[block.getId()]; + } + private void setBeginLocationsFor(Block block, LocationMap locations) { + blockBeginLocations[block.getId()] = locations; + } + + private final LocationMap[] blockEndLocations; + + private LocationMap endLocationsFor(Block block) { + return blockEndLocations[block.getId()]; + } + private void setEndLocationsFor(Block block, LocationMap locations) { + blockEndLocations[block.getId()] = locations; + } + + private final int[] variableLastUse; + + private int lastUseFor(Variable variable) { + return variableLastUse[variable.index]; + } + + private void setLastUseFor(Variable variable, int lastUse) { + variableLastUse[variable.index] = lastUse; + } + + private MoveResolver moveResolver; + private LocationMap curLocations; + private CiValue[] curInRegisterState; + private CiValue[] curOutRegisterState; + private BitSet curLiveIn; + private int curOpId; + private boolean curPhiDefs; + + private LocationMap canonicalSpillLocations; + + public void execute() { + assert LIRVerifier.verify(true, lir, frameMap); + + dataFlow.execute(); + IntervalPrinter.printBeforeAllocation("Before register allocation", lir, frameMap.registerConfig, dataFlow); + + allocate(); + + IntervalPrinter.printAfterAllocation("After linear scan allocation", lir, frameMap.registerConfig, dataFlow, blockEndLocations); + + ResolveDataFlow resolveDataFlow = new ResolveDataFlowImpl(lir, moveResolver, dataFlow); + resolveDataFlow.execute(); + frameMap.finish(); + + IntervalPrinter.printAfterAllocation("After resolve data flow", lir, frameMap.registerConfig, dataFlow, blockEndLocations); + assert RegisterVerifier.verify(lir, frameMap); + + AssignRegisters assignRegisters = new AssignRegistersImpl(lir, frameMap); + assignRegisters.execute(); + + Debug.dump(lir, "After register asignment"); + assert LIRVerifier.verify(false, lir, frameMap); + } + + private void allocate() { + ValueProcedure recordUseProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return recordUse(value); } }; + ValueProcedure killNonLiveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killNonLive(value); } }; + ValueProcedure unblockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return unblock(value); } }; + ValueProcedure killProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value); } }; + ValueProcedure blockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return block(value); } }; + ValueProcedure useProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; + ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, mode, flags); } }; + + Debug.log("==== start linear scan allocation ===="); + canonicalSpillLocations = new LocationMap(lir.numVariables()); + curInRegisterState = new CiValue[maxRegisterNum()]; + curOutRegisterState = new CiValue[maxRegisterNum()]; + for (Block block : lir.linearScanOrder()) { + Debug.log("start block %s %s", block, block.getLoop()); + + Arrays.fill(curOutRegisterState, null); + if (block.getDominator() != null) { + LocationMap dominatorState = endLocationsFor(block.getDominator()); + curLocations = new LocationMap(dominatorState); + // Clear out all variables that are not live at the begin of this block + curLiveIn = dataFlow.liveIn(block); + curLocations.forEachLocation(killNonLiveProc); + assert checkInputState(block); + } else { + curLocations = new LocationMap(lir.numVariables()); + } + Debug.log(logCurrentState()); + + for (int opIdx = 0; opIdx < block.lir.size(); opIdx++) { + LIRInstruction op = block.lir.get(opIdx); + curOpId = op.id(); + curPhiDefs = opIdx == 0; + + Debug.log(" op %d %s", op.id(), op); + + System.arraycopy(curOutRegisterState, 0, curInRegisterState, 0, curOutRegisterState.length); + + // Unblock fixed registers that are only used for inputs in curOutRegisterState. + dataFlow.forEachKilled(op, false, unblockProc); + // Block fixed registers defined by this instruction in curOutRegisterState. + op.forEachTemp(blockProc); + op.forEachOutput(blockProc); + + op.forEachInput(recordUseProc); + op.forEachAlive(recordUseProc); + + moveResolver.init(block.lir, opIdx); + // Process Alive before Input because they are more restricted and the same variable can be Alive and Input. + op.forEachAlive(useProc); + op.forEachInput(useProc); + + dataFlow.forEachKilled(op, false, killProc); + + if (op.hasCall()) { + spillCallerSaveRegisters(); + } + + op.forEachTemp(defProc); + op.forEachOutput(defProc); + + // Fixed temp and output registers can evict variables from their assigned register, allocate new location for them. + fixupEvicted(); + // State values are the least critical and can get the leftover registers (or stack slots if no more register available). + op.forEachState(useProc); + + if (opIdx == 0) { + assert !moveResolver.hasMappings() : "cannot insert spill moves before label"; + setBeginLocationsFor(block, new LocationMap(curLocations)); + } + moveResolver.resolve(); + + dataFlow.forEachKilled(op, true, unblockProc); + dataFlow.forEachKilled(op, true, killProc); + + curOpId = -1; + } + + assert endLocationsFor(block) == null; + setEndLocationsFor(block, curLocations); + + logCurrentState(); + Debug.log("end block %s", block); + } + + moveResolver.finish(); + Debug.log("==== end linear scan allocation ===="); + } + + private CiValue killNonLive(CiValue value) { + assert isLocation(value); + if (!curLiveIn.get(asLocation(value).variable.index)) { + return null; + + } else if (isAllocatableRegister(asLocation(value).location)) { + int regNum = asRegister(asLocation(value).location).number; + assert curOutRegisterState[regNum] == null; + curOutRegisterState[regNum] = value; + } + return value; + } + + private CiValue unblock(CiValue value) { + if (isAllocatableRegister(value)) { + Debug.log(" unblock register %s", value); + int regNum = asRegister(value).number; + assert curOutRegisterState[regNum] == value; + curOutRegisterState[regNum] = null; + } + return value; + } + + private CiValue kill(CiValue value) { + if (isVariable(value)) { + Location location = curLocations.get(asVariable(value)); + Debug.log(" kill location %s", location); + if (isRegister(location.location)) { + int regNum = asRegister(location.location).number; + if (curOutRegisterState[regNum] == location) { + curOutRegisterState[regNum] = null; + } + } + curLocations.clear(asVariable(value)); + } + return value; + } + + + private CiValue block(CiValue value) { + if (isAllocatableRegister(value)) { + Debug.log(" block %s", value); + int regNum = asRegister(value).number; + assert curOutRegisterState[regNum] == null || curOutRegisterState[regNum] instanceof Location; + curOutRegisterState[regNum] = value; + } + return value; + } + + private void spillCallerSaveRegisters() { + Debug.log(" spill caller save registers in curInRegisterState %s", Arrays.toString(curInRegisterState)); + for (CiRegister reg : frameMap.registerConfig.getCallerSaveRegisters()) { + CiValue in = curInRegisterState[reg.number]; + if (in != null && isLocation(in)) { + spill(asLocation(in)); + } + } + } + + private CiValue recordUse(CiValue value) { + if (isVariable(value)) { + assert lastUseFor(asVariable(value)) <= curOpId; + setLastUseFor(asVariable(value), curOpId); + + } + return value; + } + + private CiValue use(CiValue value, OperandMode mode, EnumSet flags) { + assert mode == OperandMode.Input || mode == OperandMode.Alive; + if (isVariable(value)) { + // State values are not recorded beforehand because it does not matter if they are spilled. Still, it is necessary to record them as used now. + recordUse(value); + + Location curLoc = curLocations.get(asVariable(value)); + if (isStackSlot(curLoc.location) && flags.contains(OperandFlag.Stack)) { + Debug.log(" use %s %s: use current stack slot %s", mode, value, curLoc.location); + return curLoc; + } + if (isRegister(curLoc.location)) { + int regNum = asRegister(curLoc.location).number; + assert curInRegisterState[regNum] == curLoc; + if (mode == OperandMode.Input || curOutRegisterState[regNum] == curLoc) { + Debug.log(" use %s %s: use current register %s", mode, value, curLoc.location); + return curLoc; + } + } + + Debug.log(" use %s %s", mode, value); + + Location newLoc = allocateRegister(asVariable(value), mode, flags); + if (newLoc != curLoc) { + moveResolver.add(curLoc, newLoc); + } + return newLoc; + } else { + assert !isAllocatableRegister(value) || curInRegisterState[asRegister(value).number] == value; + } + return value; + } + + private static final EnumSet SPILL_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + + private CiValue def(CiValue value, OperandMode mode, EnumSet flags) { + assert mode == OperandMode.Temp || mode == OperandMode.Output; + if (isVariable(value)) { + Debug.log(" def %s %s", mode, value); + assert curLocations.get(asVariable(value)) == null; + + Location newLoc = allocateRegister(asVariable(value), mode, flags); + return newLoc; + } + return value; + } + + + private void fixupEvicted() { + for (int i = 0; i < curInRegisterState.length; i++) { + CiValue in = curInRegisterState[i]; + CiValue out = curOutRegisterState[i]; + + if (in != null && in != out && isLocation(in) && curLocations.get(asLocation(in).variable) == in) { + Debug.log(" %s was evicted by %s, need to allocate new location", in, out); + Location oldLoc = asLocation(in); + Location newLoc = allocateRegister(oldLoc.variable, OperandMode.Alive, SPILL_FLAGS); + assert oldLoc != newLoc; + moveResolver.add(oldLoc, newLoc); + } + + + } + } + + + private Location allocateRegister(final Variable variable, OperandMode mode, EnumSet flags) { +// if (flags.contains(OperandFlag.RegisterHint)) { +// CiValue result = curInstruction.forEachRegisterHint(variable, mode, new ValueProcedure() { +// @Override +// public CiValue doValue(CiValue registerHint) { +// Debug.log(" registerHint %s", registerHint); +// CiRegister hint = null; +// if (isRegister(registerHint)) { +// hint = asRegister(registerHint); +// } else if (isLocation(registerHint) && isRegister(asLocation(registerHint).location)) { +// hint = asRegister(asLocation(registerHint).location); +// } +// if (hint != null && hint.isSet(variable.flag) && isFree(hint, inRegisterState, outRegisterState)) { +// return selectRegister(hint, variable, inRegisterState, outRegisterState); +// } +// return null; +// } +// }); +// +// if (result != null) { +// return asLocation(result); +// } +// } +// + EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); + CiRegister[] availableRegs = categorizedRegs.get(variable.flag); + + Location bestSpillCandidate = null; + for (CiRegister reg : availableRegs) { + if (isFree(reg, mode)) { + return selectRegister(reg, variable, mode); + } else { + Location spillCandidate = spillCandidate(reg); + if (betterSpillCandidate(spillCandidate, bestSpillCandidate)) { + bestSpillCandidate = spillCandidate; + } + } + } + + if (flags.contains(OperandFlag.Stack) && betterSpillCandidate(curLocations.get(variable), bestSpillCandidate)) { + return selectSpillSlot(variable); + } + + if (bestSpillCandidate == null) { + if (curPhiDefs) { + return selectSpillSlot(variable); + } + + // This should not happen as long as all LIR instructions have fulfillable register constraints. But be safe in product mode and bail out. + assert false; + throw new CiBailout("No register available"); + } + + spill(bestSpillCandidate); + + return selectRegister(asRegister(bestSpillCandidate.location), variable, mode); + } + + private void spill(Location value) { + Location newLoc = spillLocation(value.variable); + Debug.log(" spill %s to %s", value, newLoc); + if (!curPhiDefs) { + moveResolver.add(value, newLoc); + } + curLocations.put(newLoc); + + CiRegister reg = asRegister(value.location); + assert curInRegisterState[reg.number] == value; + curInRegisterState[reg.number] = null; + if (curOutRegisterState[reg.number] == value) { + curOutRegisterState[reg.number] = null; + } + } + + private boolean isFree(CiRegister reg, OperandMode mode) { + switch (mode) { + case Input: return curInRegisterState[reg.number] == null; + case Alive: return curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null; + case Temp: return curOutRegisterState[reg.number] == null; + case Output: return curOutRegisterState[reg.number] == null; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + private Location spillCandidate(CiRegister reg) { + CiValue in = curInRegisterState[reg.number]; + CiValue out = curOutRegisterState[reg.number]; + if (in == out && in != null && isLocation(in) && lastUseFor(asLocation(in).variable) < curOpId) { + return asLocation(in); + } + return null; + } + + private boolean betterSpillCandidate(Location loc, Location compare) { + if (loc == null) { + return false; + } + if (compare == null) { + return true; + } + if (canonicalSpillLocations.get(loc.variable) != null && canonicalSpillLocations.get(compare.variable) == null) { + return true; + } + return dataFlow.definition(loc.variable) < dataFlow.definition(compare.variable); + } + + private Location spillLocation(Variable variable) { + Location result = canonicalSpillLocations.get(variable); + if (result == null) { + result = new Location(variable, frameMap.allocateSpillSlot(variable.kind)); + canonicalSpillLocations.put(result); + } + return result; + } + + private Location selectRegister(CiRegister reg, Variable variable, OperandMode mode) { + assert isFree(reg, mode); + + Location loc = new Location(variable, reg.asValue(variable.kind)); + if (mode == OperandMode.Input || mode == OperandMode.Alive) { + curInRegisterState[reg.number] = loc; + } + curOutRegisterState[reg.number] = loc; + curLocations.put(loc); + recordUse(variable); + + Debug.log(" selected register %s", loc); + return loc; + } + + private Location selectSpillSlot(Variable variable) { + Location loc = spillLocation(variable); + curLocations.put(loc); + recordUse(variable); + + Debug.log(" selected spill slot %s", loc); + return loc; + } + + private boolean checkInputState(final Block block) { + final BitSet liveState = new BitSet(); + curLocations.forEachLocation(new ValueProcedure() { + @Override + public CiValue doValue(CiValue value) { + liveState.set(asLocation(value).variable.index); + + for (Block pred : block.getPredecessors()) { + LocationMap predState = endLocationsFor(pred); + if (predState != null) { + assert predState.get(asLocation(value).variable) != null; + } else { + assert block.isLoopHeader(); + } + } + return value; + } + }); + assert liveState.equals(curLiveIn); + return true; + } + + + private String logCurrentState() { + final StringBuilder sb = new StringBuilder(); + sb.append(" current lcoations: "); + curLocations.forEachLocation(new ValueProcedure() { + @Override + public CiValue doValue(CiValue value) { + sb.append(value).append(" "); + return value; + } + }); + return sb.toString(); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.simple; + +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.alloc.util.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.StandardOp.*; +import com.oracle.max.graal.lir.cfg.*; + +public abstract class ResolveDataFlow { + public final LIR lir; + public final MoveResolver moveResolver; + public final DataFlowAnalysis dataFlow; + + public ResolveDataFlow(LIR lir, MoveResolver moveResolver, DataFlowAnalysis dataFlow) { + this.lir = lir; + this.moveResolver = moveResolver; + this.dataFlow = dataFlow; + } + + private LocationMap curFromLocations; + + public void execute() { + ValueProcedure locMappingProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return locMapping(value); } }; + + Debug.log("==== start resolve data flow ===="); + for (Block toBlock : lir.linearScanOrder()) { + PhiLabelOp phiDefs = null; + if (toBlock.lir.get(0) instanceof PhiLabelOp) { + phiDefs = (PhiLabelOp) toBlock.lir.get(0); + } + + for (Block fromBlock : toBlock.getPredecessors()) { + Debug.log("start edge %s -> %s", fromBlock, toBlock); + findInsertPos(fromBlock, toBlock); + + LocationMap toLocations = locationsForBlockBegin(toBlock); + curFromLocations = locationsForBlockEnd(fromBlock); + if (toLocations != curFromLocations) { + toLocations.forEachLocation(locMappingProc); + } + + if (phiDefs != null) { + PhiJumpOp phiInputs = (PhiJumpOp) fromBlock.lir.get(fromBlock.lir.size() - 1); + phiMapping(phiInputs.getPhiInputs(), phiDefs.getPhiDefinitions()); + phiInputs.markResolved(); + } + + moveResolver.resolve(); + Debug.log("end edge %s -> %s", fromBlock, toBlock); + } + + if (phiDefs != null) { + // Phi functions are resolved with moves now, so delete them. + phiDefs.markResolved(); + } + } + moveResolver.finish(); + Debug.log("==== end resolve data flow ===="); + } + + private CiValue locMapping(CiValue value) { + Location to = asLocation(value); + Location from = curFromLocations.get(to.variable); + if (value != from && from != null) { + moveResolver.add(from, to); + } + return value; + } + + private void phiMapping(CiValue[] inputs, CiValue[] outputs) { + assert inputs.length == outputs.length; + for (int i = 0; i < inputs.length; i++) { + if (inputs[i] != outputs[i]) { + moveResolver.add(inputs[i], asLocation(outputs[i])); + } + } + } + + private void findInsertPos(Block fromBlock, Block toBlock) { + assert fromBlock.getSuccessors().contains(toBlock) && toBlock.getPredecessors().contains(fromBlock); + + if (fromBlock.numberOfSux() == 1) { + List instructions = fromBlock.lir; + LIRInstruction instr = instructions.get(instructions.size() - 1); + assert instr instanceof StandardOp.JumpOp : "block does not end with an unconditional jump"; + moveResolver.init(instructions, instructions.size() - 1); + Debug.log(" insert at end of %s before %d", fromBlock, instructions.size() - 1); + + } else if (toBlock.numberOfPreds() == 1) { + moveResolver.init(toBlock.lir, 1); + Debug.log(" insert at beginning of %s before %d", toBlock, 1); + + } else { + GraalInternalError.shouldNotReachHere("Critical edge not split"); + } + } + + protected abstract LocationMap locationsForBlockBegin(Block block); + protected abstract LocationMap locationsForBlockEnd(Block block); +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.simple; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiRegister.RegisterFlag; +import com.oracle.max.graal.alloc.util.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; + +public class SpillAllAllocator { + private final LIR lir; + private final FrameMap frameMap; + + private final DataFlowAnalysis dataFlow; + + public SpillAllAllocator(LIR lir, FrameMap frameMap) { + this.lir = lir; + this.frameMap = frameMap; + + this.dataFlow = new DataFlowAnalysis(lir, frameMap.registerConfig); + this.blockLocations = new LocationMap[lir.linearScanOrder().size()]; + this.moveResolver = new MoveResolverImpl(lir, frameMap); + } + + private class MoveResolverImpl extends MoveResolver { + public MoveResolverImpl(LIR lir, FrameMap frameMap) { + super(lir, frameMap); + } + + @Override + protected CiValue scratchRegister(Variable spilled) { + EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); + CiRegister[] availableRegs = categorizedRegs.get(spilled.flag); + for (CiRegister reg : availableRegs) { + if (curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null) { + return reg.asValue(spilled.kind); + } + } + throw new CiBailout("No register found"); + } + } + + private class ResolveDataFlowImpl extends ResolveDataFlow { + public ResolveDataFlowImpl(LIR lir, MoveResolver moveResolver, DataFlowAnalysis dataFlow) { + super(lir, moveResolver, dataFlow); + } + + @Override + protected LocationMap locationsForBlockBegin(Block block) { + assert block.numberOfPreds() > 0 && block.getDominator() != null; + return locationsFor(block.getDominator()); + } + + @Override + protected LocationMap locationsForBlockEnd(Block block) { + return locationsFor(block); + } + } + + private class AssignRegistersImpl extends AssignRegisters { + public AssignRegistersImpl(LIR lir, FrameMap frameMap) { + super(lir, frameMap); + } + + @Override + protected LocationMap locationsForBlockEnd(Block block) { + return locationsFor(block); + } + } + + + private int maxRegisterNum() { + return frameMap.target.arch.registers.length; + } + + private boolean isAllocatableRegister(CiValue value) { + return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; + } + + + private final LocationMap[] blockLocations; + + private LocationMap locationsFor(Block block) { + return blockLocations[block.getId()]; + } + private void setLocationsFor(Block block, LocationMap locations) { + blockLocations[block.getId()] = locations; + } + + private MoveResolver moveResolver; + private LocationMap curStackLocations; + private LocationMap curRegisterLocations; + private Object[] curInRegisterState; + private Object[] curOutRegisterState; + private BitSet curLiveIn; + private LIRInstruction curInstruction; + + public void execute() { + assert LIRVerifier.verify(true, lir, frameMap); + + dataFlow.execute(); + IntervalPrinter.printBeforeAllocation("Before register allocation", lir, frameMap.registerConfig, dataFlow); + + allocate(); + + IntervalPrinter.printAfterAllocation("After spill all allocation", lir, frameMap.registerConfig, dataFlow, blockLocations); + + ResolveDataFlow resolveDataFlow = new ResolveDataFlowImpl(lir, moveResolver, dataFlow); + resolveDataFlow.execute(); + frameMap.finish(); + + IntervalPrinter.printAfterAllocation("After resolve data flow", lir, frameMap.registerConfig, dataFlow, blockLocations); + assert RegisterVerifier.verify(lir, frameMap); + + AssignRegisters assignRegisters = new AssignRegistersImpl(lir, frameMap); + assignRegisters.execute(); + + Debug.dump(lir, "After register asignment"); + assert LIRVerifier.verify(false, lir, frameMap); + } + + private void allocate() { + ValueProcedure killNonLiveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killNonLive(value); } }; + ValueProcedure killBeginProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, false); } }; + ValueProcedure killEndProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, true); } }; + ValueProcedure killLocationProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killLocation(value); } }; + ValueProcedure blockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return block(value); } }; + ValueProcedure loadProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return load(value, mode, flags); } }; + ValueProcedure spillProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return spill(value, mode, flags); } }; + ValueProcedure useSlotProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return useSlot(value); } }; + + Debug.log("==== start spill all allocation ===="); + curInRegisterState = new Object[maxRegisterNum()]; + curOutRegisterState = new Object[maxRegisterNum()]; + curRegisterLocations = new LocationMap(lir.numVariables()); + for (Block block : lir.linearScanOrder()) { + Debug.log("start block %s %s", block, block.getLoop()); + assert checkEmpty(curOutRegisterState); + + if (block.getDominator() != null) { + LocationMap dominatorState = locationsFor(block.getDominator()); + curStackLocations = new LocationMap(dominatorState); + // Clear out all variables that are not live at the begin of this block + curLiveIn = dataFlow.liveIn(block); + curStackLocations.forEachLocation(killNonLiveProc); + assert checkInputState(block); + } else { + curStackLocations = new LocationMap(lir.numVariables()); + } + Debug.log(logCurrentState()); + + for (int opIdx = 0; opIdx < block.lir.size(); opIdx++) { + LIRInstruction op = block.lir.get(opIdx); + curInstruction = op; + Debug.log(" op %d %s", op.id(), op); + + assert curRegisterLocations.checkEmpty(); + + System.arraycopy(curOutRegisterState, 0, curInRegisterState, 0, curOutRegisterState.length); + + // Block fixed registers that are defined by this instruction, so that they are no longer available for normal allocation. + op.forEachTemp(blockProc); + op.forEachOutput(blockProc); + + moveResolver.init(block.lir, opIdx); + // Process Alive before Input because they are more restricted and the same variable can be Alive and Input. + op.forEachAlive(loadProc); + op.forEachInput(loadProc); + moveResolver.resolve(); + op.forEachState(useSlotProc); + + dataFlow.forEachKilled(op, false, killBeginProc); + assert !op.hasCall() || checkNoCallerSavedRegister() : "caller saved register in use accross call site"; + + moveResolver.init(block.lir, opIdx + 1); + op.forEachTemp(spillProc); + op.forEachOutput(spillProc); + moveResolver.resolve(); + + dataFlow.forEachKilled(op, true, killEndProc); + curRegisterLocations.forEachLocation(killLocationProc); + + assert curRegisterLocations.checkEmpty(); + curInstruction = null; + } + assert checkEmpty(curOutRegisterState); + assert locationsFor(block) == null; + setLocationsFor(block, curStackLocations); + + logCurrentState(); + Debug.log("end block %s", block); + } + + moveResolver.finish(); + Debug.log("==== end spill all allocation ===="); + } + + private CiValue killNonLive(CiValue value) { + assert isLocation(value); + if (!curLiveIn.get(asLocation(value).variable.index)) { + return null; + } + return value; + } + + private CiValue kill(CiValue value, boolean end) { + if (isVariable(value)) { + Debug.log(" kill variable %s", value); + + Variable variable = asVariable(value); + curStackLocations.clear(variable); + + Location loc = curRegisterLocations.get(variable); + if (loc != null) { + killLocation(loc); + curRegisterLocations.clear(variable); + + Debug.log(" location %s", loc); + assert isAllocatableRegister(loc.location); + + int regNum = asRegister(loc.location).number; + if (curOutRegisterState[regNum] == loc) { + curOutRegisterState[regNum] = null; + } + } + + } else if (isAllocatableRegister(value)) { + Debug.log(" kill register %s", value); + int regNum = asRegister(value).number; + assert curOutRegisterState[regNum] == null || curOutRegisterState[regNum] instanceof LIRInstruction && curInstruction != null; + + if (end || curOutRegisterState[regNum] != curInstruction) { + curOutRegisterState[regNum] = null; + } + + } else { + throw GraalInternalError.shouldNotReachHere(); + } + return value; + } + + private CiValue killLocation(CiValue value) { + Debug.log(" kill location %s", value); + assert isAllocatableRegister(asLocation(value).location); + + int regNum = asRegister(asLocation(value).location).number; + if (curOutRegisterState[regNum] == value) { + curOutRegisterState[regNum] = null; + } + return null; + } + + private CiValue block(CiValue value) { + if (isAllocatableRegister(value)) { + Debug.log(" block %s", value); + int regNum = asRegister(value).number; + assert curInstruction != null; + assert curOutRegisterState[regNum] == null || curOutRegisterState[regNum] instanceof LIRInstruction; + curOutRegisterState[regNum] = curInstruction; + } + return value; + } + + private CiValue load(CiValue value, OperandMode mode, EnumSet flags) { + assert mode == OperandMode.Input || mode == OperandMode.Alive; + if (flags.contains(OperandFlag.Stack)) { + return useSlot(value); + } + if (isVariable(value)) { + Debug.log(" load %s", value); + Location regLoc = curRegisterLocations.get(asVariable(value)); + if (regLoc != null) { + // This variable has already been processed before. + Debug.log(" found location %s", regLoc); + } else { + regLoc = allocateRegister(asVariable(value), curInRegisterState, mode == OperandMode.Alive ? curOutRegisterState : null, mode, flags); + Location stackLoc = curStackLocations.get(asVariable(value)); + assert stackLoc != null; + moveResolver.add(stackLoc, regLoc); + } + return regLoc; + } else { + assert !isAllocatableRegister(value) || curInRegisterState[asRegister(value).number] instanceof LIRInstruction; + return value; + } + } + + private CiValue spill(CiValue value, OperandMode mode, EnumSet flags) { + assert mode == OperandMode.Temp || mode == OperandMode.Output; + if (flags.contains(OperandFlag.Stack)) { + return defSlot(value); + } + if (isVariable(value)) { + Debug.log(" spill %s", value); + assert curStackLocations.get(asVariable(value)) == null; + Location regLoc = allocateRegister(asVariable(value), null, curOutRegisterState, mode, flags); + if (mode == OperandMode.Output) { + Location stackLoc = new Location(asVariable(value), frameMap.allocateSpillSlot(value.kind)); + curStackLocations.put(stackLoc); + moveResolver.add(regLoc, stackLoc); + } + return regLoc; + } else { + assert !isAllocatableRegister(value) || curOutRegisterState[asRegister(value).number] == curInstruction && curInstruction != null; + return value; + } + } + + private CiValue useSlot(CiValue value) { + if (isVariable(value)) { + Debug.log(" useSlot %s", value); + Location stackLoc = curStackLocations.get(asVariable(value)); + assert stackLoc != null; + Debug.log(" slot %s", stackLoc); + return stackLoc; + } else { + return value; + } + } + + private CiValue defSlot(CiValue value) { + if (isVariable(value)) { + Debug.log(" assignSlot %s", value); + Location stackLoc = new Location(asVariable(value), frameMap.allocateSpillSlot(value.kind)); + assert curStackLocations.get(asVariable(value)) == null; + curStackLocations.put(stackLoc); + Debug.log(" slot %s", stackLoc); + return stackLoc; + } else { + return value; + } + } + + private Location allocateRegister(final Variable variable, final Object[] inRegisterState, final Object[] outRegisterState, OperandMode mode, EnumSet flags) { + if (flags.contains(OperandFlag.RegisterHint)) { + CiValue result = curInstruction.forEachRegisterHint(variable, mode, new ValueProcedure() { + @Override + public CiValue doValue(CiValue registerHint) { + Debug.log(" registerHint %s", registerHint); + CiRegister hint = null; + if (isRegister(registerHint)) { + hint = asRegister(registerHint); + } else if (isLocation(registerHint) && isRegister(asLocation(registerHint).location)) { + hint = asRegister(asLocation(registerHint).location); + } + if (hint != null && hint.isSet(variable.flag) && isFree(hint, inRegisterState, outRegisterState)) { + return selectRegister(hint, variable, inRegisterState, outRegisterState); + } + return null; + } + }); + + if (result != null) { + return asLocation(result); + } + } + + EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); + CiRegister[] availableRegs = categorizedRegs.get(variable.flag); + + for (CiRegister reg : availableRegs) { + if (isFree(reg, inRegisterState, outRegisterState)) { + return selectRegister(reg, variable, inRegisterState, outRegisterState); + } + + } + throw new CiBailout("No register found"); + } + + private static boolean isFree(CiRegister reg, Object[] inRegisterState, Object[] outRegisterState) { + return (inRegisterState == null || inRegisterState[reg.number] == null) && (outRegisterState == null || outRegisterState[reg.number] == null); + } + + private Location selectRegister(CiRegister reg, Variable variable, Object[] inRegisterState, Object[] outRegisterState) { + Location loc = new Location(variable, reg.asValue(variable.kind)); + if (inRegisterState != null) { + inRegisterState[reg.number] = loc; + } + if (outRegisterState != null) { + outRegisterState[reg.number] = loc; + } + assert curRegisterLocations.get(variable) == null; + curRegisterLocations.put(loc); + Debug.log(" selected register %s", loc); + return loc; + } + + private boolean checkInputState(final Block block) { + final BitSet liveState = new BitSet(); + curStackLocations.forEachLocation(new ValueProcedure() { + @Override + public CiValue doValue(CiValue value) { + liveState.set(asLocation(value).variable.index); + + for (Block pred : block.getPredecessors()) { + LocationMap predState = locationsFor(pred); + if (predState != null) { + assert predState.get(asLocation(value).variable) == value; + } else { + assert block.isLoopHeader(); + } + } + return value; + } + }); + assert liveState.equals(curLiveIn); + return true; + } + + private boolean checkNoCallerSavedRegister() { + for (CiRegister reg : frameMap.registerConfig.getCallerSaveRegisters()) { + assert curOutRegisterState[reg.number] == null || curOutRegisterState[reg.number] == curInstruction : "caller saved register in use accross call site"; + } + return true; + } + + private static boolean checkEmpty(Object[] array) { + for (Object o : array) { + assert o == null; + } + return true; + } + + + private String logCurrentState() { + final StringBuilder sb = new StringBuilder(); + sb.append(" curVariableLocations: "); + curStackLocations.forEachLocation(new ValueProcedure() { + @Override + public CiValue doValue(CiValue value) { + sb.append(value).append(" "); + return value; + } + }); + return sb.toString(); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/IntervalPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/IntervalPrinter.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,274 @@ +/* + * 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.max.graal.alloc.util; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.alloc.simple.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; + +public final class IntervalPrinter { + + public static void printBeforeAllocation(String label, LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow) { + if (Debug.isDumpEnabled()) { + IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, null); + Debug.dump(lir, label); + Debug.dump(printer.execute(), label); + } + } + + public static void printAfterAllocation(String label, LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow, LocationMap[] blockEndLocations) { + if (Debug.isDumpEnabled()) { + IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, blockEndLocations); + Debug.dump(lir, label); + Debug.dump(printer.execute(), label); + } + } + + + public static class Range { + public final int from; + public final int to; + + public Range(int from, int to) { + this.from = from; + this.to = to; + } + } + + public static class UsePosition { + public final int pos; + public final String kind; + + public UsePosition(int pos, String kind) { + this.pos = pos; + this.kind = kind; + } + } + + public static class Interval { + public final String name; + public final String description; + public final String variable; + public final String type; + public final List ranges; + public final List uses; + + protected final int orderNum; + protected int lastTo; + + public Interval(int orderNum, String name, String description, String variable, String type) { + this.orderNum = orderNum; + this.name = name; + this.description = description; + this.variable = variable; + this.type = type; + this.ranges = new ArrayList<>(); + this.uses = new ArrayList<>(); + } + } + + + private final LIR lir; + private final RiRegisterConfig registerConfig; + private final DataFlowAnalysis dataFlow; + private final LocationMap[] blockEndLocations; + private final Variable[] variables; + private final Map intervals; + + private IntervalPrinter(LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow, LocationMap[] blockEndLocations) { + this.lir = lir; + this.registerConfig = registerConfig; + this.dataFlow = dataFlow; + this.blockEndLocations = blockEndLocations; + this.variables = new Variable[lir.numVariables()]; + this.intervals = new HashMap<>(); + } + + private boolean isAllocatableRegister(CiValue value) { + return isRegister(value) && registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; + } + + private int curOpId; + private String curUseKind; + + public Interval[] execute() { + ValueProcedure varProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return var(value); } }; + + for (Block block : lir.linearScanOrder()) { + for (LIRInstruction op : block.lir) { + op.forEachOutput(varProc); + } + } + + ValueProcedure useProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; + ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, flags); } }; + + intervals.put("call", new Interval(-2, "call", "", "call", "hasCall")); + intervals.put("st", new Interval(-1, "st", "", "st", "hasState")); + + for (int i = lir.linearScanOrder().size() - 1; i >= 0; i--) { + Block block = lir.linearScanOrder().get(i); + + curOpId = block.getLastLirInstructionId() + 2; + for (Block sux : block.getSuccessors()) { + BitSet suxIn = dataFlow.liveIn(sux); + for (int idx = suxIn.nextSetBit(0); idx >= 0; idx = suxIn.nextSetBit(idx + 1)) { + if (blockEndLocations != null) { + out(blockEndLocations[block.getId()].get(variables[idx])); + } else { + out(variables[idx]); + } + } + } + + for (int j = block.lir.size() - 1; j >= 0; j--) { + LIRInstruction op = block.lir.get(j); + if (op.id() >= 0) { + curOpId = op.id(); + } else { + curOpId = (curOpId - 1) | 1; + } + + op.forEachOutput(defProc); + op.forEachTemp(defProc); + op.forEachInput(useProc); + op.forEachAlive(useProc); + curUseKind = "L"; + op.forEachState(useProc); + curUseKind = null; + + if (op.hasCall()) { + intervals.get("call").ranges.add(new Range(curOpId, curOpId + 1)); + } + if (op.info != null) { + intervals.get("st").ranges.add(new Range(curOpId, curOpId + 1)); + } + } + + for (Interval interval : intervals.values()) { + if (interval.lastTo != 0) { + interval.ranges.add(new Range(block.getFirstLirInstructionId(), interval.lastTo)); + interval.lastTo = 0; + } + } + } + + Interval[] intervalsArray = intervals.values().toArray(new Interval[0]); + Arrays.sort(intervalsArray, new Comparator() { + @Override + public int compare(Interval o1, Interval o2) { + return o1.orderNum - o2.orderNum; + } + }); + return intervalsArray; + } + + public CiValue var(CiValue value) { + if (isLocation(value)) { + variables[asLocation(value).variable.index] = asLocation(value).variable; + } else if (isVariable(value)) { + variables[asVariable(value).index] = asVariable(value); + } + return value; + } + + private Interval findInterval(CiValue value) { + Interval interval; + if (isLocation(value)) { + Interval parent = findInterval(asLocation(value).variable); + String name = "v" + asLocation(value).variable.index + ":" + asLocation(value).location; + String description = isStackSlot(asLocation(value).location) ? "stack" : ""; + interval = new Interval(asLocation(value).variable.index * 2 + 1001, name, description, parent.name, value.kind.javaName); + + } else if (isVariable(value)) { + interval = new Interval(asVariable(value).index * 2 + 1000, value.toString(), "", value.toString(), value.kind.javaName); + + } else if (isAllocatableRegister(value)) { + interval = new Interval(asRegister(value).number, asRegister(value).toString(), "", asRegister(value).toString(), "fixed"); + + } else { + return null; + } + + Interval existing = intervals.get(interval.name); + if (existing != null) { + return existing; + } + intervals.put(interval.name, interval); + return interval; + } + + private String useKind(EnumSet flags) { + if (curUseKind != null) { + return curUseKind; + } else if (flags.contains(OperandFlag.Stack)) { + return "S"; + } else { + return "M"; + } + } + + private CiValue use(CiValue value, OperandMode mode, EnumSet flags) { + Interval interval = findInterval(value); + if (interval != null) { + if (interval.uses.size() == 0 || interval.uses.get(interval.uses.size() - 1).pos != curOpId) { + interval.uses.add(new UsePosition(curOpId, useKind(flags))); + } + if (interval.lastTo == 0) { + interval.lastTo = curOpId + (mode == OperandMode.Alive ? 1 : 0); + } + } + return value; + } + + private CiValue def(CiValue value, EnumSet flags) { + Interval interval = findInterval(value); + if (interval != null) { + interval.uses.add(new UsePosition(curOpId, useKind(flags))); + if (interval.lastTo == 0) { + interval.ranges.add(new Range(curOpId, curOpId + 1)); + } else { + interval.ranges.add(new Range(curOpId, interval.lastTo)); + } + interval.lastTo = 0; + } + return value; + } + + private CiValue out(CiValue value) { + Interval interval = findInterval(value); + if (interval != null) { + interval.lastTo = curOpId; + } + return value; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/Location.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/Location.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.util; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.lir.*; + +public class Location extends CiValue { + private static final long serialVersionUID = -1786677729152726126L; + + public final Variable variable; + public final CiValue location; + + public Location(Variable variable, CiValue location) { + super(variable.kind); + this.variable = variable; + this.location = location; + + assert variable.kind == location.kind; + } + + @Override + public String toString() { + return variable + "[" + location + "]"; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/LocationMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/LocationMap.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.util; + +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; + +public class LocationMap { + private final Location[] locations; + + public LocationMap(int numVariables) { + locations = new Location[numVariables]; + } + + public LocationMap(LocationMap template) { + locations = Arrays.copyOf(template.locations, template.locations.length); + } + + public Location get(Variable variable) { + assert locations[variable.index] == null || locations[variable.index].variable == variable; + return locations[variable.index]; + } + + public void put(Location location) { + locations[location.variable.index] = location; + } + + public void clear(Variable variable) { + locations[variable.index] = null; + } + + public void forEachLocation(ValueProcedure proc) { + for (int i = 0; i < locations.length; i++) { + if (locations[i] != null) { + CiValue newValue = proc.doValue(locations[i], null, null); + assert newValue == null || asLocation(newValue).variable == locations[i].variable; + locations[i] = (Location) newValue; + } + } + } + + public boolean checkEmpty() { + for (int i = 0; i < locations.length; i++) { + assert locations[i] == null; + } + return true; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/LocationUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/LocationUtil.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011, 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.max.graal.alloc.util; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.lir.*; + +public class LocationUtil extends ValueUtil { + + public static boolean isLocation(CiValue value) { + assert value != null; + return value instanceof Location; + } + + public static Location asLocation(CiValue value) { + assert value != null; + return (Location) value; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/MoveResolver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/MoveResolver.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2009, 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.max.graal.alloc.util; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; + +public abstract class MoveResolver { + private final LIR lir; + private final FrameMap frameMap; + private final int[] registersBlocked; + private final Map valuesBlocked; + private final List mappingFrom; + private final List mappingTo; + private final LIRInsertionBuffer insertionBuffer; + private int insertPos; + + public MoveResolver(LIR lir, FrameMap frameMap) { + this.lir = lir; + this.frameMap = frameMap; + + registersBlocked = new int[frameMap.target.arch.registers.length]; + valuesBlocked = new HashMap<>(); + + mappingFrom = new ArrayList<>(); + mappingTo = new ArrayList<>(); + insertionBuffer = new LIRInsertionBuffer(); + insertPos = -1; + + assert checkEmpty(); + } + + public void init(List newInsertList, int newInsertPos) { + assert checkEmpty(); + + if (insertionBuffer.lirList() != newInsertList) { + // Block changed, so append insertionBuffer because it is bound to a specific block + finish(); + insertionBuffer.init(newInsertList); + } + insertPos = newInsertPos; + + assert checkValid(); + } + + public void add(CiValue from, Location to) { + assert checkValid(); + assert isLocation(from) || isConstant(from); + assert from != to; + + Debug.log("mr add mapping from %s to %s", from, to); + mappingFrom.add(from); + mappingTo.add(to); + + assert checkValid(); + } + + public boolean hasMappings() { + return mappingFrom.size() > 0; + } + + public void resolve() { + assert checkValid(); + + if (mappingFrom.size() == 1) { + // If there is only one mapping, it is trivial that this mapping is safe to resolve. + Debug.log("mr resolve mappings: %d", mappingFrom.size()); + insertMove(mappingFrom.get(0), mappingTo.get(0)); + mappingFrom.remove(0); + mappingTo.remove(0); + } else if (mappingFrom.size() > 1) { + Debug.log("mr resolve mappings: %d", mappingFrom.size()); + doResolve(); + } + insertPos = -1; + + assert checkEmpty(); + } + + public void finish() { + assert checkEmpty(); + + if (insertionBuffer.initialized()) { + insertionBuffer.finish(); + } + + assert !insertionBuffer.initialized() : "must be uninitialized now"; + assert checkEmpty(); + } + + + private void doResolve() { + // Block all registers and stack slots that are used as inputs of a move. + // When a register is blocked, no move to this register is emitted. + // This is necessary for detecting cycles in moves. + for (CiValue from : mappingFrom) { + block(from); + } + + while (mappingFrom.size() > 0) { + boolean processed = false; + for (int i = mappingFrom.size() - 1; i >= 0; i--) { + CiValue from = mappingFrom.get(i); + Location to = mappingTo.get(i); + + if (safeToProcessMove(from, to)) { + insertMove(from, to); + unblock(from); + mappingFrom.remove(i); + mappingTo.remove(i); + processed = true; + } + } + + if (!processed) { + // No move could be processed because there is a cycle in the move list + // (e.g., r1 -> r2, r2 -> r1), so one location must be spilled. + spill(); + } + } + } + + private void spill() { + Location spillCandidate = null; + int exchangeCandidate = -1; + int exchangeOther = -1; + + for (int i = mappingFrom.size() - 1; i >= 0; i--) { + CiValue from = mappingFrom.get(i); + Location to = mappingTo.get(i); + assert !safeToProcessMove(from, to) : "would not be in this code otherwise"; + + if (isConstant(from)) { + continue; + } + CiValue fromLoc = asLocation(from).location; + + // Check if we can insert an exchange to save us from spilling. + if (isRegister(fromLoc) && isRegister(to) && asRegister(fromLoc) != asRegister(to) && blockedCount(to) == 1) { + for (int j = mappingFrom.size() - 1; j >= 0; j--) { + CiValue possibleOther = mappingFrom.get(j); + if (isLocation(possibleOther)) { + if (asLocation(possibleOther).location == to.location) { + assert exchangeCandidate == -1 : "must not find twice because of blocked check above"; + exchangeCandidate = i; + exchangeOther = j; + } else if (i != j && asLocation(possibleOther).location == fromLoc) { + // From is read multiple times, so exchange would be too complicated. + exchangeCandidate = -1; + break; + } + } + } + } + + if (exchangeCandidate != -1) { + // Already found a result, no need to search further + break; + } + if (spillCandidate == null || isStackSlot(spillCandidate.location)) { + // this interval cannot be processed now because target is not free + spillCandidate = asLocation(from); + } + } + + if (exchangeCandidate != -1) { + Location from = asLocation(mappingFrom.get(exchangeCandidate)); + Location to = mappingTo.get(exchangeCandidate); + Location other = asLocation(mappingFrom.get(exchangeOther)); + + Location newOther = new Location(other.variable, from.variable); + mappingFrom.set(exchangeOther, newOther); + + insertExchange(newOther, to); + unblock(to); + mappingFrom.remove(exchangeCandidate); + mappingTo.remove(exchangeCandidate); + + } else { + assert spillCandidate != null : "no location for spilling found"; + + Location spillLocation = new Location(spillCandidate.variable, frameMap.allocateSpillSlot(spillCandidate.kind)); + insertMove(spillCandidate, spillLocation); + + for (int i = mappingFrom.size() - 1; i >= 0; i--) { + if (mappingFrom.get(i) == spillCandidate) { + mappingFrom.set(i, spillLocation); + unblock(spillCandidate); + block(spillLocation); + } + } + assert blockedCount(spillCandidate) == 0 : "register must be unblocked after spilling"; + } + } + + private void block(CiValue value) { + if (isLocation(value)) { + CiValue location = asLocation(value).location; + if (isRegister(location)) { + registersBlocked[asRegister(location).number]++; + } else { + Integer count = valuesBlocked.get(location); + valuesBlocked.put(location, count == null ? 1 : count + 1); + } + } + } + + private void unblock(CiValue value) { + if (isLocation(value)) { + assert blockedCount(asLocation(value)) > 0; + CiValue location = asLocation(value).location; + if (isRegister(location)) { + registersBlocked[asRegister(location).number]--; + } else { + Integer count = valuesBlocked.remove(location); + if (count > 1) { + valuesBlocked.put(location, count - 1); + } + } + } + } + + private int blockedCount(Location value) { + CiValue location = asLocation(value).location; + if (isRegister(location)) { + return registersBlocked[asRegister(location).number]; + } else { + Integer count = valuesBlocked.get(location); + return count == null ? 0 : count; + } + } + + private boolean safeToProcessMove(CiValue from, Location to) { + int count = blockedCount(to); + return count == 0 || (count == 1 && isLocation(from) && asLocation(from).location == to.location); + } + + private void insertExchange(Location from, Location to) { + Debug.log("mr XCHG %s, %s", from, to); + // TODO create XCHG instruction and use it here + insertionBuffer.append(insertPos, null); + throw GraalInternalError.unimplemented(); + } + + private void insertMove(CiValue src, Location dst) { + if (isStackSlot(dst.location) && isLocation(src) && isStackSlot(asLocation(src).location)) { + // Move between two stack slots. We need a temporary registers. If the allocator can give + // us a free register, we need two moves: src->scratch, scratch->dst + // If the allocator cannot give us a free register (it returns a Location in this case), + // we need to spill the scratch register first, so we need four moves in total. + + CiValue scratch = scratchRegister(dst.variable); + + Location scratchSaved = null; + CiValue scratchRegister = scratch; + if (isLocation(scratch)) { + scratchSaved = new Location(asLocation(scratch).variable, frameMap.allocateSpillSlot(scratch.kind)); + insertMove(scratch, scratchSaved); + scratchRegister = asLocation(scratch).location; + } + assert isRegister(scratchRegister); + + Location scratchLocation = new Location(dst.variable, scratchRegister); + insertMove(src, scratchLocation); + insertMove(scratchLocation, dst); + + if (scratchSaved != null) { + insertMove(scratchSaved, asLocation(scratch)); + } + + } else { + Debug.log("mr MOV %s -> %s", src, dst); + insertionBuffer.append(insertPos, lir.spillMoveFactory.createMove(dst, src)); + } + } + + /** + * Provides a register that can be used by the move resolver. If the returned value is a + * {@link CiRegisterValue}, the register can be overwritten without precautions. If the + * returned value is a {@link Location}, it needs to be spilled and rescued itself. + */ + protected abstract CiValue scratchRegister(Variable spilled); + + private boolean checkEmpty() { + assert insertPos == -1; + assert mappingFrom.size() == 0 && mappingTo.size() == 0; + for (int registerBlocked : registersBlocked) { + assert registerBlocked == 0; + } + assert valuesBlocked.size() == 0; + return true; + } + + private boolean checkValid() { + assert insertPos != -1; + for (int registerBlocked : registersBlocked) { + assert registerBlocked == 0; + } + assert mappingFrom.size() == mappingTo.size(); + assert insertionBuffer.initialized() && insertPos != -1; + + for (int i = 0; i < mappingTo.size(); i++) { + CiValue from = mappingFrom.get(i); + Location to = mappingTo.get(i); + + assert from.kind.stackKind() == to.kind; + + for (int j = i + 1; j < mappingTo.size(); j++) { + Location otherTo = mappingTo.get(j); + assert to != otherTo && to.variable != otherTo.variable && to.location != otherTo.location : "Cannot write to same location twice"; + } + } + return true; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/RegisterVerifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.alloc/src/com/oracle/max/graal/alloc/util/RegisterVerifier.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2009, 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.max.graal.alloc.util; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; + +public final class RegisterVerifier { + private final FrameMap frameMap; + + /** + * All blocks that must be processed. + */ + private final List workList; + + /** + * Saved information of previous check. + *
+ * State mapping: mapping from registers and stack slots ({@link CiRegister} and {@link Integer} stack slot offsets) to the + * value that is currently contained in there ({@link Location} for operands that were variables; {@link CiRegisterValue} or + * {@link CiStackSlot} for operands that used fixed registers or stack slots). + */ + private final Map[] blockStates; + + private void addToWorkList(Block block) { + if (!workList.contains(block)) { + workList.add(block); + } + } + + private Map stateFor(Block block) { + return blockStates[block.getId()]; + } + + private void setStateFor(Block block, Map savedState) { + blockStates[block.getId()] = savedState; + } + + private static Map copy(Map inputState) { + return new HashMap<>(inputState); + } + + public static boolean verify(LIR lir, FrameMap frameMap) { + RegisterVerifier verifier = new RegisterVerifier(lir, frameMap); + verifier.verify(lir.cfg.getStartBlock()); + return true; + } + + @SuppressWarnings("unchecked") + private RegisterVerifier(LIR lir, FrameMap frameMap) { + this.frameMap = frameMap; + this.workList = new LinkedList<>(); + this.blockStates = new Map[lir.linearScanOrder().size()]; + } + + private Map curInputState; + + private void verify(Block startBlock) { + ValueProcedure useProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, flags); } }; + ValueProcedure tempProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return temp(value); } }; + ValueProcedure outputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return output(value); } }; + + curInputState = new HashMap<>(); + setStateFor(startBlock, curInputState); + addToWorkList(startBlock); + + Debug.log("==== start verify register allocation ===="); + do { + Block block = workList.remove(0); + + // Must copy state because it is modified. + curInputState = copy(stateFor(block)); + Debug.log("start block %s %s", block, block.getLoop()); + Debug.log(logCurrentState()); + + for (LIRInstruction op : block.lir) { + Debug.log(" op %d %s", op.id(), op); + + op.forEachInput(useProc); + if (op.hasCall()) { + invalidateRegisters(); + } + op.forEachAlive(useProc); + op.forEachState(useProc); + op.forEachTemp(tempProc); + op.forEachOutput(outputProc); + } + + for (Block succ : block.getSuccessors()) { + processSuccessor(succ); + } + + Debug.log("end block %s", block); + } while (!workList.isEmpty()); + Debug.log("==== end verify register allocation ===="); + } + + private void processSuccessor(Block succ) { + Map savedState = stateFor(succ); + if (savedState == null) { + // Block was not processed before, so set initial inputState. + Debug.log(" successor %s: initial visit", succ); + setStateFor(succ, copy(curInputState)); + addToWorkList(succ); + + } else { + // This block was already processed before. + // Check if new inputState is consistent with savedState. + Debug.log(" successor %s: state present", succ); + Iterator> iter = savedState.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + CiValue savedValue = entry.getValue(); + CiValue inputValue = curInputState.get(entry.getKey()); + + if (savedValue != inputValue) { + // Current inputState and previous savedState assume a different value in this register. + // Assume that this register is invalid and remove it from the saved state. + Debug.log(" invalididating %s because it is inconsistent with %s", savedValue, inputValue); + iter.remove(); + // Must re-visit this block. + addToWorkList(succ); + } + } + } + } + + private void invalidateRegisters() { + // Invalidate all caller save registers at calls. + Iterator iter = curInputState.keySet().iterator(); + while (iter.hasNext()) { + Object value1 = iter.next(); + if (value1 instanceof CiRegister && frameMap.registerConfig.getAttributesMap()[((CiRegister) value1).number].isCallerSave) { + Debug.log(" remove caller save register %s", value1); + iter.remove(); + } + } + } + + /** + * Gets the mapping key for a value. The key should be as narrow as possible, e.g., it should not + * include the kind of the value because we do not want to distinguish between the same register with + * different kinds. + */ + private Object key(CiValue value) { + if (isLocation(value)) { + return key(asLocation(value).location); + } else if (isRegister(value)) { + return asRegister(value); + } else if (isStackSlot(value)) { + return Integer.valueOf(frameMap.offsetForStackSlot(asStackSlot(value))); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } + + private boolean isIgnoredRegister(CiValue value) { + return isRegister(value) && !frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; + } + + private CiValue use(CiValue value, EnumSet flags) { + if (!isConstant(value) && value != CiValue.IllegalValue && !isIgnoredRegister(value)) { + CiValue actual = curInputState.get(key(value)); + if (actual == null && flags.contains(OperandFlag.Uninitialized)) { + // OK, since uninitialized values are allowed explicitly. + } else if (value != actual) { + Debug.log("Error in register allocation: %s != %s for key %s", value, actual, key(value)); + Debug.log(logCurrentState()); + throw GraalInternalError.shouldNotReachHere(); + } + } + return value; + } + + private CiValue temp(CiValue value) { + if (!isConstant(value) && value != CiValue.IllegalValue && !isIgnoredRegister(value)) { + Debug.log(" temp %s -> remove key %s", value, key(value)); + curInputState.remove(key(value)); + } + return value; + } + + private CiValue output(CiValue value) { + if (value != CiValue.IllegalValue && !isIgnoredRegister(value)) { + Debug.log(" output %s -> set key %s", value, key(value)); + curInputState.put(key(value), value); + } + return value; + } + + + private String logCurrentState() { + ArrayList keys = new ArrayList<>(curInputState.keySet()); + Collections.sort(keys, new Comparator() { + @Override + public int compare(Object o1, Object o2) { + if (o1 instanceof CiRegister) { + if (o2 instanceof CiRegister) { + return ((CiRegister) o1).number - ((CiRegister) o2).number; + } else { + return -1; + } + } else { + if (o2 instanceof CiRegister) { + return 1; + } else { + return ((Integer) o1).intValue() - ((Integer) o2).intValue(); + } + } + } + }); + + StringBuilder sb = new StringBuilder(" state: "); + for (Object key : keys) { + sb.append(key).append("=").append(curInputState.get(key)).append(" "); + } + return sb.toString(); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/AssignRegisters.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/AssignRegisters.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.simple; - -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.alloc.util.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; - -public abstract class AssignRegisters { - public final LIR lir; - public final FrameMap frameMap; - - public AssignRegisters(LIR lir, FrameMap frameMap) { - this.lir = lir; - this.frameMap = frameMap; - } - - private CiBitMap curRegisterRefMap; - private CiBitMap curFrameRefMap; - - public void execute() { - ValueProcedure useProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value); } }; - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value); } }; - ValueProcedure setReferenceProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return setReference(value); } }; - - assert trace("==== start assign registers ===="); - for (int i = lir.linearScanOrder().size() - 1; i >= 0; i--) { - Block block = lir.linearScanOrder().get(i); - assert trace("start block %s", block); - assert block.phis == null : "Register assignment must run after phi functions have been replaced by moves"; - - curRegisterRefMap = frameMap.initRegisterRefMap(); - curFrameRefMap = frameMap.initFrameRefMap(); - - // Put all values live at the end of the block into the reference map. - locationsForBlockEnd(block).forEachLocation(setReferenceProc); - - for (int j = block.lir.size() - 1; j >= 0; j--) { - LIRInstruction op = block.lir.get(j); - assert trace(" op %d %s", op.id(), op); - - op.forEachOutput(defProc); - op.forEachTemp(defProc); - op.forEachState(useProc); - op.forEachAlive(useProc); - - if (op.info != null) { - assert trace(" registerRefMap: %s frameRefMap: %s", curRegisterRefMap, curFrameRefMap); - op.info.finish(new CiBitMap(curRegisterRefMap), new CiBitMap(curFrameRefMap), frameMap); - - if (op instanceof LIRXirInstruction) { - LIRXirInstruction xir = (LIRXirInstruction) op; - if (xir.infoAfter != null) { - xir.infoAfter.finish(new CiBitMap(curRegisterRefMap), new CiBitMap(curFrameRefMap), frameMap); - } - } - } - - // Process input operands after assigning the reference map, so that input operands that are used - // for the last time at this instruction are not part of the reference map. - op.forEachInput(useProc); - } - assert trace("end block %s", block); - } - assert trace("==== end assign registers ===="); - } - - private CiValue use(CiValue value) { - assert trace(" use %s", value); - if (isLocation(value)) { - CiValue location = asLocation(value).location; - frameMap.setReference(location, curRegisterRefMap, curFrameRefMap); - return location; - } else { - frameMap.setReference(value, curRegisterRefMap, curFrameRefMap); - return value; - } - } - - private CiValue def(CiValue value) { - assert trace(" def %s", value); - if (isLocation(value)) { - CiValue location = asLocation(value).location; - frameMap.clearReference(location, curRegisterRefMap, curFrameRefMap); - return location; - } else { - frameMap.clearReference(value, curRegisterRefMap, curFrameRefMap); - return value; - } - } - - private CiValue setReference(CiValue value) { - assert trace(" setReference %s", value); - frameMap.setReference(asLocation(value).location, curRegisterRefMap, curFrameRefMap); - return value; - } - - protected abstract LocationMap locationsForBlockEnd(Block block); - - private static boolean trace(String format, Object...args) { - if (GraalOptions.TraceRegisterAllocation) { - TTY.println(format, args); - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,330 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.simple; - -import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.alloc.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; - -public class DataFlowAnalysis { - private final LIR lir; - private final RiRegisterConfig registerConfig; - - public DataFlowAnalysis(LIR lir, RiRegisterConfig registerConfig) { - this.lir = lir; - this.registerConfig = registerConfig; - } - - public void execute() { - numberInstructions(); - backwardDataFlow(); - } - - - private List blocks() { - return lir.linearScanOrder(); - } - - private int numVariables() { - return lir.numVariables(); - } - - private boolean isAllocatableRegister(CiValue value) { - return isRegister(value) && registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; - } - - - private int[] definitions; - private BitSet[] blockLiveIn; - private Block[] opIdBlock; - private Object[] opIdKilledValues; - - - public BitSet liveIn(Block block) { - return blockLiveIn[block.getId()]; - } - private void setLiveIn(Block block, BitSet liveIn) { - blockLiveIn[block.getId()] = liveIn; - } - - private Block blockOf(int opId) { - return opIdBlock[opId >> 1]; - } - private void setBlockOf(int opId, Block block) { - opIdBlock[opId >> 1] = block; - } - - private Object killedValues(int opId) { - return opIdKilledValues[opId]; - } - private void setKilledValues(int opId, Object killedValues) { - opIdKilledValues[opId] = killedValues; - } - - public void forEachKilled(LIRInstruction op, boolean end, ValueProcedure proc) { - Object entry = killedValues(op.id() + (end ? 1 : 0)); - if (entry == null) { - // Nothing to do - } else if (entry instanceof CiValue) { - CiValue newValue = proc.doValue((CiValue) entry, null, null); - assert newValue == entry : "procedure does not allow to change values"; - } else { - CiValue[] values = (CiValue[]) entry; - for (int i = 0; i < values.length; i++) { - if (values[i] != null) { - CiValue newValue = proc.doValue(values[i], null, null); - assert newValue == values[i] : "procedure does not allow to change values"; - } - } - } - } - - public int definition(Variable value) { - return definitions[value.index]; - } - - /** - * Numbers all instructions in all blocks. The numbering follows the {@linkplain ComputeLinearScanOrder linear scan order}. - */ - private void numberInstructions() { - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return setDef(value); } }; - - int numInstructions = 0; - for (Block block : blocks()) { - numInstructions += block.lir.size(); - } - opIdBlock = new Block[numInstructions]; - opIdKilledValues = new Object[numInstructions << 1]; - definitions = new int[numVariables()]; - - curOpId = 0; - for (Block block : blocks()) { - if (block.phis != null) { - block.phis.forEachOutput(defProc); - } - - for (LIRInstruction op : block.lir) { - op.setId(curOpId); - setBlockOf(curOpId, block); - - op.forEachTemp(defProc); - op.forEachOutput(defProc); - - curOpId += 2; // numbering of lirOps by two - } - } - assert curOpId == numInstructions << 1; - } - - private CiValue setDef(CiValue value) { - if (isVariable(value)) { - assert definitions[asVariable(value).index] == 0 : "Variable defined twice"; - definitions[asVariable(value).index] = curOpId; - } - return value; - } - - - private BitSet variableLive; - private BitSet registerLive; - private int curOpId; - - private void backwardDataFlow() { - ValueProcedure inputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId); } }; - ValueProcedure aliveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId + 1); } }; - PhiValueProcedure phiInputProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, -1); } }; - ValueProcedure tempProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, true); } }; - ValueProcedure outputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, false); } }; - - blockLiveIn = new BitSet[blocks().size()]; - registerLive = new BitSet(); - - assert trace("==== start backward data flow analysis ===="); - for (int i = blocks().size() - 1; i >= 0; i--) { - Block block = blocks().get(i); - assert trace("start block %s loop %s", block, block.getLoop()); - - variableLive = new BitSet(); - for (Block sux : block.getSuccessors()) { - BitSet suxLive = liveIn(sux); - if (suxLive != null) { - assert trace(" sux %s suxLive: %s", sux, suxLive); - variableLive.or(suxLive); - } - - if (sux.phis != null) { - curOpId = block.getLastLirInstructionId(); - assert trace(" phis %d variableLive: %s", curOpId, variableLive); - sux.phis.forEachInput(block, phiInputProc); - } - } - - assert registerLive.isEmpty() : "no fixed register must be alive before processing a block"; - - for (int j = block.lir.size() - 1; j >= 0; j--) { - LIRInstruction op = block.lir.get(j); - curOpId = op.id(); - assert trace(" op %d %s variableLive: %s registerLive: %s", curOpId, op, variableLive, registerLive); - - op.forEachOutput(outputProc); - op.forEachTemp(tempProc); - op.forEachState(aliveProc); - op.forEachAlive(aliveProc); - op.forEachInput(inputProc); - } - - if (block.phis != null) { - curOpId = block.getFirstLirInstructionId(); - assert trace(" phis %d variableLive: %s registerLive: %s", curOpId, variableLive, registerLive); - block.phis.forEachOutput(outputProc); - } - - assert registerLive.isEmpty() : "no fixed register must be alive after processing a block"; - assert liveIn(block) == null; - setLiveIn(block, variableLive); - - if (block.isLoopHeader()) { - assert trace(" loop header, propagating live set to loop blocks variableLive: %s", variableLive); - // All variables that are live at the beginning of a loop are also live the whole loop. - // This is guaranteed by the SSA form. - for (Block loop : block.getLoop().blocks) { - BitSet loopLiveIn = liveIn(loop); - assert loopLiveIn != null : "All loop blocks must have been processed before the loop header"; - loopLiveIn.or(variableLive); - assert trace(" block %s loopLiveIn %s", loop, loopLiveIn); - } - } - - assert trace("end block %s variableLive: %s", block, variableLive); - } - assert trace("==== end backward data flow analysis ===="); - } - - private CiValue use(CiValue value, int killOpId) { - assert trace(" use %s", value); - if (isVariable(value)) { - int variableIdx = asVariable(value).index; - assert definitions[variableIdx] < curOpId; - if (!variableLive.get(variableIdx)) { - assert trace(" set live variable %d", variableIdx); - variableLive.set(variableIdx); - kill(value, killOpId); - } - - } else if (isAllocatableRegister(value)) { - int regNum = asRegister(value).number; - if (!registerLive.get(regNum)) { - assert trace(" set live register %d", regNum); - registerLive.set(regNum); - kill(value, killOpId); - } - } - return value; - } - - private CiValue def(CiValue value, boolean isTemp) { - assert trace(" def %s", value); - if (isVariable(value)) { - int variableIdx = asVariable(value).index; - assert definitions[variableIdx] == curOpId; - if (variableLive.get(variableIdx)) { - assert trace(" clear live variable %d", variableIdx); - assert !isTemp : "temp variable cannot be used after the operation"; - variableLive.clear(variableIdx); - } else { - // Variable has never been used, so kill it immediately after the definition. - kill(value, curOpId + 1); - } - - } else if (isAllocatableRegister(value)) { - int regNum = asRegister(value).number; - if (registerLive.get(regNum)) { - assert trace(" clear live register %d", regNum); - assert !isTemp : "temp variable cannot be used after the operation"; - registerLive.clear(regNum); - } else { - // Register has never been used, so kill it immediately after the definition. - kill(value, curOpId + 1); - } - } - return value; - } - - private void kill(CiValue value, int opId) { - if (opId < 0) { - return; - } - if (isVariable(value)) { - int defOpId = definitions[asVariable(value).index]; - assert defOpId > 0 && defOpId <= opId; - - Block defBlock = blockOf(defOpId); - Block useBlock = blockOf(opId); - - if (useBlock.getLoop() != null && useBlock.getLoop() != defBlock.getLoop()) { - // This is a value defined outside of the loop it is currently used in. Therefore, it is live the whole loop - // and is not killed by the current instruction. - assert trace(" no kill because use in %s, definition in %s", useBlock.getLoop(), defBlock.getLoop()); - return; - } - } - assert trace(" kill %s at %d", value, opId); - - Object entry = killedValues(opId); - if (entry == null) { - setKilledValues(opId, value); - } else if (entry instanceof CiValue) { - setKilledValues(opId, new CiValue[] {(CiValue) entry, value}); - } else { - CiValue[] killed = (CiValue[]) entry; - for (int i = 0; i < killed.length; i++) { - if (killed[i] == null) { - killed[i] = value; - return; - } - } - int oldLen = killed.length; - killed = Arrays.copyOf(killed, oldLen * 2); - setKilledValues(opId, killed); - killed[oldLen] = value; - } - } - - private static boolean trace(String format, Object...args) { - if (GraalOptions.TraceRegisterAllocation) { - TTY.println(format, args); - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/LinearScanAllocator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/LinearScanAllocator.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,604 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.simple; - -import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ci.CiRegister.RegisterFlag; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.alloc.util.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; -import com.oracle.max.graal.compiler.util.*; -import com.oracle.max.graal.debug.*; - -public class LinearScanAllocator { - private final LIR lir; - private final FrameMap frameMap; - - private final DataFlowAnalysis dataFlow; - - public LinearScanAllocator(LIR lir, FrameMap frameMap) { - this.lir = lir; - this.frameMap = frameMap; - - this.dataFlow = new DataFlowAnalysis(lir, frameMap.registerConfig); - this.blockBeginLocations = new LocationMap[lir.linearScanOrder().size()]; - this.blockEndLocations = new LocationMap[lir.linearScanOrder().size()]; - this.moveResolver = new MoveResolverImpl(lir, frameMap); - - this.variableLastUse = new int[lir.numVariables()]; - } - - private class MoveResolverImpl extends MoveResolver { - public MoveResolverImpl(LIR lir, FrameMap frameMap) { - super(lir, frameMap); - } - - @Override - protected CiValue scratchRegister(Variable spilled) { - Util.shouldNotReachHere("needs working implementation"); - - EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); - CiRegister[] availableRegs = categorizedRegs.get(spilled.flag); - for (CiRegister reg : availableRegs) { - if (curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null) { - return reg.asValue(spilled.kind); - } - } - throw new CiBailout("No register found"); - } - } - - private class ResolveDataFlowImpl extends ResolveDataFlow { - public ResolveDataFlowImpl(LIR lir, MoveResolver moveResolver, DataFlowAnalysis dataFlow) { - super(lir, moveResolver, dataFlow); - } - - @Override - protected LocationMap locationsForBlockBegin(Block block) { - return beginLocationsFor(block); - } - - @Override - protected LocationMap locationsForBlockEnd(Block block) { - return endLocationsFor(block); - } - } - - private class AssignRegistersImpl extends AssignRegisters { - public AssignRegistersImpl(LIR lir, FrameMap frameMap) { - super(lir, frameMap); - } - - @Override - protected LocationMap locationsForBlockEnd(Block block) { - return endLocationsFor(block); - } - } - - - private int maxRegisterNum() { - return frameMap.target.arch.registers.length; - } - - private boolean isAllocatableRegister(CiValue value) { - return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; - } - - - private final LocationMap[] blockBeginLocations; - - private LocationMap beginLocationsFor(Block block) { - return blockBeginLocations[block.getId()]; - } - private void setBeginLocationsFor(Block block, LocationMap locations) { - blockBeginLocations[block.getId()] = locations; - } - - private final LocationMap[] blockEndLocations; - - private LocationMap endLocationsFor(Block block) { - return blockEndLocations[block.getId()]; - } - private void setEndLocationsFor(Block block, LocationMap locations) { - blockEndLocations[block.getId()] = locations; - } - - private final int[] variableLastUse; - - private int lastUseFor(Variable variable) { - return variableLastUse[variable.index]; - } - - private void setLastUseFor(Variable variable, int lastUse) { - variableLastUse[variable.index] = lastUse; - } - - private MoveResolver moveResolver; - private LocationMap curLocations; - private CiValue[] curInRegisterState; - private CiValue[] curOutRegisterState; - private BitSet curLiveIn; - private int curOpId; - private Block curPhiBlock; - - private LocationMap canonicalSpillLocations; - - public void execute() { - assert LIRVerifier.verify(true, lir, frameMap); - - dataFlow.execute(); - IntervalPrinter.printBeforeAllocation("Before register allocation", lir, frameMap.registerConfig, dataFlow); - - allocate(); - - IntervalPrinter.printAfterAllocation("After linear scan allocation", lir, frameMap.registerConfig, dataFlow, blockEndLocations); - - ResolveDataFlow resolveDataFlow = new ResolveDataFlowImpl(lir, moveResolver, dataFlow); - resolveDataFlow.execute(); - frameMap.finish(); - - IntervalPrinter.printAfterAllocation("After resolve data flow", lir, frameMap.registerConfig, dataFlow, blockEndLocations); - assert RegisterVerifier.verify(lir, frameMap); - - AssignRegisters assignRegisters = new AssignRegistersImpl(lir, frameMap); - assignRegisters.execute(); - - Debug.dump(lir, "After register asignment"); - assert LIRVerifier.verify(false, lir, frameMap); - } - - private void allocate() { - ValueProcedure recordUseProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return recordUse(value, mode); } }; - ValueProcedure killNonLiveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killNonLive(value); } }; - ValueProcedure unblockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return unblock(value); } }; - ValueProcedure killProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value); } }; - ValueProcedure blockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return block(value); } }; - PhiValueProcedure useProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, mode, flags); } }; - - assert trace("==== start linear scan allocation ===="); - canonicalSpillLocations = new LocationMap(lir.numVariables()); - curInRegisterState = new CiValue[maxRegisterNum()]; - curOutRegisterState = new CiValue[maxRegisterNum()]; - for (Block block : lir.linearScanOrder()) { - assert trace("start block %s %s", block, block.getLoop()); - - Arrays.fill(curOutRegisterState, null); - if (block.getDominator() != null) { - LocationMap dominatorState = endLocationsFor(block.getDominator()); - curLocations = new LocationMap(dominatorState); - // Clear out all variables that are not live at the begin of this block - curLiveIn = dataFlow.liveIn(block); - curLocations.forEachLocation(killNonLiveProc); - assert checkInputState(block); - } else { - curLocations = new LocationMap(lir.numVariables()); - } - assert traceState(); - - if (block.phis != null) { - assert trace(" phis"); - curPhiBlock = block; - curOpId = block.getFirstLirInstructionId(); - block.phis.forEachOutput(defProc); - curOpId = -1; - curPhiBlock = null; - } - - setBeginLocationsFor(block, new LocationMap(curLocations)); - - for (int opIdx = 0; opIdx < block.lir.size(); opIdx++) { - LIRInstruction op = block.lir.get(opIdx); - curOpId = op.id(); - assert trace(" op %d %s", op.id(), op); - - System.arraycopy(curOutRegisterState, 0, curInRegisterState, 0, curOutRegisterState.length); - - // Unblock fixed registers that are only used for inputs in curOutRegisterState. - dataFlow.forEachKilled(op, false, unblockProc); - // Block fixed registers defined by this instruction in curOutRegisterState. - op.forEachTemp(blockProc); - op.forEachOutput(blockProc); - - op.forEachInput(recordUseProc); - op.forEachAlive(recordUseProc); - - moveResolver.init(block.lir, opIdx); - // Process Alive before Input because they are more restricted and the same variable can be Alive and Input. - op.forEachAlive(useProc); - op.forEachInput(useProc); - - dataFlow.forEachKilled(op, false, killProc); - - if (op.hasCall()) { - spillCallerSaveRegisters(); - } - - op.forEachTemp(defProc); - op.forEachOutput(defProc); - - // Fixed temp and output registers can evict variables from their assigned register, allocate new location for them. - fixupEvicted(); - // State values are the least critical and can get the leftover registers (or stack slots if no more register available). - op.forEachState(useProc); - - - moveResolver.resolve(); - - dataFlow.forEachKilled(op, true, unblockProc); - dataFlow.forEachKilled(op, true, killProc); - -// curInstruction = null; - curOpId = -1; - } - - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - assert trace(" phis of successor %s", sux); - System.arraycopy(curOutRegisterState, 0, curInRegisterState, 0, curOutRegisterState.length); - curOpId = block.getLastLirInstructionId() + 1; - sux.phis.forEachInput(block, useProc); - curOpId = -1; - } - } - - assert endLocationsFor(block) == null; - setEndLocationsFor(block, curLocations); - - traceState(); - assert trace("end block %s", block); - } - - moveResolver.finish(); - assert trace("==== end linear scan allocation ===="); - } - - private CiValue killNonLive(CiValue value) { - assert isLocation(value); - if (!curLiveIn.get(asLocation(value).variable.index)) { - return null; - - } else if (isAllocatableRegister(asLocation(value).location)) { - int regNum = asRegister(asLocation(value).location).number; - assert curOutRegisterState[regNum] == null; - curOutRegisterState[regNum] = value; - } - return value; - } - - private CiValue unblock(CiValue value) { - if (isAllocatableRegister(value)) { - assert trace(" unblock register %s", value); - int regNum = asRegister(value).number; - assert curOutRegisterState[regNum] == value; - curOutRegisterState[regNum] = null; - } - return value; - } - - private CiValue kill(CiValue value) { - if (isVariable(value)) { - Location location = curLocations.get(asVariable(value)); - assert trace(" kill location %s", location); - if (isRegister(location.location)) { - int regNum = asRegister(location.location).number; - if (curOutRegisterState[regNum] == location) { - curOutRegisterState[regNum] = null; - } - } - curLocations.clear(asVariable(value)); - } - return value; - } - - - private CiValue block(CiValue value) { - if (isAllocatableRegister(value)) { - assert trace(" block %s", value); - int regNum = asRegister(value).number; - assert curOutRegisterState[regNum] == null || curOutRegisterState[regNum] instanceof Location; - curOutRegisterState[regNum] = value; - } - return value; - } - - private void spillCallerSaveRegisters() { - assert trace(" spill caller save registers in curInRegisterState %s", Arrays.toString(curInRegisterState)); - for (CiRegister reg : frameMap.registerConfig.getCallerSaveRegisters()) { - CiValue in = curInRegisterState[reg.number]; - if (in != null && isLocation(in)) { - spill(asLocation(in)); - } - } - } - - private CiValue recordUse(CiValue value, OperandMode mode) { - if (isVariable(value)) { - int id = mode == OperandMode.Input ? curOpId : curOpId + 1; - assert lastUseFor(asVariable(value)) <= id; - setLastUseFor(asVariable(value), id); - - } - return value; - } - - private CiValue use(CiValue value, OperandMode mode, EnumSet flags) { - assert mode == OperandMode.Input || mode == OperandMode.Alive; - if (isVariable(value)) { - // State values are not recorded beforehand because it does not matter if they are spilled. Still, it is necessary to record them as used now. - recordUse(value, mode); - - Location curLoc = curLocations.get(asVariable(value)); - if (isStackSlot(curLoc.location) && flags.contains(OperandFlag.Stack)) { - assert trace(" use %s %s: use current stack slot %s", mode, value, curLoc.location); - return curLoc; - } - if (isRegister(curLoc.location)) { - int regNum = asRegister(curLoc.location).number; - assert curInRegisterState[regNum] == curLoc; - if (mode == OperandMode.Input || curOutRegisterState[regNum] == curLoc) { - assert trace(" use %s %s: use current register %s", mode, value, curLoc.location); - return curLoc; - } - } - - assert trace(" use %s %s", mode, value); - - Location newLoc = allocateRegister(asVariable(value), mode, flags); - if (newLoc != curLoc) { - moveResolver.add(curLoc, newLoc); - } - return newLoc; - } else { - assert !isAllocatableRegister(value) || curInRegisterState[asRegister(value).number] == value; - } - return value; - } - - private static final EnumSet SPILL_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - - private CiValue def(CiValue value, OperandMode mode, EnumSet flags) { - assert mode == OperandMode.Temp || mode == OperandMode.Output; - if (isVariable(value)) { - assert trace(" def %s %s", mode, value); - assert curLocations.get(asVariable(value)) == null; - - Location newLoc = allocateRegister(asVariable(value), mode, flags); - return newLoc; - } - return value; - } - - - private void fixupEvicted() { - for (int i = 0; i < curInRegisterState.length; i++) { - CiValue in = curInRegisterState[i]; - CiValue out = curOutRegisterState[i]; - - if (in != null && in != out && isLocation(in) && curLocations.get(asLocation(in).variable) == in) { - assert trace(" %s was evicted by %s, need to allocate new location", in, out); - Location oldLoc = asLocation(in); - Location newLoc = allocateRegister(oldLoc.variable, OperandMode.Alive, SPILL_FLAGS); - assert oldLoc != newLoc; - moveResolver.add(oldLoc, newLoc); - } - - - } - } - - - private Location allocateRegister(final Variable variable, OperandMode mode, EnumSet flags) { -// if (flags.contains(OperandFlag.RegisterHint)) { -// CiValue result = curInstruction.forEachRegisterHint(variable, mode, new ValueProcedure() { -// @Override -// public CiValue doValue(CiValue registerHint) { -// assert trace(" registerHint %s", registerHint); -// CiRegister hint = null; -// if (isRegister(registerHint)) { -// hint = asRegister(registerHint); -// } else if (isLocation(registerHint) && isRegister(asLocation(registerHint).location)) { -// hint = asRegister(asLocation(registerHint).location); -// } -// if (hint != null && hint.isSet(variable.flag) && isFree(hint, inRegisterState, outRegisterState)) { -// return selectRegister(hint, variable, inRegisterState, outRegisterState); -// } -// return null; -// } -// }); -// -// if (result != null) { -// return asLocation(result); -// } -// } -// - EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); - CiRegister[] availableRegs = categorizedRegs.get(variable.flag); - - Location bestSpillCandidate = null; - for (CiRegister reg : availableRegs) { - if (isFree(reg, mode)) { - return selectRegister(reg, variable, mode); - } else { - Location spillCandidate = spillCandidate(reg); - if (betterSpillCandidate(spillCandidate, bestSpillCandidate)) { - bestSpillCandidate = spillCandidate; - } - } - } - - if (flags.contains(OperandFlag.Stack) && betterSpillCandidate(curLocations.get(variable), bestSpillCandidate)) { - return selectSpillSlot(variable, mode); - } - - if (bestSpillCandidate == null) { - if (curPhiBlock != null) { - return selectSpillSlot(variable, mode); - } - // This should not happen as long as all LIR instructions have fulfillable register constraints. But be safe in product mode and bail out. - assert false; - throw new CiBailout("No register available"); - } - - spill(bestSpillCandidate); - - return selectRegister(asRegister(bestSpillCandidate.location), variable, mode); - } - - private void spill(Location value) { - Location newLoc = spillLocation(value.variable); - assert trace(" spill %s to %s", value, newLoc); - if (curPhiBlock == null) { - moveResolver.add(value, newLoc); - } - curLocations.put(newLoc); - - CiRegister reg = asRegister(value.location); - assert curInRegisterState[reg.number] == value; - curInRegisterState[reg.number] = null; - if (curOutRegisterState[reg.number] == value) { - curOutRegisterState[reg.number] = null; - } - } - - private boolean isFree(CiRegister reg, OperandMode mode) { - switch (mode) { - case Input: return curInRegisterState[reg.number] == null; - case Alive: return curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null; - case Temp: return curOutRegisterState[reg.number] == null; - case Output: return curOutRegisterState[reg.number] == null; - default: throw Util.shouldNotReachHere(); - } - } - - private Location spillCandidate(CiRegister reg) { - CiValue in = curInRegisterState[reg.number]; - CiValue out = curOutRegisterState[reg.number]; - if (in == out && in != null && isLocation(in) && lastUseFor(asLocation(in).variable) < curOpId) { - return asLocation(in); - } - return null; - } - - private boolean betterSpillCandidate(Location loc, Location compare) { - if (loc == null) { - return false; - } - if (compare == null) { - return true; - } - if (canonicalSpillLocations.get(loc.variable) != null && canonicalSpillLocations.get(compare.variable) == null) { - return true; - } - return dataFlow.definition(loc.variable) < dataFlow.definition(compare.variable); - } - - private Location spillLocation(Variable variable) { - Location result = canonicalSpillLocations.get(variable); - if (result == null) { - result = new Location(variable, frameMap.allocateSpillSlot(variable.kind)); - canonicalSpillLocations.put(result); - } - return result; - } - - private Location selectRegister(CiRegister reg, Variable variable, OperandMode mode) { - assert isFree(reg, mode); - - Location loc = new Location(variable, reg.asValue(variable.kind)); - if (mode == OperandMode.Input || mode == OperandMode.Alive) { - curInRegisterState[reg.number] = loc; - } - curOutRegisterState[reg.number] = loc; - curLocations.put(loc); - recordUse(variable, mode); - - assert trace(" selected register %s", loc); - return loc; - } - - private Location selectSpillSlot(Variable variable, OperandMode mode) { - Location loc = spillLocation(variable); - curLocations.put(loc); - recordUse(variable, mode); - - assert trace(" selected spill slot %s", loc); - return loc; - } - - private boolean checkInputState(final Block block) { - final BitSet liveState = new BitSet(); - curLocations.forEachLocation(new ValueProcedure() { - @Override - public CiValue doValue(CiValue value) { - liveState.set(asLocation(value).variable.index); - - for (Block pred : block.getPredecessors()) { - LocationMap predState = endLocationsFor(pred); - if (predState != null) { - assert predState.get(asLocation(value).variable) != null; - } else { - assert block.isLoopHeader(); - } - } - return value; - } - }); - assert liveState.equals(curLiveIn); - return true; - } - - - private boolean traceState() { - if (GraalOptions.TraceRegisterAllocation) { - TTY.print(" current lcoations: "); - curLocations.forEachLocation(new ValueProcedure() { - @Override - public CiValue doValue(CiValue value) { - TTY.print("%s ", value); - return value; - } - }); - TTY.println(); - } - return true; - } - - private static boolean trace(String format, Object...args) { - if (GraalOptions.TraceRegisterAllocation) { - TTY.println(format, args); - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.simple; - -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.alloc.util.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; -import com.oracle.max.graal.compiler.util.*; - -public abstract class ResolveDataFlow { - public final LIR lir; - public final MoveResolver moveResolver; - public final DataFlowAnalysis dataFlow; - - public ResolveDataFlow(LIR lir, MoveResolver moveResolver, DataFlowAnalysis dataFlow) { - this.lir = lir; - this.moveResolver = moveResolver; - this.dataFlow = dataFlow; - } - - private Block curToBlock; - private LocationMap curFromLocations; - - public void execute() { - ValueProcedure locMappingProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return locMapping(value); } }; - PhiValueProcedure phiMappingProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue input, CiValue output) { return phiMapping(input, output); } }; - - assert trace("==== start resolve data flow ===="); - for (Block toBlock : lir.linearScanOrder()) { - curToBlock = toBlock; - - for (Block fromBlock : toBlock.getPredecessors()) { - assert trace("start edge %s -> %s", fromBlock, toBlock); - findInsertPos(fromBlock, toBlock); - - LocationMap toLocations = locationsForBlockBegin(toBlock); - curFromLocations = locationsForBlockEnd(fromBlock); - if (toLocations != curFromLocations) { - toLocations.forEachLocation(locMappingProc); - } - - if (toBlock.phis != null) { - toBlock.phis.forEachInput(fromBlock, phiMappingProc); - } - - moveResolver.resolve(); - assert trace("end edge %s -> %s", fromBlock, toBlock); - } - - // Phi functions are resolved with moves now, so delete them. - toBlock.phis = null; - } - moveResolver.finish(); - assert trace("==== end resolve data flow ===="); - } - - private CiValue locMapping(CiValue value) { - Location to = asLocation(value); - Location from = curFromLocations.get(to.variable); - if (value != from && dataFlow.liveIn(curToBlock).get(to.variable.index)) { - moveResolver.add(from, to); - } - return value; - } - - private CiValue phiMapping(CiValue input, CiValue output) { - if (input != output) { - moveResolver.add(input, asLocation(output)); - } - return input; - } - - private void findInsertPos(Block fromBlock, Block toBlock) { - assert fromBlock.getSuccessors().contains(toBlock) && toBlock.getPredecessors().contains(fromBlock); - - if (fromBlock.numberOfSux() == 1) { - List instructions = fromBlock.lir; - LIRInstruction instr = instructions.get(instructions.size() - 1); - assert instr instanceof StandardOp.JumpOp : "block does not end with an unconditional jump"; - moveResolver.init(instructions, instructions.size() - 1); - assert trace(" insert at end of %s before %d", fromBlock, instructions.size() - 1); - - } else if (toBlock.numberOfPreds() == 1) { - moveResolver.init(toBlock.lir, 1); - assert trace(" insert at beginning of %s before %d", toBlock, 1); - - } else { - Util.shouldNotReachHere("Critical edge not split"); - } - } - - protected abstract LocationMap locationsForBlockBegin(Block block); - protected abstract LocationMap locationsForBlockEnd(Block block); - - - private static boolean trace(String format, Object...args) { - if (GraalOptions.TraceRegisterAllocation) { - TTY.println(format, args); - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,495 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.simple; - -import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ci.CiRegister.RegisterFlag; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.alloc.util.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; -import com.oracle.max.graal.compiler.util.*; -import com.oracle.max.graal.debug.*; - -public class SpillAllAllocator { - private final LIR lir; - private final FrameMap frameMap; - - private final DataFlowAnalysis dataFlow; - - public SpillAllAllocator(LIR lir, FrameMap frameMap) { - this.lir = lir; - this.frameMap = frameMap; - - this.dataFlow = new DataFlowAnalysis(lir, frameMap.registerConfig); - this.blockLocations = new LocationMap[lir.linearScanOrder().size()]; - this.moveResolver = new MoveResolverImpl(lir, frameMap); - } - - private class MoveResolverImpl extends MoveResolver { - public MoveResolverImpl(LIR lir, FrameMap frameMap) { - super(lir, frameMap); - } - - @Override - protected CiValue scratchRegister(Variable spilled) { - EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); - CiRegister[] availableRegs = categorizedRegs.get(spilled.flag); - for (CiRegister reg : availableRegs) { - if (curInRegisterState[reg.number] == null && curOutRegisterState[reg.number] == null) { - return reg.asValue(spilled.kind); - } - } - throw new CiBailout("No register found"); - } - } - - private class ResolveDataFlowImpl extends ResolveDataFlow { - public ResolveDataFlowImpl(LIR lir, MoveResolver moveResolver, DataFlowAnalysis dataFlow) { - super(lir, moveResolver, dataFlow); - } - - @Override - protected LocationMap locationsForBlockBegin(Block block) { - assert block.numberOfPreds() > 0 && block.getDominator() != null; - return locationsFor(block.getDominator()); - } - - @Override - protected LocationMap locationsForBlockEnd(Block block) { - return locationsFor(block); - } - } - - private class AssignRegistersImpl extends AssignRegisters { - public AssignRegistersImpl(LIR lir, FrameMap frameMap) { - super(lir, frameMap); - } - - @Override - protected LocationMap locationsForBlockEnd(Block block) { - return locationsFor(block); - } - } - - - private int maxRegisterNum() { - return frameMap.target.arch.registers.length; - } - - private boolean isAllocatableRegister(CiValue value) { - return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; - } - - - private final LocationMap[] blockLocations; - - private LocationMap locationsFor(Block block) { - return blockLocations[block.getId()]; - } - private void setLocationsFor(Block block, LocationMap locations) { - blockLocations[block.getId()] = locations; - } - - private MoveResolver moveResolver; - private LocationMap curStackLocations; - private LocationMap curRegisterLocations; - private Object[] curInRegisterState; - private Object[] curOutRegisterState; - private BitSet curLiveIn; - private LIRInstruction curInstruction; - - public void execute() { - assert LIRVerifier.verify(true, lir, frameMap); - - dataFlow.execute(); - IntervalPrinter.printBeforeAllocation("Before register allocation", lir, frameMap.registerConfig, dataFlow); - - allocate(); - - IntervalPrinter.printAfterAllocation("After spill all allocation", lir, frameMap.registerConfig, dataFlow, blockLocations); - - ResolveDataFlow resolveDataFlow = new ResolveDataFlowImpl(lir, moveResolver, dataFlow); - resolveDataFlow.execute(); - frameMap.finish(); - - IntervalPrinter.printAfterAllocation("After resolve data flow", lir, frameMap.registerConfig, dataFlow, blockLocations); - assert RegisterVerifier.verify(lir, frameMap); - - AssignRegisters assignRegisters = new AssignRegistersImpl(lir, frameMap); - assignRegisters.execute(); - - Debug.dump(lir, "After register asignment"); - assert LIRVerifier.verify(false, lir, frameMap); - } - - private void allocate() { - ValueProcedure killNonLiveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killNonLive(value); } }; - ValueProcedure killBeginProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, false); } }; - ValueProcedure killEndProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, true); } }; - ValueProcedure killLocationProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killLocation(value); } }; - ValueProcedure blockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return block(value); } }; - ValueProcedure loadProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return load(value, mode, flags); } }; - ValueProcedure spillProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return spill(value, mode, flags); } }; - PhiValueProcedure useSlotProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value) { return useSlot(value); } }; - ValueProcedure defSlotProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return defSlot(value); } }; - - assert trace("==== start spill all allocation ===="); - curInRegisterState = new Object[maxRegisterNum()]; - curOutRegisterState = new Object[maxRegisterNum()]; - curRegisterLocations = new LocationMap(lir.numVariables()); - for (Block block : lir.linearScanOrder()) { - assert trace("start block %s %s", block, block.getLoop()); - assert checkEmpty(curOutRegisterState); - - if (block.getDominator() != null) { - LocationMap dominatorState = locationsFor(block.getDominator()); - curStackLocations = new LocationMap(dominatorState); - // Clear out all variables that are not live at the begin of this block - curLiveIn = dataFlow.liveIn(block); - curStackLocations.forEachLocation(killNonLiveProc); - assert checkInputState(block); - } else { - curStackLocations = new LocationMap(lir.numVariables()); - } - assert traceState(); - - if (block.phis != null) { - assert trace(" phis"); - block.phis.forEachOutput(defSlotProc); - } - - for (int opIdx = 0; opIdx < block.lir.size(); opIdx++) { - LIRInstruction op = block.lir.get(opIdx); - curInstruction = op; - assert trace(" op %d %s", op.id(), op); - - assert curRegisterLocations.checkEmpty(); - - System.arraycopy(curOutRegisterState, 0, curInRegisterState, 0, curOutRegisterState.length); - - // Block fixed registers that are defined by this instruction, so that they are no longer available for normal allocation. - op.forEachTemp(blockProc); - op.forEachOutput(blockProc); - - moveResolver.init(block.lir, opIdx); - // Process Alive before Input because they are more restricted and the same variable can be Alive and Input. - op.forEachAlive(loadProc); - op.forEachInput(loadProc); - moveResolver.resolve(); - op.forEachState(useSlotProc); - - dataFlow.forEachKilled(op, false, killBeginProc); - assert !op.hasCall() || checkNoCallerSavedRegister() : "caller saved register in use accross call site"; - - moveResolver.init(block.lir, opIdx + 1); - op.forEachTemp(spillProc); - op.forEachOutput(spillProc); - moveResolver.resolve(); - - dataFlow.forEachKilled(op, true, killEndProc); - curRegisterLocations.forEachLocation(killLocationProc); - - assert curRegisterLocations.checkEmpty(); - curInstruction = null; - } - assert checkEmpty(curOutRegisterState); - - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - assert trace(" phis of successor %s", sux); - sux.phis.forEachInput(block, useSlotProc); - } - } - - assert checkEmpty(curOutRegisterState); - assert locationsFor(block) == null; - setLocationsFor(block, curStackLocations); - - traceState(); - assert trace("end block %s", block); - } - - moveResolver.finish(); - assert trace("==== end spill all allocation ===="); - } - - private CiValue killNonLive(CiValue value) { - assert isLocation(value); - if (!curLiveIn.get(asLocation(value).variable.index)) { - return null; - } - return value; - } - - private CiValue kill(CiValue value, boolean end) { - if (isVariable(value)) { - assert trace(" kill variable %s", value); - - Variable variable = asVariable(value); - curStackLocations.clear(variable); - - Location loc = curRegisterLocations.get(variable); - if (loc != null) { - killLocation(loc); - curRegisterLocations.clear(variable); - - assert trace(" location %s", loc); - assert isAllocatableRegister(loc.location); - - int regNum = asRegister(loc.location).number; - if (curOutRegisterState[regNum] == loc) { - curOutRegisterState[regNum] = null; - } - } - - } else if (isAllocatableRegister(value)) { - assert trace(" kill register %s", value); - int regNum = asRegister(value).number; - assert curOutRegisterState[regNum] == null || curOutRegisterState[regNum] instanceof LIRInstruction && curInstruction != null; - - if (end || curOutRegisterState[regNum] != curInstruction) { - curOutRegisterState[regNum] = null; - } - - } else { - throw Util.shouldNotReachHere(); - } - return value; - } - - private CiValue killLocation(CiValue value) { - assert trace(" kill location %s", value); - assert isAllocatableRegister(asLocation(value).location); - - int regNum = asRegister(asLocation(value).location).number; - if (curOutRegisterState[regNum] == value) { - curOutRegisterState[regNum] = null; - } - return null; - } - - private CiValue block(CiValue value) { - if (isAllocatableRegister(value)) { - assert trace(" block %s", value); - int regNum = asRegister(value).number; - assert curInstruction != null; - assert curOutRegisterState[regNum] == null || curOutRegisterState[regNum] instanceof LIRInstruction; - curOutRegisterState[regNum] = curInstruction; - } - return value; - } - - private CiValue load(CiValue value, OperandMode mode, EnumSet flags) { - assert mode == OperandMode.Input || mode == OperandMode.Alive; - if (flags.contains(OperandFlag.Stack)) { - return useSlot(value); - } - if (isVariable(value)) { - assert trace(" load %s", value); - Location regLoc = curRegisterLocations.get(asVariable(value)); - if (regLoc != null) { - // This variable has already been processed before. - assert trace(" found location %s", regLoc); - } else { - regLoc = allocateRegister(asVariable(value), curInRegisterState, mode == OperandMode.Alive ? curOutRegisterState : null, mode, flags); - Location stackLoc = curStackLocations.get(asVariable(value)); - assert stackLoc != null; - moveResolver.add(stackLoc, regLoc); - } - return regLoc; - } else { - assert !isAllocatableRegister(value) || curInRegisterState[asRegister(value).number] instanceof LIRInstruction; - return value; - } - } - - private CiValue spill(CiValue value, OperandMode mode, EnumSet flags) { - assert mode == OperandMode.Temp || mode == OperandMode.Output; - if (flags.contains(OperandFlag.Stack)) { - return defSlot(value); - } - if (isVariable(value)) { - assert trace(" spill %s", value); - assert curStackLocations.get(asVariable(value)) == null; - Location regLoc = allocateRegister(asVariable(value), null, curOutRegisterState, mode, flags); - if (mode == OperandMode.Output) { - Location stackLoc = new Location(asVariable(value), frameMap.allocateSpillSlot(value.kind)); - curStackLocations.put(stackLoc); - moveResolver.add(regLoc, stackLoc); - } - return regLoc; - } else { - assert !isAllocatableRegister(value) || curOutRegisterState[asRegister(value).number] == curInstruction && curInstruction != null; - return value; - } - } - - private CiValue useSlot(CiValue value) { - if (isVariable(value)) { - assert trace(" useSlot %s", value); - Location stackLoc = curStackLocations.get(asVariable(value)); - assert stackLoc != null; - assert trace(" slot %s", stackLoc); - return stackLoc; - } else { - return value; - } - } - - private CiValue defSlot(CiValue value) { - if (isVariable(value)) { - assert trace(" assignSlot %s", value); - Location stackLoc = new Location(asVariable(value), frameMap.allocateSpillSlot(value.kind)); - assert curStackLocations.get(asVariable(value)) == null; - curStackLocations.put(stackLoc); - assert trace(" slot %s", stackLoc); - return stackLoc; - } else { - return value; - } - } - - private Location allocateRegister(final Variable variable, final Object[] inRegisterState, final Object[] outRegisterState, OperandMode mode, EnumSet flags) { - if (flags.contains(OperandFlag.RegisterHint)) { - CiValue result = curInstruction.forEachRegisterHint(variable, mode, new ValueProcedure() { - @Override - public CiValue doValue(CiValue registerHint) { - assert trace(" registerHint %s", registerHint); - CiRegister hint = null; - if (isRegister(registerHint)) { - hint = asRegister(registerHint); - } else if (isLocation(registerHint) && isRegister(asLocation(registerHint).location)) { - hint = asRegister(asLocation(registerHint).location); - } - if (hint != null && hint.isSet(variable.flag) && isFree(hint, inRegisterState, outRegisterState)) { - return selectRegister(hint, variable, inRegisterState, outRegisterState); - } - return null; - } - }); - - if (result != null) { - return asLocation(result); - } - } - - EnumMap categorizedRegs = frameMap.registerConfig.getCategorizedAllocatableRegisters(); - CiRegister[] availableRegs = categorizedRegs.get(variable.flag); - - for (CiRegister reg : availableRegs) { - if (isFree(reg, inRegisterState, outRegisterState)) { - return selectRegister(reg, variable, inRegisterState, outRegisterState); - } - - } - throw new CiBailout("No register found"); - } - - private static boolean isFree(CiRegister reg, Object[] inRegisterState, Object[] outRegisterState) { - return (inRegisterState == null || inRegisterState[reg.number] == null) && (outRegisterState == null || outRegisterState[reg.number] == null); - } - - private Location selectRegister(CiRegister reg, Variable variable, Object[] inRegisterState, Object[] outRegisterState) { - Location loc = new Location(variable, reg.asValue(variable.kind)); - if (inRegisterState != null) { - inRegisterState[reg.number] = loc; - } - if (outRegisterState != null) { - outRegisterState[reg.number] = loc; - } - assert curRegisterLocations.get(variable) == null; - curRegisterLocations.put(loc); - assert trace(" selected register %s", loc); - return loc; - } - - private boolean checkInputState(final Block block) { - final BitSet liveState = new BitSet(); - curStackLocations.forEachLocation(new ValueProcedure() { - @Override - public CiValue doValue(CiValue value) { - liveState.set(asLocation(value).variable.index); - - for (Block pred : block.getPredecessors()) { - LocationMap predState = locationsFor(pred); - if (predState != null) { - assert predState.get(asLocation(value).variable) == value; - } else { - assert block.isLoopHeader(); - } - } - return value; - } - }); - assert liveState.equals(curLiveIn); - return true; - } - - private boolean checkNoCallerSavedRegister() { - for (CiRegister reg : frameMap.registerConfig.getCallerSaveRegisters()) { - assert curOutRegisterState[reg.number] == null || curOutRegisterState[reg.number] == curInstruction : "caller saved register in use accross call site"; - } - return true; - } - - private static boolean checkEmpty(Object[] array) { - for (Object o : array) { - assert o == null; - } - return true; - } - - - private boolean traceState() { - if (GraalOptions.TraceRegisterAllocation) { - TTY.print(" curVariableLocations: "); - curStackLocations.forEachLocation(new ValueProcedure() { - @Override - public CiValue doValue(CiValue value) { - TTY.print("%s ", value); - return value; - } - }); - TTY.println(); - } - return true; - } - - private static boolean trace(String format, Object...args) { - if (GraalOptions.TraceRegisterAllocation) { - TTY.println(format, args); - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/IntervalPrinter.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/IntervalPrinter.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,293 +0,0 @@ -/* - * 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.max.graal.alloc.util; - -import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.graal.alloc.simple.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; - -public final class IntervalPrinter { - - @SuppressWarnings("unused") - public static void printBeforeAllocation(String label, LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow) { - // TODO(tw): Fix printing. -// if (context.isObserved()) { -// IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, null); -// context.observable.fireCompilationEvent(label, lir, printer.execute()); -// } - } - - @SuppressWarnings("unused") - public static void printAfterAllocation(String label, LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow, LocationMap[] blockEndLocations) { - // TODO(tw): Fix printing. -// if (context.isObserved()) { -// IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, blockEndLocations); -// context.observable.fireCompilationEvent(label, lir, printer.execute()); -// } - } - - - public static class Range { - public final int from; - public final int to; - - public Range(int from, int to) { - this.from = from; - this.to = to; - } - } - - public static class UsePosition { - public final int pos; - public final String kind; - - public UsePosition(int pos, String kind) { - this.pos = pos; - this.kind = kind; - } - } - - public static class Interval { - public final String name; - public final String description; - public final String variable; - public final String type; - public final List ranges; - public final List uses; - - protected final int orderNum; - protected int lastTo; - - public Interval(int orderNum, String name, String description, String variable, String type) { - this.orderNum = orderNum; - this.name = name; - this.description = description; - this.variable = variable; - this.type = type; - this.ranges = new ArrayList<>(); - this.uses = new ArrayList<>(); - } - } - - - private final LIR lir; - private final RiRegisterConfig registerConfig; - private final DataFlowAnalysis dataFlow; - private final LocationMap[] blockEndLocations; - private final Variable[] variables; - private final Map intervals; - - private IntervalPrinter(LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow, LocationMap[] blockEndLocations) { - this.lir = lir; - this.registerConfig = registerConfig; - this.dataFlow = dataFlow; - this.blockEndLocations = blockEndLocations; - this.variables = new Variable[lir.numVariables()]; - this.intervals = new HashMap<>(); - } - - private boolean isAllocatableRegister(CiValue value) { - return isRegister(value) && registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; - } - - private int curOpId; - private String curUseKind; - - public Interval[] execute() { - ValueProcedure varProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return var(value); } }; - - for (Block block : lir.linearScanOrder()) { - if (block.phis != null) { - block.phis.forEachOutput(varProc); - } - for (LIRInstruction op : block.lir) { - op.forEachOutput(varProc); - } - } - - PhiValueProcedure useProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, flags); } }; - - intervals.put("call", new Interval(-2, "call", "", "call", "hasCall")); - intervals.put("st", new Interval(-1, "st", "", "st", "hasState")); - - for (int i = lir.linearScanOrder().size() - 1; i >= 0; i--) { - Block block = lir.linearScanOrder().get(i); - - curOpId = block.getLastLirInstructionId() + 2; - for (Block sux : block.getSuccessors()) { - BitSet suxIn = dataFlow.liveIn(sux); - for (int idx = suxIn.nextSetBit(0); idx >= 0; idx = suxIn.nextSetBit(idx + 1)) { - if (blockEndLocations != null) { - out(blockEndLocations[block.getId()].get(variables[idx])); - } else { - out(variables[idx]); - } - } - } - - curOpId = block.getLastLirInstructionId() + 1; - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - sux.phis.forEachInput(block, useProc); - } - } - - for (int j = block.lir.size() - 1; j >= 0; j--) { - LIRInstruction op = block.lir.get(j); - if (op.id() >= 0) { - curOpId = op.id(); - } else { - curOpId = (curOpId - 1) | 1; - } - - op.forEachOutput(defProc); - op.forEachTemp(defProc); - op.forEachInput(useProc); - op.forEachAlive(useProc); - curUseKind = "L"; - op.forEachState(useProc); - curUseKind = null; - - if (op.hasCall()) { - intervals.get("call").ranges.add(new Range(curOpId, curOpId + 1)); - } - if (op.info != null) { - intervals.get("st").ranges.add(new Range(curOpId, curOpId + 1)); - } - } - - if (block.phis != null) { - curOpId = block.getFirstLirInstructionId() + 1; - block.phis.forEachOutput(defProc); - } - - for (Interval interval : intervals.values()) { - if (interval.lastTo != 0) { - interval.ranges.add(new Range(block.getFirstLirInstructionId(), interval.lastTo)); - interval.lastTo = 0; - } - } - } - - Interval[] intervalsArray = intervals.values().toArray(new Interval[0]); - Arrays.sort(intervalsArray, new Comparator() { - @Override - public int compare(Interval o1, Interval o2) { - return o1.orderNum - o2.orderNum; - } - }); - return intervalsArray; - } - - public CiValue var(CiValue value) { - if (isLocation(value)) { - variables[asLocation(value).variable.index] = asLocation(value).variable; - } else if (isVariable(value)) { - variables[asVariable(value).index] = asVariable(value); - } - return value; - } - - private Interval findInterval(CiValue value) { - Interval interval; - if (isLocation(value)) { - Interval parent = findInterval(asLocation(value).variable); - String name = "v" + asLocation(value).variable.index + ":" + asLocation(value).location; - String description = isStackSlot(asLocation(value).location) ? "stack" : ""; - interval = new Interval(asLocation(value).variable.index * 2 + 1001, name, description, parent.name, value.kind.javaName); - - } else if (isVariable(value)) { - interval = new Interval(asVariable(value).index * 2 + 1000, value.toString(), "", value.toString(), value.kind.javaName); - - } else if (isAllocatableRegister(value)) { - interval = new Interval(asRegister(value).number, asRegister(value).toString(), "", asRegister(value).toString(), "fixed"); - - } else { - return null; - } - - Interval existing = intervals.get(interval.name); - if (existing != null) { - return existing; - } - intervals.put(interval.name, interval); - return interval; - } - - private String useKind(EnumSet flags) { - if (curUseKind != null) { - return curUseKind; - } else if (flags.contains(OperandFlag.Stack)) { - return "S"; - } else { - return "M"; - } - } - - private CiValue use(CiValue value, OperandMode mode, EnumSet flags) { - Interval interval = findInterval(value); - if (interval != null) { - if (interval.uses.size() == 0 || interval.uses.get(interval.uses.size() - 1).pos != curOpId) { - interval.uses.add(new UsePosition(curOpId, useKind(flags))); - } - if (interval.lastTo == 0) { - interval.lastTo = curOpId + (mode == OperandMode.Alive ? 1 : 0); - } - } - return value; - } - - private CiValue def(CiValue value, EnumSet flags) { - Interval interval = findInterval(value); - if (interval != null) { - interval.uses.add(new UsePosition(curOpId, useKind(flags))); - if (interval.lastTo == 0) { - interval.ranges.add(new Range(curOpId, curOpId + 1)); - } else { - interval.ranges.add(new Range(curOpId, interval.lastTo)); - } - interval.lastTo = 0; - } - return value; - } - - private CiValue out(CiValue value) { - Interval interval = findInterval(value); - if (interval != null) { - interval.lastTo = curOpId; - } - return value; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/Location.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/Location.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.util; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.lir.*; - -public class Location extends CiValue { - private static final long serialVersionUID = -1786677729152726126L; - - public final Variable variable; - public final CiValue location; - - public Location(Variable variable, CiValue location) { - super(variable.kind); - this.variable = variable; - this.location = location; - - assert variable.kind == location.kind; - } - - @Override - public String toString() { - return variable + "[" + location + "]"; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LocationMap.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LocationMap.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.util; - -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; - -public class LocationMap { - private final Location[] locations; - - public LocationMap(int numVariables) { - locations = new Location[numVariables]; - } - - public LocationMap(LocationMap template) { - locations = Arrays.copyOf(template.locations, template.locations.length); - } - - public Location get(Variable variable) { - assert locations[variable.index] == null || locations[variable.index].variable == variable; - return locations[variable.index]; - } - - public void put(Location location) { - locations[location.variable.index] = location; - } - - public void clear(Variable variable) { - locations[variable.index] = null; - } - - public void forEachLocation(ValueProcedure proc) { - for (int i = 0; i < locations.length; i++) { - if (locations[i] != null) { - CiValue newValue = proc.doValue(locations[i], null, null); - assert newValue == null || asLocation(newValue).variable == locations[i].variable; - locations[i] = (Location) newValue; - } - } - } - - public boolean checkEmpty() { - for (int i = 0; i < locations.length; i++) { - assert locations[i] == null; - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/MoveResolver.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/MoveResolver.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,347 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.alloc.util; - -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.alloc.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; - -public abstract class MoveResolver { - private final LIR lir; - private final FrameMap frameMap; - private final int[] registersBlocked; - private final Map valuesBlocked; - private final List mappingFrom; - private final List mappingTo; - private final LIRInsertionBuffer insertionBuffer; - private int insertPos; - - public MoveResolver(LIR lir, FrameMap frameMap) { - this.lir = lir; - this.frameMap = frameMap; - - registersBlocked = new int[frameMap.target.arch.registers.length]; - valuesBlocked = new HashMap<>(); - - mappingFrom = new ArrayList<>(); - mappingTo = new ArrayList<>(); - insertionBuffer = new LIRInsertionBuffer(); - insertPos = -1; - - assert checkEmpty(); - } - - public void init(List newInsertList, int newInsertPos) { - assert checkEmpty(); - - if (insertionBuffer.lirList() != newInsertList) { - // Block changed, so append insertionBuffer because it is bound to a specific block - finish(); - insertionBuffer.init(newInsertList); - } - insertPos = newInsertPos; - - assert checkValid(); - } - - public void add(CiValue from, Location to) { - assert checkValid(); - assert isLocation(from) || isConstant(from); - assert from != to; - - assert trace("mr add mapping from %s to %s", from, to); - mappingFrom.add(from); - mappingTo.add(to); - - assert checkValid(); - } - - public void resolve() { - assert checkValid(); - - if (mappingFrom.size() == 1) { - // If there is only one mapping, it is trivial that this mapping is safe to resolve. - assert trace("mr resolve mappings: %d", mappingFrom.size()); - insertMove(mappingFrom.get(0), mappingTo.get(0)); - mappingFrom.remove(0); - mappingTo.remove(0); - } else if (mappingFrom.size() > 1) { - assert trace("mr resolve mappings: %d", mappingFrom.size()); - doResolve(); - } - insertPos = -1; - - assert checkEmpty(); - } - - public void finish() { - assert checkEmpty(); - - if (insertionBuffer.initialized()) { - insertionBuffer.finish(); - } - - assert !insertionBuffer.initialized() : "must be uninitialized now"; - assert checkEmpty(); - } - - - private void doResolve() { - // Block all registers and stack slots that are used as inputs of a move. - // When a register is blocked, no move to this register is emitted. - // This is necessary for detecting cycles in moves. - for (CiValue from : mappingFrom) { - block(from); - } - - while (mappingFrom.size() > 0) { - boolean processed = false; - for (int i = mappingFrom.size() - 1; i >= 0; i--) { - CiValue from = mappingFrom.get(i); - Location to = mappingTo.get(i); - - if (safeToProcessMove(from, to)) { - insertMove(from, to); - unblock(from); - mappingFrom.remove(i); - mappingTo.remove(i); - processed = true; - } - } - - if (!processed) { - // No move could be processed because there is a cycle in the move list - // (e.g., r1 -> r2, r2 -> r1), so one location must be spilled. - spill(); - } - } - } - - private void spill() { - Location spillCandidate = null; - int exchangeCandidate = -1; - int exchangeOther = -1; - - for (int i = mappingFrom.size() - 1; i >= 0; i--) { - CiValue from = mappingFrom.get(i); - Location to = mappingTo.get(i); - assert !safeToProcessMove(from, to) : "would not be in this code otherwise"; - - if (isConstant(from)) { - continue; - } - CiValue fromLoc = asLocation(from).location; - - // Check if we can insert an exchange to save us from spilling. - if (isRegister(fromLoc) && isRegister(to) && asRegister(fromLoc) != asRegister(to) && blockedCount(to) == 1) { - for (int j = mappingFrom.size() - 1; j >= 0; j--) { - CiValue possibleOther = mappingFrom.get(j); - if (isLocation(possibleOther)) { - if (asLocation(possibleOther).location == to.location) { - assert exchangeCandidate == -1 : "must not find twice because of blocked check above"; - exchangeCandidate = i; - exchangeOther = j; - } else if (i != j && asLocation(possibleOther).location == fromLoc) { - // From is read multiple times, so exchange would be too complicated. - exchangeCandidate = -1; - break; - } - } - } - } - - if (exchangeCandidate != -1) { - // Already found a result, no need to search further - break; - } - if (spillCandidate == null || isStackSlot(spillCandidate.location)) { - // this interval cannot be processed now because target is not free - spillCandidate = asLocation(from); - } - } - - if (exchangeCandidate != -1) { - Location from = asLocation(mappingFrom.get(exchangeCandidate)); - Location to = mappingTo.get(exchangeCandidate); - Location other = asLocation(mappingFrom.get(exchangeOther)); - - Location newOther = new Location(other.variable, from.variable); - mappingFrom.set(exchangeOther, newOther); - - insertExchange(newOther, to); - unblock(to); - mappingFrom.remove(exchangeCandidate); - mappingTo.remove(exchangeCandidate); - - } else { - assert spillCandidate != null : "no location for spilling found"; - - Location spillLocation = new Location(spillCandidate.variable, frameMap.allocateSpillSlot(spillCandidate.kind)); - insertMove(spillCandidate, spillLocation); - - for (int i = mappingFrom.size() - 1; i >= 0; i--) { - if (mappingFrom.get(i) == spillCandidate) { - mappingFrom.set(i, spillLocation); - unblock(spillCandidate); - block(spillLocation); - } - } - assert blockedCount(spillCandidate) == 0 : "register must be unblocked after spilling"; - } - } - - private void block(CiValue value) { - if (isLocation(value)) { - CiValue location = asLocation(value).location; - if (isRegister(location)) { - registersBlocked[asRegister(location).number]++; - } else { - Integer count = valuesBlocked.get(location); - valuesBlocked.put(location, count == null ? 1 : count + 1); - } - } - } - - private void unblock(CiValue value) { - if (isLocation(value)) { - assert blockedCount(asLocation(value)) > 0; - CiValue location = asLocation(value).location; - if (isRegister(location)) { - registersBlocked[asRegister(location).number]--; - } else { - Integer count = valuesBlocked.remove(location); - if (count > 1) { - valuesBlocked.put(location, count - 1); - } - } - } - } - - private int blockedCount(Location value) { - CiValue location = asLocation(value).location; - if (isRegister(location)) { - return registersBlocked[asRegister(location).number]; - } else { - Integer count = valuesBlocked.get(location); - return count == null ? 0 : count; - } - } - - private boolean safeToProcessMove(CiValue from, Location to) { - int count = blockedCount(to); - return count == 0 || (count == 1 && isLocation(from) && asLocation(from).location == to.location); - } - - private void insertExchange(Location from, Location to) { - assert trace("mr XCHG %s, %s", from, to); - // TODO create XCHG instruction and use it here - insertionBuffer.append(insertPos, null); - throw Util.unimplemented(); - } - - private void insertMove(CiValue src, Location dst) { - if (isStackSlot(dst.location) && isLocation(src) && isStackSlot(asLocation(src).location)) { - // Move between two stack slots. We need a temporary registers. If the allocator can give - // us a free register, we need two moves: src->scratch, scratch->dst - // If the allocator cannot give us a free register (it returns a Location in this case), - // we need to spill the scratch register first, so we need four moves in total. - - CiValue scratch = scratchRegister(dst.variable); - - Location scratchSaved = null; - CiValue scratchRegister = scratch; - if (isLocation(scratch)) { - scratchSaved = new Location(asLocation(scratch).variable, frameMap.allocateSpillSlot(scratch.kind)); - insertMove(scratch, scratchSaved); - scratchRegister = asLocation(scratch).location; - } - assert isRegister(scratchRegister); - - Location scratchLocation = new Location(dst.variable, scratchRegister); - insertMove(src, scratchLocation); - insertMove(scratchLocation, dst); - - if (scratchSaved != null) { - insertMove(scratchSaved, asLocation(scratch)); - } - - } else { - assert trace("mr MOV %s -> %s", src, dst); - insertionBuffer.append(insertPos, lir.spillMoveFactory.createMove(dst, src)); - } - } - - /** - * Provides a register that can be used by the move resolver. If the returned value is a - * {@link CiRegisterValue}, the register can be overwritten without precautions. If the - * returned value is a {@link Location}, it needs to be spilled and rescued itself. - */ - protected abstract CiValue scratchRegister(Variable spilled); - - private boolean checkEmpty() { - assert insertPos == -1; - assert mappingFrom.size() == 0 && mappingTo.size() == 0; - for (int registerBlocked : registersBlocked) { - assert registerBlocked == 0; - } - assert valuesBlocked.size() == 0; - return true; - } - - private boolean checkValid() { - assert insertPos != -1; - for (int registerBlocked : registersBlocked) { - assert registerBlocked == 0; - } - assert mappingFrom.size() == mappingTo.size(); - assert insertionBuffer.initialized() && insertPos != -1; - - for (int i = 0; i < mappingTo.size(); i++) { - CiValue from = mappingFrom.get(i); - Location to = mappingTo.get(i); - - assert from.kind.stackKind() == to.kind; - - for (int j = i + 1; j < mappingTo.size(); j++) { - Location otherTo = mappingTo.get(j); - assert to != otherTo && to.variable != otherTo.variable && to.location != otherTo.location : "Cannot write to same location twice"; - } - } - return true; - } - - - private static boolean trace(String format, Object...args) { - if (GraalOptions.TraceRegisterAllocation) { - TTY.println(format, args); - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/RegisterVerifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/RegisterVerifier.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,260 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.alloc.util; - -import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.*; -import com.oracle.max.graal.compiler.util.*; - -public final class RegisterVerifier { - private final FrameMap frameMap; - - /** - * All blocks that must be processed. - */ - private final List workList; - - /** - * Saved information of previous check. - *
- * State mapping: mapping from registers and stack slots ({@link CiRegister} and {@link Integer} stack slot offsets) to the - * value that is currently contained in there ({@link Location} for operands that were variables; {@link CiRegisterValue} or - * {@link CiStackSlot} for operands that used fixed registers or stack slots). - */ - private final Map[] blockStates; - - private void addToWorkList(Block block) { - if (!workList.contains(block)) { - workList.add(block); - } - } - - private Map stateFor(Block block) { - return blockStates[block.getId()]; - } - - private void setStateFor(Block block, Map savedState) { - blockStates[block.getId()] = savedState; - } - - private static Map copy(Map inputState) { - return new HashMap<>(inputState); - } - - public static boolean verify(LIR lir, FrameMap frameMap) { - RegisterVerifier verifier = new RegisterVerifier(lir, frameMap); - verifier.verify(lir.cfg.getStartBlock()); - return true; - } - - @SuppressWarnings("unchecked") - private RegisterVerifier(LIR lir, FrameMap frameMap) { - this.frameMap = frameMap; - this.workList = new LinkedList<>(); - this.blockStates = new Map[lir.linearScanOrder().size()]; - } - - private Map curInputState; - - private void verify(Block startBlock) { - ValueProcedure useProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, flags); } }; - ValueProcedure tempProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return temp(value); } }; - ValueProcedure outputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return output(value); } }; - - curInputState = new HashMap<>(); - setStateFor(startBlock, curInputState); - addToWorkList(startBlock); - - assert trace("==== start verify register allocation ===="); - do { - Block block = workList.remove(0); - assert block.phis == null : "phi functions must have been resolved with moves"; - - // Must copy state because it is modified. - curInputState = copy(stateFor(block)); - assert trace("start block %s %s", block, block.getLoop()); - assert traceState(); - - for (LIRInstruction op : block.lir) { - assert trace(" op %d %s", op.id(), op); - - op.forEachInput(useProc); - if (op.hasCall()) { - invalidateRegisters(); - } - op.forEachAlive(useProc); - op.forEachState(useProc); - op.forEachTemp(tempProc); - op.forEachOutput(outputProc); - } - - for (Block succ : block.getSuccessors()) { - processSuccessor(succ); - } - - assert trace("end block %s", block); - } while (!workList.isEmpty()); - assert trace("==== end verify register allocation ===="); - } - - private void processSuccessor(Block succ) { - Map savedState = stateFor(succ); - if (savedState == null) { - // Block was not processed before, so set initial inputState. - assert trace(" successor %s: initial visit", succ); - setStateFor(succ, copy(curInputState)); - addToWorkList(succ); - - } else { - // This block was already processed before. - // Check if new inputState is consistent with savedState. - assert trace(" successor %s: state present", succ); - Iterator> iter = savedState.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - CiValue savedValue = entry.getValue(); - CiValue inputValue = curInputState.get(entry.getKey()); - - if (savedValue != inputValue) { - // Current inputState and previous savedState assume a different value in this register. - // Assume that this register is invalid and remove it from the saved state. - assert trace(" invalididating %s because it is inconsistent with %s", savedValue, inputValue); - iter.remove(); - // Must re-visit this block. - addToWorkList(succ); - } - } - } - } - - private void invalidateRegisters() { - // Invalidate all caller save registers at calls. - Iterator iter = curInputState.keySet().iterator(); - while (iter.hasNext()) { - Object value1 = iter.next(); - if (value1 instanceof CiRegister && frameMap.registerConfig.getAttributesMap()[((CiRegister) value1).number].isCallerSave) { - assert trace(" remove caller save register %s", value1); - iter.remove(); - } - } - } - - /** - * Gets the mapping key for a value. The key should be as narrow as possible, e.g., it should not - * include the kind of the value because we do not want to distinguish between the same register with - * different kinds. - */ - private Object key(CiValue value) { - if (isLocation(value)) { - return key(asLocation(value).location); - } else if (isRegister(value)) { - return asRegister(value); - } else if (isStackSlot(value)) { - return Integer.valueOf(frameMap.offsetForStackSlot(asStackSlot(value))); - } else { - throw Util.shouldNotReachHere(); - } - } - - private boolean isIgnoredRegister(CiValue value) { - return isRegister(value) && !frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; - } - - private CiValue use(CiValue value, EnumSet flags) { - if (!isConstant(value) && value != CiValue.IllegalValue && !isIgnoredRegister(value)) { - CiValue actual = curInputState.get(key(value)); - if (actual == null && flags.contains(OperandFlag.Uninitialized)) { - // OK, since uninitialized values are allowed explicitly. - } else if (value != actual) { - TTY.println("!! Error in register allocation: %s != %s for key %s", value, actual, key(value)); - traceState(); - throw Util.shouldNotReachHere(); - } - } - return value; - } - - private CiValue temp(CiValue value) { - if (!isConstant(value) && value != CiValue.IllegalValue && !isIgnoredRegister(value)) { - assert trace(" temp %s -> remove key %s", value, key(value)); - curInputState.remove(key(value)); - } - return value; - } - - private CiValue output(CiValue value) { - if (value != CiValue.IllegalValue && !isIgnoredRegister(value)) { - assert trace(" output %s -> set key %s", value, key(value)); - curInputState.put(key(value), value); - } - return value; - } - - - private boolean traceState() { - if (GraalOptions.TraceRegisterAllocation) { - ArrayList keys = new ArrayList<>(curInputState.keySet()); - Collections.sort(keys, new Comparator() { - @Override - public int compare(Object o1, Object o2) { - if (o1 instanceof CiRegister) { - if (o2 instanceof CiRegister) { - return ((CiRegister) o1).number - ((CiRegister) o2).number; - } else { - return -1; - } - } else { - if (o2 instanceof CiRegister) { - return 1; - } else { - return ((Integer) o1).intValue() - ((Integer) o2).intValue(); - } - } - } - }); - - TTY.print(" state: "); - for (Object key : keys) { - TTY.print("%s=%s ", key, curInputState.get(key)); - } - TTY.println(); - } - return true; - } - - private static boolean trace(String format, Object...args) { - if (GraalOptions.TraceRegisterAllocation) { - TTY.println(format, args); - } - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/ValueUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/ValueUtil.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.alloc.util; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.lir.*; - -public class ValueUtil extends CiValueUtil { - - public static boolean isVariable(CiValue value) { - assert value != null; - return value instanceof Variable; - } - - public static Variable asVariable(CiValue value) { - assert value != null; - return (Variable) value; - } - - - public static boolean isLocation(CiValue value) { - assert value != null; - return value instanceof Location; - } - - public static Location asLocation(CiValue value) { - assert value != null; - return (Location) value; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Thu Feb 09 10:03:21 2012 +0100 @@ -29,19 +29,18 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; import com.oracle.max.cri.xir.*; -import com.oracle.max.criutils.*; import com.oracle.max.graal.alloc.simple.*; import com.oracle.max.graal.compiler.alloc.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.phases.*; import com.oracle.max.graal.compiler.phases.PhasePlan.PhasePosition; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.compiler.target.*; import com.oracle.max.graal.cri.*; import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; public class GraalCompiler { @@ -81,6 +80,9 @@ if (osrBCI != -1) { throw new CiBailout("No OSR supported"); } + Debug.dump(this, "compiler"); + Debug.dump(method, "method"); + return Debug.scope(createScopeName(method), new Callable() { public CiTargetMethod call() { final CiAssumptions assumptions = GraalOptions.OptAssumptions ? new CiAssumptions() : null; @@ -189,6 +191,7 @@ final SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); + Debug.dump(schedule, "final schedule"); final Block[] blocks = schedule.getCFG().getBlocks(); final Block startBlock = schedule.getCFG().getStartBlock(); @@ -219,6 +222,7 @@ public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final RiResolvedMethod method) { final FrameMap frameMap = backend.newFrameMap(runtime.getRegisterConfig(method)); final LIRGenerator lirGenerator = backend.newLIRGenerator(graph, frameMap, method, lir, xir); + Debug.dump(lirGenerator, "LIRGenerator"); Debug.scope("LIRGen", new Runnable() { public void run() { @@ -226,16 +230,7 @@ lirGenerator.doBlock(b); } - for (Block b : lir.linearScanOrder()) { - if (b.phis != null) { - b.phis.fillInputs(lirGenerator); - } - } - - Debug.dump(lirGenerator, "After LIR generation"); - if (GraalOptions.PrintLIR && !TTY.isSuppressed()) { - LIR.printLIR(lir.linearScanOrder()); - } + Debug.dump(lir, "After LIR generation"); } }); @@ -269,6 +264,7 @@ targetMethod.setAssumptions(assumptions); } + Debug.dump(lir, "After code generation"); Debug.dump(targetMethod, "After code generation"); return targetMethod; } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java Thu Feb 09 10:03:21 2012 +0100 @@ -44,18 +44,23 @@ public static boolean CacheGraphs = ____; public static boolean InlineMonomorphicCalls = true; public static boolean InlinePolymorphicCalls = true; + public static boolean InlineMegamorphicCalls = true; public static int InliningPolicy = 0; - public static int MaximumInlineSize = 35; - public static int MaximumFreqInlineSize = 300; - public static float NestedInliningSizeRatio = 0.9f; - public static int FreqInlineRatio = 20; public static int MaximumTrivialSize = 6; public static int MaximumInlineLevel = 30; public static int MaximumDesiredSize = 6000; + // WeightBasedInliningPolicy (0) public static boolean ParseBeforeInlining = ____; public static float InliningSizePenaltyExp = 20; public static float MaximumInlineWeight = 1.25f; public static float InliningSizePenalty = 1; + // StaticSizeBasedInliningPolicy (1), DynamicSizeBasedInliningPolicy (2), GreedySizeBasedInlining (3) + public static int MaximumInlineSize = 35; + public static float NestedInliningSizeRatio = 0.9f; + public static float BoostInliningForEscapeAnalysis = 2f; + public static float ProbabilityCapForInlining = 1f; + public static int MaximumGreedyInlineSize = 250; + public static int SmallCompiledCodeSize = 1500; // escape analysis settings public static boolean EscapeAnalysis = true; @@ -129,7 +134,7 @@ public static int MatureInvocationCount = 100; public static boolean GenSafepoints = true; public static boolean GenLoopSafepoints = true; - public static boolean UseInstanceOfHints = true; + public static boolean UseTypeCheckHints = true; public static boolean GenAssertionCode = ____; public static boolean AlignCallsForPatching = true; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ComputeLinearScanOrder.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ComputeLinearScanOrder.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ComputeLinearScanOrder.java Thu Feb 09 10:03:21 2012 +0100 @@ -27,8 +27,8 @@ import com.oracle.max.criutils.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.cfg.*; public final class ComputeLinearScanOrder { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java Thu Feb 09 10:03:21 2012 +0100 @@ -24,10 +24,10 @@ import java.util.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.cfg.*; /** * This class performs basic optimizations on the control flow graph after LIR generation. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java Thu Feb 09 10:03:21 2012 +0100 @@ -24,9 +24,9 @@ import java.util.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.StandardOp.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.StandardOp.*; +import com.oracle.max.graal.lir.cfg.*; /** * This class optimizes moves, particularly those that result from eliminating SSA form. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Interval.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Interval.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Interval.java Thu Feb 09 10:03:21 2012 +0100 @@ -22,15 +22,15 @@ */ package com.oracle.max.graal.compiler.alloc; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; import java.util.*; import com.oracle.max.cri.ci.*; import com.oracle.max.criutils.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.lir.*; /** * Represents an interval in the {@linkplain LinearScan linear scan register allocator}. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LIRInsertionBuffer.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LIRInsertionBuffer.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2009, 2011, 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.max.graal.compiler.alloc; - -import java.util.*; - -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; - -/** - * A buffer to enqueue updates to a list. This avoids frequent re-sizing of the list and copying of list elements - * when insertions are done at multiple positions of the list. Additionally, it ensures that the list is not modified - * while it is, e.g., iterated, and instead only modified once after the iteration is done. - *
- * The buffer uses internal data structures to store the enqueued updates. To avoid allocations, a buffer can be re-used. - * Call the methods in the following order: - * {@link #init()}, {@link #append()}, {@link #append()}, ..., {@link #finish()}, {@link #init()}, ... - *
- * Note: This class does not depend on LIRInstruction, so we could make it a generic utility class. - */ -public final class LIRInsertionBuffer { - - /** - * The lir list where ops of this buffer should be inserted later (null when uninitialized). - */ - private List lir; - - /** - * List of insertion points. index and count are stored alternately: - * indexAndCount[i * 2]: the index into lir list where "count" ops should be inserted - * indexAndCount[i * 2 + 1]: the number of ops to be inserted at index - */ - private final IntList indexAndCount; - - /** - * The LIROps to be inserted. - */ - private final List ops; - - - public LIRInsertionBuffer() { - indexAndCount = new IntList(8); - ops = new ArrayList<>(8); - } - - /** - * Initialize this buffer. This method must be called before using {@link #append()}. - */ - public void init(List newLir) { - assert !initialized() : "already initialized"; - assert indexAndCount.size() == 0 && ops.size() == 0; - this.lir = newLir; - } - - public boolean initialized() { - return lir != null; - } - - public List lirList() { - return lir; - } - - /** - * Enqueue a new instruction that will be appended to the instruction list when {@link #finish()} is called. - * The new instruction is added before the existing instruction with the given index. This method can only be called - * with increasing values of index, e.g., once an instruction was appended with index 4, subsequent instructions can - * only be appended with index 4 or higher. - */ - public void append(int index, LIRInstruction op) { - int i = numberOfInsertionPoints() - 1; - if (i < 0 || indexAt(i) < index) { - appendNew(index, 1); - } else { - assert indexAt(i) == index : "can append LIROps in ascending order only"; - assert countAt(i) > 0 : "check"; - setCountAt(i, countAt(i) + 1); - } - ops.add(op); - - assert verify(); - } - - /** - * Append all enqueued instructions to the instruction list. After that, {@link init()} can be called again to re-use this buffer. - */ - public void finish() { - if (ops.size() > 0) { - int n = lir.size(); - // increase size of instructions list - for (int i = 0; i < ops.size(); i++) { - lir.add(null); - } - // insert ops from buffer into instructions list - int opIndex = ops.size() - 1; - int ipIndex = numberOfInsertionPoints() - 1; - int fromIndex = n - 1; - int toIndex = lir.size() - 1; - while (ipIndex >= 0) { - int index = indexAt(ipIndex); - // make room after insertion point - while (fromIndex >= index) { - lir.set(toIndex--, lir.get(fromIndex--)); - } - // insert ops from buffer - for (int i = countAt(ipIndex); i > 0; i--) { - lir.set(toIndex--, ops.get(opIndex--)); - } - ipIndex--; - } - indexAndCount.clear(); - ops.clear(); - } - lir = null; - } - - private void appendNew(int index, int count) { - indexAndCount.add(index); - indexAndCount.add(count); - } - - private void setCountAt(int i, int value) { - indexAndCount.set((i << 1) + 1, value); - } - - private int numberOfInsertionPoints() { - assert indexAndCount.size() % 2 == 0 : "must have a count for each index"; - return indexAndCount.size() >> 1; - } - - private int indexAt(int i) { - return indexAndCount.get((i << 1)); - } - - private int countAt(int i) { - return indexAndCount.get((i << 1) + 1); - } - - private boolean verify() { - int sum = 0; - int prevIdx = -1; - - for (int i = 0; i < numberOfInsertionPoints(); i++) { - assert prevIdx < indexAt(i) : "index must be ordered ascending"; - sum += countAt(i); - } - assert sum == ops.size() : "wrong total sum"; - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Thu Feb 09 10:03:21 2012 +0100 @@ -24,7 +24,7 @@ import static com.oracle.max.cri.ci.CiUtil.*; import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; import java.util.*; @@ -35,16 +35,14 @@ import com.oracle.max.graal.compiler.alloc.Interval.RegisterBinding; import com.oracle.max.graal.compiler.alloc.Interval.RegisterPriority; import com.oracle.max.graal.compiler.alloc.Interval.SpillState; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.StandardOp.MoveOp; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.StandardOp.*; +import com.oracle.max.graal.lir.cfg.*; /** * An implementation of the linear scan register allocator algorithm described @@ -1589,7 +1587,7 @@ } default: { - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } } @@ -1902,14 +1900,6 @@ } void printLir(String label, @SuppressWarnings("unused") boolean hirValid) { - // TODO(tw): Fix printing. - if (GraalOptions.TraceLinearScanLevel >= 1 && !TTY.isSuppressed()) { - TTY.println(); - TTY.println(label); - LIR.printLIR(ir.linearScanOrder()); - TTY.println(); - } - Debug.dump(ir, label); } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java Thu Feb 09 10:03:21 2012 +0100 @@ -23,7 +23,7 @@ package com.oracle.max.graal.compiler.alloc; import static com.oracle.max.cri.ci.CiUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; +import static com.oracle.max.graal.alloc.util.LocationUtil.*; import java.util.*; @@ -35,10 +35,10 @@ import com.oracle.max.graal.compiler.alloc.Interval.RegisterPriority; import com.oracle.max.graal.compiler.alloc.Interval.SpillState; import com.oracle.max.graal.compiler.alloc.Interval.State; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.util.*; -import com.oracle.max.graal.compiler.lir.StandardOp.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.StandardOp.*; +import com.oracle.max.graal.lir.cfg.*; /** */ diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java Thu Feb 09 10:03:21 2012 +0100 @@ -29,7 +29,7 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.criutils.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.lir.*; +import com.oracle.max.graal.lir.*; /** */ diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java Thu Feb 09 10:03:21 2012 +0100 @@ -29,10 +29,10 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.criutils.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.*; import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; /** */ diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/ExceptionInfo.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/ExceptionInfo.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2009, 2011, 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.max.graal.compiler.asm; - -import com.oracle.max.graal.compiler.lir.*; - -public class ExceptionInfo { - - public final int codeOffset; - public final LabelRef exceptionEdge; - public final int bci; - - public ExceptionInfo(int pcOffset, LabelRef exceptionEdge, int bci) { - this.codeOffset = pcOffset; - this.exceptionEdge = exceptionEdge; - this.bci = bci; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/TargetMethodAssembler.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/asm/TargetMethodAssembler.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.asm; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIR.SlowPath; -import com.oracle.max.graal.compiler.util.*; -import com.oracle.max.graal.debug.*; - -public class TargetMethodAssembler { - - public final AbstractAssembler asm; - public final CiTargetMethod targetMethod; - public final CiTarget target; - public final RiRuntime runtime; - public final FrameMap frameMap; - public final List slowPaths; - - private List exceptionInfoList; - private int lastSafepointPos; - public TargetMethodAssembler(CiTarget target, RiRuntime runtime, FrameMap frameMap, List slowPaths, AbstractAssembler asm) { - this.target = target; - this.runtime = runtime; - this.frameMap = frameMap; - this.slowPaths = slowPaths; - this.asm = asm; - this.targetMethod = new CiTargetMethod(); - // 0 is a valid pc for safepoints in template methods - this.lastSafepointPos = -1; - } - - public void setFrameSize(int frameSize) { - targetMethod.setFrameSize(frameSize); - } - - public CiTargetMethod.Mark recordMark(Object id, CiTargetMethod.Mark[] references) { - return targetMethod.recordMark(asm.codeBuffer.position(), id, references); - } - - public void blockComment(String s) { - targetMethod.addAnnotation(new CiTargetMethod.CodeComment(asm.codeBuffer.position(), s)); - } - - public CiTargetMethod finishTargetMethod(Object name, boolean isStub) { - // Install code, data and frame size - targetMethod.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); - - // Record exception handlers if they exist - if (exceptionInfoList != null) { - for (ExceptionInfo ei : exceptionInfoList) { - int codeOffset = ei.codeOffset; - targetMethod.recordExceptionHandler(codeOffset, -1, 0, ei.exceptionEdge.label().position(), -1, null); - } - } - - Debug.metric("TargetMethods").increment(); - Debug.metric("CodeBytesEmitted").add(targetMethod.targetCodeSize()); - Debug.metric("SafepointsEmitted").add(targetMethod.safepoints.size()); - Debug.metric("DataPatches").add(targetMethod.dataReferences.size()); - Debug.metric("ExceptionHandlersEmitted").add(targetMethod.exceptionHandlers.size()); - - if (GraalOptions.PrintAssembly && !TTY.isSuppressed() && !isStub) { - Util.printSection("Target Method", Util.SECTION_CHARACTER); - TTY.println("Name: " + name); - TTY.println("Frame size: " + targetMethod.frameSize()); - TTY.println("Register size: " + asm.target.arch.registerReferenceMapBitCount); - - if (GraalOptions.PrintCodeBytes) { - Util.printSection("Code", Util.SUB_SECTION_CHARACTER); - TTY.println("Code: %d bytes", targetMethod.targetCodeSize()); - Util.printBytes(0L, targetMethod.targetCode(), 0, targetMethod.targetCodeSize(), GraalOptions.PrintAssemblyBytesPerLine); - } - - Util.printSection("Disassembly", Util.SUB_SECTION_CHARACTER); - String disassembly = runtime.disassemble(targetMethod); - TTY.println(disassembly); - boolean noDis = disassembly == null || disassembly.length() == 0; - - Util.printSection("Safepoints", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.Safepoint x : targetMethod.safepoints) { - TTY.println(x.toString()); - if (noDis && x.debugInfo != null) { - TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); - } - } - - Util.printSection("Data Patches", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.DataPatch x : targetMethod.dataReferences) { - TTY.println(x.toString()); - } - - Util.printSection("Marks", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.Mark x : targetMethod.marks) { - TTY.println(x.toString()); - } - - Util.printSection("Exception Handlers", Util.SUB_SECTION_CHARACTER); - for (CiTargetMethod.ExceptionHandler x : targetMethod.exceptionHandlers) { - TTY.println(x.toString()); - } - } - - return targetMethod; - } - - public void recordExceptionHandlers(int pcOffset, LIRDebugInfo info) { - if (info != null) { - if (info.exceptionEdge != null) { - if (exceptionInfoList == null) { - exceptionInfoList = new ArrayList<>(4); - } - exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionEdge, info.topFrame.bci)); - } - } - } - - public void recordImplicitException(int pcOffset, LIRDebugInfo info) { - // record an implicit exception point - if (info != null) { - assert lastSafepointPos < pcOffset : lastSafepointPos + "<" + pcOffset; - lastSafepointPos = pcOffset; - targetMethod.recordSafepoint(pcOffset, info.debugInfo()); - assert info.exceptionEdge == null; - } - } - - public void recordDirectCall(int posBefore, int posAfter, Object callTarget, LIRDebugInfo info) { - CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; - assert lastSafepointPos < posAfter; - lastSafepointPos = posAfter; - targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true); - } - - public void recordIndirectCall(int posBefore, int posAfter, Object callTarget, LIRDebugInfo info) { - CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; - assert lastSafepointPos < posAfter; - lastSafepointPos = posAfter; - targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false); - } - - public void recordSafepoint(int pos, LIRDebugInfo info) { - // safepoints always need debug info - CiDebugInfo debugInfo = info.debugInfo(); - assert lastSafepointPos < pos; - lastSafepointPos = pos; - targetMethod.recordSafepoint(pos, debugInfo); - } - - public CiAddress recordDataReferenceInCode(CiConstant data, int alignment) { - assert data != null; - int pos = asm.codeBuffer.position(); - Debug.log("Data reference in code: pos = %d, data = %s", pos, data.toString()); - targetMethod.recordDataReference(pos, data, alignment); - return CiAddress.Placeholder; - } - - public int lastSafepointPos() { - return lastSafepointPos; - } - - - /** - * Returns the integer value of any constants that can be represented by a 32-bit integer value, - * including long constants that fit into the 32-bit range. - */ - public int asIntConst(CiValue value) { - assert (value.kind.stackKind() == CiKind.Int || value.kind == CiKind.Jsr || value.kind == CiKind.Long) && isConstant(value); - long c = ((CiConstant) value).asLong(); - if (!(NumUtil.isInt(c))) { - throw Util.shouldNotReachHere(); - } - return (int) c; - } - - /** - * Returns the address of a float constant that is embedded as a data references into the code. - */ - public CiAddress asFloatConstRef(CiValue value) { - return asFloatConstRef(value, 4); - } - - public CiAddress asFloatConstRef(CiValue value, int alignment) { - assert value.kind == CiKind.Float && isConstant(value); - return recordDataReferenceInCode((CiConstant) value, alignment); - } - - /** - * Returns the address of a double constant that is embedded as a data references into the code. - */ - public CiAddress asDoubleConstRef(CiValue value) { - return asDoubleConstRef(value, 8); - } - - public CiAddress asDoubleConstRef(CiValue value, int alignment) { - assert value.kind == CiKind.Double && isConstant(value); - return recordDataReferenceInCode((CiConstant) value, alignment); - } - - /** - * Returns the address of a long constant that is embedded as a data references into the code. - */ - public CiAddress asLongConstRef(CiValue value) { - assert value.kind == CiKind.Long && isConstant(value); - return recordDataReferenceInCode((CiConstant) value, 8); - } - - public CiAddress asIntAddr(CiValue value) { - assert value.kind == CiKind.Int; - return asAddress(value); - } - - public CiAddress asLongAddr(CiValue value) { - assert value.kind == CiKind.Long; - return asAddress(value); - } - - public CiAddress asObjectAddr(CiValue value) { - assert value.kind == CiKind.Object; - return asAddress(value); - } - - public CiAddress asFloatAddr(CiValue value) { - assert value.kind == CiKind.Float; - return asAddress(value); - } - - public CiAddress asDoubleAddr(CiValue value) { - assert value.kind == CiKind.Double; - return asAddress(value); - } - - public CiAddress asAddress(CiValue value) { - if (isStackSlot(value)) { - CiStackSlot slot = (CiStackSlot) value; - return new CiAddress(slot.kind, frameMap.registerConfig.getFrameRegister().asValue(), frameMap.offsetForStackSlot(slot)); - } - return (CiAddress) value; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/Block.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/Block.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.cfg; - -import java.util.*; - -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.graph.*; -import com.oracle.max.graal.nodes.*; -import com.oracle.max.graal.nodes.java.*; - -public class Block { - protected int id; - - protected BeginNode beginNode; - protected Node endNode; - protected Loop loop; - protected double probability; - - protected List predecessors; - protected List successors; - - protected Block dominator; - protected List dominated; - protected Block postdominator; - - // Fields that still need to be worked on, try to remove them later. - public FrameState lastState; - public List lir; - public boolean align; - public int linearScanNumber; - public LIRPhiMapping phis; - - public Block() { - id = -1; - } - - public int getId() { - assert id >= 0; - return id; - } - - public BeginNode getBeginNode() { - return beginNode; - } - - public Node getEndNode() { - return endNode; - } - - public Loop getLoop() { - return loop; - } - - public int getLoopDepth() { - return loop == null ? 0 : loop.depth; - } - - public boolean isLoopHeader() { - return getBeginNode() instanceof LoopBeginNode; - } - - public boolean isLoopEnd() { - return getEndNode() instanceof LoopEndNode; - } - - public boolean isExceptionEntry() { - return getBeginNode().next() instanceof ExceptionObjectNode; - } - - public List getPredecessors() { - return predecessors; - } - - public List getSuccessors() { - return successors; - } - - public Block getDominator() { - return dominator; - } - - public List getDominated() { - if (dominated == null) { - return Collections.emptyList(); - } - return dominated; - } - - public Block getPostdominator() { - return postdominator; - } - - private class NodeIterator implements Iterator { - private Node cur; - - public NodeIterator() { - cur = getBeginNode(); - } - - @Override - public boolean hasNext() { - return cur != null; - } - - @Override - public Node next() { - Node result = cur; - if (cur == getEndNode()) { - cur = null; - } else { - cur = ((FixedWithNextNode) cur).next(); - } - assert !(cur instanceof BeginNode); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - public Iterable getNodes() { - return new Iterable() { - @Override - public Iterator iterator() { - return new NodeIterator(); - } - }; - } - - public int getFirstLirInstructionId() { - int result = lir.get(0).id(); - assert result >= 0; - return result; - } - - public int getLastLirInstructionId() { - int result = lir.get(lir.size() - 1).id(); - assert result >= 0; - return result; - } - - @Override - public String toString() { - return "B" + id; - } - - -// to be inlined later on - public int numberOfPreds() { - return getPredecessors().size(); - } - - public int numberOfSux() { - return getSuccessors().size(); - } - - public Block predAt(int i) { - return getPredecessors().get(i); - } - - public Block suxAt(int i) { - return getSuccessors().get(i); - } -// end to be inlined later on -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/BlockMap.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/BlockMap.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/* - * 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.max.graal.compiler.cfg; - -public class BlockMap { - private final T[] data; - - @SuppressWarnings("unchecked") - public BlockMap(ControlFlowGraph cfg) { - data = (T[]) new Object[cfg.getBlocks().length]; - } - - public T get(Block block) { - return data[block.getId()]; - } - - public void put(Block block, T value) { - data[block.getId()] = value; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/CFGVerifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/CFGVerifier.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * 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.max.graal.compiler.cfg; - -public class CFGVerifier { - public static boolean verify(ControlFlowGraph cfg) { - for (Block block : cfg.getBlocks()) { - assert cfg.getBlocks()[block.getId()] == block; - - for (Block pred : block.getPredecessors()) { - assert pred.getSuccessors().contains(block); - assert pred.getId() < block.getId() || pred.isLoopEnd(); - } - - for (Block sux : block.getSuccessors()) { - assert sux.getPredecessors().contains(block); - assert sux.getId() > block.getId() || sux.isLoopHeader(); - } - - if (block.getDominator() != null) { - assert block.getDominator().getId() < block.getId(); - assert block.getDominator().getDominated().contains(block); - } - for (Block dominated : block.getDominated()) { - assert dominated.getId() > block.getId(); - assert dominated.getDominator() == block; - } - - assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block; - } - - if (cfg.getLoops() != null) { - for (Loop loop : cfg.getLoops()) { - assert loop.header.isLoopHeader(); - - for (Block block : loop.blocks) { - assert block.getId() >= loop.header.getId(); - - Loop blockLoop = block.getLoop(); - while (blockLoop != loop) { - blockLoop = blockLoop.parent; - assert blockLoop != null; - } - } - - for (Block block : loop.exits) { - assert block.getId() >= loop.header.getId(); - - Loop blockLoop = block.getLoop(); - while (blockLoop != null) { - blockLoop = blockLoop.parent; - assert blockLoop != loop; - } - } - } - } - - return true; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/ControlFlowGraph.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/ControlFlowGraph.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.cfg; - -import java.util.*; - -import com.oracle.max.graal.graph.*; -import com.oracle.max.graal.nodes.*; - -public class ControlFlowGraph { - - public final StructuredGraph graph; - - private final NodeMap nodeToBlock; - private Block[] reversePostOrder; - private Loop[] loops; - - public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { - ControlFlowGraph cfg = new ControlFlowGraph(graph); - cfg.identifyBlocks(); - if (connectBlocks || computeLoops || computeDominators || computePostdominators) { - cfg.connectBlocks(); - } - if (computeLoops) { - cfg.computeLoopInformation(); - } - if (computeDominators) { - cfg.computeDominators(); - } - if (computePostdominators) { - cfg.computePostdominators(); - } - assert CFGVerifier.verify(cfg); - return cfg; - } - - protected ControlFlowGraph(StructuredGraph graph) { - this.graph = graph; - this.nodeToBlock = graph.createNodeMap(); - } - - public Block[] getBlocks() { - return reversePostOrder; - } - - public Block getStartBlock() { - return reversePostOrder[0]; - } - - public NodeMap getNodeToBlock() { - return nodeToBlock; - } - - public Block blockFor(Node node) { - return nodeToBlock.get(node); - } - - public Loop[] getLoops() { - return loops; - } - - private void identifyBlocks() { - // Find all block headers - int numBlocks = 0; - for (Node node : graph.getNodes()) { - if (node instanceof BeginNode) { - Block block = new Block(); - numBlocks++; - - block.beginNode = (BeginNode) node; - Node cur = node; - do { - assert !cur.isDeleted(); - block.endNode = cur; - - assert nodeToBlock.get(cur) == null; - nodeToBlock.set(cur, block); - if (cur instanceof MergeNode) { - for (PhiNode phi : ((MergeNode) cur).phis()) { - nodeToBlock.set(phi, block); - } - } - - if (cur instanceof FixedNode) { - double probability = ((FixedNode) cur).probability(); - if (probability > block.probability) { - block.probability = probability; - } - } - - Node next = null; - for (Node sux : cur.successors()) { - if (sux != null && !(sux instanceof BeginNode)) { - assert next == null; - next = sux; - } - } - cur = next; - } while (cur != null); - } - } - - // Compute reverse postorder. - reversePostOrder = new Block[numBlocks]; - int reversePostOrderId = numBlocks - 1; - - ArrayList stack = new ArrayList<>(); - stack.add(blockFor(graph.start())); - - do { - Block block = stack.get(stack.size() - 1); - if (block.id == -1) { - // First time we see this block: push all successors. - for (Node suxNode : block.getEndNode().cfgSuccessors()) { - Block suxBlock = blockFor(suxNode); - if (suxBlock.id < 0) { - stack.add(suxBlock); - } - } - block.id = -2; - } else { - // Second time we see this block: All successors haved been processed, so insert block into reverse postorder list. - assert block.id == -2; - stack.remove(stack.size() - 1); - block.id = reversePostOrderId; - reversePostOrder[reversePostOrderId] = block; - reversePostOrderId--; - } - } while (!stack.isEmpty()); - assert reversePostOrderId == -1; - } - - // Connect blocks (including loop backward edges). - private void connectBlocks() { - for (Block block : reversePostOrder) { - List predecessors = new ArrayList<>(); - for (Node predNode : block.getBeginNode().cfgPredecessors()) { - predecessors.add(nodeToBlock.get(predNode)); - } - if (block.getBeginNode() instanceof LoopBeginNode) { - predecessors.add(nodeToBlock.get(((LoopBeginNode) block.getBeginNode()).loopEnd())); - } - block.predecessors = predecessors; - - List successors = new ArrayList<>(); - for (Node suxNode : block.getEndNode().cfgSuccessors()) { - successors.add(nodeToBlock.get(suxNode)); - } - if (block.getEndNode() instanceof LoopEndNode) { - successors.add(nodeToBlock.get(((LoopEndNode) block.getEndNode()).loopBegin())); - } - block.successors = successors; - } - } - - private void computeLoopInformation() { - List loopsList = 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); - - LoopEndNode end = ((LoopBeginNode) beginNode).loopEnd(); - Block endBlock = nodeToBlock.get(end); - computeLoopBlocks(endBlock, loop); - } - } - loops = loopsList.toArray(new Loop[loopsList.size()]); - - for (Loop loop : loops) { - for (Block block : loop.blocks) { - for (Block sux : block.getSuccessors()) { - if (sux.getLoopDepth() < loop.depth) { - loop.exits.add(sux); - } - } - } - } - } - - private void computeLoopBlocks(Block block, Loop loop) { - if (block.getLoop() == loop) { - return; - } - assert block.loop == loop.parent; - block.loop = loop; - - assert !loop.blocks.contains(block); - loop.blocks.add(block); - - if (block != loop.header) { - for (Block pred : block.getPredecessors()) { - computeLoopBlocks(pred, loop); - } - } - } - - private void computeDominators() { - assert reversePostOrder[0].getPredecessors().size() == 0 : "start block has no predecessor and therefore no dominator"; - for (int i = 1; i < reversePostOrder.length; i++) { - Block block = reversePostOrder[i]; - List predecessors = block.getPredecessors(); - assert predecessors.size() > 0; - - if (block.isLoopHeader()) { - // Loop headers have exactly one non-loop predecessor, and that is the dominator. - setDominator(block, predecessors.get(0)); - continue; - } - - Block dominator = predecessors.get(0); - for (int j = 1; j < predecessors.size(); j++) { - Block pred = predecessors.get(j); - dominator = commonDominator(dominator, pred); - } - setDominator(block, dominator); - } - } - - private static void setDominator(Block block, Block dominator) { - block.dominator = dominator; - if (dominator.dominated == null) { - dominator.dominated = new ArrayList<>(); - } - dominator.dominated.add(block); - } - - public static Block commonDominator(Block a, Block b) { - Block iterA = a; - Block iterB = b; - while (iterA != iterB) { - if (iterA.getId() > iterB.getId()) { - iterA = iterA.getDominator(); - } else { - assert iterB.getId() > iterA.getId(); - iterB = iterB.getDominator(); - } - } - return iterA; - } - - private void computePostdominators() { - for (Block block : reversePostOrder) { - if (block.isLoopEnd()) { - // We do not want the loop header registered as the postdominator of the loop end. - continue; - } - Block postdominator = null; - for (Block sux : block.getSuccessors()) { - if (sux.isExceptionEntry()) { - // We ignore exception handlers. - } else if (postdominator == null) { - postdominator = sux; - } else { - postdominator = commonPostdominator(postdominator, sux); - } - } - block.postdominator = postdominator; - } - } - - private static Block commonPostdominator(Block a, Block b) { - Block iterA = a; - Block iterB = b; - while (iterA != iterB) { - if (iterA.getId() < iterB.getId()) { - iterA = iterA.getPostdominator(); - if (iterA == null) { - return null; - } - } else { - assert iterB.getId() < iterA.getId(); - iterB = iterB.getPostdominator(); - if (iterB == null) { - return null; - } - } - } - return iterA; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/Loop.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/Loop.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * 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.max.graal.compiler.cfg; - -import java.util.*; - -public class Loop { - 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; - - protected Loop(Loop parent, int index, Block header) { - this.parent = parent; - if (parent != null) { - this.depth = parent.depth + 1; - parent.children.add(this); - } else { - this.depth = 1; - } - this.index = index; - this.header = header; - this.blocks = new ArrayList<>(); - this.children = new ArrayList<>(); - this.exits = new ArrayList<>(); - } - - @Override - public String toString() { - return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : ""); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Thu Feb 09 10:03:21 2012 +0100 @@ -27,8 +27,8 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.graal.compiler.gen.LIRGenerator.LockScope; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.virtual.*; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Thu Feb 09 10:03:21 2012 +0100 @@ -26,7 +26,7 @@ import static com.oracle.max.cri.ci.CiValue.*; import static com.oracle.max.cri.ci.CiValueUtil.*; import static com.oracle.max.cri.util.MemoryBarriers.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; +import static com.oracle.max.graal.lir.ValueUtil.*; import java.lang.reflect.*; import java.util.*; @@ -46,12 +46,12 @@ import com.oracle.max.cri.xir.*; import com.oracle.max.criutils.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.StandardOp.ParametersOp; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.StandardOp.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.max.graal.nodes.PhiNode.PhiType; @@ -130,7 +130,9 @@ /** * Mapping from blocks to the lock state at the end of the block, indexed by the id number of the block. */ - private LockScope[] blockLocks; + private BlockMap blockLocks; + + private BlockMap blockLastState; /** * The list of currently locked monitors. @@ -149,7 +151,8 @@ this.xir = xir; this.xirSupport = new XirSupport(); this.debugInfoBuilder = new DebugInfoBuilder(nodeOperands); - this.blockLocks = new LockScope[lir.linearScanOrder().size()]; + this.blockLocks = new BlockMap<>(lir.cfg); + this.blockLastState = new BlockMap<>(lir.cfg); } @Override @@ -157,14 +160,6 @@ return target; } - private LockScope locksFor(Block block) { - return blockLocks[block.getId()]; - } - - private void setLocksFor(Block block, LockScope locks) { - blockLocks[block.getId()] = locks; - } - /** * Returns the operand that has been previously initialized by {@link #setResult()} * with the result of an instruction. @@ -196,7 +191,7 @@ case Double: return new Variable(stackKind, lir.nextVariable(), CiRegister.RegisterFlag.FPU); default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } @@ -300,7 +295,21 @@ assert block.lir == null : "LIR list already computed for this block"; block.lir = new ArrayList<>(); - emitLabel(new Label(), block.align); + if (GraalOptions.AllocSSA && block.getBeginNode() instanceof MergeNode) { + assert phiValues.isEmpty(); + MergeNode merge = (MergeNode) block.getBeginNode(); + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value) { + CiValue phiValue = newVariable(phi.kind()); + setResult(phi, phiValue); + phiValues.add(phiValue); + } + } + append(new PhiLabelOp(new Label(), block.align, phiValues.toArray(new CiValue[phiValues.size()]))); + phiValues.clear(); + } else { + append(new LabelOp(new Label(), block.align)); + } if (GraalOptions.TraceLIRGeneratorLevel >= 1) { TTY.println("BEGIN Generating LIR for block B" + block.getId()); @@ -308,7 +317,7 @@ curLocks = null; for (Block pred : block.getPredecessors()) { - LockScope predLocks = locksFor(pred); + LockScope predLocks = blockLocks.get(pred); if (curLocks == null) { curLocks = predLocks; } else if (curLocks != predLocks && (!pred.isLoopEnd() || predLocks != null)) { @@ -326,8 +335,8 @@ for (Block pred : block.getPredecessors()) { if (fs == null) { - fs = pred.lastState; - } else if (fs != pred.lastState) { + fs = blockLastState.get(pred); + } else if (fs != blockLastState.get(pred)) { fs = null; break; } @@ -345,10 +354,6 @@ lastState = fs; } - if (GraalOptions.AllocSSA && block.getBeginNode() instanceof MergeNode) { - block.phis = new LIRPhiMapping(block, this); - } - List nodes = lir.nodesFor(block); for (int i = 0; i < nodes.size(); i++) { Node instr = nodes.get(i); @@ -406,8 +411,8 @@ TTY.println("END Generating LIR for block B" + block.getId()); } - setLocksFor(currentBlock, curLocks); - block.lastState = lastState; + blockLocks.put(currentBlock, curLocks); + blockLastState.put(block, lastState); currentBlock = null; if (GraalOptions.PrintIRWithLIR) { @@ -665,27 +670,65 @@ @Override public void visitMerge(MergeNode x) { - if (x.next() instanceof LoopBeginNode) { - moveToPhi((LoopBeginNode) x.next(), x); - } } @Override public void visitEndNode(EndNode end) { - assert end.merge() != null; moveToPhi(end.merge(), end); - emitJump(getLIRBlock(end.merge()), null); } @Override public void visitLoopEnd(LoopEndNode x) { - moveToPhi(x.loopBegin(), x); if (GraalOptions.GenLoopSafepoints && x.hasSafepointPolling()) { emitSafepointPoll(x); } - emitJump(getLIRBlock(x.loopBegin()), null); + moveToPhi(x.loopBegin(), x); } + private ArrayList phiValues = new ArrayList<>(); + + private void moveToPhi(MergeNode merge, FixedNode pred) { + if (GraalOptions.AllocSSA) { + assert phiValues.isEmpty(); + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value) { + phiValues.add(operand(phi.valueAt(pred))); + } + } + append(new PhiJumpOp(getLIRBlock(merge), phiValues.toArray(new CiValue[phiValues.size()]))); + phiValues.clear(); + return; + } + + if (GraalOptions.TraceLIRGeneratorLevel >= 1) { + TTY.println("MOVE TO PHI from " + pred + " to " + merge); + } + PhiResolver resolver = new PhiResolver(this); + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value) { + ValueNode curVal = phi.valueAt(pred); + resolver.move(operand(curVal), operandForPhi(phi)); + } + } + resolver.dispose(); + + append(new JumpOp(getLIRBlock(merge), null)); + } + + private CiValue operandForPhi(PhiNode phi) { + assert phi.type() == PhiType.Value : "wrong phi type: " + phi; + CiValue result = operand(phi); + if (result == null) { + // allocate a variable for this phi + Variable newOperand = newVariable(phi.kind()); + setResult(phi, newOperand); + return newOperand; + } else { + return result; + } + } + + public void emitSafepointPoll(FixedNode x) { if (!lastState.method().noSafepointPolls()) { XirSnippet snippet = xir.genSafepointPoll(site(x)); @@ -727,7 +770,7 @@ } else if (node instanceof IsTypeNode) { emitTypeBranch((IsTypeNode) node, trueSuccessor, falseSuccessor, info); } else { - throw Util.unimplemented(node.toString()); + throw GraalInternalError.unimplemented(node.toString()); } } @@ -789,7 +832,7 @@ } else if (node instanceof ConstantNode) { return emitConstantConditional(((ConstantNode) node).asConstant().asBoolean(), trueValue, falseValue); } else { - throw Util.unimplemented(node.toString()); + throw GraalInternalError.unimplemented(node.toString()); } } @@ -921,7 +964,7 @@ } else if (isStackSlot(value)) { return CiStackSlot.get(value.kind.stackKind(), asStackSlot(value).rawOffset(), asStackSlot(value).rawAddFrameSize()); } else { - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } return value; @@ -945,7 +988,7 @@ argList.add(operand); } else { - throw Util.shouldNotReachHere("I thought we no longer have null entries for two-slot types..."); + throw GraalInternalError.shouldNotReachHere("I thought we no longer have null entries for two-slot types..."); } } return argList; @@ -1127,40 +1170,6 @@ } - - private void moveToPhi(MergeNode merge, FixedNode pred) { - if (GraalOptions.AllocSSA) { - return; - } - - if (GraalOptions.TraceLIRGeneratorLevel >= 1) { - TTY.println("MOVE TO PHI from " + pred + " to " + merge); - } - PhiResolver resolver = new PhiResolver(this); - for (PhiNode phi : merge.phis()) { - if (phi.type() == PhiType.Value) { - ValueNode curVal = phi.valueAt(pred); - resolver.move(operand(curVal), operandForPhi(phi)); - } - } - resolver.dispose(); - } - - private CiValue operandForPhi(PhiNode phi) { - assert phi.type() == PhiType.Value : "wrong phi type: " + phi; - CiValue result = operand(phi); - if (result == null) { - // allocate a variable for this phi - Variable newOperand = newVariable(phi.kind()); - setResult(phi, newOperand); - return newOperand; - } else { - return result; - } - } - - - protected XirArgument toXirArgument(CiValue v) { if (v == null) { return null; @@ -1185,7 +1194,7 @@ } else if (op instanceof XirTemp) { return newVariable(op.kind); } else { - Util.shouldNotReachHere(); + GraalInternalError.shouldNotReachHere(); return null; } } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiResolver.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiResolver.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiResolver.java Thu Feb 09 10:03:21 2012 +0100 @@ -23,7 +23,7 @@ package com.oracle.max.graal.compiler.gen; import static com.oracle.max.cri.ci.CiValue.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; +import static com.oracle.max.graal.lir.ValueUtil.*; import java.util.*; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/FrameMap.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/FrameMap.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,344 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.lir; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ci.CiCallingConvention.Type; -import com.oracle.max.cri.ri.*; -import com.oracle.max.graal.compiler.util.*; - -/** - * This class is used to build the stack frame layout for a compiled method. - * A {@link CiStackSlot} is used to index slots of the frame relative to the stack pointer. - * The frame size is only fixed after register allocation when all spill slots have - * been allocated. Both the outgoing argument area and the spill are can grow until then. - * Therefore, outgoing arguments are indexed from the stack pointer, while spill slots - * are indexed from the beginning of the frame (and the total frame size has to be added - * to get the actual offset from the stack pointer). - *
- * This is the format of a stack frame: - *
- *   Base       Contents
- *
- *            :                                :  -----
- *   caller   | incoming overflow argument n   |    ^
- *   frame    :     ...                        :    | positive
- *            | incoming overflow argument 0   |    | offsets
- *   ---------+--------------------------------+---------------------
- *            | return address                 |    |            ^
- *   current  +--------------------------------+    |            |    -----
- *   frame    |                                |    |            |      ^
- *            : callee save area               :    |            |      |
- *            |                                |    |            |      |
- *            +--------------------------------+    |            |      |
- *            | spill slot 0                   |    | negative   |      |
- *            :     ...                        :    v offsets    |      |
- *            | spill slot n                   |  -----        total  frame
- *            +--------------------------------+               frame  size
- *            | alignment padding              |               size     |
- *            +--------------------------------+  -----          |      |
- *            | outgoing overflow argument n   |    ^            |      |
- *            :     ...                        :    | positive   |      |
- *            | outgoing overflow argument 0   |    | offsets    v      v
- *    %sp-->  +--------------------------------+---------------------------
- *
- * 
- * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size - * of such a block may be greater than the size of a normal spill slot or the word size. - *
- * A runtime has two ways to reserve space in the stack frame for its own use:
    - *
  • A memory block somewhere in the frame of size {@link RiRuntime#getCustomStackAreaSize()}. The offset - * to this block is returned in {@link CiTargetMethod#customStackAreaOffset()}. - *
  • At the beginning of the overflow argument area: The calling convention can specify that the first - * overflow stack argument is not at offset 0, but at a specified offset o. Use - * {@link RiRuntime#getMinimumOutgoingSize()} to make sure that call-free methods also have this space - * reserved. Then the VM can use memory the memory at offset 0 relative to the stack pointer. - *
- */ -public final class FrameMap { - public final RiRuntime runtime; - public final CiTarget target; - public final RiRegisterConfig registerConfig; - - /** - * The final frame size, not including the size of the return address. - * The value is only set after register allocation is complete, i.e., after all spill slots have been allocated. - */ - private int frameSize; - - /** - * Size of the area occupied by spill slots and other stack-allocated memory blocks. - */ - private int spillSize; - - /** - * Size of the area occupied by outgoing overflow arguments. - * This value is adjusted as calling conventions for outgoing calls are retrieved. - */ - private int outgoingSize; - - /** - * The list of stack areas allocated in this frame that are present in every reference map. - */ - private final List objectStackBlocks; - - /** - * The stack area reserved for use by the VM, or {@code null} if the VM does not request stack space. - */ - private final CiStackSlot customArea; - - /** - * Creates a new frame map for the specified method. - */ - public FrameMap(RiRuntime runtime, CiTarget target, RiRegisterConfig registerConfig) { - this.runtime = runtime; - this.target = target; - this.registerConfig = registerConfig; - this.frameSize = -1; - this.spillSize = returnAddressSize() + calleeSaveAreaSize(); - this.outgoingSize = runtime.getMinimumOutgoingSize(); - this.objectStackBlocks = new ArrayList<>(); - this.customArea = allocateStackBlock(runtime.getCustomStackAreaSize(), false); - } - - - private int returnAddressSize() { - return target.arch.returnAddressSize; - } - - private int calleeSaveAreaSize() { - CiCalleeSaveLayout csl = registerConfig.getCalleeSaveLayout(); - return csl != null ? csl.size : 0; - } - - /** - * Gets the frame size of the compiled frame, not including the size of the return address. - * @return The size of the frame (in bytes). - */ - public int frameSize() { - assert frameSize != -1 : "frame size not computed yet"; - return frameSize; - } - - /** - * Gets the total frame size of the compiled frame, including the size of the return address. - * @return The total size of the frame (in bytes). - */ - public int totalFrameSize() { - return frameSize() + returnAddressSize(); - } - - /** - * Sets the frame size for this frame. - * @param frameSize The frame size (in bytes). - */ - public void setFrameSize(int frameSize) { - assert this.frameSize == -1 : "must only be set once"; - this.frameSize = frameSize; - } - - /** - * Computes the frame size for this frame. After this method has been called, methods that change the - * frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can be requested. - */ - public void finish() { - setFrameSize(target.alignFrameSize(outgoingSize + spillSize - returnAddressSize())); - } - - /** - * Computes the offset of a stack slot relative to the frame register. - * This is also the bit index of stack slots in the reference map. - * - * @param slot a stack slot - * @return the offset of the stack slot - */ - public int offsetForStackSlot(CiStackSlot slot) { - assert (!slot.rawAddFrameSize() && slot.rawOffset() < outgoingSize) || - (slot.rawAddFrameSize() && slot.rawOffset() < 0 && -slot.rawOffset() <= spillSize) || - (slot.rawAddFrameSize() && slot.rawOffset() >= 0); - return slot.offset(totalFrameSize()); - } - - /** - * Gets the offset to the stack area where callee-saved registers are stored. - * @return The offset to the callee save area (in bytes). - */ - public int offsetToCalleeSaveArea() { - return frameSize() - calleeSaveAreaSize(); - } - - /** - * Gets the offset of the stack area stack block reserved for use by the VM, or -1 if the VM does not request stack space. - * @return The offset to the custom area (in bytes). - */ - public int offsetToCustomArea() { - return customArea == null ? -1 : offsetForStackSlot(customArea); - } - - /** - * Informs the frame map that the compiled code calls a particular method, which - * may need stack space for outgoing arguments. - * @param cc The calling convention for the called method. - * @param type The type of calling convention. - */ - public void callsMethod(CiCallingConvention cc, Type type) { - // TODO look at the actual stack offsets? - assert type.out; - reserveOutgoing(cc.stackSize); - } - - /** - * Reserves space for stack-based outgoing arguments. - * @param argsSize The amount of space (in bytes) to reserve for stack-based outgoing arguments. - */ - public void reserveOutgoing(int argsSize) { - assert frameSize == -1 : "frame size must not yet be fixed"; - outgoingSize = Math.max(outgoingSize, argsSize); - } - - private CiStackSlot getSlot(CiKind kind, int additionalOffset) { - return CiStackSlot.get(kind, -spillSize + additionalOffset, true); - } - - /** - * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned on its natural alignment, - * i.e., an 8-byte spill slot is aligned at an 8-byte boundary. - * @param kind The kind of the spill slot to be reserved. - * @return A spill slot denoting the reserved memory area. - */ - public CiStackSlot allocateSpillSlot(CiKind kind) { - assert frameSize == -1 : "frame size must not yet be fixed"; - int size = target.sizeInBytes(kind); - spillSize = Util.roundUp(spillSize + size, size); - return getSlot(kind, 0); - } - - /** - * Reserves a block of memory in the frame of the method being compiled. The returned block is aligned on a word boundary. - * If the requested size is 0, the method returns {@code null}. - * - * @param size The size to reserve (in bytes). - * @param refs Specifies if the block is all references. If true, the block will be in all reference maps for this method. - * The caller is responsible to initialize the memory block before the first instruction that uses a reference map. - * @return A stack slot describing the begin of the memory block. - */ - public CiStackSlot allocateStackBlock(int size, boolean refs) { - assert frameSize == -1 : "frame size must not yet be fixed"; - if (size == 0) { - return null; - } - spillSize = Util.roundUp(spillSize + size, target.wordSize); - - if (refs) { - assert size % target.wordSize == 0; - CiStackSlot result = getSlot(CiKind.Object, 0); - objectStackBlocks.add(result); - for (int i = target.wordSize; i < size; i += target.wordSize) { - objectStackBlocks.add(getSlot(CiKind.Object, i)); - } - return result; - - } else { - return getSlot(target.wordKind, 0); - } - } - - - private int frameRefMapIndex(CiStackSlot slot) { - assert offsetForStackSlot(slot) % target.wordSize == 0; - return offsetForStackSlot(slot) / target.wordSize; - } - - /** - * Initializes a reference map that covers all registers of the target architecture. - */ - public CiBitMap initRegisterRefMap() { - return new CiBitMap(target.arch.registerReferenceMapBitCount); - } - - /** - * Initializes a reference map. Initially, the size is large enough to cover all the - * slots in the frame. If the method has incoming reference arguments on the stack, - * the reference map might grow later when such a reference is set. - */ - public CiBitMap initFrameRefMap() { - CiBitMap frameRefMap = new CiBitMap(frameSize() / target.wordSize); - for (CiStackSlot slot : objectStackBlocks) { - setReference(slot, null, frameRefMap); - } - return frameRefMap; - } - - /** - * Marks the specified location as a reference in the reference map of the debug information. - * The tracked location can be a {@link CiRegisterValue} or a {@link CiStackSlot}. Note that a - * {@link CiConstant} is automatically tracked. - * - * @param location The location to be added to the reference map. - * @param registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}. - * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}. - */ - public void setReference(CiValue location, CiBitMap registerRefMap, CiBitMap frameRefMap) { - if (location.kind == CiKind.Object) { - if (isRegister(location)) { - assert registerRefMap.size() == target.arch.registerReferenceMapBitCount; - registerRefMap.set(asRegister(location).number); - } else if (isStackSlot(location)) { - int index = frameRefMapIndex(asStackSlot(location)); - frameRefMap.grow(index + 1); - frameRefMap.set(index); - } else { - assert isConstant(location); - } - } - } - - /** - * Clears the specified location as a reference in the reference map of the debug information. - * The tracked location can be a {@link CiRegisterValue} or a {@link CiStackSlot}. Note that a - * {@link CiConstant} is automatically tracked. - * - * @param location The location to be removed from the reference map. - * @param registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}. - * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}. - */ - public void clearReference(CiValue location, CiBitMap registerRefMap, CiBitMap frameRefMap) { - if (location.kind == CiKind.Object) { - if (location instanceof CiRegisterValue) { - assert registerRefMap.size() == target.arch.registerReferenceMapBitCount; - registerRefMap.clear(asRegister(location).number); - } else if (isStackSlot(location)) { - int index = frameRefMapIndex(asStackSlot(location)); - if (index < frameRefMap.size()) { - frameRefMap.clear(index); - } - } else { - assert isConstant(location); - } - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIR.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIR.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.lir; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.util.*; -import com.oracle.max.graal.graph.*; - -/** - * This class implements the overall container for the LIR graph - * and directs its construction, optimization, and finalization. - */ -public class LIR { - - public final ControlFlowGraph cfg; - - /** - * The nodes for the blocks. - * TODO: This should go away, we want all nodes connected with a next-pointer. - */ - private final BlockMap> nodesFor; - - /** - * The linear-scan ordered list of blocks. - */ - private final List linearScanOrder; - - /** - * The order in which the code is emitted. - */ - private final List codeEmittingOrder; - - - public final List slowPaths; - - public final List deoptimizationStubs; - - /** - * The last slow path emitted, which can be used emit marker bytes. - */ - public SlowPath methodEndMarker; - - private int numVariables; - - public SpillMoveFactory spillMoveFactory; - - public interface SpillMoveFactory { - LIRInstruction createMove(CiValue result, CiValue input); - LIRInstruction createExchange(CiValue input1, CiValue input2); - } - - public interface SlowPath { - void emitCode(TargetMethodAssembler tasm); - } - - /** - * Creates a new LIR instance for the specified compilation. - * @param numLoops number of loops - * @param compilation the compilation - */ - public LIR(ControlFlowGraph cfg, BlockMap> nodesFor, List linearScanOrder, List codeEmittingOrder) { - this.cfg = cfg; - this.nodesFor = nodesFor; - this.codeEmittingOrder = codeEmittingOrder; - this.linearScanOrder = linearScanOrder; - - slowPaths = new ArrayList<>(); - deoptimizationStubs = new ArrayList<>(); - } - - public List nodesFor(Block block) { - return nodesFor.get(block); - } - - /** - * Gets the linear scan ordering of blocks as a list. - * @return the blocks in linear scan order - */ - public List linearScanOrder() { - return linearScanOrder; - } - - public List codeEmittingOrder() { - return codeEmittingOrder; - } - - public int numVariables() { - return numVariables; - } - - public int nextVariable() { - return numVariables++; - } - - public void emitCode(TargetMethodAssembler tasm) { - if (GraalOptions.PrintLIR && !TTY.isSuppressed()) { - printLIR(codeEmittingOrder()); - } - - for (Block b : codeEmittingOrder()) { - emitBlock(tasm, b); - } - - // generate code for slow cases - for (SlowPath sp : slowPaths) { - emitSlowPath(tasm, sp); - } - // generate deoptimization stubs - for (SlowPath sp : deoptimizationStubs) { - emitSlowPath(tasm, sp); - } - // generate traps at the end of the method - emitSlowPath(tasm, methodEndMarker); - } - - private void emitBlock(TargetMethodAssembler tasm, Block block) { - if (GraalOptions.PrintLIRWithAssembly) { - TTY.println(block.toString()); - } - - if (GraalOptions.CommentedAssembly) { - tasm.blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); - } - - for (LIRInstruction op : block.lir) { - if (GraalOptions.CommentedAssembly) { - tasm.blockComment(String.format("%d %s", op.id(), op)); - } - if (GraalOptions.PrintLIRWithAssembly && !TTY.isSuppressed()) { - // print out the LIR operation followed by the resulting assembly - TTY.println(op.toStringWithIdPrefix()); - TTY.println(); - } - - emitOp(tasm, op); - - if (GraalOptions.PrintLIRWithAssembly) { - printAssembly(tasm); - } - } - } - - private static void emitOp(TargetMethodAssembler tasm, LIRInstruction op) { - try { - try { - op.emitCode(tasm); - } catch (AssertionError t) { - throw new GraalInternalError(t); - } catch (RuntimeException t) { - throw new GraalInternalError(t); - } - } catch (GraalInternalError e) { - throw e.addContext("lir instruction", op); - } - } - - private static void emitSlowPath(TargetMethodAssembler tasm, SlowPath sp) { - if (GraalOptions.CommentedAssembly) { - tasm.blockComment(String.format("slow case %s", sp.getClass().getName())); - } - sp.emitCode(tasm); - } - - private int lastDecodeStart; - - private void printAssembly(TargetMethodAssembler tasm) { - byte[] currentBytes = tasm.asm.codeBuffer.copyData(lastDecodeStart, tasm.asm.codeBuffer.position()); - if (currentBytes.length > 0) { - String disasm = tasm.runtime.disassemble(currentBytes, lastDecodeStart); - if (disasm.length() != 0) { - TTY.println(disasm); - } else { - TTY.println("Code [+%d]: %d bytes", lastDecodeStart, currentBytes.length); - Util.printBytes(lastDecodeStart, currentBytes, GraalOptions.PrintAssemblyBytesPerLine); - } - } - lastDecodeStart = tasm.asm.codeBuffer.position(); - } - - - public static void printBlock(Block x) { - // print block id - TTY.print("B%d ", x.getId()); - - // print flags - if (x.isLoopHeader()) { - TTY.print("lh "); - } - if (x.isLoopEnd()) { - TTY.print("le "); - } - - // print block bci range - TTY.print("[%d, %d] ", -1, -1); - - // print predecessors and successors - if (x.numberOfPreds() > 0) { - TTY.print("preds: "); - for (int i = 0; i < x.numberOfPreds(); i++) { - TTY.print("B%d ", x.predAt(i).getId()); - } - } - - if (x.numberOfSux() > 0) { - TTY.print("sux: "); - for (int i = 0; i < x.numberOfSux(); i++) { - TTY.print("B%d ", x.suxAt(i).getId()); - } - } - - TTY.println(); - } - - public static void printLIR(List blocks) { - if (TTY.isSuppressed()) { - return; - } - TTY.println("LIR:"); - int i; - for (i = 0; i < blocks.size(); i++) { - Block bb = blocks.get(i); - printBlock(bb); - TTY.println("__id_Instruction___________________________________________"); - for (LIRInstruction op : bb.lir) { - TTY.println(op.toStringWithIdPrefix()); - TTY.println(); - } - TTY.println(); - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRDebugInfo.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRDebugInfo.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.lir; - -import static com.oracle.max.graal.compiler.lir.LIRInstruction.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; - -/** - * This class represents garbage collection and deoptimization information attached to a LIR instruction. - */ -public class LIRDebugInfo { - public final CiFrame topFrame; - private final CiVirtualObject[] virtualObjects; - private final List pointerSlots; - public final LabelRef exceptionEdge; - private CiDebugInfo debugInfo; - - public LIRDebugInfo(CiFrame topFrame, CiVirtualObject[] virtualObjects, List pointerSlots, LabelRef exceptionEdge) { - this.topFrame = topFrame; - this.virtualObjects = virtualObjects; - this.pointerSlots = pointerSlots; - this.exceptionEdge = exceptionEdge; - } - - public boolean hasDebugInfo() { - return debugInfo != null; - } - - public CiDebugInfo debugInfo() { - assert debugInfo != null : "debug info not allocated yet"; - return debugInfo; - } - - /** - * Iterates the frame state and calls the {@link ValueProcedure} for every variable. - * - * @param proc The procedure called for variables. - */ - public void forEachState(ValueProcedure proc) { - for (CiFrame cur = topFrame; cur != null; cur = cur.caller()) { - processValues(cur.values, proc); - } - if (virtualObjects != null) { - for (CiVirtualObject obj : virtualObjects) { - processValues(obj.values(), proc); - } - } - } - - /** - * We filter out constant and illegal values ourself before calling the procedure, so {@link OperandFlag#Constant} and {@link OperandFlag#Illegal} need not be set. - */ - private static final EnumSet STATE_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - - private void processValues(CiValue[] values, ValueProcedure proc) { - for (int i = 0; i < values.length; i++) { - CiValue value = values[i]; - if (value instanceof CiMonitorValue) { - CiMonitorValue monitor = (CiMonitorValue) value; - if (processed(monitor.owner)) { - monitor.owner = proc.doValue(monitor.owner, OperandMode.Alive, STATE_FLAGS); - } - - } else if (processed(value)) { - values[i] = proc.doValue(value, OperandMode.Alive, STATE_FLAGS); - } - } - } - - private boolean processed(CiValue value) { - if (isIllegal(value)) { - // Ignore dead local variables. - return false; - } else if (isConstant(value)) { - // Ignore constants, the register allocator does not need to see them. - return false; - } else if (isVirtualObject(value)) { - assert Arrays.asList(virtualObjects).contains(value); - return false; - } else { - return true; - } - } - - - public void finish(CiBitMap registerRefMap, CiBitMap frameRefMap, FrameMap frameMap) { - debugInfo = new CiDebugInfo(topFrame, registerRefMap, frameRefMap); - - // Add additional stack slots for outgoing method parameters. - if (pointerSlots != null) { - for (CiStackSlot v : pointerSlots) { - frameMap.setReference(v, registerRefMap, frameRefMap); - } - } - } - - - @Override - public String toString() { - return debugInfo != null ? debugInfo.toString() : topFrame.toString(); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,446 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.lir; - -import static com.oracle.max.graal.alloc.util.ValueUtil.*; -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.util.*; - -/** - * The {@code LIRInstruction} class definition. - */ -public abstract class LIRInstruction { - - public static final CiValue[] NO_OPERANDS = {}; - - /** - * Iterator for iterating over a list of values. Subclasses must overwrite one of the doValue methods. - * Clients of the class must only call the doValue method that takes additional parameters. - */ - public abstract static class ValueProcedure { - /** - * Iterator method to be overwritten. This version of the iterator does not take additional parameters - * to keep the signature short. - * - * @param value The value that is iterated. - * @return The new value to replace the value that was passed in. - */ - protected CiValue doValue(CiValue value) { - throw Util.shouldNotReachHere("One of the doValue() methods must be overwritten"); - } - - /** - * Iterator method to be overwritten. This version of the iterator gets additional parameters about the - * processed value. - * - * @param value The value that is iterated. - * @param mode The operand mode for the value. - * @param flags A set of flags for the value. - * @return The new value to replace the value that was passed in. - */ - public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { - return doValue(value); - } - } - - - /** - * Constants denoting how a LIR instruction uses an operand. - */ - public enum OperandMode { - /** - * The value must have been defined before. It is alive before the instruction until the beginning of the - * instruction, but not necessarily throughout the instruction. A register assigned to it can also be assigend - * to a Temp or Output operand. The value can be used again after the instruction, so the instruction must not - * modify the register. - */ - Input, - - /** - * The value must have been defined before. It is alive before the instruction and throughout the instruction. A - * register assigned to it cannot be assigned to a Temp or Output operand. The value can be used again after the - * instruction, so the instruction must not modify the register. - */ - Alive, - - /** - * The value must not have been defined before, and must not be used after the instruction. The instruction can - * do whatever it wants with the register assigned to it (or not use it at all). - */ - Temp, - - /** - * The value must not have been defined before. The instruction has to assign a value to the register. The - * value can (and most likely will) be used after the instruction. - */ - Output, - } - - /** - * Flags for an operand. - */ - public enum OperandFlag { - /** - * The value can be a {@link CiRegisterValue}. - */ - Register, - - /** - * The value can be a {@link CiStackSlot}. - */ - Stack, - - /** - * The value can be a {@link CiAddress}. - */ - Address, - - /** - * The value can be a {@link CiConstant}. - */ - Constant, - - /** - * The value can be {@link CiValue#IllegalValue}. - */ - Illegal, - - /** - * The register allocator should try to assign a certain register to improve code quality. - * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints. - */ - RegisterHint, - - /** - * The value can be uninitialized, e.g., a stack slot that has not written to before. This is only - * used to avoid false positives in verification code. - */ - Uninitialized, - } - - /** - * For validity checking of the operand flags defined by instruction subclasses. - */ - private static final EnumMap> ALLOWED_FLAGS; - - static { - ALLOWED_FLAGS = new EnumMap<>(OperandMode.class); - ALLOWED_FLAGS.put(OperandMode.Input, EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Address, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint, OperandFlag.Uninitialized)); - ALLOWED_FLAGS.put(OperandMode.Alive, EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Address, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint, OperandFlag.Uninitialized)); - ALLOWED_FLAGS.put(OperandMode.Temp, EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint)); - ALLOWED_FLAGS.put(OperandMode.Output, EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Illegal, OperandFlag.RegisterHint)); - } - - /** - * The opcode of this instruction. - */ - protected final Object code; - - /** - * The output operands for this instruction (modified by the register allocator). - */ - protected final CiValue[] outputs; - - /** - * The input operands for this instruction (modified by the register allocator). - */ - protected final CiValue[] inputs; - - /** - * The alive operands for this instruction (modified by the register allocator). - */ - protected final CiValue[] alives; - - /** - * The temp operands for this instruction (modified by the register allocator). - */ - protected final CiValue[] temps; - - /** - * Used to emit debug information. - */ - public final LIRDebugInfo info; - - /** - * Instruction id for register allocation. - */ - private int id; - - /** - * Constructs a new LIR instruction that has input and temp operands. - * - * @param opcode the opcode of the new instruction - * @param outputs the operands that holds the operation results of this instruction. - * @param info the {@link LIRDebugInfo} info that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. - * @param inputs the input operands for the instruction. - * @param temps the temp operands for the instruction. - */ - public LIRInstruction(Object opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) { - this.code = opcode; - this.outputs = outputs; - this.inputs = inputs; - this.alives = alives; - this.temps = temps; - this.info = info; - this.id = -1; - } - - public abstract void emitCode(TargetMethodAssembler tasm); - - - public final int id() { - return id; - } - - public final void setId(int id) { - this.id = id; - } - - /** - * Gets an input operand of this instruction. - * - * @param index the index of the operand requested. - * @return the {@code index}'th input operand. - */ - protected final CiValue input(int index) { - return inputs[index]; - } - - /** - * Gets an alive operand of this instruction. - * - * @param index the index of the operand requested. - * @return the {@code index}'th alive operand. - */ - protected final CiValue alive(int index) { - return alives[index]; - } - - /** - * Gets a temp operand of this instruction. - * - * @param index the index of the operand requested. - * @return the {@code index}'th temp operand. - */ - protected final CiValue temp(int index) { - return temps[index]; - } - - /** - * Gets the result operand for this instruction. - * - * @return return the result operand - */ - protected final CiValue output(int index) { - return outputs[index]; - } - - /** - * Gets the instruction name. - */ - public String name() { - return code.toString(); - } - - public boolean hasOperands() { - return inputs.length > 0 || alives.length > 0 || temps.length > 0 || outputs.length > 0 || info != null || hasCall(); - } - - private static final EnumSet ADDRESS_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); - - private void forEach(CiValue[] values, OperandMode mode, ValueProcedure proc) { - for (int i = 0; i < values.length; i++) { - assert ALLOWED_FLAGS.get(mode).containsAll(flagsFor(mode, i)); - - CiValue value = values[i]; - if (isAddress(value)) { - assert flagsFor(mode, i).contains(OperandFlag.Address); - CiAddress address = asAddress(value); - address.base = proc.doValue(address.base, mode, ADDRESS_FLAGS); - address.index = proc.doValue(address.index, mode, ADDRESS_FLAGS); - } else { - values[i] = proc.doValue(values[i], mode, flagsFor(mode, i)); - } - } - } - - public final void forEachInput(ValueProcedure proc) { - forEach(inputs, OperandMode.Input, proc); - } - - public final void forEachAlive(ValueProcedure proc) { - forEach(alives, OperandMode.Alive, proc); - } - - public final void forEachTemp(ValueProcedure proc) { - forEach(temps, OperandMode.Temp, proc); - } - - public final void forEachOutput(ValueProcedure proc) { - forEach(outputs, OperandMode.Output, proc); - } - - public final void forEachState(ValueProcedure proc) { - if (info != null) { - info.forEachState(proc); - - if (this instanceof LIRXirInstruction) { - LIRXirInstruction xir = (LIRXirInstruction) this; - if (xir.infoAfter != null) { - xir.infoAfter.forEachState(proc); - } - } - } - } - - /** - * Returns true when this instruction is a call instruction that destroys all caller-saved registers. - */ - public final boolean hasCall() { - return this instanceof StandardOp.CallOp; - } - - /** - * Iterates all register hints for the specified value, i.e., all preferred candidates for the register to be - * assigned to the value. - *
- * Subclasses can override this method. The default implementation processes all Input operands as the hints for - * an Output operand, and all Output operands as the hints for an Input operand. - * - * @param value The value the hints are needed for. - * @param mode The operand mode of the value. - * @param proc The procedure invoked for all the hints. If the procedure returns a non-null value, the iteration is stopped - * and the value is returned by this method, i.e., clients can stop the iteration once a suitable hint has been found. - * @return The non-null value returned by the procedure, or null. - */ - public CiValue forEachRegisterHint(CiValue value, OperandMode mode, ValueProcedure proc) { - CiValue[] hints; - if (mode == OperandMode.Input) { - hints = outputs; - } else if (mode == OperandMode.Output) { - hints = inputs; - } else { - return null; - } - - for (int i = 0; i < hints.length; i++) { - CiValue result = proc.doValue(hints[i], null, null); - if (result != null) { - return result; - } - } - return null; - } - - /** - * Used by the register allocator to decide which kind of location can be assigned to the operand. - * @param mode The kind of operand. - * @param index The index of the operand. - * @return The flags for the operand. - */ - // TODO this method will go away when we have named operands, the flags will be specified as annotations instead. - protected abstract EnumSet flagsFor(OperandMode mode, int index); - - protected void verify() { - } - - - public final String toStringWithIdPrefix() { - if (id != -1) { - return String.format("%4d %s", id, toString()); - } - return " " + toString(); - } - - /** - * Gets the operation performed by this instruction in terms of its operands as a string. - */ - public String operationString() { - StringBuilder buf = new StringBuilder(); - String sep = ""; - if (outputs.length > 1) { - buf.append("("); - } - for (CiValue output : outputs) { - buf.append(sep).append(output); - sep = ", "; - } - if (outputs.length > 1) { - buf.append(")"); - } - if (outputs.length > 0) { - buf.append(" = "); - } - - if (inputs.length + alives.length != 1) { - buf.append("("); - } - sep = ""; - for (CiValue input : inputs) { - buf.append(sep).append(input); - sep = ", "; - } - for (CiValue input : alives) { - buf.append(sep).append(input).append(" ~"); - sep = ", "; - } - if (inputs.length + alives.length != 1) { - buf.append(")"); - } - - if (temps.length > 0) { - buf.append(" ["); - } - sep = ""; - for (CiValue temp : temps) { - buf.append(sep).append(temp); - sep = ", "; - } - if (temps.length > 0) { - buf.append("]"); - } - return buf.toString(); - } - - protected void appendDebugInfo(StringBuilder buf) { - if (info != null) { - buf.append(" [bci:"); - String sep = ""; - for (CiFrame cur = info.topFrame; cur != null; cur = cur.caller()) { - buf.append(sep).append(cur.bci); - sep = ","; - } - buf.append("]"); - } - } - - @Override - public String toString() { - StringBuilder buf = new StringBuilder(name()).append(' ').append(operationString()); - appendDebugInfo(buf); - return buf.toString(); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRPhiMapping.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRPhiMapping.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2011, 2011, 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.max.graal.compiler.lir; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.nodes.*; -import com.oracle.max.graal.nodes.PhiNode.*; - -public class LIRPhiMapping { - private final Block block; - - private CiValue[][] inputs; - private CiValue[] results; - - public LIRPhiMapping(Block block, LIRGenerator gen) { - this.block = block; - - assert block.getBeginNode() instanceof MergeNode : "phi functions are only present at control flow merges"; - MergeNode mergeNode = (MergeNode) block.getBeginNode(); - List phis = mergeNode.phis().snapshot(); - - for (int i = 0; i < phis.size(); i++) { - PhiNode phi = phis.get(i); - if (phi.type() == PhiType.Value) { - gen.setResult(phi, gen.newVariable(phi.kind())); - } - } - } - - public void fillInputs(LIRGenerator gen) { - assert block.getBeginNode() instanceof MergeNode : "phi functions are only present at control flow merges"; - MergeNode mergeNode = (MergeNode) block.getBeginNode(); - List phis = mergeNode.phis().snapshot(); - - int numPhis = 0; - for (int i = 0; i < phis.size(); i++) { - if (phis.get(i).type() == PhiType.Value) { - numPhis++; - } - } - int numPreds = block.numberOfPreds(); - - results = new CiValue[numPhis]; - inputs = new CiValue[numPreds][numPhis]; - - int phiIdx = 0; - for (int i = 0; i < phis.size(); i++) { - PhiNode phi = phis.get(i); - if (phi.type() == PhiType.Value) { - results[phiIdx] = gen.operand(phi); - for (int j = 0; j < numPreds; j++) { - assert j == mergeNode.phiPredecessorIndex((FixedNode) block.predAt(j).getEndNode()) : "block predecessors and node predecessors must have same order"; - inputs[j][phiIdx] = gen.operand(phi.valueAt(j)); - } - phiIdx++; - } - } - assert phiIdx == numPhis; - } - - public CiValue[] results() { - return results; - } - - public CiValue[] inputs(Block pred) { - assert pred.numberOfSux() == 1 && pred.suxAt(0) == block; - return inputs[block.getPredecessors().indexOf(pred)]; - } - - private static final EnumSet INPUT_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - private static final EnumSet OUTPUT_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - - public void forEachInput(Block pred, PhiValueProcedure proc) { - CiValue[] predInputs = inputs(pred); - for (int i = 0; i < predInputs.length; i++) { - predInputs[i] = proc.doValue(predInputs[i], results[i]); - } - } - - public void forEachOutput(ValueProcedure proc) { - for (int i = 0; i < results.length; i++) { - results[i] = proc.doValue(results[i], OperandMode.Output, OUTPUT_FLAGS); - } - } - - public abstract static class PhiValueProcedure extends ValueProcedure { - /** - * Iterator method to be overwritten. This version of the iterator has both the input and output of the phi function as parameters. - * to keep the signature short. - * - * @param input The input value that is iterated. - * @param output The output value that is iterated. - * @return The new value to replace the input value that was passed in. - */ - protected CiValue doValue(CiValue input, CiValue output) { - return doValue(input, OperandMode.Input, INPUT_FLAGS); - } - } - - @Override - public String toString() { - return "PhiMapping for " + block + ": " + Arrays.toString(results); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRVerifier.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRVerifier.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,241 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.lir; - -import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.alloc.util.ValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.criutils.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; -import com.oracle.max.graal.compiler.util.*; - -public final class LIRVerifier { - private final LIR lir; - private final FrameMap frameMap; - - private final boolean beforeRegisterAllocation; - - private final BitSet[] blockLiveOut; - private final Object[] variableDefinitions; - - private BitSet liveOutFor(Block block) { - return blockLiveOut[block.getId()]; - } - private void setLiveOutFor(Block block, BitSet liveOut) { - blockLiveOut[block.getId()] = liveOut; - } - - private int maxRegisterNum() { - return frameMap.target.arch.registers.length; - } - - private boolean isAllocatableRegister(CiValue value) { - return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; - } - - public static boolean verify(final LIRInstruction op) { - ValueProcedure allowedProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return allowed(op, value, mode, flags); } }; - - op.forEachInput(allowedProc); - op.forEachAlive(allowedProc); - op.forEachState(allowedProc); - op.forEachTemp(allowedProc); - op.forEachOutput(allowedProc); - - op.verify(); - return true; - } - - public static boolean verify(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) { - LIRVerifier verifier = new LIRVerifier(beforeRegisterAllocation, lir, frameMap); - verifier.verify(); - return true; - } - - - private LIRVerifier(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) { - this.beforeRegisterAllocation = beforeRegisterAllocation; - this.lir = lir; - this.frameMap = frameMap; - this.blockLiveOut = new BitSet[lir.linearScanOrder().size()]; - this.variableDefinitions = new Object[lir.numVariables()]; - } - - private BitSet curVariablesLive; - private CiValue[] curRegistersLive; - - private Block curBlock; - private Object curInstruction; - private BitSet curRegistersDefined; - - private void verify() { - PhiValueProcedure useProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, mode, flags); } }; - - curRegistersDefined = new BitSet(); - for (Block block : lir.linearScanOrder()) { - curBlock = block; - curVariablesLive = new BitSet(); - curRegistersLive = new CiValue[maxRegisterNum()]; - - if (block.getDominator() != null) { - curVariablesLive.or(liveOutFor(block.getDominator())); - } - - if (block.phis != null) { - assert beforeRegisterAllocation; - curInstruction = block.phis; - block.phis.forEachOutput(defProc); - } - - assert block.lir.get(0) instanceof StandardOp.LabelOp : "block must start with label"; - if (block.numberOfSux() > 0) { - LIRInstruction last = block.lir.get(block.lir.size() - 1); - assert last instanceof StandardOp.JumpOp || last instanceof LIRXirInstruction : "block with successor must end with unconditional jump"; - } - - for (LIRInstruction op : block.lir) { - curInstruction = op; - - op.forEachInput(useProc); - if (op.hasCall()) { - for (CiRegister register : frameMap.registerConfig.getCallerSaveRegisters()) { - curRegistersLive[register.number] = null; - } - } - curRegistersDefined.clear(); - op.forEachAlive(useProc); - op.forEachState(useProc); - op.forEachTemp(defProc); - op.forEachOutput(defProc); - - curInstruction = null; - } - - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - assert beforeRegisterAllocation; - curInstruction = sux.phis; - sux.phis.forEachInput(block, useProc); - } - } - - setLiveOutFor(block, curVariablesLive); - } - } - - private CiValue use(CiValue value, OperandMode mode, EnumSet flags) { - allowed(curInstruction, value, mode, flags); - - if (isVariable(value)) { - assert beforeRegisterAllocation; - - int variableIdx = asVariable(value).index; - if (!curVariablesLive.get(variableIdx)) { - TTY.println("block %s instruction %s", curBlock, curInstruction); - TTY.println("live variables: %s", curVariablesLive); - if (variableDefinitions[variableIdx] != null) { - TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]); - } - TTY.println("ERROR: Use of variable %s that is not defined in dominator", value); - throw Util.shouldNotReachHere(); - } - - } else if (isAllocatableRegister(value)) { - int regNum = asRegister(value).number; - if (mode == OperandMode.Alive) { - curRegistersDefined.set(regNum); - } - - if (beforeRegisterAllocation && curRegistersLive[regNum] != value) { - TTY.println("block %s instruction %s", curBlock, curInstruction); - TTY.println("live registers: %s", Arrays.toString(curRegistersLive)); - TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value); - throw Util.shouldNotReachHere(); - } - } - return value; - } - - private CiValue def(CiValue value, OperandMode mode, EnumSet flags) { - allowed(curInstruction, value, mode, flags); - - if (isVariable(value)) { - assert beforeRegisterAllocation; - - int variableIdx = asVariable(value).index; - if (variableDefinitions[variableIdx] != null) { - TTY.println("block %s instruction %s", curBlock, curInstruction); - TTY.println("live variables: %s", curVariablesLive); - TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]); - TTY.println("ERROR: Variable %s defined multiple times", value); - throw Util.shouldNotReachHere(); - } - assert curInstruction != null; - variableDefinitions[variableIdx] = curInstruction; - assert !curVariablesLive.get(variableIdx); - if (mode == OperandMode.Output) { - curVariablesLive.set(variableIdx); - } - - } else if (isAllocatableRegister(value)) { - int regNum = asRegister(value).number; - if (curRegistersDefined.get(regNum)) { - TTY.println("block %s instruction %s", curBlock, curInstruction); - TTY.println("ERROR: Same register defined twice in the same instruction: %s", value); - throw Util.shouldNotReachHere(); - } - curRegistersDefined.set(regNum); - - if (beforeRegisterAllocation) { - if (mode == OperandMode.Output) { - curRegistersLive[regNum] = value; - } else { - curRegistersLive[regNum] = null; - } - } - } - return value; - } - - private static CiValue allowed(Object op, CiValue value, OperandMode mode, EnumSet flags) { - if ((isVariable(value) && flags.contains(OperandFlag.Register)) || - (isRegister(value) && flags.contains(OperandFlag.Register)) || - (isStackSlot(value) && flags.contains(OperandFlag.Stack)) || - (isConstant(value) && flags.contains(OperandFlag.Constant) && mode != OperandMode.Output) || - (isIllegal(value) && flags.contains(OperandFlag.Illegal))) { - return value; - } - TTY.println("instruction %s", op); - TTY.println("mode: %s flags: %s", mode, flags); - TTY.println("Unexpected value: %s %s", value.getClass().getSimpleName(), value); - throw Util.shouldNotReachHere(); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2009, 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.max.graal.compiler.lir; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.xir.*; -import com.oracle.max.graal.compiler.util.*; - -public abstract class LIRXirInstruction extends LIRInstruction { - - public final CiValue[] originalOperands; - public final int outputOperandIndex; - public final int[] inputOperandIndices; - public final int[] tempOperandIndices; - public final XirSnippet snippet; - public final LIRDebugInfo infoAfter; - public final LabelRef trueSuccessor; - public final LabelRef falseSuccessor; - - public LIRXirInstruction(Object opcode, - XirSnippet snippet, - CiValue[] originalOperands, - CiValue outputOperand, - CiValue[] inputs, CiValue[] temps, - int[] inputOperandIndices, int[] tempOperandIndices, - int outputOperandIndex, - LIRDebugInfo info, - LIRDebugInfo infoAfter, - LabelRef trueSuccessor, - LabelRef falseSuccessor) { - // Note that we register the XIR input operands as Alive, because the XIR specification allows that input operands - // are used at any time, even when the temp operands and the actual output operands have already be assigned. - super(opcode, isLegal(outputOperand) ? new CiValue[] {outputOperand} : LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, inputs, temps); - this.infoAfter = infoAfter; - this.snippet = snippet; - this.inputOperandIndices = inputOperandIndices; - this.tempOperandIndices = tempOperandIndices; - this.outputOperandIndex = outputOperandIndex; - this.originalOperands = originalOperands; - this.falseSuccessor = falseSuccessor; - this.trueSuccessor = trueSuccessor; - assert isLegal(outputOperand) || outputOperandIndex == -1; - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Alive || mode == OperandMode.Temp) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.Illegal); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - - public CiValue[] getOperands() { - for (int i = 0; i < inputOperandIndices.length; i++) { - originalOperands[inputOperandIndices[i]] = alive(i); - } - for (int i = 0; i < tempOperandIndices.length; i++) { - originalOperands[tempOperandIndices[i]] = temp(i); - } - if (outputOperandIndex != -1) { - originalOperands[outputOperandIndex] = output(0); - } - return originalOperands; - } - - @Override - public String name() { - return "XIR: " + snippet.template; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LabelRef.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LabelRef.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2011, 2011, 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.max.graal.compiler.lir; - -import com.oracle.max.asm.*; -import com.oracle.max.graal.compiler.cfg.*; - -/** - * LIR instructions such as JUMP and BRANCH need to reference their target {@link Block}. However, - * direct references are not possible since the control flow graph (and therefore successors lists) can - * be changed by optimizations - and fixing the instructions is error prone. - * Therefore, we only reference of block B from block A only via the tuple (A, successor-index-of-B), i.e., - * indirectly by storing the index into the successor list of A. - * Note that therefore it is not allowed to reorder the successor list! - * - * Labels of out-of-line stubs can be referenced directly, therefore it is also possible to construct a - * LabelRef for a Label directly via {@link #forLabel}. - */ -public abstract class LabelRef { - - public abstract Label label(); - - /** - * Returns a new reference to a statically defined label. - * @param label The label that is always returned. - * @return The newly created label reference. - */ - public static LabelRef forLabel(final Label label) { - return new LabelRef() { - @Override - public Label label() { - return label; - } - - @Override - public String toString() { - return label.toString(); - } - }; - } - - /** - * Returns a new reference to a successor of the given block. - * This allows to reference the given successor even when the successor list - * is modified between the creation of the reference and the call to {@link #getLabel}. - * @param block The base block that contains the successor list. - * @param suxIndex The index of the successor. - * @return The newly created label reference. - */ - public static LabelRef forSuccessor(final Block block, final int suxIndex) { - return new LabelRef() { - @Override - public Label label() { - return ((StandardOp.LabelOp) block.suxAt(suxIndex).lir.get(0)).getLabel(); - } - - @Override - public String toString() { - return suxIndex < block.numberOfSux() ? block.suxAt(suxIndex).toString() : "?" + block + ":" + suxIndex + "?"; - } - }; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/StandardOp.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/StandardOp.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.lir; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.util.*; - -/** - * A collection of machine-independent LIR operations, as well as interfaces to be implemented for specific kinds or LIR - * operations. - */ -public class StandardOp { - - /** - * Marker interface for a LIR operation that defines the position of a label. - * The first operation of every block must implement this interface. - */ - public interface LabelOp { - Label getLabel(); - } - - /** - * Marker interface for a LIR operation that is an unconditional jump to {@link #destination()}. - * When the LIR is constructed, the last operation of every block must implement this interface. After - * register allocation, unnecessary jumps can be deleted. - * - * TODO Currently, a block can also end with an XIR operation. - */ - public interface JumpOp { - LabelRef destination(); - } - - /** - * Marker interface for a LIR operation that is a conditional jump to {@link #destination()}. - * Conditional jumps may be negated or optimized away after register allocation. - */ - public interface BranchOp { - LabelRef destination(); - void negate(LabelRef newDestination); - } - - /** - * Marker interface for a LIR operation that moves a value from {@link #getInput()} to {@link #getResult()}. - */ - public interface MoveOp { - CiValue getInput(); - CiValue getResult(); - } - - /** - * Marker interface for a LIR operation that calls a method, i.e., destroys all caller-saved registers. - */ - public interface CallOp { - } - - - /** - * Meta-operation that defines the incoming method parameters. In the LIR, every register and variable must be - * defined before it is used. This operation is the definition point of method parameters, but is otherwise a no-op. - * In particular, it is not the actual method prologue. - */ - public static final class ParametersOp extends LIRInstruction { - public ParametersOp(CiValue[] params) { - super("PARAMS", params, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm) { - // No code to emit. - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Output) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - } - throw Util.shouldNotReachHere(); - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/Variable.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/Variable.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2010, 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.max.graal.compiler.lir; - -import com.oracle.max.cri.ci.*; - -/** - * Represents a value that is yet to be bound to a machine location (such as - * a {@link CiRegisterValue} or {@link CiStackSlot}) by a register allocator. - */ -public final class Variable extends CiValue { - private static final long serialVersionUID = 4507578431686109809L; - - /** - * The identifier of the variable. This is a non-zero index in a contiguous 0-based name space. - */ - public final int index; - - /** - * The type of register that this variable needs to get assigned. - */ - public final CiRegister.RegisterFlag flag; - - /** - * Creates a new variable. - * @param kind - * @param index - */ - public Variable(CiKind kind, int index, CiRegister.RegisterFlag flag) { - super(kind); - assert kind == kind.stackKind() : "Variables can be only created for stack kinds"; - assert index >= 0; - this.index = index; - this.flag = flag; - } - - @Override - public int hashCode() { - return (index << 4) | kind.ordinal(); - } - - @Override - public String toString() { - return "v" + index + kindSuffix(); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.observer; - -import java.util.*; - -/** - * An event that occurred during compilation. Instances of this class provide information about the event and the state - * of the compilation when the event was raised. Depending on the state of the compiler and the compilation phase, - * different types of objects are provided in the {@link #debugObjects}. The observer should filter events that it is - * interested in by checking if an object of a specific type is provided by the event. - */ -public class CompilationEvent { - - /** - * Marker object for the {@link #debugObject} array: When this object is present, the event is the result of a compilation error. - */ - public static final Object ERROR = new Object() {}; - - public final String label; - private List debugObjects; - - protected CompilationEvent(String label, ArrayList debugObjects) { - this.label = label; - this.debugObjects = debugObjects; - } - - @SuppressWarnings("unchecked") - public T debugObject(Class type) { - for (ListIterator iter = debugObjects.listIterator(debugObjects.size()); iter.hasPrevious();) { - Object o = iter.previous(); - if (type.isInstance(o)) { - return (T) o; - } - } - return null; - } - - public boolean hasDebugObject(Object search) { - for (ListIterator iter = debugObjects.listIterator(debugObjects.size()); iter.hasPrevious();) { - Object o = iter.previous(); - if (o == search) { - return true; - } - } - return false; - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationObserver.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationObserver.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.observer; - - -/** - * Interface for classes that observe events of an {@link ObservableCompiler}. - */ -public interface CompilationObserver { - - /** - * Called when compilation of a method has started. This is always the first event raised for a particular - * method compilation. - * - * @param event Information associated with the event and current state of the compilation. - */ - void compilationStarted(CompilationEvent event); - - /** - * Called when an event has occurred, for example that a particular phase in the compilation has been entered. - * - * @param event Information associated with the event and current state of the compilation. - */ - void compilationEvent(CompilationEvent event); - - /** - * Called when compilation of a method has completed (successfully or not). This is always the last event raised for - * a particular method compilation. - * - * @param event Information associated with the event and current state of the compilation. - */ - void compilationFinished(CompilationEvent event); - -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/ObservableContext.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/ObservableContext.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.observer; - -import java.util.*; - -/** - * Base class for compilers that notify subscribed {@link CompilationObserver CompilationObservers} of - * {@link CompilationEvent CompilationEvents} that occur during their compilations. - */ -public class ObservableContext { - - private List observers; - - private ThreadLocal scopeName = new ThreadLocal() { - @Override - protected StringBuilder initialValue() { - return new StringBuilder(); - } - }; - - private ThreadLocal> debugObjects = new ThreadLocal>() { - @Override - protected ArrayList initialValue() { - return new ArrayList<>(); - } - }; - - /** - * @return {@code true} if one or more observers are subscribed to receive notifications from this compiler, - * {@code false} otherwise. - */ - public boolean isObserved() { - return observers != null; - } - - /** - * Add the specified observer to receive events from this compiler. - * - * @param observer The observer to add. - */ - public void addCompilationObserver(CompilationObserver observer) { - assert observer != null; - - if (observers == null) { - observers = new LinkedList<>(); - } - observers.add(observer); - } - - public void fireCompilationStarted(Object... additionalDebugObjects) { - if (isObserved()) { - addDebugObjects(null, additionalDebugObjects); - CompilationEvent event = new CompilationEvent("started", debugObjects.get()); - for (CompilationObserver observer : observers) { - observer.compilationStarted(event); - } - removeDebugObjects(null, additionalDebugObjects); - } - } - - public void fireCompilationEvent(String label, Object... additionalDebugObjects) { - if (isObserved()) { - addDebugObjects(null, additionalDebugObjects); - CompilationEvent event = new CompilationEvent(label, debugObjects.get()); - for (CompilationObserver observer : observers) { - observer.compilationEvent(event); - } - removeDebugObjects(null, additionalDebugObjects); - } - } - - public void fireCompilationFinished(Object... additionalDebugObjects) { - if (isObserved()) { - addDebugObjects(null, additionalDebugObjects); - CompilationEvent event = new CompilationEvent("finished", debugObjects.get()); - for (CompilationObserver observer : observers) { - observer.compilationFinished(event); - } - removeDebugObjects(null, additionalDebugObjects); - } - } - - /** - * Remove the specified observer so that it no longer receives events from this compiler. - * - * @param observer The observer to remove. - */ - public void removeCompilationObserver(CompilationObserver observer) { - if (observers != null) { - observers.remove(observer); - if (observers.size() == 0) { - observers = null; - } - } - } - - public void clear() { - if (observers != null) { - observers = null; - } - } - - public void addDebugObjects(String name, Object[] additionalDebugObjects) { - if (name != null) { - if (scopeName.get().length() > 0) { - scopeName.get().append('.'); - } - scopeName.get().append(name); - } - for (Object obj : additionalDebugObjects) { - debugObjects.get().add(obj); - } - } - - public void removeDebugObjects(String name, Object[] additionalDebugObjects) { - if (name != null) { - scopeName.get().setLength(Math.max(0, scopeName.get().length() - name.length())); - } - for (int i = 0; i < additionalDebugObjects.length; i++) { - debugObjects.get().remove(debugObjects.get().size() - 1); - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/package-info.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/package-info.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2011, 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. - */ - -/** - * Classes and interfaces for observing compilations. - */ -package com.oracle.max.graal.compiler.observer; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/FloatingReadPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/FloatingReadPhase.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/FloatingReadPhase.java Thu Feb 09 10:03:21 2012 +0100 @@ -25,9 +25,9 @@ import java.util.*; import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.PhiNode.PhiType; import com.oracle.max.graal.nodes.extended.*; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java Thu Feb 09 10:03:21 2012 +0100 @@ -191,9 +191,13 @@ if (GraalOptions.InliningPolicy == 0) { return new WeightBasedInliningPolicy(); } else if (GraalOptions.InliningPolicy == 1) { - return new SizeBasedInliningPolicy(); + return new StaticSizeBasedInliningPolicy(); + } else if (GraalOptions.InliningPolicy == 2) { + return new DynamicSizeBasedInliningPolicy(); + } else if (GraalOptions.InliningPolicy == 3) { + return new GreedySizeBasedInliningPolicy(); } else { - Util.shouldNotReachHere(); + GraalInternalError.shouldNotReachHere(); return null; } } @@ -272,14 +276,14 @@ } } - private class SizeBasedInliningPolicy implements InliningPolicy { + private class StaticSizeBasedInliningPolicy implements InliningPolicy { @Override public double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke) { + double codeSize = method.codeSize(); if (preferredInvoke) { - return method.codeSize() / 2; - } else { - return method.codeSize(); + codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis; } + return codeSize; } @Override @@ -288,4 +292,51 @@ return info.weight <= maxSize; } } + + private class DynamicSizeBasedInliningPolicy implements InliningPolicy { + @Override + public double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke) { + double codeSize = method.codeSize(); + if (preferredInvoke) { + codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis; + } + return codeSize; + } + + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + assert GraalOptions.ProbabilityAnalysis; + if (info.compiledCodeSize() <= GraalOptions.SmallCompiledCodeSize) { + double inlineBoost = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); + double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumInlineSize; + maxSize = maxSize + maxSize * inlineBoost; + maxSize = Math.max(GraalOptions.MaximumTrivialSize, maxSize); + return info.weight <= maxSize; + } + return false; + } + } + + private class GreedySizeBasedInliningPolicy implements InliningPolicy { + @Override + public double computeWeight(RiResolvedMethod caller, RiResolvedMethod method, Invoke invoke, boolean preferredInvoke) { + double codeSize = method.codeSize(); + if (preferredInvoke) { + codeSize = codeSize / GraalOptions.BoostInliningForEscapeAnalysis; + } + return codeSize; + } + + @Override + public boolean isWorthInlining(StructuredGraph callerGraph, InlineInfo info) { + assert GraalOptions.ProbabilityAnalysis; + if (info.compiledCodeSize() <= GraalOptions.SmallCompiledCodeSize) { + double inlineRatio = Math.min(GraalOptions.ProbabilityCapForInlining, info.invoke.probability()); + double maxSize = Math.pow(GraalOptions.NestedInliningSizeRatio, info.level) * GraalOptions.MaximumGreedyInlineSize * inlineRatio; + maxSize = Math.max(maxSize, GraalOptions.MaximumInlineSize); + return info.weight <= maxSize; + } + return false; + } + } } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoweringPhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoweringPhase.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoweringPhase.java Thu Feb 09 10:03:21 2012 +0100 @@ -23,9 +23,9 @@ package com.oracle.max.graal.compiler.phases; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.cri.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.spi.*; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/BlockClosure.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/BlockClosure.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/BlockClosure.java Thu Feb 09 10:03:21 2012 +0100 @@ -22,7 +22,7 @@ */ package com.oracle.max.graal.compiler.schedule; -import com.oracle.max.graal.compiler.cfg.*; +import com.oracle.max.graal.lir.cfg.*; /** * The {@code BlockClosure} interface represents a closure for iterating over blocks. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/SchedulePhase.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/SchedulePhase.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/SchedulePhase.java Thu Feb 09 10:03:21 2012 +0100 @@ -27,10 +27,10 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.criutils.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.phases.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.graph.Node.Verbosity; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.extended.*; import com.oracle.max.graal.nodes.virtual.*; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/Backend.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/Backend.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/Backend.java Thu Feb 09 10:03:21 2012 +0100 @@ -29,8 +29,8 @@ import com.oracle.max.cri.ri.*; import com.oracle.max.cri.xir.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; /** * The {@code Backend} class represents a compiler backend for Graal. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Arithmetic.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Arithmetic.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,559 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.target.amd64; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; - -public enum AMD64Arithmetic { - IADD, ISUB, IMUL, IDIV, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, - LADD, LSUB, LMUL, LDIV, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, - FADD, FSUB, FMUL, FDIV, FAND, FOR, FXOR, - DADD, DSUB, DMUL, DDIV, DAND, DOR, DXOR, - INEG, LNEG, - I2L, L2I, I2B, I2C, I2S, - F2D, D2F, - I2F, I2D, F2I, D2I, - L2F, L2D, F2L, D2L, - MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L; - - - public static class Op1Reg extends AMD64LIRInstruction { - public Op1Reg(AMD64Arithmetic opcode, CiValue result, CiValue x) { - super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue result = output(0); - CiValue x = input(0); - - emit(tasm, masm, (AMD64Arithmetic) code, result, x, null); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - } - - public static class Op1Stack extends AMD64LIRInstruction { - public Op1Stack(AMD64Arithmetic opcode, CiValue result, CiValue x) { - super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue result = output(0); - CiValue x = input(0); - - AMD64Move.move(tasm, masm, result, x); - emit(tasm, masm, (AMD64Arithmetic) code, result); - } - - @Override - public EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); - } - throw Util.shouldNotReachHere(); - } - } - - public static class Op2Stack extends AMD64LIRInstruction { - public Op2Stack(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { - super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, new CiValue[] {y}, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = alive(0); - - AMD64Move.move(tasm, masm, result, x); - emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Alive && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); - } - throw Util.shouldNotReachHere(); - } - - @Override - public void verify() { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = alive(0); - - super.verify(); - assert differentRegisters(result, y) || sameRegister(x, y); - verifyKind((AMD64Arithmetic) code, result, x, y); - } - } - - public static class Op2Reg extends AMD64LIRInstruction { - public Op2Reg(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { - super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, new CiValue[] {y}, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = alive(0); - - AMD64Move.move(tasm, masm, result, x); - emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Alive && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); - } - throw Util.shouldNotReachHere(); - } - - @Override - public void verify() { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = alive(0); - - super.verify(); - assert differentRegisters(result, y) || sameRegister(x, y); - verifyKind((AMD64Arithmetic) code, result, x, y); - } - } - - public static class Op2RegCommutative extends AMD64LIRInstruction { - public Op2RegCommutative(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { - super(opcode, new CiValue[] {result}, null, new CiValue[] {x, y}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = input(1); - - if (sameRegister(result, y)) { - emit(tasm, masm, (AMD64Arithmetic) code, result, x, null); - } else { - AMD64Move.move(tasm, masm, result, x); - emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); - } - } - - @Override - public EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Input && index == 1) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); - } - throw Util.shouldNotReachHere(); - } - - @Override - protected void verify() { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = input(1); - - super.verify(); - verifyKind((AMD64Arithmetic) code, result, x, y); - } - } - - public static class ShiftOp extends AMD64LIRInstruction { - public ShiftOp(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { - super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, new CiValue[] {y}, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = alive(0); - - AMD64Move.move(tasm, masm, result, x); - emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); - } - - @Override - public EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Alive && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); - } - throw Util.shouldNotReachHere(); - } - - @Override - public void verify() { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = alive(0); - - super.verify(); - assert isConstant(y) || asRegister(y) == AMD64.rcx; - assert differentRegisters(result, y) || sameRegister(x, y); - verifyKind((AMD64Arithmetic) code, result, x, x); - assert y.kind.stackKind() == CiKind.Int; - } - } - - public static class DivOp extends AMD64LIRInstruction { - public DivOp(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y, LIRDebugInfo info) { - super(opcode, new CiValue[] {result}, info, new CiValue[] {x}, new CiValue[] {y}, new CiValue[] {asRegister(result) == AMD64.rax ? AMD64.rdx.asValue(result.kind) : AMD64.rax.asValue(result.kind)}); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue result = output(0); - CiValue y = alive(0); - - emit(tasm, masm, (AMD64Arithmetic) code, result, y, info); - } - - @Override - public EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Alive && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Temp && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - - @Override - protected void verify() { - CiValue result = output(0); - CiValue x = input(0); - CiValue y = alive(0); - - super.verify(); - // left input in rax, right input in any register but rax and rdx, result quotient in rax, result remainder in rdx - assert asRegister(x) == AMD64.rax; - assert differentRegisters(y, AMD64.rax.asValue(), AMD64.rdx.asValue()); - assert (name().endsWith("DIV") && asRegister(result) == AMD64.rax) || (name().endsWith("REM") && asRegister(result) == AMD64.rdx); - verifyKind((AMD64Arithmetic) code, result, x, y); - } - } - - - @SuppressWarnings("unused") - protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, CiValue result) { - switch (opcode) { - case INEG: masm.negl(asIntReg(result)); break; - case LNEG: masm.negq(asLongReg(result)); break; - case L2I: masm.andl(asIntReg(result), 0xFFFFFFFF); break; - case I2B: masm.signExtendByte(asIntReg(result)); break; - case I2C: masm.andl(asIntReg(result), 0xFFFF); break; - case I2S: masm.signExtendShort(asIntReg(result)); break; - default: throw Util.shouldNotReachHere(); - } - } - - protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, CiValue dst, CiValue src, LIRDebugInfo info) { - int exceptionOffset = -1; - if (isRegister(src)) { - switch (opcode) { - case IADD: masm.addl(asIntReg(dst), asIntReg(src)); break; - case ISUB: masm.subl(asIntReg(dst), asIntReg(src)); break; - case IAND: masm.andl(asIntReg(dst), asIntReg(src)); break; - case IMUL: masm.imull(asIntReg(dst), asIntReg(src)); break; - case IOR: masm.orl(asIntReg(dst), asIntReg(src)); break; - case IXOR: masm.xorl(asIntReg(dst), asIntReg(src)); break; - case ISHL: masm.shll(asIntReg(dst)); break; - case ISHR: masm.sarl(asIntReg(dst)); break; - case IUSHR:masm.shrl(asIntReg(dst)); break; - - case LADD: masm.addq(asLongReg(dst), asLongReg(src)); break; - case LSUB: masm.subq(asLongReg(dst), asLongReg(src)); break; - case LMUL: masm.imulq(asLongReg(dst), asLongReg(src)); break; - case LAND: masm.andq(asLongReg(dst), asLongReg(src)); break; - case LOR: masm.orq(asLongReg(dst), asLongReg(src)); break; - case LXOR: masm.xorq(asLongReg(dst), asLongReg(src)); break; - case LSHL: masm.shlq(asLongReg(dst)); break; - case LSHR: masm.sarq(asLongReg(dst)); break; - case LUSHR:masm.shrq(asLongReg(dst)); break; - - case FADD: masm.addss(asFloatReg(dst), asFloatReg(src)); break; - case FSUB: masm.subss(asFloatReg(dst), asFloatReg(src)); break; - case FMUL: masm.mulss(asFloatReg(dst), asFloatReg(src)); break; - case FDIV: masm.divss(asFloatReg(dst), asFloatReg(src)); break; - case FAND: masm.andps(asFloatReg(dst), asFloatReg(src)); break; - case FOR: masm.orps(asFloatReg(dst), asFloatReg(src)); break; - case FXOR: masm.xorps(asFloatReg(dst), asFloatReg(src)); break; - - case DADD: masm.addsd(asDoubleReg(dst), asDoubleReg(src)); break; - case DSUB: masm.subsd(asDoubleReg(dst), asDoubleReg(src)); break; - case DMUL: masm.mulsd(asDoubleReg(dst), asDoubleReg(src)); break; - case DDIV: masm.divsd(asDoubleReg(dst), asDoubleReg(src)); break; - case DAND: masm.andpd(asDoubleReg(dst), asDoubleReg(src)); break; - case DOR: masm.orpd(asDoubleReg(dst), asDoubleReg(src)); break; - case DXOR: masm.xorpd(asDoubleReg(dst), asDoubleReg(src)); break; - - case I2L: masm.movslq(asLongReg(dst), asIntReg(src)); break; - case F2D: masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src)); break; - case D2F: masm.cvtsd2ss(asFloatReg(dst), asDoubleReg(src)); break; - case I2F: masm.cvtsi2ssl(asFloatReg(dst), asIntReg(src)); break; - case I2D: masm.cvtsi2sdl(asDoubleReg(dst), asIntReg(src)); break; - case L2F: masm.cvtsi2ssq(asFloatReg(dst), asLongReg(src)); break; - case L2D: masm.cvtsi2sdq(asDoubleReg(dst), asLongReg(src)); break; - case F2I: - masm.cvttss2sil(asIntReg(dst), asFloatReg(src)); - emitConvertFixup(tasm, masm, dst, src); - break; - case D2I: - masm.cvttsd2sil(asIntReg(dst), asDoubleReg(src)); - emitConvertFixup(tasm, masm, dst, src); - break; - case F2L: - masm.cvttss2siq(asLongReg(dst), asFloatReg(src)); - emitConvertFixup(tasm, masm, dst, src); - break; - case D2L: - masm.cvttsd2siq(asLongReg(dst), asDoubleReg(src)); - emitConvertFixup(tasm, masm, dst, src); - break; - case MOV_I2F: masm.movdl(asFloatReg(dst), asIntReg(src)); break; - case MOV_L2D: masm.movdq(asDoubleReg(dst), asLongReg(src)); break; - case MOV_F2I: masm.movdl(asIntReg(dst), asFloatReg(src)); break; - case MOV_D2L: masm.movdq(asLongReg(dst), asDoubleReg(src)); break; - - case IDIV: - case IREM: - masm.cdql(); - exceptionOffset = masm.codeBuffer.position(); - masm.idivl(asRegister(src)); - break; - - case LDIV: - case LREM: - Label continuation = new Label(); - if (opcode == LDIV) { - // check for special case of Long.MIN_VALUE / -1 - Label normalCase = new Label(); - masm.movq(AMD64.rdx, java.lang.Long.MIN_VALUE); - masm.cmpq(AMD64.rax, AMD64.rdx); - masm.jcc(ConditionFlag.notEqual, normalCase); - masm.cmpl(asRegister(src), -1); - masm.jcc(ConditionFlag.equal, continuation); - masm.bind(normalCase); - } - - masm.cdqq(); - exceptionOffset = masm.codeBuffer.position(); - masm.idivq(asRegister(src)); - masm.bind(continuation); - break; - - case IUDIV: - case IUREM: - // Must zero the high 64-bit word (in RDX) of the dividend - masm.xorq(AMD64.rdx, AMD64.rdx); - exceptionOffset = masm.codeBuffer.position(); - masm.divl(asRegister(src)); - break; - - case LUDIV: - case LUREM: - // Must zero the high 64-bit word (in RDX) of the dividend - masm.xorq(AMD64.rdx, AMD64.rdx); - exceptionOffset = masm.codeBuffer.position(); - masm.divq(asRegister(src)); - break; - default: - throw Util.shouldNotReachHere(); - } - } else if (isConstant(src)) { - switch (opcode) { - case IADD: masm.incrementl(asIntReg(dst), tasm.asIntConst(src)); break; - case ISUB: masm.decrementl(asIntReg(dst), tasm.asIntConst(src)); break; - case IMUL: masm.imull(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break; - case IAND: masm.andl(asIntReg(dst), tasm.asIntConst(src)); break; - case IOR: masm.orl(asIntReg(dst), tasm.asIntConst(src)); break; - case IXOR: masm.xorl(asIntReg(dst), tasm.asIntConst(src)); break; - case ISHL: masm.shll(asIntReg(dst), tasm.asIntConst(src) & 31); break; - case ISHR: masm.sarl(asIntReg(dst), tasm.asIntConst(src) & 31); break; - case IUSHR:masm.shrl(asIntReg(dst), tasm.asIntConst(src) & 31); break; - - case LADD: masm.addq(asLongReg(dst), tasm.asIntConst(src)); break; - case LSUB: masm.subq(asLongReg(dst), tasm.asIntConst(src)); break; - case LMUL: masm.imulq(asLongReg(dst), asLongReg(dst), tasm.asIntConst(src)); break; - case LAND: masm.andq(asLongReg(dst), tasm.asIntConst(src)); break; - case LOR: masm.orq(asLongReg(dst), tasm.asIntConst(src)); break; - case LXOR: masm.xorq(asLongReg(dst), tasm.asIntConst(src)); break; - case LSHL: masm.shlq(asLongReg(dst), tasm.asIntConst(src) & 63); break; - case LSHR: masm.sarq(asLongReg(dst), tasm.asIntConst(src) & 63); break; - case LUSHR:masm.shrq(asLongReg(dst), tasm.asIntConst(src) & 63); break; - - case FADD: masm.addss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; - case FSUB: masm.subss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; - case FMUL: masm.mulss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; - case FAND: masm.andps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; - case FOR: masm.orps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; - case FXOR: masm.xorps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; - case FDIV: masm.divss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; - - case DADD: masm.addsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DSUB: masm.subsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DMUL: masm.mulsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DDIV: masm.divsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; - case DAND: masm.andpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; - case DOR: masm.orpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; - case DXOR: masm.xorpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; - default: throw Util.shouldNotReachHere(); - } - } else { - switch (opcode) { - case IADD: masm.addl(asIntReg(dst), tasm.asIntAddr(src)); break; - case ISUB: masm.subl(asIntReg(dst), tasm.asIntAddr(src)); break; - case IAND: masm.andl(asIntReg(dst), tasm.asIntAddr(src)); break; - case IOR: masm.orl(asIntReg(dst), tasm.asIntAddr(src)); break; - case IXOR: masm.xorl(asIntReg(dst), tasm.asIntAddr(src)); break; - - case LADD: masm.addq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LSUB: masm.subq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LAND: masm.andq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LOR: masm.orq(asLongReg(dst), tasm.asLongAddr(src)); break; - case LXOR: masm.xorq(asLongReg(dst), tasm.asLongAddr(src)); break; - - case FADD: masm.addss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - case FSUB: masm.subss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - case FMUL: masm.mulss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - case FDIV: masm.divss(asFloatReg(dst), tasm.asFloatAddr(src)); break; - - case DADD: masm.addsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; - case DSUB: masm.subsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; - case DMUL: masm.mulsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; - case DDIV: masm.divsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; - default: throw Util.shouldNotReachHere(); - } - } - - if (info != null) { - assert exceptionOffset != -1; - tasm.recordImplicitException(exceptionOffset, info); - } - } - - private static void emitConvertFixup(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue x) { - ConvertSlowPath slowPath = new ConvertSlowPath(result, x); - tasm.slowPaths.add(slowPath); - switch (result.kind) { - case Int: masm.cmpl(asIntReg(result), Integer.MIN_VALUE); break; - case Long: masm.cmpq(asLongReg(result), tasm.asLongConstRef(CiConstant.forLong(java.lang.Long.MIN_VALUE))); break; - default: throw Util.shouldNotReachHere(); - } - masm.jcc(ConditionFlag.equal, slowPath.start); - masm.bind(slowPath.continuation); - } - - private static class ConvertSlowPath extends AMD64SlowPath { - public final Label start = new Label(); - public final Label continuation = new Label(); - private final CiValue result; - private final CiValue x; - - public ConvertSlowPath(CiValue result, CiValue x) { - this.result = result; - this.x = x; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.bind(start); - switch (x.kind) { - case Float: masm.ucomiss(asFloatReg(x), tasm.asFloatConstRef(CiConstant.FLOAT_0)); break; - case Double: masm.ucomisd(asDoubleReg(x), tasm.asDoubleConstRef(CiConstant.DOUBLE_0)); break; - default: throw Util.shouldNotReachHere(); - } - Label nan = new Label(); - masm.jcc(ConditionFlag.parity, nan); - masm.jcc(ConditionFlag.below, continuation); - - // input is > 0 -> return maxInt - // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff - switch (result.kind) { - case Int: masm.decrementl(asIntReg(result), 1); break; - case Long: masm.decrementq(asLongReg(result), 1); break; - default: throw Util.shouldNotReachHere(); - } - masm.jmp(continuation); - - // input is NaN -> return 0 - masm.bind(nan); - masm.xorptr(asRegister(result), asRegister(result)); - masm.jmp(continuation); - } - } - - - private static void verifyKind(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { - assert (opcode.name().startsWith("I") && result.kind == CiKind.Int && x.kind.stackKind() == CiKind.Int && y.kind.stackKind() == CiKind.Int) - || (opcode.name().startsWith("L") && result.kind == CiKind.Long && x.kind == CiKind.Long && y.kind == CiKind.Long) - || (opcode.name().startsWith("F") && result.kind == CiKind.Float && x.kind == CiKind.Float && y.kind == CiKind.Float) - || (opcode.name().startsWith("D") && result.kind == CiKind.Double && x.kind == CiKind.Double && y.kind == CiKind.Double); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Backend.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Backend.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Backend.java Thu Feb 09 10:03:21 2012 +0100 @@ -28,9 +28,9 @@ import com.oracle.max.cri.ri.*; import com.oracle.max.cri.xir.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.target.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; /** * The {@code X86Backend} class represents the backend for the AMD64 architecture. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Call.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Call.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.target.amd64; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ci.CiTargetMethod.Mark; -import com.oracle.max.cri.xir.CiXirAssembler.XirMark; -import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; - -public class AMD64Call { - - public static class DirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { - private final Object targetMethod; - private final Map marks; - - public DirectCallOp(Object targetMethod, CiValue result, CiValue[] parameters, LIRDebugInfo info, Map marks) { - super("CALL_DIRECT", new CiValue[] {result}, info, parameters, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.targetMethod = targetMethod; - this.marks = marks; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - callAlignment(tasm, masm); - if (marks != null) { - marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); - } - directCall(tasm, masm, targetMethod, info); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - } else if (mode == OperandMode.Output) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); - } - throw Util.shouldNotReachHere(); - } - } - - public static class IndirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { - private final Object targetMethod; - private final Map marks; - - private static CiValue[] concat(CiValue[] parameters, CiValue targetAddress) { - CiValue[] result = Arrays.copyOf(parameters, parameters.length + 1); - result[result.length - 1] = targetAddress; - return result; - } - - public IndirectCallOp(Object targetMethod, CiValue result, CiValue[] parameters, CiValue targetAddress, LIRDebugInfo info, Map marks) { - super("CALL_INDIRECT", new CiValue[] {result}, info, concat(parameters, targetAddress), LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.targetMethod = targetMethod; - this.marks = marks; - } - - private CiValue targetAddress() { - return input(inputs.length - 1); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - callAlignment(tasm, masm); - if (marks != null) { - marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); - } - indirectCall(tasm, masm, asRegister(targetAddress()), targetMethod, info); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - } else if (mode == OperandMode.Output) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); - } - throw Util.shouldNotReachHere(); - } - } - - - public static void callAlignment(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (GraalOptions.AlignCallsForPatching) { - // make sure that the displacement word of the call ends up word aligned - int offset = masm.codeBuffer.position(); - offset += tasm.target.arch.machineCodeCallDisplacementOffset; - while (offset++ % tasm.target.wordSize != 0) { - masm.nop(); - } - } - } - - public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target, LIRDebugInfo info) { - int before = masm.codeBuffer.position(); - if (target instanceof CiRuntimeCall) { - long maxOffset = tasm.runtime.getMaxCallTargetOffset((CiRuntimeCall) target); - if (maxOffset != (int) maxOffset) { - // offset might not fit a 32-bit immediate, generate an - // indirect call with a 64-bit immediate - CiRegister scratch = tasm.frameMap.registerConfig.getScratchRegister(); - // TODO(cwi): we want to get rid of a generally reserved scratch register. - masm.movq(scratch, 0L); - masm.call(scratch); - } else { - masm.call(); - } - } else { - masm.call(); - } - int after = masm.codeBuffer.position(); - tasm.recordDirectCall(before, after, tasm.runtime.asCallTarget(target), info); - tasm.recordExceptionHandlers(after, info); - masm.ensureUniquePC(); - } - - public static void directJmp(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target) { - int before = masm.codeBuffer.position(); - masm.jmp(0, true); - int after = masm.codeBuffer.position(); - tasm.recordDirectCall(before, after, tasm.runtime.asCallTarget(target), null); - masm.ensureUniquePC(); - } - - public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiRegister dst, Object target, LIRDebugInfo info) { - int before = masm.codeBuffer.position(); - masm.call(dst); - int after = masm.codeBuffer.position(); - tasm.recordIndirectCall(before, after, tasm.runtime.asCallTarget(target), info); - tasm.recordExceptionHandlers(after, info); - masm.ensureUniquePC(); - } - - public static void shouldNotReachHere(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (GraalOptions.GenAssertionCode) { - directCall(tasm, masm, CiRuntimeCall.Debug, null); - masm.hlt(); - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Compare.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Compare.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.target.amd64; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; - -public enum AMD64Compare { - ICMP, LCMP, ACMP, FCMP, DCMP; - - public static class CompareOp extends AMD64LIRInstruction { - public CompareOp(AMD64Compare opcode, CiValue x, CiValue y) { - super(opcode, LIRInstruction.NO_OPERANDS, null, new CiValue[] {x, y}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - CiValue x = input(0); - CiValue y = input(1); - emit(tasm, masm, (AMD64Compare) code, x, y); - } - - @Override - public EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Input && index == 1) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } - throw Util.shouldNotReachHere(); - } - - @Override - protected void verify() { - CiValue x = input(0); - CiValue y = input(1); - - super.verify(); - assert (name().startsWith("I") && x.kind == CiKind.Int && y.kind.stackKind() == CiKind.Int) - || (name().startsWith("I") && x.kind == CiKind.Jsr && y.kind == CiKind.Jsr) - || (name().startsWith("L") && x.kind == CiKind.Long && y.kind == CiKind.Long) - || (name().startsWith("A") && x.kind == CiKind.Object && y.kind == CiKind.Object) - || (name().startsWith("F") && x.kind == CiKind.Float && y.kind == CiKind.Float) - || (name().startsWith("D") && x.kind == CiKind.Double && y.kind == CiKind.Double); - } - } - - protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Compare opcode, CiValue x, CiValue y) { - if (isRegister(y)) { - switch (opcode) { - case ICMP: masm.cmpl(asIntReg(x), asIntReg(y)); break; - case LCMP: masm.cmpq(asLongReg(x), asLongReg(y)); break; - case ACMP: masm.cmpptr(asObjectReg(x), asObjectReg(y)); break; - case FCMP: masm.ucomiss(asFloatReg(x), asFloatReg(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), asDoubleReg(y)); break; - default: throw Util.shouldNotReachHere(); - } - } else if (isConstant(y)) { - switch (opcode) { - case ICMP: masm.cmpl(asIntReg(x), tasm.asIntConst(y)); break; - case LCMP: masm.cmpq(asLongReg(x), tasm.asIntConst(y)); break; - case ACMP: - if (((CiConstant) y).isNull()) { - masm.cmpq(asObjectReg(x), 0); break; - } else { - throw Util.shouldNotReachHere("Only null object constants are allowed in comparisons"); - } - case FCMP: masm.ucomiss(asFloatReg(x), tasm.asFloatConstRef(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), tasm.asDoubleConstRef(y)); break; - default: throw Util.shouldNotReachHere(); - } - } else { - switch (opcode) { - case ICMP: masm.cmpl(asIntReg(x), tasm.asIntAddr(y)); break; - case LCMP: masm.cmpq(asLongReg(x), tasm.asLongAddr(y)); break; - case ACMP: masm.cmpptr(asObjectReg(x), tasm.asObjectAddr(y)); break; - case FCMP: masm.ucomiss(asFloatReg(x), tasm.asFloatAddr(y)); break; - case DCMP: masm.ucomisd(asDoubleReg(x), tasm.asDoubleAddr(y)); break; - default: throw Util.shouldNotReachHere(); - } - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64CompareToIntOpcode.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64CompareToIntOpcode.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.target.amd64; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; - -/** - * Implementation of the Java bytecodes that compare a long, float, or double value and produce the - * integer constants -1, 0, 1 on less, equal, or greater, respectively. For floating point compares, - * unordered can be either greater {@link #CMP2INT_UG} or less {@link #CMP2INT_UL}. - */ -public enum AMD64CompareToIntOpcode { - CMP2INT, CMP2INT_UG, CMP2INT_UL; - - public LIRInstruction create(CiValue result) { - CiValue[] outputs = new CiValue[] {result}; - - return new AMD64LIRInstruction(this, outputs, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS) { - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - emit(masm, output(0)); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - }; - } - - private void emit(AMD64MacroAssembler masm, CiValue result) { - CiRegister dest = asIntReg(result); - Label high = new Label(); - Label low = new Label(); - Label done = new Label(); - - // comparison is done by a separate LIR instruction before - switch (this) { - case CMP2INT: - masm.jcc(ConditionFlag.greater, high); - masm.jcc(ConditionFlag.less, low); - break; - case CMP2INT_UG: - masm.jcc(ConditionFlag.parity, high); - masm.jcc(ConditionFlag.above, high); - masm.jcc(ConditionFlag.below, low); - break; - case CMP2INT_UL: - masm.jcc(ConditionFlag.parity, low); - masm.jcc(ConditionFlag.above, high); - masm.jcc(ConditionFlag.below, low); - break; - default: - throw Util.shouldNotReachHere(); - } - - // equal -> 0 - masm.xorptr(dest, dest); - masm.jmp(done); - - // greater -> 1 - masm.bind(high); - masm.xorptr(dest, dest); - masm.incrementl(dest, 1); - masm.jmp(done); - - // less -> -1 - masm.bind(low); - masm.xorptr(dest, dest); - masm.decrementl(dest, 1); - - masm.bind(done); - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ControlFlow.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ControlFlow.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.target.amd64; - -import static com.oracle.max.cri.ci.CiValueUtil.*; - -import java.util.*; - -import com.oracle.max.asm.*; -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ci.CiAddress.Scale; -import com.oracle.max.cri.ci.CiTargetMethod.JumpTable; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; -import com.oracle.max.graal.nodes.calc.*; - -public class AMD64ControlFlow { - - public static class LabelOp extends AMD64LIRInstruction implements StandardOp.LabelOp { - private final Label label; - private final boolean align; - - public LabelOp(Label label, boolean align) { - super("LABEL", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.label = label; - this.align = align; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (align) { - masm.align(tasm.target.wordSize); - } - masm.bind(label); - } - - @Override - public String operationString() { - return label.toString(); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - throw Util.shouldNotReachHere(); - } - - @Override - public Label getLabel() { - return label; - } - } - - - public static class ReturnOp extends AMD64LIRInstruction { - public ReturnOp(CiValue input) { - super("RETURN", LIRInstruction.NO_OPERANDS, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.ret(0); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class JumpOp extends AMD64LIRInstruction implements StandardOp.JumpOp { - private final LabelRef destination; - - public JumpOp(LabelRef destination, LIRDebugInfo info) { - super("JUMP", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.destination = destination; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.jmp(destination.label()); - } - - @Override - public LabelRef destination() { - return destination; - } - - @Override - public String operationString() { - return "[" + destination + "]"; - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - throw Util.shouldNotReachHere(); - } - } - - - public static class BranchOp extends AMD64LIRInstruction implements StandardOp.BranchOp { - protected Condition condition; - protected LabelRef destination; - - public BranchOp(Condition condition, LabelRef destination, LIRDebugInfo info) { - super("BRANCH", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.condition = condition; - this.destination = destination; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.jcc(intCond(condition), destination.label()); - } - - @Override - public LabelRef destination() { - return destination; - } - - @Override - public void negate(LabelRef newDestination) { - destination = newDestination; - condition = condition.negate(); - } - - @Override - public String operationString() { - return condition.operator + " [" + destination + "]"; - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - throw Util.shouldNotReachHere(); - } - } - - - public static class FloatBranchOp extends BranchOp { - protected boolean unorderedIsTrue; - - public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef destination, LIRDebugInfo info) { - super(condition, destination, info); - this.unorderedIsTrue = unorderedIsTrue; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - floatJcc(masm, condition, unorderedIsTrue, destination.label()); - } - - @Override - public void negate(LabelRef newDestination) { - super.negate(newDestination); - unorderedIsTrue = !unorderedIsTrue; - } - - @Override - public String operationString() { - return condition.operator + " [" + destination + "]" + (unorderedIsTrue ? " unorderedIsTrue" : " unorderedIsFalse"); - } - } - - - public static class TableSwitchOp extends AMD64LIRInstruction { - private final int lowKey; - private final LabelRef defaultTarget; - private final LabelRef[] targets; - - public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) { - super("TABLE_SWITCH", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, new CiValue[] {index}, new CiValue[] {scratch}); - this.lowKey = lowKey; - this.defaultTarget = defaultTarget; - this.targets = targets; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - tableswitch(tasm, masm, lowKey, defaultTarget, targets, asIntReg(alive(0)), asLongReg(temp(0))); - } - - @Override - public String operationString() { - StringBuilder buf = new StringBuilder(super.operationString()); - buf.append("\ndefault: [").append(defaultTarget).append(']'); - int key = lowKey; - for (LabelRef l : targets) { - buf.append("\ncase ").append(key).append(": [").append(l).append(']'); - key++; - } - return buf.toString(); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Alive && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Temp && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class CondMoveOp extends AMD64LIRInstruction { - private final Condition condition; - - public CondMoveOp(Variable result, Condition condition, Variable trueValue, CiValue falseValue) { - super("CMOVE", new CiValue[] {result}, null, new CiValue[] {falseValue}, new CiValue[] {trueValue}, LIRInstruction.NO_OPERANDS); - this.condition = condition; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - cmove(tasm, masm, output(0), false, condition, false, alive(0), input(0)); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Alive && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); - } - throw Util.shouldNotReachHere(); - } - - @Override - public String operationString() { - return condition.toString() + " " + super.operationString(); - } - } - - - public static class FloatCondMoveOp extends AMD64LIRInstruction { - private final Condition condition; - private final boolean unorderedIsTrue; - - public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { - super("FLOAT_CMOVE", new CiValue[] {result}, null, LIRInstruction.NO_OPERANDS, new CiValue[] {trueValue, falseValue}, LIRInstruction.NO_OPERANDS); - this.condition = condition; - this.unorderedIsTrue = unorderedIsTrue; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - cmove(tasm, masm, output(0), true, condition, unorderedIsTrue, alive(0), alive(1)); - } - - @Override - public String operationString() { - return condition.toString() + " unordered=" + unorderedIsTrue + " " + super.operationString(); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Alive && index == 0) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Alive && index == 1) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - } - - - private static void tableswitch(TargetMethodAssembler tasm, AMD64MacroAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, CiRegister value, CiRegister scratch) { - Buffer buf = masm.codeBuffer; - // Compare index against jump table bounds - int highKey = lowKey + targets.length - 1; - if (lowKey != 0) { - // subtract the low value from the switch value - masm.subl(value, lowKey); - masm.cmpl(value, highKey - lowKey); - } else { - masm.cmpl(value, highKey); - } - - // Jump to default target if index is not within the jump table - masm.jcc(ConditionFlag.above, defaultTarget.label()); - - // Set scratch to address of jump table - int leaPos = buf.position(); - masm.leaq(scratch, new CiAddress(tasm.target.wordKind, AMD64.rip.asValue(), 0)); - int afterLea = buf.position(); - - // Load jump table entry into scratch and jump to it - masm.movslq(value, new CiAddress(CiKind.Int, scratch.asValue(), value.asValue(), Scale.Times4, 0)); - masm.addq(scratch, value); - masm.jmp(scratch); - - // Inserting padding so that jump table address is 4-byte aligned - if ((buf.position() & 0x3) != 0) { - masm.nop(4 - (buf.position() & 0x3)); - } - - // Patch LEA instruction above now that we know the position of the jump table - int jumpTablePos = buf.position(); - buf.setPosition(leaPos); - masm.leaq(scratch, new CiAddress(tasm.target.wordKind, AMD64.rip.asValue(), jumpTablePos - afterLea)); - buf.setPosition(jumpTablePos); - - // Emit jump table entries - for (LabelRef target : targets) { - Label label = target.label(); - int offsetToJumpTableBase = buf.position() - jumpTablePos; - if (label.isBound()) { - int imm32 = label.position() - jumpTablePos; - buf.emitInt(imm32); - } else { - label.addPatchAt(buf.position()); - - buf.emitByte(0); // psuedo-opcode for jump table entry - buf.emitShort(offsetToJumpTableBase); - buf.emitByte(0); // padding to make jump table entry 4 bytes wide - } - } - - JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4); - tasm.targetMethod.addAnnotation(jt); - } - - private static void floatJcc(AMD64MacroAssembler masm, Condition condition, boolean unorderedIsTrue, Label label) { - ConditionFlag cond = floatCond(condition); - Label endLabel = new Label(); - if (unorderedIsTrue && !trueOnUnordered(cond)) { - masm.jcc(ConditionFlag.parity, label); - } else if (!unorderedIsTrue && trueOnUnordered(cond)) { - masm.jcc(ConditionFlag.parity, endLabel); - } - masm.jcc(cond, label); - masm.bind(endLabel); - } - - private static void cmove(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, boolean isFloat, Condition condition, boolean unorderedIsTrue, CiValue trueValue, CiValue falseValue) { - ConditionFlag cond = isFloat ? floatCond(condition) : intCond(condition); - // check that we don't overwrite an input operand before it is used. - assert !result.equals(trueValue); - - AMD64Move.move(tasm, masm, result, falseValue); - cmove(tasm, masm, result, cond, trueValue); - - if (isFloat) { - if (unorderedIsTrue && !trueOnUnordered(cond)) { - cmove(tasm, masm, result, ConditionFlag.parity, trueValue); - } else if (!unorderedIsTrue && trueOnUnordered(cond)) { - cmove(tasm, masm, result, ConditionFlag.parity, falseValue); - } - } - } - - private static void cmove(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, ConditionFlag cond, CiValue other) { - if (isRegister(other)) { - assert asRegister(other) != asRegister(result) : "other already overwritten by previous move"; - switch (other.kind) { - case Int: masm.cmovl(cond, asRegister(result), asRegister(other)); break; - case Long: masm.cmovq(cond, asRegister(result), asRegister(other)); break; - default: throw Util.shouldNotReachHere(); - } - } else { - switch (other.kind) { - case Int: masm.cmovl(cond, asRegister(result), tasm.asAddress(other)); break; - case Long: masm.cmovq(cond, asRegister(result), tasm.asAddress(other)); break; - default: throw Util.shouldNotReachHere(); - } - } - } - - private static ConditionFlag intCond(Condition cond) { - switch (cond) { - case EQ: return ConditionFlag.equal; - case NE: return ConditionFlag.notEqual; - case LT: return ConditionFlag.less; - case LE: return ConditionFlag.lessEqual; - case GE: return ConditionFlag.greaterEqual; - case GT: return ConditionFlag.greater; - case BE: return ConditionFlag.belowEqual; - case AE: return ConditionFlag.aboveEqual; - case AT: return ConditionFlag.above; - case BT: return ConditionFlag.below; - case OF: return ConditionFlag.overflow; - case NOF: return ConditionFlag.noOverflow; - default: throw Util.shouldNotReachHere(); - } - } - - private static ConditionFlag floatCond(Condition cond) { - switch (cond) { - case EQ: return ConditionFlag.equal; - case NE: return ConditionFlag.notEqual; - case BT: return ConditionFlag.below; - case BE: return ConditionFlag.belowEqual; - case AE: return ConditionFlag.aboveEqual; - case AT: return ConditionFlag.above; - default: throw Util.shouldNotReachHere(); - } - } - - private static boolean trueOnUnordered(ConditionFlag condition) { - switch(condition) { - case aboveEqual: - case notEqual: - case above: - case less: - case overflow: - return false; - case equal: - case belowEqual: - case below: - case greaterEqual: - case noOverflow: - return true; - default: - throw Util.shouldNotReachHere(); - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64DeoptimizationStub.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64DeoptimizationStub.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64DeoptimizationStub.java Thu Feb 09 10:03:21 2012 +0100 @@ -28,9 +28,10 @@ import com.oracle.max.asm.target.amd64.*; import com.oracle.max.cri.ci.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.amd64.*; +import com.oracle.max.graal.lir.asm.*; import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction; public class AMD64DeoptimizationStub extends AMD64SlowPath { @@ -79,7 +80,7 @@ code = 4; break; default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } masm.movq(scratch, code); // TODO Why use scratch register here? Is it an implicit calling convention that the runtime function reads this register? diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Thu Feb 09 10:03:21 2012 +0100 @@ -24,9 +24,9 @@ package com.oracle.max.graal.compiler.target.amd64; import static com.oracle.max.cri.ci.CiValueUtil.*; -import static com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.*; -import static com.oracle.max.graal.compiler.target.amd64.AMD64Compare.*; -import static com.oracle.max.graal.compiler.target.amd64.AMD64CompareToIntOpcode.*; +import static com.oracle.max.graal.lir.amd64.AMD64Arithmetic.*; +import static com.oracle.max.graal.lir.amd64.AMD64Compare.*; +import static com.oracle.max.graal.lir.amd64.AMD64CompareToIntOpcode.*; import java.util.*; @@ -38,35 +38,35 @@ import com.oracle.max.cri.xir.CiXirAssembler.XirMark; import com.oracle.max.cri.xir.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.DivOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.Op1Reg; -import com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.Op1Stack; -import com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.Op2Reg; -import com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.Op2Stack; -import com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.ShiftOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Call.DirectCallOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Call.IndirectCallOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Compare.CompareOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.BranchOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.CondMoveOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.FloatBranchOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.FloatCondMoveOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.JumpOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.LabelOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.ReturnOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.TableSwitchOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.CompareAndSwapOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.LeaOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.LoadOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.MembarOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.MoveFromRegOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.MoveToRegOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.NullCheckOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.SpillMoveOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64Move.StoreOp; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.StandardOp.JumpOp; +import com.oracle.max.graal.lir.StandardOp.LabelOp; +import com.oracle.max.graal.lir.amd64.AMD64Arithmetic.DivOp; +import com.oracle.max.graal.lir.amd64.AMD64Arithmetic.Op1Reg; +import com.oracle.max.graal.lir.amd64.AMD64Arithmetic.Op1Stack; +import com.oracle.max.graal.lir.amd64.AMD64Arithmetic.Op2Reg; +import com.oracle.max.graal.lir.amd64.AMD64Arithmetic.Op2Stack; +import com.oracle.max.graal.lir.amd64.AMD64Arithmetic.ShiftOp; +import com.oracle.max.graal.lir.amd64.AMD64Call.DirectCallOp; +import com.oracle.max.graal.lir.amd64.AMD64Call.IndirectCallOp; +import com.oracle.max.graal.lir.amd64.AMD64Compare.CompareOp; +import com.oracle.max.graal.lir.amd64.AMD64ControlFlow.BranchOp; +import com.oracle.max.graal.lir.amd64.AMD64ControlFlow.CondMoveOp; +import com.oracle.max.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp; +import com.oracle.max.graal.lir.amd64.AMD64ControlFlow.FloatCondMoveOp; +import com.oracle.max.graal.lir.amd64.AMD64ControlFlow.ReturnOp; +import com.oracle.max.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.CompareAndSwapOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.LeaOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.LoadOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.MembarOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.MoveFromRegOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.MoveToRegOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.NullCheckOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.SpillMoveOp; +import com.oracle.max.graal.lir.amd64.AMD64Move.StoreOp; import com.oracle.max.graal.nodes.DeoptimizeNode.DeoptAction; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.calc.*; @@ -222,7 +222,7 @@ case Object: append(new BranchOp(cond, label, info)); break; case Float: case Double: append(new FloatBranchOp(cond, unorderedIsTrue, label, info)); break; - default: throw Util.shouldNotReachHere("" + left.kind); + default: throw GraalInternalError.shouldNotReachHere("" + left.kind); } } @@ -253,7 +253,7 @@ case Object: append(new CompareOp(ACMP, left, right)); break; case Float: append(new CompareOp(FCMP, left, right)); break; case Double: append(new CompareOp(DCMP, left, right)); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } } @@ -265,7 +265,7 @@ case Long: append(new Op1Stack(LNEG, result, input)); break; case Float: append(new Op2Reg(FXOR, result, input, CiConstant.forFloat(Float.intBitsToFloat(0x80000000)))); break; case Double: append(new Op2Reg(DXOR, result, input, CiConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)))); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -278,7 +278,7 @@ case Long: append(new Op2Stack(LADD, result, a, loadNonConst(b))); break; case Float: append(new Op2Stack(FADD, result, a, loadNonConst(b))); break; case Double: append(new Op2Stack(DADD, result, a, loadNonConst(b))); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -291,7 +291,7 @@ case Long: append(new Op2Stack(LSUB, result, a, loadNonConst(b))); break; case Float: append(new Op2Stack(FSUB, result, a, loadNonConst(b))); break; case Double: append(new Op2Stack(DSUB, result, a, loadNonConst(b))); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -304,7 +304,7 @@ case Long: append(new Op2Reg(LMUL, result, a, loadNonConst(b))); break; case Float: append(new Op2Stack(FMUL, result, a, loadNonConst(b))); break; case Double: append(new Op2Stack(DMUL, result, a, loadNonConst(b))); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -331,7 +331,7 @@ return result; } default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } @@ -351,7 +351,7 @@ case Double: return emitCallToRuntime(CiRuntimeCall.ArithmeticDrem, false, a, b); default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } @@ -367,7 +367,7 @@ append(new DivOp(LUDIV, RAX_L, RAX_L, load(b), state())); return emitMove(RAX_L); default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } @@ -383,7 +383,7 @@ append(new DivOp(LUREM, RDX_L, RAX_L, load(b), state())); return emitMove(RDX_L); default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } @@ -394,7 +394,7 @@ switch(a.kind) { case Int: append(new Op2Stack(IAND, result, a, loadNonConst(b))); break; case Long: append(new Op2Stack(LAND, result, a, loadNonConst(b))); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -405,7 +405,7 @@ switch(a.kind) { case Int: append(new Op2Stack(IOR, result, a, loadNonConst(b))); break; case Long: append(new Op2Stack(LOR, result, a, loadNonConst(b))); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -416,7 +416,7 @@ switch(a.kind) { case Int: append(new Op2Stack(IXOR, result, a, loadNonConst(b))); break; case Long: append(new Op2Stack(LXOR, result, a, loadNonConst(b))); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -428,7 +428,7 @@ switch (a.kind) { case Int: append(new ShiftOp(ISHL, result, a, loadShiftCount(b))); break; case Long: append(new ShiftOp(LSHL, result, a, loadShiftCount(b))); break; - default: Util.shouldNotReachHere(); + default: GraalInternalError.shouldNotReachHere(); } return result; } @@ -439,7 +439,7 @@ switch (a.kind) { case Int: append(new ShiftOp(ISHR, result, a, loadShiftCount(b))); break; case Long: append(new ShiftOp(LSHR, result, a, loadShiftCount(b))); break; - default: Util.shouldNotReachHere(); + default: GraalInternalError.shouldNotReachHere(); } return result; } @@ -450,7 +450,7 @@ switch (a.kind) { case Int: append(new ShiftOp(IUSHR, result, a, loadShiftCount(b))); break; case Long: append(new ShiftOp(LUSHR, result, a, loadShiftCount(b))); break; - default: Util.shouldNotReachHere(); + default: GraalInternalError.shouldNotReachHere(); } return result; } @@ -489,7 +489,7 @@ case MOV_L2D: append(new Op1Reg(MOV_L2D, result, input)); break; case MOV_F2I: append(new Op1Reg(MOV_F2I, result, input)); break; case MOV_D2L: append(new Op1Reg(MOV_D2L, result, input)); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } return result; } @@ -618,7 +618,7 @@ append(CMP2INT.create(result)); break; default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } setResult(x, result); } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRInstruction.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRInstruction.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.target.amd64; - -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; - -/** - * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. - */ -public abstract class AMD64LIRInstruction extends LIRInstruction { - - public AMD64LIRInstruction(Object opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) { - super(opcode, outputs, info, inputs, alives, temps); - } - - @Override - public final void emitCode(TargetMethodAssembler tasm) { - emitCode(tasm, (AMD64MacroAssembler) tasm.asm); - } - - public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm); -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MethodEndStub.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MethodEndStub.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MethodEndStub.java Thu Feb 09 10:03:21 2012 +0100 @@ -24,7 +24,8 @@ import com.oracle.max.asm.target.amd64.*; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.asm.*; +import com.oracle.max.graal.lir.amd64.*; +import com.oracle.max.graal.lir.asm.*; public class AMD64MethodEndStub extends AMD64SlowPath { @Override diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Move.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Move.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,485 +0,0 @@ -/* - * Copyright (c) 2011, 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.max.graal.compiler.target.amd64; - -import static com.oracle.max.cri.ci.CiValueUtil.*; -import static java.lang.Double.*; -import static java.lang.Float.*; - -import java.util.*; - -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.StandardOp.MoveOp; -import com.oracle.max.graal.compiler.util.*; - -public class AMD64Move { - - public static class SpillMoveOp extends AMD64LIRInstruction implements MoveOp { - public SpillMoveOp(CiValue result, CiValue input) { - super("MOVE", new CiValue[] {result}, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - move(tasm, masm, getResult(), getInput()); - } - - @Override - public CiValue getInput() { - return input(0); - } - @Override - public CiValue getResult() { - return output(0); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp { - public MoveToRegOp(CiValue result, CiValue input) { - super("MOVE", new CiValue[] {result}, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - move(tasm, masm, getResult(), getInput()); - } - - @Override - public CiValue getInput() { - return input(0); - } - @Override - public CiValue getResult() { - return output(0); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp { - public MoveFromRegOp(CiValue result, CiValue input) { - super("MOVE", new CiValue[] {result}, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - move(tasm, masm, getResult(), getInput()); - } - - @Override - public CiValue getInput() { - return input(0); - } - @Override - public CiValue getResult() { - return output(0); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.RegisterHint); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class LoadOp extends AMD64LIRInstruction { - public LoadOp(CiValue result, CiValue address, LIRDebugInfo info) { - super("LOAD", new CiValue[] {result}, info, new CiValue[] {address}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - load(tasm, masm, output(0), (CiAddress) input(0), info); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Address); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class StoreOp extends AMD64LIRInstruction { - public StoreOp(CiValue address, CiValue input, LIRDebugInfo info) { - super("STORE", LIRInstruction.NO_OPERANDS, info, new CiValue[] {address, input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - store(tasm, masm, (CiAddress) input(0), input(1), info); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Address); - } else if (mode == OperandMode.Input && index == 1) { - return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class LeaOp extends AMD64LIRInstruction { - public LeaOp(CiValue result, CiValue address) { - super("LEA", new CiValue[] {result}, null, new CiValue[] {address}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.leaq(asLongReg(output(0)), tasm.asAddress(input(0))); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Address, OperandFlag.Stack, OperandFlag.Uninitialized); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class MembarOp extends AMD64LIRInstruction { - private final int barriers; - - public MembarOp(final int barriers) { - super("MEMBAR", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.barriers = barriers; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.membar(barriers); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - throw Util.shouldNotReachHere(); - } - } - - - public static class NullCheckOp extends AMD64LIRInstruction { - public NullCheckOp(Variable input, LIRDebugInfo info) { - super("NULL_CHECK", LIRInstruction.NO_OPERANDS, info, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - tasm.recordImplicitException(masm.codeBuffer.position(), info); - masm.nullCheck(asRegister(input(0))); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - } - - - public static class CompareAndSwapOp extends AMD64LIRInstruction { - public CompareAndSwapOp(CiValue result, CiAddress address, CiValue cmpValue, CiValue newValue) { - super("CAS", new CiValue[] {result}, null, new CiValue[] {address, cmpValue, newValue}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - compareAndSwap(tasm, masm, output(0), asAddress(input(0)), input(1), input(2)); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - if (mode == OperandMode.Input && index == 0) { - return EnumSet.of(OperandFlag.Address); - } else if (mode == OperandMode.Input && index == 1) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Input && index == 2) { - return EnumSet.of(OperandFlag.Register); - } else if (mode == OperandMode.Output && index == 0) { - return EnumSet.of(OperandFlag.Register); - } - throw Util.shouldNotReachHere(); - } - } - - - protected static void move(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue input) { - if (isRegister(input)) { - if (isRegister(result)) { - reg2reg(masm, result, input); - } else if (isStackSlot(result)) { - reg2stack(tasm, masm, result, input); - } else { - throw Util.shouldNotReachHere(); - } - } else if (isStackSlot(input)) { - if (isRegister(result)) { - stack2reg(tasm, masm, result, input); - } else { - throw Util.shouldNotReachHere(); - } - } else if (isConstant(input)) { - if (isRegister(result)) { - const2reg(tasm, masm, result, (CiConstant) input); - } else if (isStackSlot(result)) { - const2stack(tasm, masm, result, (CiConstant) input); - } else { - throw Util.shouldNotReachHere(); - } - } else { - throw Util.shouldNotReachHere(); - } - } - - private static void reg2reg(AMD64MacroAssembler masm, CiValue result, CiValue input) { - if (input.equals(result)) { - return; - } - switch (result.kind) { - case Jsr: - case Int: masm.movl(asRegister(result), asRegister(input)); break; - case Long: masm.movq(asRegister(result), asRegister(input)); break; - case Float: masm.movflt(asFloatReg(result), asFloatReg(input)); break; - case Double: masm.movdbl(asDoubleReg(result), asDoubleReg(input)); break; - case Object: masm.movq(asRegister(result), asRegister(input)); break; - default: throw Util.shouldNotReachHere("kind=" + result.kind); - } - } - - private static void reg2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue input) { - switch (result.kind) { - case Jsr: - case Int: masm.movl(tasm.asAddress(result), asRegister(input)); break; - case Long: masm.movq(tasm.asAddress(result), asRegister(input)); break; - case Float: masm.movflt(tasm.asAddress(result), asFloatReg(input)); break; - case Double: masm.movsd(tasm.asAddress(result), asDoubleReg(input)); break; - case Object: masm.movq(tasm.asAddress(result), asRegister(input)); break; - default: throw Util.shouldNotReachHere(); - } - } - - private static void stack2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue input) { - switch (result.kind) { - case Jsr: - case Int: masm.movl(asRegister(result), tasm.asAddress(input)); break; - case Long: masm.movq(asRegister(result), tasm.asAddress(input)); break; - case Float: masm.movflt(asFloatReg(result), tasm.asAddress(input)); break; - case Double: masm.movdbl(asDoubleReg(result), tasm.asAddress(input)); break; - case Object: masm.movq(asRegister(result), tasm.asAddress(input)); break; - default: throw Util.shouldNotReachHere(); - } - } - - private static void const2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiConstant c) { - switch (result.kind) { - case Jsr: - case Int: - // Do not optimize with an XOR as this instruction may be between - // a CMP and a Jcc in which case the XOR will modify the condition - // flags and interfere with the Jcc. - masm.movl(asRegister(result), tasm.asIntConst(c)); - break; - case Long: - // Do not optimize with an XOR as this instruction may be between - // a CMP and a Jcc in which case the XOR will modify the condition - // flags and interfere with the Jcc. - masm.movq(asRegister(result), c.asLong()); - break; - case Float: - // This is *not* the same as 'constant == 0.0f' in the case where constant is -0.0f - if (Float.floatToRawIntBits(c.asFloat()) == Float.floatToRawIntBits(0.0f)) { - masm.xorps(asFloatReg(result), asFloatReg(result)); - } else { - masm.movflt(asFloatReg(result), tasm.asFloatConstRef(c)); - } - break; - case Double: - // This is *not* the same as 'constant == 0.0d' in the case where constant is -0.0d - if (Double.doubleToRawLongBits(c.asDouble()) == Double.doubleToRawLongBits(0.0d)) { - masm.xorpd(asDoubleReg(result), asDoubleReg(result)); - } else { - masm.movdbl(asDoubleReg(result), tasm.asDoubleConstRef(c)); - } - break; - case Object: - // Do not optimize with an XOR as this instruction may be between - // a CMP and a Jcc in which case the XOR will modify the condition - // flags and interfere with the Jcc. - if (c.isNull()) { - masm.movq(asRegister(result), 0x0L); - } else if (tasm.target.inlineObjects) { - tasm.recordDataReferenceInCode(c, 0); - masm.movq(asRegister(result), 0xDEADDEADDEADDEADL); - } else { - masm.movq(asRegister(result), tasm.recordDataReferenceInCode(c, 0)); - } - break; - default: - throw Util.shouldNotReachHere(); - } - } - - private static void const2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiConstant c) { - switch (result.kind) { - case Jsr: - case Int: masm.movl(tasm.asAddress(result), c.asInt()); break; - case Long: masm.movlong(tasm.asAddress(result), c.asLong()); break; - case Float: masm.movl(tasm.asAddress(result), floatToRawIntBits(c.asFloat())); break; - case Double: masm.movlong(tasm.asAddress(result), doubleToRawLongBits(c.asDouble())); break; - case Object: - if (c.isNull()) { - masm.movlong(tasm.asAddress(result), 0L); - } else { - throw Util.shouldNotReachHere("Non-null object constants must be in register"); - } - break; - default: - throw Util.shouldNotReachHere(); - } - } - - - protected static void load(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiAddress loadAddr, LIRDebugInfo info) { - if (info != null) { - tasm.recordImplicitException(masm.codeBuffer.position(), info); - } - switch (loadAddr.kind) { - case Boolean: - case Byte: masm.movsxb(asRegister(result), loadAddr); break; - case Char: masm.movzxl(asRegister(result), loadAddr); break; - case Short: masm.movswl(asRegister(result), loadAddr); break; - case Int: masm.movslq(asRegister(result), loadAddr); break; - case Long: masm.movq(asRegister(result), loadAddr); break; - case Float: masm.movflt(asFloatReg(result), loadAddr); break; - case Double: masm.movdbl(asDoubleReg(result), loadAddr); break; - case Object: masm.movq(asRegister(result), loadAddr); break; - default: throw Util.shouldNotReachHere(); - } - } - - protected static void store(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiAddress storeAddr, CiValue input, LIRDebugInfo info) { - if (info != null) { - tasm.recordImplicitException(masm.codeBuffer.position(), info); - } - - if (isRegister(input)) { - switch (storeAddr.kind) { - case Boolean: - case Byte: masm.movb(storeAddr, asRegister(input)); break; - case Char: - case Short: masm.movw(storeAddr, asRegister(input)); break; - case Int: masm.movl(storeAddr, asRegister(input)); break; - case Long: masm.movq(storeAddr, asRegister(input)); break; - case Float: masm.movflt(storeAddr, asFloatReg(input)); break; - case Double: masm.movsd(storeAddr, asDoubleReg(input)); break; - case Object: masm.movq(storeAddr, asRegister(input)); break; - default: throw Util.shouldNotReachHere(); - } - } else if (isConstant(input)) { - CiConstant c = (CiConstant) input; - switch (storeAddr.kind) { - case Boolean: - case Byte: masm.movb(storeAddr, c.asInt() & 0xFF); break; - case Char: - case Short: masm.movw(storeAddr, c.asInt() & 0xFFFF); break; - case Jsr: - case Int: masm.movl(storeAddr, c.asInt()); break; - case Long: - if (Util.isInt(c.asLong())) { - masm.movslq(storeAddr, (int) c.asLong()); - } else { - throw Util.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - case Float: masm.movl(storeAddr, floatToRawIntBits(c.asFloat())); break; - case Double: throw Util.shouldNotReachHere("Cannot store 64-bit constants to memory"); - case Object: - if (c.isNull()) { - masm.movptr(storeAddr, 0); - } else { - throw Util.shouldNotReachHere("Cannot store 64-bit constants to memory"); - } - break; - default: - throw Util.shouldNotReachHere(); - } - - } else { - throw Util.shouldNotReachHere(); - } - } - - protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiAddress address, CiValue cmpValue, CiValue newValue) { - assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax; - - if (tasm.target.isMP) { - masm.lock(); - } - switch (cmpValue.kind) { - case Int: masm.cmpxchgl(asRegister(newValue), address); break; - case Long: - case Object: masm.cmpxchgq(asRegister(newValue), address); break; - default: throw Util.shouldNotReachHere(); - } - } -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64SlowPath.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64SlowPath.java Thu Feb 09 10:03:00 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - * 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.max.graal.compiler.target.amd64; - -import com.oracle.max.asm.target.amd64.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; - -/** - * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. - */ -public abstract class AMD64SlowPath implements LIR.SlowPath { - @Override - public final void emitCode(TargetMethodAssembler tasm) { - emitCode(tasm, (AMD64MacroAssembler) tasm.asm); - } - - public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm); -} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirOp.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirOp.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirOp.java Thu Feb 09 10:03:21 2012 +0100 @@ -39,9 +39,10 @@ import com.oracle.max.cri.xir.CiXirAssembler.XirLabel; import com.oracle.max.cri.xir.CiXirAssembler.XirMark; import com.oracle.max.graal.compiler.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.amd64.*; +import com.oracle.max.graal.lir.asm.*; public class AMD64XirOp extends LIRXirInstruction { public AMD64XirOp(XirSnippet snippet, CiValue[] operands, CiValue outputOperand, CiValue[] inputs, CiValue[] temps, int[] inputOperandIndices, int[] tempOperandIndices, int outputOperandIndex, @@ -480,7 +481,7 @@ break; } default: - throw Util.shouldNotReachHere("Unknown XIR operation " + inst.op); + throw GraalInternalError.shouldNotReachHere("Unknown XIR operation " + inst.op); } } } @@ -493,7 +494,7 @@ case Long: code = longOp; break; case Float: code = floatOp; break; case Double: code = doubleOp; break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } assert left == result; if (isRegister(right) && right.kind != result.kind) { @@ -514,7 +515,7 @@ case Object: code = AMD64Compare.ACMP; break; case Float: code = AMD64Compare.FCMP; break; case Double: code = AMD64Compare.DCMP; break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } AMD64Compare.emit(tasm, masm, code, x, y); masm.jcc(cflag, label); diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java Thu Feb 09 10:03:21 2012 +0100 @@ -82,6 +82,8 @@ this.level = level; } + public abstract int compiledCodeSize(); + @Override public int compareTo(InlineInfo o) { return (weight < o.weight) ? -1 : (weight > o.weight) ? 1 : 0; @@ -128,6 +130,11 @@ } @Override + public int compiledCodeSize() { + return concrete.compiledCodeSize(); + } + + @Override public String toString() { return "exact inlining " + CiUtil.format("%H.%n(%p):%r", concrete); } @@ -153,6 +160,11 @@ } @Override + public int compiledCodeSize() { + return concrete.compiledCodeSize(); + } + + @Override public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { // receiver null check must be before the type check InliningUtil.receiverNullCheck(invoke); @@ -206,6 +218,15 @@ } @Override + public int compiledCodeSize() { + int result = 0; + for (RiResolvedMethod m: concretes) { + result += m.compiledCodeSize(); + } + return result; + } + + @Override public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) { int numberOfMethods = concretes.size(); boolean hasReturnValue = invoke.node().kind() != CiKind.Void; @@ -384,9 +405,12 @@ InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke; BeginNode exceptionEdge = invokeWithException.exceptionEdge(); ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next(); + FrameState stateAfter = exceptionObject.stateAfter(); BeginNode newExceptionEdge = (BeginNode) exceptionEdge.copyWithInputs(); ExceptionObjectNode newExceptionObject = (ExceptionObjectNode) exceptionObject.copyWithInputs(); + // set new state (pop old exception object, push new one) + newExceptionObject.setStateAfter(stateAfter.duplicateModified(stateAfter.bci, stateAfter.rethrowException(), CiKind.Object, newExceptionObject)); newExceptionEdge.setNext(newExceptionObject); EndNode endNode = graph.add(new EndNode()); @@ -401,7 +425,7 @@ @Override public String toString() { - StringBuilder builder = new StringBuilder(String.format("type-checked inlining of %d methods with %d type checks: ", concretes.size(), types.length)); + StringBuilder builder = new StringBuilder(String.format("inlining %d methods with %d type checks: ", concretes.size(), types.length)); for (int i = 0; i < concretes.size(); i++) { builder.append(CiUtil.format(" %H.%n(%p):%r", concretes.get(i))); } @@ -518,7 +542,7 @@ if (GraalOptions.InlineMonomorphicCalls) { RiResolvedType type = types[0]; RiResolvedMethod concrete = type.resolveMethodImpl(callTarget.targetMethod()); - if (concrete != null && checkTargetConditions(concrete)) { + if (checkTargetConditions(concrete)) { double weight = callback == null ? 0 : callback.inliningWeight(parent, concrete, invoke); return new TypeGuardInlineInfo(invoke, weight, level, concrete, type); } @@ -530,7 +554,7 @@ return null; } } else { - if (GraalOptions.InlinePolymorphicCalls) { + if (GraalOptions.InlinePolymorphicCalls && notRecordedTypeProbability == 0 || GraalOptions.InlineMegamorphicCalls && notRecordedTypeProbability > 0) { // TODO (ch) inlining of multiple methods should work differently // 1. check which methods can be inlined // 2. for those methods, use weight and probability to compute which of them should be inlined @@ -556,7 +580,7 @@ double totalWeight = 0; boolean canInline = true; for (RiResolvedMethod concrete: concreteMethods) { - if (concrete == null || !checkTargetConditions(concrete)) { + if (!checkTargetConditions(concrete)) { canInline = false; break; } @@ -613,6 +637,10 @@ } private static boolean checkTargetConditions(RiMethod method) { + if (method == null) { + Debug.log("method not resolved"); + return false; + } if (!(method instanceof RiResolvedMethod)) { Debug.log("not inlining %s because it is unresolved", method.toString()); return false; @@ -738,6 +766,7 @@ frameState.replaceAndDelete(stateAfter); } else if (frameState.bci == FrameState.AFTER_EXCEPTION_BCI) { if (frameState.isAlive()) { + // TODO (ch) it happens sometimes that we have a FrameState.AFTER_EXCEPTION_BCI but no stateAtExceptionEdge assert stateAtExceptionEdge != null; frameState.replaceAndDelete(stateAtExceptionEdge); } else { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/Util.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/Util.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/Util.java Thu Feb 09 10:03:21 2012 +0100 @@ -42,22 +42,6 @@ public static final char SUB_SECTION_CHARACTER = '='; public static final char SEPERATOR_CHARACTER = '-'; - public static RuntimeException unimplemented() { - throw new GraalInternalError("unimplemented"); - } - - public static RuntimeException unimplemented(String msg, Object... args) { - throw new GraalInternalError("unimplemented: " + msg, args); - } - - public static RuntimeException shouldNotReachHere() { - throw new GraalInternalError("should not reach here"); - } - - public static RuntimeException shouldNotReachHere(String msg, Object... args) { - throw new GraalInternalError("should not reach here: " + msg, args); - } - public static boolean replaceInList(T a, T b, List list) { final int max = list.size(); for (int i = 0; i < max; i++) { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/GraalInternalError.java --- a/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/GraalInternalError.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.graph/src/com/oracle/max/graal/graph/GraalInternalError.java Thu Feb 09 10:03:21 2012 +0100 @@ -30,13 +30,30 @@ public class GraalInternalError extends Error { /** - * + * */ private static final long serialVersionUID = 8776065085829593278L; private Node node; private Graph graph; private final ArrayList context = new ArrayList<>(); + public static RuntimeException unimplemented() { + throw new GraalInternalError("unimplemented"); + } + + public static RuntimeException unimplemented(String msg) { + throw new GraalInternalError("unimplemented: %s", msg); + } + + public static RuntimeException shouldNotReachHere() { + throw new GraalInternalError("should not reach here"); + } + + public static RuntimeException shouldNotReachHere(String msg) { + throw new GraalInternalError("should not reach here: %s", msg); + } + + /** * This constructor creates a {@link GraalInternalError} with a message assembled via {@link String#format(String, Object...)}. * It always uses the ENGLISH locale in order to always generate the same output. diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java Thu Feb 09 10:03:21 2012 +0100 @@ -49,6 +49,7 @@ this.dumpFilter = dumpFilter; this.methodFilter = methodFilter; dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort)); + dumpHandlers.add(new CFGPrinterObserver()); } public boolean isLogEnabled() { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVM.java Thu Feb 09 10:03:21 2012 +0100 @@ -99,6 +99,8 @@ boolean RiMethod_hasCompiledCode(HotSpotMethodResolved method); + int RiMethod_getCompiledCodeSize(HotSpotMethodResolved method); + RiMethod getRiMethod(Method reflectionMethod); long getMaxCallTargetOffset(CiRuntimeCall rtcall); diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/bridge/CompilerToVMImpl.java Thu Feb 09 10:03:21 2012 +0100 @@ -145,6 +145,9 @@ public native boolean RiMethod_hasCompiledCode(HotSpotMethodResolved method); @Override + public native int RiMethod_getCompiledCodeSize(HotSpotMethodResolved method); + + @Override public native long getMaxCallTargetOffset(CiRuntimeCall rtcall); @Override diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java Thu Feb 09 10:03:21 2012 +0100 @@ -44,7 +44,8 @@ // TODO (ch) use same logic as in NodeClass? private static final Unsafe unsafe = Unsafe.getUnsafe(); - private static final HotSpotMethodDataAccessor NO_DATA_ACCESSOR = new NoMethodData(); + private static final HotSpotMethodDataAccessor NO_DATA_NO_EXCEPTION_ACCESSOR = new NoMethodData(RiExceptionSeen.FALSE); + private static final HotSpotMethodDataAccessor NO_DATA_EXCEPTION_POSSIBLE_ACCESSOR = new NoMethodData(RiExceptionSeen.UNKNOWN); private static final HotSpotVMConfig config; // sorted by tag private static final HotSpotMethodDataAccessor[] PROFILE_DATA_ACCESSORS = { @@ -109,8 +110,12 @@ return getData(position); } - public static HotSpotMethodDataAccessor getNoMethodData() { - return NO_DATA_ACCESSOR; + public static HotSpotMethodDataAccessor getNoDataNoExceptionAccessor() { + return NO_DATA_NO_EXCEPTION_ACCESSOR; + } + + public static HotSpotMethodDataAccessor getNoDataExceptionPossibleAccessor() { + return NO_DATA_EXCEPTION_POSSIBLE_ACCESSOR; } private HotSpotMethodDataAccessor getData(int position) { @@ -196,8 +201,8 @@ } @Override - public boolean getExceptionSeen(HotSpotMethodData data, int position) { - return (getFlags(data, position) & EXCEPTIONS_MASK) != 0; + public RiExceptionSeen getExceptionSeen(HotSpotMethodData data, int position) { + return RiExceptionSeen.get((getFlags(data, position) & EXCEPTIONS_MASK) != 0); } @Override @@ -233,8 +238,11 @@ private static final int NO_DATA_TAG = 0; private static final int NO_DATA_SIZE = cellIndexToOffset(0); - protected NoMethodData() { + private final RiExceptionSeen exceptionSeen; + + protected NoMethodData(RiExceptionSeen exceptionSeen) { super(NO_DATA_TAG, NO_DATA_SIZE); + this.exceptionSeen = exceptionSeen; } @Override @@ -244,8 +252,8 @@ @Override - public boolean getExceptionSeen(HotSpotMethodData data, int position) { - return false; + public RiExceptionSeen getExceptionSeen(HotSpotMethodData data, int position) { + return exceptionSeen; } } @@ -363,7 +371,11 @@ return createRiTypeProfile(sparseTypes, counts, totalCount, entries); } - protected abstract long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position); + protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { + // checkcast/aastore/instanceof profiling in the HotSpot template-based interpreter was adjusted so that the counter + // is incremented to indicate the polymorphic case instead of decrementing it for failed type checks + return getCounterValue(data, position); + } private static RiTypeProfile createRiTypeProfile(RiResolvedType[] sparseTypes, double[] counts, long totalCount, int entries) { RiResolvedType[] types; @@ -410,12 +422,6 @@ public int getExecutionCount(HotSpotMethodData data, int position) { return -1; } - - @Override - protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { - // TODO (ch) if types do not fit, profiling is skipped for typechecks - return 0; - } } private static class VirtualCallData extends AbstractTypeData { @@ -437,11 +443,6 @@ total += getCounterValue(data, position); return truncateLongToInt(total); } - - @Override - protected long getTypesNotRecordedExecutionCount(HotSpotMethodData data, int position) { - return getCounterValue(data, position); - } } private static class RetData extends CounterData { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodDataAccessor.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodDataAccessor.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodDataAccessor.java Thu Feb 09 10:03:21 2012 +0100 @@ -51,6 +51,6 @@ RiTypeProfile getTypeProfile(HotSpotMethodData data, int position); double getBranchTakenProbability(HotSpotMethodData data, int position); double[] getSwitchProbabilities(HotSpotMethodData data, int position); - boolean getExceptionSeen(HotSpotMethodData data, int position); + RiExceptionSeen getExceptionSeen(HotSpotMethodData data, int position); int getExecutionCount(HotSpotMethodData data, int position); } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodResolvedImpl.java Thu Feb 09 10:03:21 2012 +0100 @@ -178,6 +178,10 @@ return compiler.getVMEntries().RiMethod_hasCompiledCode(this); } + public int compiledCodeSize() { + return compiler.getVMEntries().RiMethod_getCompiledCodeSize(this); + } + @Override public RiResolvedType accessor() { return null; @@ -242,8 +246,8 @@ TTY.println(); } - if (profilingInfo.getExceptionSeen(i)) { - TTY.println(" exceptionSeen@%d: true", i); + if (profilingInfo.getExceptionSeen(i) != RiExceptionSeen.FALSE) { + TTY.println(" exceptionSeen@%d: %s", i, profilingInfo.getExceptionSeen(i).name()); } RiTypeProfile typeProfile = profilingInfo.getTypeProfile(i); diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotNoProfilingInfo.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotNoProfilingInfo.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotNoProfilingInfo.java Thu Feb 09 10:03:21 2012 +0100 @@ -32,7 +32,7 @@ * */ private static final long serialVersionUID = 4357945025049704109L; - private static final HotSpotMethodDataAccessor noData = HotSpotMethodData.getNoMethodData(); + private static final HotSpotMethodDataAccessor noData = HotSpotMethodData.getNoDataExceptionPossibleAccessor(); public HotSpotNoProfilingInfo(Compiler compiler) { super(compiler); @@ -54,7 +54,7 @@ } @Override - public boolean getExceptionSeen(int bci) { + public RiExceptionSeen getExceptionSeen(int bci) { return noData.getExceptionSeen(null, -1); } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotProfilingInfo.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotProfilingInfo.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotProfilingInfo.java Thu Feb 09 10:03:21 2012 +0100 @@ -66,7 +66,7 @@ } @Override - public boolean getExceptionSeen(int bci) { + public RiExceptionSeen getExceptionSeen(int bci) { findBCI(bci, true); return dataAccessor.getExceptionSeen(methodData, position); } @@ -95,6 +95,7 @@ } } + boolean exceptionPossiblyNotRecorded = false; if (searchExtraData && methodData.hasExtraData()) { int currentPosition = methodData.getExtraDataBeginOffset(); HotSpotMethodDataAccessor currentAccessor; @@ -106,11 +107,11 @@ } currentPosition = currentPosition + currentAccessor.getSize(methodData, currentPosition); } + + exceptionPossiblyNotRecorded = !methodData.isWithin(currentPosition); } - // TODO (ch) getExceptionSeen() should return UNKNOWN if not enough extra data - - noDataFound(); + noDataFound(exceptionPossiblyNotRecorded); } private void normalDataFound(HotSpotMethodDataAccessor data, int pos, int bci) { @@ -123,8 +124,9 @@ setCurrentData(data, pos); } - private void noDataFound() { - setCurrentData(HotSpotMethodData.getNoMethodData(), -1); + private void noDataFound(boolean exceptionPossible) { + HotSpotMethodDataAccessor accessor = exceptionPossible ? HotSpotMethodData.getNoDataNoExceptionAccessor() : HotSpotMethodData.getNoDataNoExceptionAccessor(); + setCurrentData(accessor, -1); } private void setCurrentData(HotSpotMethodDataAccessor dataAccessor, int position) { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRegisterConfig.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRegisterConfig.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRegisterConfig.java Thu Feb 09 10:03:21 2012 +0100 @@ -28,10 +28,10 @@ import com.oracle.max.asm.target.amd64.*; import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ci.CiCallingConvention.*; -import com.oracle.max.cri.ci.CiRegister.*; +import com.oracle.max.cri.ci.CiCallingConvention.Type; +import com.oracle.max.cri.ci.CiRegister.RegisterFlag; import com.oracle.max.cri.ri.*; -import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; import com.oracle.max.graal.hotspot.*; public class HotSpotRegisterConfig implements RiRegisterConfig { @@ -146,7 +146,7 @@ } break; default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } if (locations[i] == null) { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotTypePrimitive.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotTypePrimitive.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotTypePrimitive.java Thu Feb 09 10:03:21 2012 +0100 @@ -26,7 +26,7 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; -import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; import com.oracle.max.graal.hotspot.Compiler; /** @@ -74,7 +74,7 @@ @Override public CiConstant getEncoding(Representation r) { - throw Util.unimplemented("HotSpotTypePrimitive.getEncoding"); + throw GraalInternalError.unimplemented("HotSpotTypePrimitive.getEncoding"); } @Override diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java Thu Feb 09 10:03:21 2012 +0100 @@ -1173,7 +1173,7 @@ private SimpleTemplates typeCheckTemplates = new SimpleTemplates(NULL_CHECK) { @Override protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(); + asm.restart(CiKind.Void); XirParameter objHub = asm.createInputParameter("objectHub", CiKind.Object); XirOperand hub = asm.createConstantInputParameter("hub", CiKind.Object); XirLabel falseSucc = asm.createInlineLabel(XirLabel.FalseSuccessor); @@ -1185,10 +1185,10 @@ } asm.mov(checkHub, hub); - // if we get an exact match: continue + // if we get an exact match: continue. asm.jneq(falseSucc, objHub, checkHub); - return asm.finishTemplate(objHub, "typeCheck"); + return asm.finishTemplate("typeCheck"); } }; diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/target/amd64/AMD64TailcallOp.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/target/amd64/AMD64TailcallOp.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/target/amd64/AMD64TailcallOp.java Thu Feb 09 10:03:21 2012 +0100 @@ -28,10 +28,10 @@ import com.oracle.max.asm.target.amd64.*; import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.target.amd64.*; -import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.amd64.*; +import com.oracle.max.graal.lir.asm.*; /** * Performs a hard-coded tail call to the specified target, which normally should be an RiCompiledCode instance. @@ -72,6 +72,6 @@ } else if (mode == OperandMode.Temp) { return EnumSet.of(OperandFlag.Register); } - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/BciBlockMapping.java Thu Feb 09 10:03:21 2012 +0100 @@ -388,7 +388,7 @@ case PUTFIELD: case GETFIELD: { if (GraalOptions.AllowExplicitExceptionChecks) { - return profilingInfo.getExceptionSeen(bci); + return profilingInfo.getExceptionSeen(bci) != RiExceptionSeen.FALSE; } } } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java Thu Feb 09 10:03:21 2012 +0100 @@ -323,7 +323,8 @@ assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci"; if (GraalOptions.UseExceptionProbability && method.invocationCount() > GraalOptions.MatureInvocationCount) { - if (bci != FrameState.BEFORE_BCI && exceptionObject == null && !profilingInfo.getExceptionSeen(bci)) { + // be conservative if information was not recorded (could result in endless recompiles otherwise) + if (bci != FrameState.BEFORE_BCI && exceptionObject == null && profilingInfo.getExceptionSeen(bci) == RiExceptionSeen.FALSE) { return null; } } @@ -499,7 +500,7 @@ break; } default: - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } @@ -691,7 +692,7 @@ private static final RiResolvedType[] EMPTY_TYPE_ARRAY = new RiResolvedType[0]; private RiResolvedType[] getTypeCheckHints(RiResolvedType type, int maxHints) { - if (!GraalOptions.UseInstanceOfHints || Util.isFinalClass(type)) { + if (!GraalOptions.UseTypeCheckHints || Util.isFinalClass(type)) { return new RiResolvedType[] {type}; } else { RiResolvedType uniqueSubtype = type.uniqueConcreteSubtype(); diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Arithmetic.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Arithmetic.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.amd64; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; + +public enum AMD64Arithmetic { + IADD, ISUB, IMUL, IDIV, IREM, IUDIV, IUREM, IAND, IOR, IXOR, ISHL, ISHR, IUSHR, + LADD, LSUB, LMUL, LDIV, LREM, LUDIV, LUREM, LAND, LOR, LXOR, LSHL, LSHR, LUSHR, + FADD, FSUB, FMUL, FDIV, FAND, FOR, FXOR, + DADD, DSUB, DMUL, DDIV, DAND, DOR, DXOR, + INEG, LNEG, + I2L, L2I, I2B, I2C, I2S, + F2D, D2F, + I2F, I2D, F2I, D2I, + L2F, L2D, F2L, D2L, + MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L; + + + public static class Op1Reg extends AMD64LIRInstruction { + public Op1Reg(AMD64Arithmetic opcode, CiValue result, CiValue x) { + super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue x = input(0); + + emit(tasm, masm, (AMD64Arithmetic) code, result, x, null); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + public static class Op1Stack extends AMD64LIRInstruction { + public Op1Stack(AMD64Arithmetic opcode, CiValue result, CiValue x) { + super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue x = input(0); + + AMD64Move.move(tasm, masm, result, x); + emit(tasm, masm, (AMD64Arithmetic) code, result); + } + + @Override + public EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + public static class Op2Stack extends AMD64LIRInstruction { + public Op2Stack(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { + super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, new CiValue[] {y}, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = alive(0); + + AMD64Move.move(tasm, masm, result, x); + emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Alive && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public void verify() { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = alive(0); + + super.verify(); + assert differentRegisters(result, y) || sameRegister(x, y); + verifyKind((AMD64Arithmetic) code, result, x, y); + } + } + + public static class Op2Reg extends AMD64LIRInstruction { + public Op2Reg(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { + super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, new CiValue[] {y}, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = alive(0); + + AMD64Move.move(tasm, masm, result, x); + emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Alive && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public void verify() { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = alive(0); + + super.verify(); + assert differentRegisters(result, y) || sameRegister(x, y); + verifyKind((AMD64Arithmetic) code, result, x, y); + } + } + + public static class Op2RegCommutative extends AMD64LIRInstruction { + public Op2RegCommutative(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { + super(opcode, new CiValue[] {result}, null, new CiValue[] {x, y}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = input(1); + + if (sameRegister(result, y)) { + emit(tasm, masm, (AMD64Arithmetic) code, result, x, null); + } else { + AMD64Move.move(tasm, masm, result, x); + emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); + } + } + + @Override + public EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Input && index == 1) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + protected void verify() { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = input(1); + + super.verify(); + verifyKind((AMD64Arithmetic) code, result, x, y); + } + } + + public static class ShiftOp extends AMD64LIRInstruction { + public ShiftOp(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { + super(opcode, new CiValue[] {result}, null, new CiValue[] {x}, new CiValue[] {y}, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = alive(0); + + AMD64Move.move(tasm, masm, result, x); + emit(tasm, masm, (AMD64Arithmetic) code, result, y, null); + } + + @Override + public EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Alive && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public void verify() { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = alive(0); + + super.verify(); + assert isConstant(y) || asRegister(y) == AMD64.rcx; + assert differentRegisters(result, y) || sameRegister(x, y); + verifyKind((AMD64Arithmetic) code, result, x, x); + assert y.kind.stackKind() == CiKind.Int; + } + } + + public static class DivOp extends AMD64LIRInstruction { + public DivOp(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y, LIRDebugInfo info) { + super(opcode, new CiValue[] {result}, info, new CiValue[] {x}, new CiValue[] {y}, new CiValue[] {asRegister(result) == AMD64.rax ? AMD64.rdx.asValue(result.kind) : AMD64.rax.asValue(result.kind)}); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue result = output(0); + CiValue y = alive(0); + + emit(tasm, masm, (AMD64Arithmetic) code, result, y, info); + } + + @Override + public EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Alive && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Temp && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + protected void verify() { + CiValue result = output(0); + CiValue x = input(0); + CiValue y = alive(0); + + super.verify(); + // left input in rax, right input in any register but rax and rdx, result quotient in rax, result remainder in rdx + assert asRegister(x) == AMD64.rax; + assert differentRegisters(y, AMD64.rax.asValue(), AMD64.rdx.asValue()); + assert (name().endsWith("DIV") && asRegister(result) == AMD64.rax) || (name().endsWith("REM") && asRegister(result) == AMD64.rdx); + verifyKind((AMD64Arithmetic) code, result, x, y); + } + } + + + @SuppressWarnings("unused") + protected static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, CiValue result) { + switch (opcode) { + case INEG: masm.negl(asIntReg(result)); break; + case LNEG: masm.negq(asLongReg(result)); break; + case L2I: masm.andl(asIntReg(result), 0xFFFFFFFF); break; + case I2B: masm.signExtendByte(asIntReg(result)); break; + case I2C: masm.andl(asIntReg(result), 0xFFFF); break; + case I2S: masm.signExtendShort(asIntReg(result)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + public static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Arithmetic opcode, CiValue dst, CiValue src, LIRDebugInfo info) { + int exceptionOffset = -1; + if (isRegister(src)) { + switch (opcode) { + case IADD: masm.addl(asIntReg(dst), asIntReg(src)); break; + case ISUB: masm.subl(asIntReg(dst), asIntReg(src)); break; + case IAND: masm.andl(asIntReg(dst), asIntReg(src)); break; + case IMUL: masm.imull(asIntReg(dst), asIntReg(src)); break; + case IOR: masm.orl(asIntReg(dst), asIntReg(src)); break; + case IXOR: masm.xorl(asIntReg(dst), asIntReg(src)); break; + case ISHL: masm.shll(asIntReg(dst)); break; + case ISHR: masm.sarl(asIntReg(dst)); break; + case IUSHR:masm.shrl(asIntReg(dst)); break; + + case LADD: masm.addq(asLongReg(dst), asLongReg(src)); break; + case LSUB: masm.subq(asLongReg(dst), asLongReg(src)); break; + case LMUL: masm.imulq(asLongReg(dst), asLongReg(src)); break; + case LAND: masm.andq(asLongReg(dst), asLongReg(src)); break; + case LOR: masm.orq(asLongReg(dst), asLongReg(src)); break; + case LXOR: masm.xorq(asLongReg(dst), asLongReg(src)); break; + case LSHL: masm.shlq(asLongReg(dst)); break; + case LSHR: masm.sarq(asLongReg(dst)); break; + case LUSHR:masm.shrq(asLongReg(dst)); break; + + case FADD: masm.addss(asFloatReg(dst), asFloatReg(src)); break; + case FSUB: masm.subss(asFloatReg(dst), asFloatReg(src)); break; + case FMUL: masm.mulss(asFloatReg(dst), asFloatReg(src)); break; + case FDIV: masm.divss(asFloatReg(dst), asFloatReg(src)); break; + case FAND: masm.andps(asFloatReg(dst), asFloatReg(src)); break; + case FOR: masm.orps(asFloatReg(dst), asFloatReg(src)); break; + case FXOR: masm.xorps(asFloatReg(dst), asFloatReg(src)); break; + + case DADD: masm.addsd(asDoubleReg(dst), asDoubleReg(src)); break; + case DSUB: masm.subsd(asDoubleReg(dst), asDoubleReg(src)); break; + case DMUL: masm.mulsd(asDoubleReg(dst), asDoubleReg(src)); break; + case DDIV: masm.divsd(asDoubleReg(dst), asDoubleReg(src)); break; + case DAND: masm.andpd(asDoubleReg(dst), asDoubleReg(src)); break; + case DOR: masm.orpd(asDoubleReg(dst), asDoubleReg(src)); break; + case DXOR: masm.xorpd(asDoubleReg(dst), asDoubleReg(src)); break; + + case I2L: masm.movslq(asLongReg(dst), asIntReg(src)); break; + case F2D: masm.cvtss2sd(asDoubleReg(dst), asFloatReg(src)); break; + case D2F: masm.cvtsd2ss(asFloatReg(dst), asDoubleReg(src)); break; + case I2F: masm.cvtsi2ssl(asFloatReg(dst), asIntReg(src)); break; + case I2D: masm.cvtsi2sdl(asDoubleReg(dst), asIntReg(src)); break; + case L2F: masm.cvtsi2ssq(asFloatReg(dst), asLongReg(src)); break; + case L2D: masm.cvtsi2sdq(asDoubleReg(dst), asLongReg(src)); break; + case F2I: + masm.cvttss2sil(asIntReg(dst), asFloatReg(src)); + emitConvertFixup(tasm, masm, dst, src); + break; + case D2I: + masm.cvttsd2sil(asIntReg(dst), asDoubleReg(src)); + emitConvertFixup(tasm, masm, dst, src); + break; + case F2L: + masm.cvttss2siq(asLongReg(dst), asFloatReg(src)); + emitConvertFixup(tasm, masm, dst, src); + break; + case D2L: + masm.cvttsd2siq(asLongReg(dst), asDoubleReg(src)); + emitConvertFixup(tasm, masm, dst, src); + break; + case MOV_I2F: masm.movdl(asFloatReg(dst), asIntReg(src)); break; + case MOV_L2D: masm.movdq(asDoubleReg(dst), asLongReg(src)); break; + case MOV_F2I: masm.movdl(asIntReg(dst), asFloatReg(src)); break; + case MOV_D2L: masm.movdq(asLongReg(dst), asDoubleReg(src)); break; + + case IDIV: + case IREM: + masm.cdql(); + exceptionOffset = masm.codeBuffer.position(); + masm.idivl(asRegister(src)); + break; + + case LDIV: + case LREM: + Label continuation = new Label(); + if (opcode == LDIV) { + // check for special case of Long.MIN_VALUE / -1 + Label normalCase = new Label(); + masm.movq(AMD64.rdx, java.lang.Long.MIN_VALUE); + masm.cmpq(AMD64.rax, AMD64.rdx); + masm.jcc(ConditionFlag.notEqual, normalCase); + masm.cmpl(asRegister(src), -1); + masm.jcc(ConditionFlag.equal, continuation); + masm.bind(normalCase); + } + + masm.cdqq(); + exceptionOffset = masm.codeBuffer.position(); + masm.idivq(asRegister(src)); + masm.bind(continuation); + break; + + case IUDIV: + case IUREM: + // Must zero the high 64-bit word (in RDX) of the dividend + masm.xorq(AMD64.rdx, AMD64.rdx); + exceptionOffset = masm.codeBuffer.position(); + masm.divl(asRegister(src)); + break; + + case LUDIV: + case LUREM: + // Must zero the high 64-bit word (in RDX) of the dividend + masm.xorq(AMD64.rdx, AMD64.rdx); + exceptionOffset = masm.codeBuffer.position(); + masm.divq(asRegister(src)); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(src)) { + switch (opcode) { + case IADD: masm.incrementl(asIntReg(dst), tasm.asIntConst(src)); break; + case ISUB: masm.decrementl(asIntReg(dst), tasm.asIntConst(src)); break; + case IMUL: masm.imull(asIntReg(dst), asIntReg(dst), tasm.asIntConst(src)); break; + case IAND: masm.andl(asIntReg(dst), tasm.asIntConst(src)); break; + case IOR: masm.orl(asIntReg(dst), tasm.asIntConst(src)); break; + case IXOR: masm.xorl(asIntReg(dst), tasm.asIntConst(src)); break; + case ISHL: masm.shll(asIntReg(dst), tasm.asIntConst(src) & 31); break; + case ISHR: masm.sarl(asIntReg(dst), tasm.asIntConst(src) & 31); break; + case IUSHR:masm.shrl(asIntReg(dst), tasm.asIntConst(src) & 31); break; + + case LADD: masm.addq(asLongReg(dst), tasm.asIntConst(src)); break; + case LSUB: masm.subq(asLongReg(dst), tasm.asIntConst(src)); break; + case LMUL: masm.imulq(asLongReg(dst), asLongReg(dst), tasm.asIntConst(src)); break; + case LAND: masm.andq(asLongReg(dst), tasm.asIntConst(src)); break; + case LOR: masm.orq(asLongReg(dst), tasm.asIntConst(src)); break; + case LXOR: masm.xorq(asLongReg(dst), tasm.asIntConst(src)); break; + case LSHL: masm.shlq(asLongReg(dst), tasm.asIntConst(src) & 63); break; + case LSHR: masm.sarq(asLongReg(dst), tasm.asIntConst(src) & 63); break; + case LUSHR:masm.shrq(asLongReg(dst), tasm.asIntConst(src) & 63); break; + + case FADD: masm.addss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; + case FSUB: masm.subss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; + case FMUL: masm.mulss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; + case FAND: masm.andps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; + case FOR: masm.orps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; + case FXOR: masm.xorps(asFloatReg(dst), tasm.asFloatConstRef(src, 16)); break; + case FDIV: masm.divss(asFloatReg(dst), tasm.asFloatConstRef(src)); break; + + case DADD: masm.addsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; + case DSUB: masm.subsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; + case DMUL: masm.mulsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; + case DDIV: masm.divsd(asDoubleReg(dst), tasm.asDoubleConstRef(src)); break; + case DAND: masm.andpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; + case DOR: masm.orpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; + case DXOR: masm.xorpd(asDoubleReg(dst), tasm.asDoubleConstRef(src, 16)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } else { + switch (opcode) { + case IADD: masm.addl(asIntReg(dst), tasm.asIntAddr(src)); break; + case ISUB: masm.subl(asIntReg(dst), tasm.asIntAddr(src)); break; + case IAND: masm.andl(asIntReg(dst), tasm.asIntAddr(src)); break; + case IOR: masm.orl(asIntReg(dst), tasm.asIntAddr(src)); break; + case IXOR: masm.xorl(asIntReg(dst), tasm.asIntAddr(src)); break; + + case LADD: masm.addq(asLongReg(dst), tasm.asLongAddr(src)); break; + case LSUB: masm.subq(asLongReg(dst), tasm.asLongAddr(src)); break; + case LAND: masm.andq(asLongReg(dst), tasm.asLongAddr(src)); break; + case LOR: masm.orq(asLongReg(dst), tasm.asLongAddr(src)); break; + case LXOR: masm.xorq(asLongReg(dst), tasm.asLongAddr(src)); break; + + case FADD: masm.addss(asFloatReg(dst), tasm.asFloatAddr(src)); break; + case FSUB: masm.subss(asFloatReg(dst), tasm.asFloatAddr(src)); break; + case FMUL: masm.mulss(asFloatReg(dst), tasm.asFloatAddr(src)); break; + case FDIV: masm.divss(asFloatReg(dst), tasm.asFloatAddr(src)); break; + + case DADD: masm.addsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; + case DSUB: masm.subsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; + case DMUL: masm.mulsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; + case DDIV: masm.divsd(asDoubleReg(dst), tasm.asDoubleAddr(src)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + if (info != null) { + assert exceptionOffset != -1; + tasm.recordImplicitException(exceptionOffset, info); + } + } + + private static void emitConvertFixup(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue x) { + ConvertSlowPath slowPath = new ConvertSlowPath(result, x); + tasm.slowPaths.add(slowPath); + switch (result.kind) { + case Int: masm.cmpl(asIntReg(result), Integer.MIN_VALUE); break; + case Long: masm.cmpq(asLongReg(result), tasm.asLongConstRef(CiConstant.forLong(java.lang.Long.MIN_VALUE))); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + masm.jcc(ConditionFlag.equal, slowPath.start); + masm.bind(slowPath.continuation); + } + + private static class ConvertSlowPath extends AMD64SlowPath { + public final Label start = new Label(); + public final Label continuation = new Label(); + private final CiValue result; + private final CiValue x; + + public ConvertSlowPath(CiValue result, CiValue x) { + this.result = result; + this.x = x; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + masm.bind(start); + switch (x.kind) { + case Float: masm.ucomiss(asFloatReg(x), tasm.asFloatConstRef(CiConstant.FLOAT_0)); break; + case Double: masm.ucomisd(asDoubleReg(x), tasm.asDoubleConstRef(CiConstant.DOUBLE_0)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + Label nan = new Label(); + masm.jcc(ConditionFlag.parity, nan); + masm.jcc(ConditionFlag.below, continuation); + + // input is > 0 -> return maxInt + // result register already contains 0x80000000, so subtracting 1 gives 0x7fffffff + switch (result.kind) { + case Int: masm.decrementl(asIntReg(result), 1); break; + case Long: masm.decrementq(asLongReg(result), 1); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + masm.jmp(continuation); + + // input is NaN -> return 0 + masm.bind(nan); + masm.xorptr(asRegister(result), asRegister(result)); + masm.jmp(continuation); + } + } + + + private static void verifyKind(AMD64Arithmetic opcode, CiValue result, CiValue x, CiValue y) { + assert (opcode.name().startsWith("I") && result.kind == CiKind.Int && x.kind.stackKind() == CiKind.Int && y.kind.stackKind() == CiKind.Int) + || (opcode.name().startsWith("L") && result.kind == CiKind.Long && x.kind == CiKind.Long && y.kind == CiKind.Long) + || (opcode.name().startsWith("F") && result.kind == CiKind.Float && x.kind == CiKind.Float && y.kind == CiKind.Float) + || (opcode.name().startsWith("D") && result.kind == CiKind.Double && x.kind == CiKind.Double && y.kind == CiKind.Double); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Call.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Call.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.amd64; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiTargetMethod.Mark; +import com.oracle.max.cri.xir.CiXirAssembler.XirMark; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; + +public class AMD64Call { + + public static class DirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { + private final Object targetMethod; + private final Map marks; + + public DirectCallOp(Object targetMethod, CiValue result, CiValue[] parameters, LIRDebugInfo info, Map marks) { + super("CALL_DIRECT", new CiValue[] {result}, info, parameters, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + this.targetMethod = targetMethod; + this.marks = marks; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + callAlignment(tasm, masm); + if (marks != null) { + marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); + } + directCall(tasm, masm, targetMethod, info); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + } else if (mode == OperandMode.Output) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + public static class IndirectCallOp extends AMD64LIRInstruction implements StandardOp.CallOp { + private final Object targetMethod; + private final Map marks; + + private static CiValue[] concat(CiValue[] parameters, CiValue targetAddress) { + CiValue[] result = Arrays.copyOf(parameters, parameters.length + 1); + result[result.length - 1] = targetAddress; + return result; + } + + public IndirectCallOp(Object targetMethod, CiValue result, CiValue[] parameters, CiValue targetAddress, LIRDebugInfo info, Map marks) { + super("CALL_INDIRECT", new CiValue[] {result}, info, concat(parameters, targetAddress), LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + this.targetMethod = targetMethod; + this.marks = marks; + } + + private CiValue targetAddress() { + return input(inputs.length - 1); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + callAlignment(tasm, masm); + if (marks != null) { + marks.put(XirMark.CALLSITE, tasm.recordMark(null, new Mark[0])); + } + indirectCall(tasm, masm, asRegister(targetAddress()), targetMethod, info); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + } else if (mode == OperandMode.Output) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static void callAlignment(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + // make sure that the displacement word of the call ends up word aligned + int offset = masm.codeBuffer.position(); + offset += tasm.target.arch.machineCodeCallDisplacementOffset; + while (offset++ % tasm.target.wordSize != 0) { + masm.nop(); + } + } + + public static void directCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target, LIRDebugInfo info) { + int before = masm.codeBuffer.position(); + if (target instanceof CiRuntimeCall) { + long maxOffset = tasm.runtime.getMaxCallTargetOffset((CiRuntimeCall) target); + if (maxOffset != (int) maxOffset) { + // offset might not fit a 32-bit immediate, generate an + // indirect call with a 64-bit immediate + CiRegister scratch = tasm.frameMap.registerConfig.getScratchRegister(); + // TODO(cwi): we want to get rid of a generally reserved scratch register. + masm.movq(scratch, 0L); + masm.call(scratch); + } else { + masm.call(); + } + } else { + masm.call(); + } + int after = masm.codeBuffer.position(); + tasm.recordDirectCall(before, after, tasm.runtime.asCallTarget(target), info); + tasm.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } + + public static void directJmp(TargetMethodAssembler tasm, AMD64MacroAssembler masm, Object target) { + int before = masm.codeBuffer.position(); + masm.jmp(0, true); + int after = masm.codeBuffer.position(); + tasm.recordDirectCall(before, after, tasm.runtime.asCallTarget(target), null); + masm.ensureUniquePC(); + } + + public static void indirectCall(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiRegister dst, Object target, LIRDebugInfo info) { + int before = masm.codeBuffer.position(); + masm.call(dst); + int after = masm.codeBuffer.position(); + tasm.recordIndirectCall(before, after, tasm.runtime.asCallTarget(target), info); + tasm.recordExceptionHandlers(after, info); + masm.ensureUniquePC(); + } + + public static void shouldNotReachHere(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + boolean assertions = false; + assert (assertions = true) == true; + + if (assertions) { + directCall(tasm, masm, CiRuntimeCall.Debug, null); + masm.hlt(); + } + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Compare.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Compare.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.amd64; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; + +public enum AMD64Compare { + ICMP, LCMP, ACMP, FCMP, DCMP; + + public static class CompareOp extends AMD64LIRInstruction { + public CompareOp(AMD64Compare opcode, CiValue x, CiValue y) { + super(opcode, LIRInstruction.NO_OPERANDS, null, new CiValue[] {x, y}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + CiValue x = input(0); + CiValue y = input(1); + emit(tasm, masm, (AMD64Compare) code, x, y); + } + + @Override + public EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Input && index == 1) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + protected void verify() { + CiValue x = input(0); + CiValue y = input(1); + + super.verify(); + assert (name().startsWith("I") && x.kind == CiKind.Int && y.kind.stackKind() == CiKind.Int) + || (name().startsWith("I") && x.kind == CiKind.Jsr && y.kind == CiKind.Jsr) + || (name().startsWith("L") && x.kind == CiKind.Long && y.kind == CiKind.Long) + || (name().startsWith("A") && x.kind == CiKind.Object && y.kind == CiKind.Object) + || (name().startsWith("F") && x.kind == CiKind.Float && y.kind == CiKind.Float) + || (name().startsWith("D") && x.kind == CiKind.Double && y.kind == CiKind.Double); + } + } + + public static void emit(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AMD64Compare opcode, CiValue x, CiValue y) { + if (isRegister(y)) { + switch (opcode) { + case ICMP: masm.cmpl(asIntReg(x), asIntReg(y)); break; + case LCMP: masm.cmpq(asLongReg(x), asLongReg(y)); break; + case ACMP: masm.cmpptr(asObjectReg(x), asObjectReg(y)); break; + case FCMP: masm.ucomiss(asFloatReg(x), asFloatReg(y)); break; + case DCMP: masm.ucomisd(asDoubleReg(x), asDoubleReg(y)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(y)) { + switch (opcode) { + case ICMP: masm.cmpl(asIntReg(x), tasm.asIntConst(y)); break; + case LCMP: masm.cmpq(asLongReg(x), tasm.asIntConst(y)); break; + case ACMP: + if (((CiConstant) y).isNull()) { + masm.cmpq(asObjectReg(x), 0); break; + } else { + throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons"); + } + case FCMP: masm.ucomiss(asFloatReg(x), tasm.asFloatConstRef(y)); break; + case DCMP: masm.ucomisd(asDoubleReg(x), tasm.asDoubleConstRef(y)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } else { + switch (opcode) { + case ICMP: masm.cmpl(asIntReg(x), tasm.asIntAddr(y)); break; + case LCMP: masm.cmpq(asLongReg(x), tasm.asLongAddr(y)); break; + case ACMP: masm.cmpptr(asObjectReg(x), tasm.asObjectAddr(y)); break; + case FCMP: masm.ucomiss(asFloatReg(x), tasm.asFloatAddr(y)); break; + case DCMP: masm.ucomisd(asDoubleReg(x), tasm.asDoubleAddr(y)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64CompareToIntOpcode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64CompareToIntOpcode.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.amd64; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; + +/** + * Implementation of the Java bytecodes that compare a long, float, or double value and produce the + * integer constants -1, 0, 1 on less, equal, or greater, respectively. For floating point compares, + * unordered can be either greater {@link #CMP2INT_UG} or less {@link #CMP2INT_UL}. + */ +public enum AMD64CompareToIntOpcode { + CMP2INT, CMP2INT_UG, CMP2INT_UL; + + public LIRInstruction create(CiValue result) { + CiValue[] outputs = new CiValue[] {result}; + + return new AMD64LIRInstruction(this, outputs, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS) { + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + emit(masm, output(0)); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + }; + } + + private void emit(AMD64MacroAssembler masm, CiValue result) { + CiRegister dest = asIntReg(result); + Label high = new Label(); + Label low = new Label(); + Label done = new Label(); + + // comparison is done by a separate LIR instruction before + switch (this) { + case CMP2INT: + masm.jcc(ConditionFlag.greater, high); + masm.jcc(ConditionFlag.less, low); + break; + case CMP2INT_UG: + masm.jcc(ConditionFlag.parity, high); + masm.jcc(ConditionFlag.above, high); + masm.jcc(ConditionFlag.below, low); + break; + case CMP2INT_UL: + masm.jcc(ConditionFlag.parity, low); + masm.jcc(ConditionFlag.above, high); + masm.jcc(ConditionFlag.below, low); + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + + // equal -> 0 + masm.xorptr(dest, dest); + masm.jmp(done); + + // greater -> 1 + masm.bind(high); + masm.xorptr(dest, dest); + masm.incrementl(dest, 1); + masm.jmp(done); + + // less -> -1 + masm.bind(low); + masm.xorptr(dest, dest); + masm.decrementl(dest, 1); + + masm.bind(done); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64ControlFlow.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64ControlFlow.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.amd64; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiAddress.Scale; +import com.oracle.max.cri.ci.CiTargetMethod.JumpTable; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; +import com.oracle.max.graal.nodes.calc.*; + +public class AMD64ControlFlow { + + public static class ReturnOp extends AMD64LIRInstruction { + public ReturnOp(CiValue input) { + super("RETURN", LIRInstruction.NO_OPERANDS, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + masm.ret(0); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class BranchOp extends AMD64LIRInstruction implements StandardOp.BranchOp { + protected Condition condition; + protected LabelRef destination; + + public BranchOp(Condition condition, LabelRef destination, LIRDebugInfo info) { + super("BRANCH", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + this.condition = condition; + this.destination = destination; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + masm.jcc(intCond(condition), destination.label()); + } + + @Override + public LabelRef destination() { + return destination; + } + + @Override + public void negate(LabelRef newDestination) { + destination = newDestination; + condition = condition.negate(); + } + + @Override + public String operationString() { + return condition.operator + " [" + destination + "]"; + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class FloatBranchOp extends BranchOp { + protected boolean unorderedIsTrue; + + public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef destination, LIRDebugInfo info) { + super(condition, destination, info); + this.unorderedIsTrue = unorderedIsTrue; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + floatJcc(masm, condition, unorderedIsTrue, destination.label()); + } + + @Override + public void negate(LabelRef newDestination) { + super.negate(newDestination); + unorderedIsTrue = !unorderedIsTrue; + } + + @Override + public String operationString() { + return condition.operator + " [" + destination + "]" + (unorderedIsTrue ? " unorderedIsTrue" : " unorderedIsFalse"); + } + } + + + public static class TableSwitchOp extends AMD64LIRInstruction { + private final int lowKey; + private final LabelRef defaultTarget; + private final LabelRef[] targets; + + public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) { + super("TABLE_SWITCH", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, new CiValue[] {index}, new CiValue[] {scratch}); + this.lowKey = lowKey; + this.defaultTarget = defaultTarget; + this.targets = targets; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + tableswitch(tasm, masm, lowKey, defaultTarget, targets, asIntReg(alive(0)), asLongReg(temp(0))); + } + + @Override + public String operationString() { + StringBuilder buf = new StringBuilder(super.operationString()); + buf.append("\ndefault: [").append(defaultTarget).append(']'); + int key = lowKey; + for (LabelRef l : targets) { + buf.append("\ncase ").append(key).append(": [").append(l).append(']'); + key++; + } + return buf.toString(); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Alive && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Temp && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class CondMoveOp extends AMD64LIRInstruction { + private final Condition condition; + + public CondMoveOp(Variable result, Condition condition, Variable trueValue, CiValue falseValue) { + super("CMOVE", new CiValue[] {result}, null, new CiValue[] {falseValue}, new CiValue[] {trueValue}, LIRInstruction.NO_OPERANDS); + this.condition = condition; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + cmove(tasm, masm, output(0), false, condition, false, alive(0), input(0)); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Alive && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); + } + throw GraalInternalError.shouldNotReachHere(); + } + + @Override + public String operationString() { + return condition.toString() + " " + super.operationString(); + } + } + + + public static class FloatCondMoveOp extends AMD64LIRInstruction { + private final Condition condition; + private final boolean unorderedIsTrue; + + public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) { + super("FLOAT_CMOVE", new CiValue[] {result}, null, LIRInstruction.NO_OPERANDS, new CiValue[] {trueValue, falseValue}, LIRInstruction.NO_OPERANDS); + this.condition = condition; + this.unorderedIsTrue = unorderedIsTrue; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + cmove(tasm, masm, output(0), true, condition, unorderedIsTrue, alive(0), alive(1)); + } + + @Override + public String operationString() { + return condition.toString() + " unordered=" + unorderedIsTrue + " " + super.operationString(); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Alive && index == 0) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Alive && index == 1) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + private static void tableswitch(TargetMethodAssembler tasm, AMD64MacroAssembler masm, int lowKey, LabelRef defaultTarget, LabelRef[] targets, CiRegister value, CiRegister scratch) { + Buffer buf = masm.codeBuffer; + // Compare index against jump table bounds + int highKey = lowKey + targets.length - 1; + if (lowKey != 0) { + // subtract the low value from the switch value + masm.subl(value, lowKey); + masm.cmpl(value, highKey - lowKey); + } else { + masm.cmpl(value, highKey); + } + + // Jump to default target if index is not within the jump table + masm.jcc(ConditionFlag.above, defaultTarget.label()); + + // Set scratch to address of jump table + int leaPos = buf.position(); + masm.leaq(scratch, new CiAddress(tasm.target.wordKind, AMD64.rip.asValue(), 0)); + int afterLea = buf.position(); + + // Load jump table entry into scratch and jump to it + masm.movslq(value, new CiAddress(CiKind.Int, scratch.asValue(), value.asValue(), Scale.Times4, 0)); + masm.addq(scratch, value); + masm.jmp(scratch); + + // Inserting padding so that jump table address is 4-byte aligned + if ((buf.position() & 0x3) != 0) { + masm.nop(4 - (buf.position() & 0x3)); + } + + // Patch LEA instruction above now that we know the position of the jump table + int jumpTablePos = buf.position(); + buf.setPosition(leaPos); + masm.leaq(scratch, new CiAddress(tasm.target.wordKind, AMD64.rip.asValue(), jumpTablePos - afterLea)); + buf.setPosition(jumpTablePos); + + // Emit jump table entries + for (LabelRef target : targets) { + Label label = target.label(); + int offsetToJumpTableBase = buf.position() - jumpTablePos; + if (label.isBound()) { + int imm32 = label.position() - jumpTablePos; + buf.emitInt(imm32); + } else { + label.addPatchAt(buf.position()); + + buf.emitByte(0); // psuedo-opcode for jump table entry + buf.emitShort(offsetToJumpTableBase); + buf.emitByte(0); // padding to make jump table entry 4 bytes wide + } + } + + JumpTable jt = new JumpTable(jumpTablePos, lowKey, highKey, 4); + tasm.targetMethod.addAnnotation(jt); + } + + private static void floatJcc(AMD64MacroAssembler masm, Condition condition, boolean unorderedIsTrue, Label label) { + ConditionFlag cond = floatCond(condition); + Label endLabel = new Label(); + if (unorderedIsTrue && !trueOnUnordered(cond)) { + masm.jcc(ConditionFlag.parity, label); + } else if (!unorderedIsTrue && trueOnUnordered(cond)) { + masm.jcc(ConditionFlag.parity, endLabel); + } + masm.jcc(cond, label); + masm.bind(endLabel); + } + + private static void cmove(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, boolean isFloat, Condition condition, boolean unorderedIsTrue, CiValue trueValue, CiValue falseValue) { + ConditionFlag cond = isFloat ? floatCond(condition) : intCond(condition); + // check that we don't overwrite an input operand before it is used. + assert !result.equals(trueValue); + + AMD64Move.move(tasm, masm, result, falseValue); + cmove(tasm, masm, result, cond, trueValue); + + if (isFloat) { + if (unorderedIsTrue && !trueOnUnordered(cond)) { + cmove(tasm, masm, result, ConditionFlag.parity, trueValue); + } else if (!unorderedIsTrue && trueOnUnordered(cond)) { + cmove(tasm, masm, result, ConditionFlag.parity, falseValue); + } + } + } + + private static void cmove(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, ConditionFlag cond, CiValue other) { + if (isRegister(other)) { + assert asRegister(other) != asRegister(result) : "other already overwritten by previous move"; + switch (other.kind) { + case Int: masm.cmovl(cond, asRegister(result), asRegister(other)); break; + case Long: masm.cmovq(cond, asRegister(result), asRegister(other)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } else { + switch (other.kind) { + case Int: masm.cmovl(cond, asRegister(result), tasm.asAddress(other)); break; + case Long: masm.cmovq(cond, asRegister(result), tasm.asAddress(other)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + } + + private static ConditionFlag intCond(Condition cond) { + switch (cond) { + case EQ: return ConditionFlag.equal; + case NE: return ConditionFlag.notEqual; + case LT: return ConditionFlag.less; + case LE: return ConditionFlag.lessEqual; + case GE: return ConditionFlag.greaterEqual; + case GT: return ConditionFlag.greater; + case BE: return ConditionFlag.belowEqual; + case AE: return ConditionFlag.aboveEqual; + case AT: return ConditionFlag.above; + case BT: return ConditionFlag.below; + case OF: return ConditionFlag.overflow; + case NOF: return ConditionFlag.noOverflow; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + private static ConditionFlag floatCond(Condition cond) { + switch (cond) { + case EQ: return ConditionFlag.equal; + case NE: return ConditionFlag.notEqual; + case BT: return ConditionFlag.below; + case BE: return ConditionFlag.belowEqual; + case AE: return ConditionFlag.aboveEqual; + case AT: return ConditionFlag.above; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + private static boolean trueOnUnordered(ConditionFlag condition) { + switch(condition) { + case aboveEqual: + case notEqual: + case above: + case less: + case overflow: + return false; + case equal: + case belowEqual: + case below: + case greaterEqual: + case noOverflow: + return true; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64LIRInstruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64LIRInstruction.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.amd64; + +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; + +/** + * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. + */ +public abstract class AMD64LIRInstruction extends LIRInstruction { + + public AMD64LIRInstruction(Object opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) { + super(opcode, outputs, info, inputs, alives, temps); + } + + @Override + public final void emitCode(TargetMethodAssembler tasm) { + emitCode(tasm, (AMD64MacroAssembler) tasm.asm); + } + + public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm); +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Move.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64Move.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,486 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.amd64; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static java.lang.Double.*; +import static java.lang.Float.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.StandardOp.*; +import com.oracle.max.graal.lir.asm.*; + +public class AMD64Move { + + public static class SpillMoveOp extends AMD64LIRInstruction implements MoveOp { + public SpillMoveOp(CiValue result, CiValue input) { + super("MOVE", new CiValue[] {result}, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + move(tasm, masm, getResult(), getInput()); + } + + @Override + public CiValue getInput() { + return input(0); + } + @Override + public CiValue getResult() { + return output(0); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class MoveToRegOp extends AMD64LIRInstruction implements MoveOp { + public MoveToRegOp(CiValue result, CiValue input) { + super("MOVE", new CiValue[] {result}, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + move(tasm, masm, getResult(), getInput()); + } + + @Override + public CiValue getInput() { + return input(0); + } + @Override + public CiValue getResult() { + return output(0); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class MoveFromRegOp extends AMD64LIRInstruction implements MoveOp { + public MoveFromRegOp(CiValue result, CiValue input) { + super("MOVE", new CiValue[] {result}, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + move(tasm, masm, getResult(), getInput()); + } + + @Override + public CiValue getInput() { + return input(0); + } + @Override + public CiValue getResult() { + return output(0); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.RegisterHint); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class LoadOp extends AMD64LIRInstruction { + public LoadOp(CiValue result, CiValue address, LIRDebugInfo info) { + super("LOAD", new CiValue[] {result}, info, new CiValue[] {address}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + load(tasm, masm, output(0), (CiAddress) input(0), info); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Address); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class StoreOp extends AMD64LIRInstruction { + public StoreOp(CiValue address, CiValue input, LIRDebugInfo info) { + super("STORE", LIRInstruction.NO_OPERANDS, info, new CiValue[] {address, input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + store(tasm, masm, (CiAddress) input(0), input(1), info); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Address); + } else if (mode == OperandMode.Input && index == 1) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Constant); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class LeaOp extends AMD64LIRInstruction { + public LeaOp(CiValue result, CiValue address) { + super("LEA", new CiValue[] {result}, null, new CiValue[] {address}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + masm.leaq(asLongReg(output(0)), tasm.asAddress(input(0))); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Address, OperandFlag.Stack, OperandFlag.Uninitialized); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class MembarOp extends AMD64LIRInstruction { + private final int barriers; + + public MembarOp(final int barriers) { + super("MEMBAR", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + this.barriers = barriers; + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + masm.membar(barriers); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class NullCheckOp extends AMD64LIRInstruction { + public NullCheckOp(Variable input, LIRDebugInfo info) { + super("NULL_CHECK", LIRInstruction.NO_OPERANDS, info, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + tasm.recordImplicitException(masm.codeBuffer.position(), info); + masm.nullCheck(asRegister(input(0))); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static class CompareAndSwapOp extends AMD64LIRInstruction { + public CompareAndSwapOp(CiValue result, CiAddress address, CiValue cmpValue, CiValue newValue) { + super("CAS", new CiValue[] {result}, null, new CiValue[] {address, cmpValue, newValue}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { + compareAndSwap(tasm, masm, output(0), asAddress(input(0)), input(1), input(2)); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Input && index == 0) { + return EnumSet.of(OperandFlag.Address); + } else if (mode == OperandMode.Input && index == 1) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Input && index == 2) { + return EnumSet.of(OperandFlag.Register); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static void move(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue input) { + if (isRegister(input)) { + if (isRegister(result)) { + reg2reg(masm, result, input); + } else if (isStackSlot(result)) { + reg2stack(tasm, masm, result, input); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isStackSlot(input)) { + if (isRegister(result)) { + stack2reg(tasm, masm, result, input); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(input)) { + if (isRegister(result)) { + const2reg(tasm, masm, result, (CiConstant) input); + } else if (isStackSlot(result)) { + const2stack(tasm, masm, result, (CiConstant) input); + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void reg2reg(AMD64MacroAssembler masm, CiValue result, CiValue input) { + if (input.equals(result)) { + return; + } + switch (result.kind) { + case Jsr: + case Int: masm.movl(asRegister(result), asRegister(input)); break; + case Long: masm.movq(asRegister(result), asRegister(input)); break; + case Float: masm.movflt(asFloatReg(result), asFloatReg(input)); break; + case Double: masm.movdbl(asDoubleReg(result), asDoubleReg(input)); break; + case Object: masm.movq(asRegister(result), asRegister(input)); break; + default: throw GraalInternalError.shouldNotReachHere("kind=" + result.kind); + } + } + + private static void reg2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue input) { + switch (result.kind) { + case Jsr: + case Int: masm.movl(tasm.asAddress(result), asRegister(input)); break; + case Long: masm.movq(tasm.asAddress(result), asRegister(input)); break; + case Float: masm.movflt(tasm.asAddress(result), asFloatReg(input)); break; + case Double: masm.movsd(tasm.asAddress(result), asDoubleReg(input)); break; + case Object: masm.movq(tasm.asAddress(result), asRegister(input)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void stack2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue input) { + switch (result.kind) { + case Jsr: + case Int: masm.movl(asRegister(result), tasm.asAddress(input)); break; + case Long: masm.movq(asRegister(result), tasm.asAddress(input)); break; + case Float: masm.movflt(asFloatReg(result), tasm.asAddress(input)); break; + case Double: masm.movdbl(asDoubleReg(result), tasm.asAddress(input)); break; + case Object: masm.movq(asRegister(result), tasm.asAddress(input)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void const2reg(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiConstant c) { + switch (result.kind) { + case Jsr: + case Int: + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + masm.movl(asRegister(result), tasm.asIntConst(c)); + break; + case Long: + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + masm.movq(asRegister(result), c.asLong()); + break; + case Float: + // This is *not* the same as 'constant == 0.0f' in the case where constant is -0.0f + if (Float.floatToRawIntBits(c.asFloat()) == Float.floatToRawIntBits(0.0f)) { + masm.xorps(asFloatReg(result), asFloatReg(result)); + } else { + masm.movflt(asFloatReg(result), tasm.asFloatConstRef(c)); + } + break; + case Double: + // This is *not* the same as 'constant == 0.0d' in the case where constant is -0.0d + if (Double.doubleToRawLongBits(c.asDouble()) == Double.doubleToRawLongBits(0.0d)) { + masm.xorpd(asDoubleReg(result), asDoubleReg(result)); + } else { + masm.movdbl(asDoubleReg(result), tasm.asDoubleConstRef(c)); + } + break; + case Object: + // Do not optimize with an XOR as this instruction may be between + // a CMP and a Jcc in which case the XOR will modify the condition + // flags and interfere with the Jcc. + if (c.isNull()) { + masm.movq(asRegister(result), 0x0L); + } else if (tasm.target.inlineObjects) { + tasm.recordDataReferenceInCode(c, 0); + masm.movq(asRegister(result), 0xDEADDEADDEADDEADL); + } else { + masm.movq(asRegister(result), tasm.recordDataReferenceInCode(c, 0)); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + private static void const2stack(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiConstant c) { + switch (result.kind) { + case Jsr: + case Int: masm.movl(tasm.asAddress(result), c.asInt()); break; + case Long: masm.movlong(tasm.asAddress(result), c.asLong()); break; + case Float: masm.movl(tasm.asAddress(result), floatToRawIntBits(c.asFloat())); break; + case Double: masm.movlong(tasm.asAddress(result), doubleToRawLongBits(c.asDouble())); break; + case Object: + if (c.isNull()) { + masm.movlong(tasm.asAddress(result), 0L); + } else { + throw GraalInternalError.shouldNotReachHere("Non-null object constants must be in register"); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + } + + + public static void load(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiAddress loadAddr, LIRDebugInfo info) { + if (info != null) { + tasm.recordImplicitException(masm.codeBuffer.position(), info); + } + switch (loadAddr.kind) { + case Boolean: + case Byte: masm.movsxb(asRegister(result), loadAddr); break; + case Char: masm.movzxl(asRegister(result), loadAddr); break; + case Short: masm.movswl(asRegister(result), loadAddr); break; + case Int: masm.movslq(asRegister(result), loadAddr); break; + case Long: masm.movq(asRegister(result), loadAddr); break; + case Float: masm.movflt(asFloatReg(result), loadAddr); break; + case Double: masm.movdbl(asDoubleReg(result), loadAddr); break; + case Object: masm.movq(asRegister(result), loadAddr); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } + + public static void store(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiAddress storeAddr, CiValue input, LIRDebugInfo info) { + if (info != null) { + tasm.recordImplicitException(masm.codeBuffer.position(), info); + } + + if (isRegister(input)) { + switch (storeAddr.kind) { + case Boolean: + case Byte: masm.movb(storeAddr, asRegister(input)); break; + case Char: + case Short: masm.movw(storeAddr, asRegister(input)); break; + case Int: masm.movl(storeAddr, asRegister(input)); break; + case Long: masm.movq(storeAddr, asRegister(input)); break; + case Float: masm.movflt(storeAddr, asFloatReg(input)); break; + case Double: masm.movsd(storeAddr, asDoubleReg(input)); break; + case Object: masm.movq(storeAddr, asRegister(input)); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } else if (isConstant(input)) { + CiConstant c = (CiConstant) input; + switch (storeAddr.kind) { + case Boolean: + case Byte: masm.movb(storeAddr, c.asInt() & 0xFF); break; + case Char: + case Short: masm.movw(storeAddr, c.asInt() & 0xFFFF); break; + case Jsr: + case Int: masm.movl(storeAddr, c.asInt()); break; + case Long: + if (NumUtil.isInt(c.asLong())) { + masm.movslq(storeAddr, (int) c.asLong()); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + break; + case Float: masm.movl(storeAddr, floatToRawIntBits(c.asFloat())); break; + case Double: throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + case Object: + if (c.isNull()) { + masm.movptr(storeAddr, 0); + } else { + throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory"); + } + break; + default: + throw GraalInternalError.shouldNotReachHere(); + } + + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } + + protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiAddress address, CiValue cmpValue, CiValue newValue) { + assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax; + + if (tasm.target.isMP) { + masm.lock(); + } + switch (cmpValue.kind) { + case Int: masm.cmpxchgl(asRegister(newValue), address); break; + case Long: + case Object: masm.cmpxchgq(asRegister(newValue), address); break; + default: throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64SlowPath.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir.amd64/src/com/oracle/max/graal/lir/amd64/AMD64SlowPath.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,39 @@ +/* + * 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.max.graal.lir.amd64; + +import com.oracle.max.asm.target.amd64.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.asm.*; + +/** + * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method. + */ +public abstract class AMD64SlowPath implements LIR.SlowPath { + @Override + public final void emitCode(TargetMethodAssembler tasm) { + emitCode(tasm, (AMD64MacroAssembler) tasm.asm); + } + + public abstract void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm); +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/FrameMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/FrameMap.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2009, 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.max.graal.lir; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ci.CiCallingConvention.Type; +import com.oracle.max.cri.ri.*; + +/** + * This class is used to build the stack frame layout for a compiled method. + * A {@link CiStackSlot} is used to index slots of the frame relative to the stack pointer. + * The frame size is only fixed after register allocation when all spill slots have + * been allocated. Both the outgoing argument area and the spill are can grow until then. + * Therefore, outgoing arguments are indexed from the stack pointer, while spill slots + * are indexed from the beginning of the frame (and the total frame size has to be added + * to get the actual offset from the stack pointer). + *
+ * This is the format of a stack frame: + *
+ *   Base       Contents
+ *
+ *            :                                :  -----
+ *   caller   | incoming overflow argument n   |    ^
+ *   frame    :     ...                        :    | positive
+ *            | incoming overflow argument 0   |    | offsets
+ *   ---------+--------------------------------+---------------------
+ *            | return address                 |    |            ^
+ *   current  +--------------------------------+    |            |    -----
+ *   frame    |                                |    |            |      ^
+ *            : callee save area               :    |            |      |
+ *            |                                |    |            |      |
+ *            +--------------------------------+    |            |      |
+ *            | spill slot 0                   |    | negative   |      |
+ *            :     ...                        :    v offsets    |      |
+ *            | spill slot n                   |  -----        total  frame
+ *            +--------------------------------+               frame  size
+ *            | alignment padding              |               size     |
+ *            +--------------------------------+  -----          |      |
+ *            | outgoing overflow argument n   |    ^            |      |
+ *            :     ...                        :    | positive   |      |
+ *            | outgoing overflow argument 0   |    | offsets    v      v
+ *    %sp-->  +--------------------------------+---------------------------
+ *
+ * 
+ * The spill slot area also includes stack allocated memory blocks (ALLOCA blocks). The size + * of such a block may be greater than the size of a normal spill slot or the word size. + *
+ * A runtime has two ways to reserve space in the stack frame for its own use:
    + *
  • A memory block somewhere in the frame of size {@link RiRuntime#getCustomStackAreaSize()}. The offset + * to this block is returned in {@link CiTargetMethod#customStackAreaOffset()}. + *
  • At the beginning of the overflow argument area: The calling convention can specify that the first + * overflow stack argument is not at offset 0, but at a specified offset o. Use + * {@link RiRuntime#getMinimumOutgoingSize()} to make sure that call-free methods also have this space + * reserved. Then the VM can use memory the memory at offset 0 relative to the stack pointer. + *
+ */ +public final class FrameMap { + public final RiRuntime runtime; + public final CiTarget target; + public final RiRegisterConfig registerConfig; + + /** + * The final frame size, not including the size of the return address. + * The value is only set after register allocation is complete, i.e., after all spill slots have been allocated. + */ + private int frameSize; + + /** + * Size of the area occupied by spill slots and other stack-allocated memory blocks. + */ + private int spillSize; + + /** + * Size of the area occupied by outgoing overflow arguments. + * This value is adjusted as calling conventions for outgoing calls are retrieved. + */ + private int outgoingSize; + + /** + * The list of stack areas allocated in this frame that are present in every reference map. + */ + private final List objectStackBlocks; + + /** + * The stack area reserved for use by the VM, or {@code null} if the VM does not request stack space. + */ + private final CiStackSlot customArea; + + /** + * Creates a new frame map for the specified method. + */ + public FrameMap(RiRuntime runtime, CiTarget target, RiRegisterConfig registerConfig) { + this.runtime = runtime; + this.target = target; + this.registerConfig = registerConfig; + this.frameSize = -1; + this.spillSize = returnAddressSize() + calleeSaveAreaSize(); + this.outgoingSize = runtime.getMinimumOutgoingSize(); + this.objectStackBlocks = new ArrayList<>(); + this.customArea = allocateStackBlock(runtime.getCustomStackAreaSize(), false); + } + + + private int returnAddressSize() { + return target.arch.returnAddressSize; + } + + private int calleeSaveAreaSize() { + CiCalleeSaveLayout csl = registerConfig.getCalleeSaveLayout(); + return csl != null ? csl.size : 0; + } + + /** + * Gets the frame size of the compiled frame, not including the size of the return address. + * @return The size of the frame (in bytes). + */ + public int frameSize() { + assert frameSize != -1 : "frame size not computed yet"; + return frameSize; + } + + /** + * Gets the total frame size of the compiled frame, including the size of the return address. + * @return The total size of the frame (in bytes). + */ + public int totalFrameSize() { + return frameSize() + returnAddressSize(); + } + + /** + * Sets the frame size for this frame. + * @param frameSize The frame size (in bytes). + */ + public void setFrameSize(int frameSize) { + assert this.frameSize == -1 : "must only be set once"; + this.frameSize = frameSize; + } + + /** + * Computes the frame size for this frame. After this method has been called, methods that change the + * frame size cannot be called anymore, e.g., no more spill slots or outgoing arguments can be requested. + */ + public void finish() { + setFrameSize(target.alignFrameSize(outgoingSize + spillSize - returnAddressSize())); + } + + /** + * Computes the offset of a stack slot relative to the frame register. + * This is also the bit index of stack slots in the reference map. + * + * @param slot a stack slot + * @return the offset of the stack slot + */ + public int offsetForStackSlot(CiStackSlot slot) { + assert (!slot.rawAddFrameSize() && slot.rawOffset() < outgoingSize) || + (slot.rawAddFrameSize() && slot.rawOffset() < 0 && -slot.rawOffset() <= spillSize) || + (slot.rawAddFrameSize() && slot.rawOffset() >= 0); + return slot.offset(totalFrameSize()); + } + + /** + * Gets the offset to the stack area where callee-saved registers are stored. + * @return The offset to the callee save area (in bytes). + */ + public int offsetToCalleeSaveArea() { + return frameSize() - calleeSaveAreaSize(); + } + + /** + * Gets the offset of the stack area stack block reserved for use by the VM, or -1 if the VM does not request stack space. + * @return The offset to the custom area (in bytes). + */ + public int offsetToCustomArea() { + return customArea == null ? -1 : offsetForStackSlot(customArea); + } + + /** + * Informs the frame map that the compiled code calls a particular method, which + * may need stack space for outgoing arguments. + * @param cc The calling convention for the called method. + * @param type The type of calling convention. + */ + public void callsMethod(CiCallingConvention cc, Type type) { + // TODO look at the actual stack offsets? + assert type.out; + reserveOutgoing(cc.stackSize); + } + + /** + * Reserves space for stack-based outgoing arguments. + * @param argsSize The amount of space (in bytes) to reserve for stack-based outgoing arguments. + */ + public void reserveOutgoing(int argsSize) { + assert frameSize == -1 : "frame size must not yet be fixed"; + outgoingSize = Math.max(outgoingSize, argsSize); + } + + private CiStackSlot getSlot(CiKind kind, int additionalOffset) { + return CiStackSlot.get(kind, -spillSize + additionalOffset, true); + } + + /** + * Reserves a spill slot in the frame of the method being compiled. The returned slot is aligned on its natural alignment, + * i.e., an 8-byte spill slot is aligned at an 8-byte boundary. + * @param kind The kind of the spill slot to be reserved. + * @return A spill slot denoting the reserved memory area. + */ + public CiStackSlot allocateSpillSlot(CiKind kind) { + assert frameSize == -1 : "frame size must not yet be fixed"; + int size = target.sizeInBytes(kind); + spillSize = NumUtil.roundUp(spillSize + size, size); + return getSlot(kind, 0); + } + + /** + * Reserves a block of memory in the frame of the method being compiled. The returned block is aligned on a word boundary. + * If the requested size is 0, the method returns {@code null}. + * + * @param size The size to reserve (in bytes). + * @param refs Specifies if the block is all references. If true, the block will be in all reference maps for this method. + * The caller is responsible to initialize the memory block before the first instruction that uses a reference map. + * @return A stack slot describing the begin of the memory block. + */ + public CiStackSlot allocateStackBlock(int size, boolean refs) { + assert frameSize == -1 : "frame size must not yet be fixed"; + if (size == 0) { + return null; + } + spillSize = NumUtil.roundUp(spillSize + size, target.wordSize); + + if (refs) { + assert size % target.wordSize == 0; + CiStackSlot result = getSlot(CiKind.Object, 0); + objectStackBlocks.add(result); + for (int i = target.wordSize; i < size; i += target.wordSize) { + objectStackBlocks.add(getSlot(CiKind.Object, i)); + } + return result; + + } else { + return getSlot(target.wordKind, 0); + } + } + + + private int frameRefMapIndex(CiStackSlot slot) { + assert offsetForStackSlot(slot) % target.wordSize == 0; + return offsetForStackSlot(slot) / target.wordSize; + } + + /** + * Initializes a reference map that covers all registers of the target architecture. + */ + public CiBitMap initRegisterRefMap() { + return new CiBitMap(target.arch.registerReferenceMapBitCount); + } + + /** + * Initializes a reference map. Initially, the size is large enough to cover all the + * slots in the frame. If the method has incoming reference arguments on the stack, + * the reference map might grow later when such a reference is set. + */ + public CiBitMap initFrameRefMap() { + CiBitMap frameRefMap = new CiBitMap(frameSize() / target.wordSize); + for (CiStackSlot slot : objectStackBlocks) { + setReference(slot, null, frameRefMap); + } + return frameRefMap; + } + + /** + * Marks the specified location as a reference in the reference map of the debug information. + * The tracked location can be a {@link CiRegisterValue} or a {@link CiStackSlot}. Note that a + * {@link CiConstant} is automatically tracked. + * + * @param location The location to be added to the reference map. + * @param registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}. + * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}. + */ + public void setReference(CiValue location, CiBitMap registerRefMap, CiBitMap frameRefMap) { + if (location.kind == CiKind.Object) { + if (isRegister(location)) { + assert registerRefMap.size() == target.arch.registerReferenceMapBitCount; + registerRefMap.set(asRegister(location).number); + } else if (isStackSlot(location)) { + int index = frameRefMapIndex(asStackSlot(location)); + frameRefMap.grow(index + 1); + frameRefMap.set(index); + } else { + assert isConstant(location); + } + } + } + + /** + * Clears the specified location as a reference in the reference map of the debug information. + * The tracked location can be a {@link CiRegisterValue} or a {@link CiStackSlot}. Note that a + * {@link CiConstant} is automatically tracked. + * + * @param location The location to be removed from the reference map. + * @param registerRefMap A register reference map, as created by {@link #initRegisterRefMap()}. + * @param frameRefMap A frame reference map, as created by {@link #initFrameRefMap()}. + */ + public void clearReference(CiValue location, CiBitMap registerRefMap, CiBitMap frameRefMap) { + if (location.kind == CiKind.Object) { + if (location instanceof CiRegisterValue) { + assert registerRefMap.size() == target.arch.registerReferenceMapBitCount; + registerRefMap.clear(asRegister(location).number); + } else if (isStackSlot(location)) { + int index = frameRefMapIndex(asStackSlot(location)); + if (index < frameRefMap.size()) { + frameRefMap.clear(index); + } + } else { + assert isConstant(location); + } + } + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIR.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIR.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2009, 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.max.graal.lir; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.asm.*; +import com.oracle.max.graal.lir.cfg.*; + +/** + * This class implements the overall container for the LIR graph + * and directs its construction, optimization, and finalization. + */ +public class LIR { + + public final ControlFlowGraph cfg; + + /** + * The nodes for the blocks. + * TODO: This should go away, we want all nodes connected with a next-pointer. + */ + private final BlockMap> nodesFor; + + /** + * The linear-scan ordered list of blocks. + */ + private final List linearScanOrder; + + /** + * The order in which the code is emitted. + */ + private final List codeEmittingOrder; + + + public final List slowPaths; + + public final List deoptimizationStubs; + + /** + * The last slow path emitted, which can be used emit marker bytes. + */ + public SlowPath methodEndMarker; + + private int numVariables; + + public SpillMoveFactory spillMoveFactory; + + public interface SpillMoveFactory { + LIRInstruction createMove(CiValue result, CiValue input); + LIRInstruction createExchange(CiValue input1, CiValue input2); + } + + public interface SlowPath { + void emitCode(TargetMethodAssembler tasm); + } + + /** + * Creates a new LIR instance for the specified compilation. + * @param numLoops number of loops + * @param compilation the compilation + */ + public LIR(ControlFlowGraph cfg, BlockMap> nodesFor, List linearScanOrder, List codeEmittingOrder) { + this.cfg = cfg; + this.nodesFor = nodesFor; + this.codeEmittingOrder = codeEmittingOrder; + this.linearScanOrder = linearScanOrder; + + slowPaths = new ArrayList<>(); + deoptimizationStubs = new ArrayList<>(); + } + + public List nodesFor(Block block) { + return nodesFor.get(block); + } + + /** + * Gets the linear scan ordering of blocks as a list. + * @return the blocks in linear scan order + */ + public List linearScanOrder() { + return linearScanOrder; + } + + public List codeEmittingOrder() { + return codeEmittingOrder; + } + + public int numVariables() { + return numVariables; + } + + public int nextVariable() { + return numVariables++; + } + + public void emitCode(TargetMethodAssembler tasm) { + for (Block b : codeEmittingOrder()) { + emitBlock(tasm, b); + } + + // generate code for slow cases + for (SlowPath sp : slowPaths) { + emitSlowPath(tasm, sp); + } + // generate deoptimization stubs + for (SlowPath sp : deoptimizationStubs) { + emitSlowPath(tasm, sp); + } + // generate traps at the end of the method + emitSlowPath(tasm, methodEndMarker); + } + + private static void emitBlock(TargetMethodAssembler tasm, Block block) { + if (Debug.isDumpEnabled()) { + tasm.blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); + } + + for (LIRInstruction op : block.lir) { + if (Debug.isDumpEnabled()) { + tasm.blockComment(String.format("%d %s", op.id(), op)); + } + + emitOp(tasm, op); + } + } + + private static void emitOp(TargetMethodAssembler tasm, LIRInstruction op) { + try { + try { + op.emitCode(tasm); + } catch (AssertionError t) { + throw new GraalInternalError(t); + } catch (RuntimeException t) { + throw new GraalInternalError(t); + } + } catch (GraalInternalError e) { + throw e.addContext("lir instruction", op); + } + } + + private static void emitSlowPath(TargetMethodAssembler tasm, SlowPath sp) { + if (Debug.isDumpEnabled()) { + tasm.blockComment(String.format("slow case %s", sp.getClass().getName())); + } + sp.emitCode(tasm); + } + +/* + private int lastDecodeStart; + + private void printAssembly(TargetMethodAssembler tasm) { + byte[] currentBytes = tasm.asm.codeBuffer.copyData(lastDecodeStart, tasm.asm.codeBuffer.position()); + if (currentBytes.length > 0) { + String disasm = tasm.runtime.disassemble(currentBytes, lastDecodeStart); + if (disasm.length() != 0) { + TTY.println(disasm); + } else { + TTY.println("Code [+%d]: %d bytes", lastDecodeStart, currentBytes.length); + Util.printBytes(lastDecodeStart, currentBytes, GraalOptions.PrintAssemblyBytesPerLine); + } + } + lastDecodeStart = tasm.asm.codeBuffer.position(); + } + + + public static void printBlock(Block x) { + // print block id + TTY.print("B%d ", x.getId()); + + // print flags + if (x.isLoopHeader()) { + TTY.print("lh "); + } + if (x.isLoopEnd()) { + TTY.print("le "); + } + + // print block bci range + TTY.print("[%d, %d] ", -1, -1); + + // print predecessors and successors + if (x.numberOfPreds() > 0) { + TTY.print("preds: "); + for (int i = 0; i < x.numberOfPreds(); i++) { + TTY.print("B%d ", x.predAt(i).getId()); + } + } + + if (x.numberOfSux() > 0) { + TTY.print("sux: "); + for (int i = 0; i < x.numberOfSux(); i++) { + TTY.print("B%d ", x.suxAt(i).getId()); + } + } + + TTY.println(); + } + + public static void printLIR(List blocks) { + if (TTY.isSuppressed()) { + return; + } + TTY.println("LIR:"); + int i; + for (i = 0; i < blocks.size(); i++) { + Block bb = blocks.get(i); + printBlock(bb); + TTY.println("__id_Instruction___________________________________________"); + for (LIRInstruction op : bb.lir) { + TTY.println(op.toStringWithIdPrefix()); + TTY.println(); + } + TTY.println(); + } + } +*/ +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRDebugInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRDebugInfo.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2009, 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.max.graal.lir; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.max.graal.lir.LIRInstruction.OperandMode; +import com.oracle.max.graal.lir.LIRInstruction.ValueProcedure; + +/** + * This class represents garbage collection and deoptimization information attached to a LIR instruction. + */ +public class LIRDebugInfo { + public final CiFrame topFrame; + private final CiVirtualObject[] virtualObjects; + private final List pointerSlots; + public final LabelRef exceptionEdge; + private CiDebugInfo debugInfo; + + public LIRDebugInfo(CiFrame topFrame, CiVirtualObject[] virtualObjects, List pointerSlots, LabelRef exceptionEdge) { + this.topFrame = topFrame; + this.virtualObjects = virtualObjects; + this.pointerSlots = pointerSlots; + this.exceptionEdge = exceptionEdge; + } + + public boolean hasDebugInfo() { + return debugInfo != null; + } + + public CiDebugInfo debugInfo() { + assert debugInfo != null : "debug info not allocated yet"; + return debugInfo; + } + + /** + * Iterates the frame state and calls the {@link ValueProcedure} for every variable. + * + * @param proc The procedure called for variables. + */ + public void forEachState(ValueProcedure proc) { + for (CiFrame cur = topFrame; cur != null; cur = cur.caller()) { + processValues(cur.values, proc); + } + if (virtualObjects != null) { + for (CiVirtualObject obj : virtualObjects) { + processValues(obj.values(), proc); + } + } + } + + /** + * We filter out constant and illegal values ourself before calling the procedure, so {@link OperandFlag#Constant} and {@link OperandFlag#Illegal} need not be set. + */ + private static final EnumSet STATE_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + + private void processValues(CiValue[] values, ValueProcedure proc) { + for (int i = 0; i < values.length; i++) { + CiValue value = values[i]; + if (value instanceof CiMonitorValue) { + CiMonitorValue monitor = (CiMonitorValue) value; + if (processed(monitor.owner)) { + monitor.owner = proc.doValue(monitor.owner, OperandMode.Alive, STATE_FLAGS); + } + + } else if (processed(value)) { + values[i] = proc.doValue(value, OperandMode.Alive, STATE_FLAGS); + } + } + } + + private boolean processed(CiValue value) { + if (isIllegal(value)) { + // Ignore dead local variables. + return false; + } else if (isConstant(value)) { + // Ignore constants, the register allocator does not need to see them. + return false; + } else if (isVirtualObject(value)) { + assert Arrays.asList(virtualObjects).contains(value); + return false; + } else { + return true; + } + } + + + public void finish(CiBitMap registerRefMap, CiBitMap frameRefMap, FrameMap frameMap) { + debugInfo = new CiDebugInfo(topFrame, registerRefMap, frameRefMap); + + // Add additional stack slots for outgoing method parameters. + if (pointerSlots != null) { + for (CiStackSlot v : pointerSlots) { + frameMap.setReference(v, registerRefMap, frameRefMap); + } + } + } + + + @Override + public String toString() { + return debugInfo != null ? debugInfo.toString() : topFrame.toString(); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRInsertionBuffer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRInsertionBuffer.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2009, 2011, 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.max.graal.lir; + +import java.util.*; + +/** + * A buffer to enqueue updates to a list. This avoids frequent re-sizing of the list and copying of list elements + * when insertions are done at multiple positions of the list. Additionally, it ensures that the list is not modified + * while it is, e.g., iterated, and instead only modified once after the iteration is done. + *
+ * The buffer uses internal data structures to store the enqueued updates. To avoid allocations, a buffer can be re-used. + * Call the methods in the following order: + * {@link #init()}, {@link #append()}, {@link #append()}, ..., {@link #finish()}, {@link #init()}, ... + *
+ * Note: This class does not depend on LIRInstruction, so we could make it a generic utility class. + */ +public final class LIRInsertionBuffer { + + /** + * The lir list where ops of this buffer should be inserted later (null when uninitialized). + */ + private List lir; + + /** + * List of insertion points. index and count are stored alternately: + * indexAndCount[i * 2]: the index into lir list where "count" ops should be inserted + * indexAndCount[i * 2 + 1]: the number of ops to be inserted at index + */ + private final List indexAndCount; + + /** + * The LIROps to be inserted. + */ + private final List ops; + + + public LIRInsertionBuffer() { + indexAndCount = new ArrayList<>(8); + ops = new ArrayList<>(8); + } + + /** + * Initialize this buffer. This method must be called before using {@link #append()}. + */ + public void init(List newLir) { + assert !initialized() : "already initialized"; + assert indexAndCount.size() == 0 && ops.size() == 0; + this.lir = newLir; + } + + public boolean initialized() { + return lir != null; + } + + public List lirList() { + return lir; + } + + /** + * Enqueue a new instruction that will be appended to the instruction list when {@link #finish()} is called. + * The new instruction is added before the existing instruction with the given index. This method can only be called + * with increasing values of index, e.g., once an instruction was appended with index 4, subsequent instructions can + * only be appended with index 4 or higher. + */ + public void append(int index, LIRInstruction op) { + int i = numberOfInsertionPoints() - 1; + if (i < 0 || indexAt(i) < index) { + appendNew(index, 1); + } else { + assert indexAt(i) == index : "can append LIROps in ascending order only"; + assert countAt(i) > 0 : "check"; + setCountAt(i, countAt(i) + 1); + } + ops.add(op); + + assert verify(); + } + + /** + * Append all enqueued instructions to the instruction list. After that, {@link init()} can be called again to re-use this buffer. + */ + public void finish() { + if (ops.size() > 0) { + int n = lir.size(); + // increase size of instructions list + for (int i = 0; i < ops.size(); i++) { + lir.add(null); + } + // insert ops from buffer into instructions list + int opIndex = ops.size() - 1; + int ipIndex = numberOfInsertionPoints() - 1; + int fromIndex = n - 1; + int toIndex = lir.size() - 1; + while (ipIndex >= 0) { + int index = indexAt(ipIndex); + // make room after insertion point + while (fromIndex >= index) { + lir.set(toIndex--, lir.get(fromIndex--)); + } + // insert ops from buffer + for (int i = countAt(ipIndex); i > 0; i--) { + lir.set(toIndex--, ops.get(opIndex--)); + } + ipIndex--; + } + indexAndCount.clear(); + ops.clear(); + } + lir = null; + } + + private void appendNew(int index, int count) { + indexAndCount.add(index); + indexAndCount.add(count); + } + + private void setCountAt(int i, int value) { + indexAndCount.set((i << 1) + 1, value); + } + + private int numberOfInsertionPoints() { + assert indexAndCount.size() % 2 == 0 : "must have a count for each index"; + return indexAndCount.size() >> 1; + } + + private int indexAt(int i) { + return indexAndCount.get((i << 1)); + } + + private int countAt(int i) { + return indexAndCount.get((i << 1) + 1); + } + + private boolean verify() { + int sum = 0; + int prevIdx = -1; + + for (int i = 0; i < numberOfInsertionPoints(); i++) { + assert prevIdx < indexAt(i) : "index must be ordered ascending"; + sum += countAt(i); + } + assert sum == ops.size() : "wrong total sum"; + return true; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRInstruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRInstruction.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2009, 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.max.graal.lir; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.asm.*; + +/** + * The {@code LIRInstruction} class definition. + */ +public abstract class LIRInstruction { + + public static final CiValue[] NO_OPERANDS = {}; + + /** + * Iterator for iterating over a list of values. Subclasses must overwrite one of the doValue methods. + * Clients of the class must only call the doValue method that takes additional parameters. + */ + public abstract static class ValueProcedure { + /** + * Iterator method to be overwritten. This version of the iterator does not take additional parameters + * to keep the signature short. + * + * @param value The value that is iterated. + * @return The new value to replace the value that was passed in. + */ + protected CiValue doValue(CiValue value) { + throw GraalInternalError.shouldNotReachHere("One of the doValue() methods must be overwritten"); + } + + /** + * Iterator method to be overwritten. This version of the iterator gets additional parameters about the + * processed value. + * + * @param value The value that is iterated. + * @param mode The operand mode for the value. + * @param flags A set of flags for the value. + * @return The new value to replace the value that was passed in. + */ + public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { + return doValue(value); + } + } + + + /** + * Constants denoting how a LIR instruction uses an operand. + */ + public enum OperandMode { + /** + * The value must have been defined before. It is alive before the instruction until the beginning of the + * instruction, but not necessarily throughout the instruction. A register assigned to it can also be assigend + * to a Temp or Output operand. The value can be used again after the instruction, so the instruction must not + * modify the register. + */ + Input, + + /** + * The value must have been defined before. It is alive before the instruction and throughout the instruction. A + * register assigned to it cannot be assigned to a Temp or Output operand. The value can be used again after the + * instruction, so the instruction must not modify the register. + */ + Alive, + + /** + * The value must not have been defined before, and must not be used after the instruction. The instruction can + * do whatever it wants with the register assigned to it (or not use it at all). + */ + Temp, + + /** + * The value must not have been defined before. The instruction has to assign a value to the register. The + * value can (and most likely will) be used after the instruction. + */ + Output, + } + + /** + * Flags for an operand. + */ + public enum OperandFlag { + /** + * The value can be a {@link CiRegisterValue}. + */ + Register, + + /** + * The value can be a {@link CiStackSlot}. + */ + Stack, + + /** + * The value can be a {@link CiAddress}. + */ + Address, + + /** + * The value can be a {@link CiConstant}. + */ + Constant, + + /** + * The value can be {@link CiValue#IllegalValue}. + */ + Illegal, + + /** + * The register allocator should try to assign a certain register to improve code quality. + * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints. + */ + RegisterHint, + + /** + * The value can be uninitialized, e.g., a stack slot that has not written to before. This is only + * used to avoid false positives in verification code. + */ + Uninitialized, + } + + /** + * For validity checking of the operand flags defined by instruction subclasses. + */ + private static final EnumMap> ALLOWED_FLAGS; + + static { + ALLOWED_FLAGS = new EnumMap<>(OperandMode.class); + ALLOWED_FLAGS.put(OperandMode.Input, EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Address, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint, OperandFlag.Uninitialized)); + ALLOWED_FLAGS.put(OperandMode.Alive, EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Address, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint, OperandFlag.Uninitialized)); + ALLOWED_FLAGS.put(OperandMode.Temp, EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.Illegal, OperandFlag.RegisterHint)); + ALLOWED_FLAGS.put(OperandMode.Output, EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Illegal, OperandFlag.RegisterHint)); + } + + /** + * The opcode of this instruction. + */ + protected final Object code; + + /** + * The output operands for this instruction (modified by the register allocator). + */ + protected CiValue[] outputs; + + /** + * The input operands for this instruction (modified by the register allocator). + */ + protected CiValue[] inputs; + + /** + * The alive operands for this instruction (modified by the register allocator). + */ + protected CiValue[] alives; + + /** + * The temp operands for this instruction (modified by the register allocator). + */ + protected CiValue[] temps; + + /** + * Used to emit debug information. + */ + public final LIRDebugInfo info; + + /** + * Instruction id for register allocation. + */ + private int id; + + /** + * Constructs a new LIR instruction that has input and temp operands. + * + * @param opcode the opcode of the new instruction + * @param outputs the operands that holds the operation results of this instruction. + * @param info the {@link LIRDebugInfo} info that is to be preserved for the instruction. This will be {@code null} when no debug info is required for the instruction. + * @param inputs the input operands for the instruction. + * @param temps the temp operands for the instruction. + */ + public LIRInstruction(Object opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) { + this.code = opcode; + this.outputs = outputs; + this.inputs = inputs; + this.alives = alives; + this.temps = temps; + this.info = info; + this.id = -1; + } + + public abstract void emitCode(TargetMethodAssembler tasm); + + + public final int id() { + return id; + } + + public final void setId(int id) { + this.id = id; + } + + /** + * Gets an input operand of this instruction. + * + * @param index the index of the operand requested. + * @return the {@code index}'th input operand. + */ + protected final CiValue input(int index) { + return inputs[index]; + } + + /** + * Gets an alive operand of this instruction. + * + * @param index the index of the operand requested. + * @return the {@code index}'th alive operand. + */ + protected final CiValue alive(int index) { + return alives[index]; + } + + /** + * Gets a temp operand of this instruction. + * + * @param index the index of the operand requested. + * @return the {@code index}'th temp operand. + */ + protected final CiValue temp(int index) { + return temps[index]; + } + + /** + * Gets the result operand for this instruction. + * + * @return return the result operand + */ + protected final CiValue output(int index) { + return outputs[index]; + } + + /** + * Gets the instruction name. + */ + public String name() { + return code.toString(); + } + + public boolean hasOperands() { + return inputs.length > 0 || alives.length > 0 || temps.length > 0 || outputs.length > 0 || info != null || hasCall(); + } + + private static final EnumSet ADDRESS_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Illegal); + + private void forEach(CiValue[] values, OperandMode mode, ValueProcedure proc) { + for (int i = 0; i < values.length; i++) { + assert ALLOWED_FLAGS.get(mode).containsAll(flagsFor(mode, i)); + + CiValue value = values[i]; + if (isAddress(value)) { + assert flagsFor(mode, i).contains(OperandFlag.Address); + CiAddress address = asAddress(value); + address.base = proc.doValue(address.base, mode, ADDRESS_FLAGS); + address.index = proc.doValue(address.index, mode, ADDRESS_FLAGS); + } else { + values[i] = proc.doValue(values[i], mode, flagsFor(mode, i)); + } + } + } + + public final void forEachInput(ValueProcedure proc) { + forEach(inputs, OperandMode.Input, proc); + } + + public final void forEachAlive(ValueProcedure proc) { + forEach(alives, OperandMode.Alive, proc); + } + + public final void forEachTemp(ValueProcedure proc) { + forEach(temps, OperandMode.Temp, proc); + } + + public final void forEachOutput(ValueProcedure proc) { + forEach(outputs, OperandMode.Output, proc); + } + + public final void forEachState(ValueProcedure proc) { + if (info != null) { + info.forEachState(proc); + + if (this instanceof LIRXirInstruction) { + LIRXirInstruction xir = (LIRXirInstruction) this; + if (xir.infoAfter != null) { + xir.infoAfter.forEachState(proc); + } + } + } + } + + /** + * Returns true when this instruction is a call instruction that destroys all caller-saved registers. + */ + public final boolean hasCall() { + return this instanceof StandardOp.CallOp; + } + + /** + * Iterates all register hints for the specified value, i.e., all preferred candidates for the register to be + * assigned to the value. + *
+ * Subclasses can override this method. The default implementation processes all Input operands as the hints for + * an Output operand, and all Output operands as the hints for an Input operand. + * + * @param value The value the hints are needed for. + * @param mode The operand mode of the value. + * @param proc The procedure invoked for all the hints. If the procedure returns a non-null value, the iteration is stopped + * and the value is returned by this method, i.e., clients can stop the iteration once a suitable hint has been found. + * @return The non-null value returned by the procedure, or null. + */ + public CiValue forEachRegisterHint(CiValue value, OperandMode mode, ValueProcedure proc) { + CiValue[] hints; + if (mode == OperandMode.Input) { + hints = outputs; + } else if (mode == OperandMode.Output) { + hints = inputs; + } else { + return null; + } + + for (int i = 0; i < hints.length; i++) { + CiValue result = proc.doValue(hints[i], null, null); + if (result != null) { + return result; + } + } + return null; + } + + /** + * Used by the register allocator to decide which kind of location can be assigned to the operand. + * @param mode The kind of operand. + * @param index The index of the operand. + * @return The flags for the operand. + */ + // TODO this method will go away when we have named operands, the flags will be specified as annotations instead. + protected abstract EnumSet flagsFor(OperandMode mode, int index); + + protected void verify() { + } + + + public final String toStringWithIdPrefix() { + if (id != -1) { + return String.format("%4d %s", id, toString()); + } + return " " + toString(); + } + + /** + * Gets the operation performed by this instruction in terms of its operands as a string. + */ + public String operationString() { + StringBuilder buf = new StringBuilder(); + String sep = ""; + if (outputs.length > 1) { + buf.append("("); + } + for (CiValue output : outputs) { + buf.append(sep).append(output); + sep = ", "; + } + if (outputs.length > 1) { + buf.append(")"); + } + if (outputs.length > 0) { + buf.append(" = "); + } + + if (inputs.length + alives.length != 1) { + buf.append("("); + } + sep = ""; + for (CiValue input : inputs) { + buf.append(sep).append(input); + sep = ", "; + } + for (CiValue input : alives) { + buf.append(sep).append(input).append(" ~"); + sep = ", "; + } + if (inputs.length + alives.length != 1) { + buf.append(")"); + } + + if (temps.length > 0) { + buf.append(" ["); + } + sep = ""; + for (CiValue temp : temps) { + buf.append(sep).append(temp); + sep = ", "; + } + if (temps.length > 0) { + buf.append("]"); + } + return buf.toString(); + } + + protected void appendDebugInfo(StringBuilder buf) { + if (info != null) { + buf.append(" [bci:"); + String sep = ""; + for (CiFrame cur = info.topFrame; cur != null; cur = cur.caller()) { + buf.append(sep).append(cur.bci); + sep = ","; + } + buf.append("]"); + } + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(name()).append(' ').append(operationString()); + appendDebugInfo(buf); + return buf.toString(); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRVerifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRVerifier.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2009, 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.max.graal.lir; + +import static com.oracle.max.cri.ci.CiValueUtil.*; +import static com.oracle.max.graal.lir.ValueUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.criutils.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.LIRInstruction.*; +import com.oracle.max.graal.lir.cfg.*; + +public final class LIRVerifier { + private final LIR lir; + private final FrameMap frameMap; + + private final boolean beforeRegisterAllocation; + + private final BitSet[] blockLiveOut; + private final Object[] variableDefinitions; + + private BitSet liveOutFor(Block block) { + return blockLiveOut[block.getId()]; + } + private void setLiveOutFor(Block block, BitSet liveOut) { + blockLiveOut[block.getId()] = liveOut; + } + + private int maxRegisterNum() { + return frameMap.target.arch.registers.length; + } + + private boolean isAllocatableRegister(CiValue value) { + return isRegister(value) && frameMap.registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable; + } + + public static boolean verify(final LIRInstruction op) { + ValueProcedure allowedProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return allowed(op, value, mode, flags); } }; + + op.forEachInput(allowedProc); + op.forEachAlive(allowedProc); + op.forEachState(allowedProc); + op.forEachTemp(allowedProc); + op.forEachOutput(allowedProc); + + op.verify(); + return true; + } + + public static boolean verify(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) { + LIRVerifier verifier = new LIRVerifier(beforeRegisterAllocation, lir, frameMap); + verifier.verify(); + return true; + } + + + private LIRVerifier(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap) { + this.beforeRegisterAllocation = beforeRegisterAllocation; + this.lir = lir; + this.frameMap = frameMap; + this.blockLiveOut = new BitSet[lir.linearScanOrder().size()]; + this.variableDefinitions = new Object[lir.numVariables()]; + } + + private BitSet curVariablesLive; + private CiValue[] curRegistersLive; + + private Block curBlock; + private Object curInstruction; + private BitSet curRegistersDefined; + + private void verify() { + ValueProcedure useProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; + ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, mode, flags); } }; + + curRegistersDefined = new BitSet(); + for (Block block : lir.linearScanOrder()) { + curBlock = block; + curVariablesLive = new BitSet(); + curRegistersLive = new CiValue[maxRegisterNum()]; + + if (block.getDominator() != null) { + curVariablesLive.or(liveOutFor(block.getDominator())); + } + + assert block.lir.get(0) instanceof StandardOp.LabelOp : "block must start with label"; + if (block.numberOfPreds() > 1) { + assert block.lir.get(0) instanceof StandardOp.PhiLabelOp : "phi mapping required for multiple predecessors"; + CiValue[] phiDefinitions = ((StandardOp.PhiLabelOp) block.lir.get(0)).getPhiDefinitions(); + if (!beforeRegisterAllocation) { + assert phiDefinitions.length == 0; + } + for (Block pred : block.getPredecessors()) { + assert pred.numberOfSux() == 1; + LIRInstruction last = pred.lir.get(pred.lir.size() - 1); + assert last instanceof StandardOp.PhiJumpOp : "phi mapping required for multiple successors"; + CiValue[] phiUses = ((StandardOp.PhiJumpOp) last).getPhiInputs(); + if (!beforeRegisterAllocation) { + assert phiUses.length == 0; + } + } + } + + if (block.numberOfSux() > 0) { + LIRInstruction last = block.lir.get(block.lir.size() - 1); + assert last instanceof StandardOp.JumpOp || last instanceof LIRXirInstruction : "block with successor must end with unconditional jump"; + } + + for (LIRInstruction op : block.lir) { + curInstruction = op; + + op.forEachInput(useProc); + if (op.hasCall()) { + for (CiRegister register : frameMap.registerConfig.getCallerSaveRegisters()) { + curRegistersLive[register.number] = null; + } + } + curRegistersDefined.clear(); + op.forEachAlive(useProc); + op.forEachState(useProc); + op.forEachTemp(defProc); + op.forEachOutput(defProc); + + curInstruction = null; + } + + setLiveOutFor(block, curVariablesLive); + } + } + + private CiValue use(CiValue value, OperandMode mode, EnumSet flags) { + allowed(curInstruction, value, mode, flags); + + if (isVariable(value)) { + assert beforeRegisterAllocation; + + int variableIdx = asVariable(value).index; + if (!curVariablesLive.get(variableIdx)) { + TTY.println("block %s instruction %s", curBlock, curInstruction); + TTY.println("live variables: %s", curVariablesLive); + if (variableDefinitions[variableIdx] != null) { + TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]); + } + TTY.println("ERROR: Use of variable %s that is not defined in dominator", value); + throw GraalInternalError.shouldNotReachHere(); + } + + } else if (isAllocatableRegister(value)) { + int regNum = asRegister(value).number; + if (mode == OperandMode.Alive) { + curRegistersDefined.set(regNum); + } + + if (beforeRegisterAllocation && curRegistersLive[regNum] != value) { + TTY.println("block %s instruction %s", curBlock, curInstruction); + TTY.println("live registers: %s", Arrays.toString(curRegistersLive)); + TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value); + throw GraalInternalError.shouldNotReachHere(); + } + } + return value; + } + + private CiValue def(CiValue value, OperandMode mode, EnumSet flags) { + allowed(curInstruction, value, mode, flags); + + if (isVariable(value)) { + assert beforeRegisterAllocation; + + int variableIdx = asVariable(value).index; + if (variableDefinitions[variableIdx] != null) { + TTY.println("block %s instruction %s", curBlock, curInstruction); + TTY.println("live variables: %s", curVariablesLive); + TTY.println("definition of %s: %s", value, variableDefinitions[variableIdx]); + TTY.println("ERROR: Variable %s defined multiple times", value); + throw GraalInternalError.shouldNotReachHere(); + } + assert curInstruction != null; + variableDefinitions[variableIdx] = curInstruction; + assert !curVariablesLive.get(variableIdx); + if (mode == OperandMode.Output) { + curVariablesLive.set(variableIdx); + } + + } else if (isAllocatableRegister(value)) { + int regNum = asRegister(value).number; + if (curRegistersDefined.get(regNum)) { + TTY.println("block %s instruction %s", curBlock, curInstruction); + TTY.println("ERROR: Same register defined twice in the same instruction: %s", value); + throw GraalInternalError.shouldNotReachHere(); + } + curRegistersDefined.set(regNum); + + if (beforeRegisterAllocation) { + if (mode == OperandMode.Output) { + curRegistersLive[regNum] = value; + } else { + curRegistersLive[regNum] = null; + } + } + } + return value; + } + + private static CiValue allowed(Object op, CiValue value, OperandMode mode, EnumSet flags) { + if ((isVariable(value) && flags.contains(OperandFlag.Register)) || + (isRegister(value) && flags.contains(OperandFlag.Register)) || + (isStackSlot(value) && flags.contains(OperandFlag.Stack)) || + (isConstant(value) && flags.contains(OperandFlag.Constant) && mode != OperandMode.Output) || + (isIllegal(value) && flags.contains(OperandFlag.Illegal))) { + return value; + } + TTY.println("instruction %s", op); + TTY.println("mode: %s flags: %s", mode, flags); + TTY.println("Unexpected value: %s %s", value.getClass().getSimpleName(), value); + throw GraalInternalError.shouldNotReachHere(); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRXirInstruction.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LIRXirInstruction.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2009, 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.max.graal.lir; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.xir.*; +import com.oracle.max.graal.graph.*; + +public abstract class LIRXirInstruction extends LIRInstruction { + + public final CiValue[] originalOperands; + public final int outputOperandIndex; + public final int[] inputOperandIndices; + public final int[] tempOperandIndices; + public final XirSnippet snippet; + public final LIRDebugInfo infoAfter; + public final LabelRef trueSuccessor; + public final LabelRef falseSuccessor; + + public LIRXirInstruction(Object opcode, + XirSnippet snippet, + CiValue[] originalOperands, + CiValue outputOperand, + CiValue[] inputs, CiValue[] temps, + int[] inputOperandIndices, int[] tempOperandIndices, + int outputOperandIndex, + LIRDebugInfo info, + LIRDebugInfo infoAfter, + LabelRef trueSuccessor, + LabelRef falseSuccessor) { + // Note that we register the XIR input operands as Alive, because the XIR specification allows that input operands + // are used at any time, even when the temp operands and the actual output operands have already be assigned. + super(opcode, isLegal(outputOperand) ? new CiValue[] {outputOperand} : LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, inputs, temps); + this.infoAfter = infoAfter; + this.snippet = snippet; + this.inputOperandIndices = inputOperandIndices; + this.tempOperandIndices = tempOperandIndices; + this.outputOperandIndex = outputOperandIndex; + this.originalOperands = originalOperands; + this.falseSuccessor = falseSuccessor; + this.trueSuccessor = trueSuccessor; + assert isLegal(outputOperand) || outputOperandIndex == -1; + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Alive || mode == OperandMode.Temp) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.Illegal); + } else if (mode == OperandMode.Output && index == 0) { + return EnumSet.of(OperandFlag.Register); + } + throw GraalInternalError.shouldNotReachHere(); + } + + public CiValue[] getOperands() { + for (int i = 0; i < inputOperandIndices.length; i++) { + originalOperands[inputOperandIndices[i]] = alive(i); + } + for (int i = 0; i < tempOperandIndices.length; i++) { + originalOperands[tempOperandIndices[i]] = temp(i); + } + if (outputOperandIndex != -1) { + originalOperands[outputOperandIndex] = output(0); + } + return originalOperands; + } + + @Override + public String name() { + return "XIR: " + snippet.template; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LabelRef.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/LabelRef.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011, 2011, 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.max.graal.lir; + +import com.oracle.max.asm.*; +import com.oracle.max.graal.lir.cfg.*; + +/** + * LIR instructions such as JUMP and BRANCH need to reference their target {@link Block}. However, + * direct references are not possible since the control flow graph (and therefore successors lists) can + * be changed by optimizations - and fixing the instructions is error prone. + * Therefore, we only reference of block B from block A only via the tuple (A, successor-index-of-B), i.e., + * indirectly by storing the index into the successor list of A. + * Note that therefore it is not allowed to reorder the successor list! + * + * Labels of out-of-line stubs can be referenced directly, therefore it is also possible to construct a + * LabelRef for a Label directly via {@link #forLabel}. + */ +public abstract class LabelRef { + + public abstract Label label(); + + /** + * Returns a new reference to a statically defined label. + * @param label The label that is always returned. + * @return The newly created label reference. + */ + public static LabelRef forLabel(final Label label) { + return new LabelRef() { + @Override + public Label label() { + return label; + } + + @Override + public String toString() { + return label.toString(); + } + }; + } + + /** + * Returns a new reference to a successor of the given block. + * This allows to reference the given successor even when the successor list + * is modified between the creation of the reference and the call to {@link #getLabel}. + * @param block The base block that contains the successor list. + * @param suxIndex The index of the successor. + * @return The newly created label reference. + */ + public static LabelRef forSuccessor(final Block block, final int suxIndex) { + return new LabelRef() { + @Override + public Label label() { + return ((StandardOp.LabelOp) block.suxAt(suxIndex).lir.get(0)).getLabel(); + } + + @Override + public String toString() { + return suxIndex < block.numberOfSux() ? block.suxAt(suxIndex).toString() : "?" + block + ":" + suxIndex + "?"; + } + }; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/StandardOp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/StandardOp.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.asm.*; + +/** + * A collection of machine-independent LIR operations, as well as interfaces to be implemented for specific kinds or LIR + * operations. + */ +public class StandardOp { + + private static CiValue[] EMPTY = new CiValue[0]; + + /** + * LIR operation that defines the position of a label. + * The first operation of every block must implement this interface. + */ + public static class LabelOp extends LIRInstruction { + private final Label label; + private final boolean align; + + protected LabelOp(Object opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps, Label label, boolean align) { + super(opcode, outputs, info, inputs, alives, temps); + this.label = label; + this.align = align; + } + + public LabelOp(Label label, boolean align) { + this("LABEL", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, label, align); + } + + @Override + public void emitCode(TargetMethodAssembler tasm) { + if (align) { + tasm.asm.align(tasm.target.wordSize); + } + tasm.asm.bind(label); + } + + @Override + public String operationString() { + return label.toString() + " " + super.operationString(); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + throw GraalInternalError.shouldNotReachHere(); + } + + public Label getLabel() { + return label; + } + } + + public static class PhiLabelOp extends LabelOp { + public PhiLabelOp(Label label, boolean align, CiValue[] phiDefinitions) { + super("PHI_LABEL", phiDefinitions, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, label, align); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Output) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + } + throw GraalInternalError.shouldNotReachHere(); + } + + public void markResolved() { + outputs = EMPTY; + } + + public CiValue[] getPhiDefinitions() { + return outputs; + } + } + + /** + * LIR operation that is an unconditional jump to {@link #destination()}. + * When the LIR is constructed, the last operation of every block must implement this interface. After + * register allocation, unnecessary jumps can be deleted. + * + * TODO Currently, a block can also end with an XIR operation. + */ + public static class JumpOp extends LIRInstruction { + private final LabelRef destination; + + protected JumpOp(Object opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps, LabelRef destination) { + super(opcode, outputs, info, inputs, alives, temps); + this.destination = destination; + } + + public JumpOp(LabelRef destination, LIRDebugInfo info) { + this("JUMP", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, destination); + } + + @Override + public void emitCode(TargetMethodAssembler tasm) { + tasm.asm.jmp(destination.label()); + } + + @Override + public String operationString() { + return destination + " " + super.operationString(); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + throw GraalInternalError.shouldNotReachHere(); + } + + public LabelRef destination() { + return destination; + } + } + + public static class PhiJumpOp extends JumpOp { + public PhiJumpOp(LabelRef destination, CiValue[] phiInputs) { + super("PHI_JUMP", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, phiInputs, LIRInstruction.NO_OPERANDS, destination); + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Alive) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); + } + throw GraalInternalError.shouldNotReachHere(); + } + + public void markResolved() { + alives = EMPTY; + } + + public CiValue[] getPhiInputs() { + return alives; + } + } + + /** + * Marker interface for a LIR operation that is a conditional jump to {@link #destination()}. + * Conditional jumps may be negated or optimized away after register allocation. + */ + public interface BranchOp { + LabelRef destination(); + void negate(LabelRef newDestination); + } + + /** + * Marker interface for a LIR operation that moves a value from {@link #getInput()} to {@link #getResult()}. + */ + public interface MoveOp { + CiValue getInput(); + CiValue getResult(); + } + + /** + * Marker interface for a LIR operation that calls a method, i.e., destroys all caller-saved registers. + */ + public interface CallOp { + } + + + /** + * Meta-operation that defines the incoming method parameters. In the LIR, every register and variable must be + * defined before it is used. This operation is the definition point of method parameters, but is otherwise a no-op. + * In particular, it is not the actual method prologue. + */ + public static final class ParametersOp extends LIRInstruction { + public ParametersOp(CiValue[] params) { + super("PARAMS", params, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); + } + + @Override + public void emitCode(TargetMethodAssembler tasm) { + // No code to emit. + } + + @Override + protected EnumSet flagsFor(OperandMode mode, int index) { + if (mode == OperandMode.Output) { + return EnumSet.of(OperandFlag.Register, OperandFlag.Stack); + } + throw GraalInternalError.shouldNotReachHere(); + } + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/ValueUtil.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/ValueUtil.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir; + +import com.oracle.max.cri.ci.*; + +public class ValueUtil extends CiValueUtil { + + public static boolean isVariable(CiValue value) { + assert value != null; + return value instanceof Variable; + } + + public static Variable asVariable(CiValue value) { + assert value != null; + return (Variable) value; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/Variable.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/Variable.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010, 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.max.graal.lir; + +import com.oracle.max.cri.ci.*; + +/** + * Represents a value that is yet to be bound to a machine location (such as + * a {@link CiRegisterValue} or {@link CiStackSlot}) by a register allocator. + */ +public final class Variable extends CiValue { + private static final long serialVersionUID = 4507578431686109809L; + + /** + * The identifier of the variable. This is a non-zero index in a contiguous 0-based name space. + */ + public final int index; + + /** + * The type of register that this variable needs to get assigned. + */ + public final CiRegister.RegisterFlag flag; + + /** + * Creates a new variable. + * @param kind + * @param index + */ + public Variable(CiKind kind, int index, CiRegister.RegisterFlag flag) { + super(kind); + assert kind == kind.stackKind() : "Variables can be only created for stack kinds"; + assert index >= 0; + this.index = index; + this.flag = flag; + } + + @Override + public int hashCode() { + return (index << 4) | kind.ordinal(); + } + + @Override + public String toString() { + return "v" + index + kindSuffix(); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/asm/TargetMethodAssembler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/asm/TargetMethodAssembler.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.asm; + +import static com.oracle.max.cri.ci.CiValueUtil.*; + +import java.util.*; + +import com.oracle.max.asm.*; +import com.oracle.max.cri.ci.*; +import com.oracle.max.cri.ri.*; +import com.oracle.max.graal.debug.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.LIR.*; + +public class TargetMethodAssembler { + + private static class ExceptionInfo { + public final int codeOffset; + public final LabelRef exceptionEdge; + + public ExceptionInfo(int pcOffset, LabelRef exceptionEdge) { + this.codeOffset = pcOffset; + this.exceptionEdge = exceptionEdge; + } + } + + public final AbstractAssembler asm; + public final CiTargetMethod targetMethod; + public final CiTarget target; + public final RiRuntime runtime; + public final FrameMap frameMap; + public final List slowPaths; + + private List exceptionInfoList; + private int lastSafepointPos; + + public TargetMethodAssembler(CiTarget target, RiRuntime runtime, FrameMap frameMap, List slowPaths, AbstractAssembler asm) { + this.target = target; + this.runtime = runtime; + this.frameMap = frameMap; + this.slowPaths = slowPaths; + this.asm = asm; + this.targetMethod = new CiTargetMethod(); + // 0 is a valid pc for safepoints in template methods + this.lastSafepointPos = -1; + } + + public void setFrameSize(int frameSize) { + targetMethod.setFrameSize(frameSize); + } + + public CiTargetMethod.Mark recordMark(Object id, CiTargetMethod.Mark[] references) { + return targetMethod.recordMark(asm.codeBuffer.position(), id, references); + } + + public void blockComment(String s) { + targetMethod.addAnnotation(new CiTargetMethod.CodeComment(asm.codeBuffer.position(), s)); + } + + public CiTargetMethod finishTargetMethod(Object name, boolean isStub) { + // Install code, data and frame size + targetMethod.setTargetCode(asm.codeBuffer.close(false), asm.codeBuffer.position()); + + // Record exception handlers if they exist + if (exceptionInfoList != null) { + for (ExceptionInfo ei : exceptionInfoList) { + int codeOffset = ei.codeOffset; + targetMethod.recordExceptionHandler(codeOffset, -1, 0, ei.exceptionEdge.label().position(), -1, null); + } + } + + Debug.metric("TargetMethods").increment(); + Debug.metric("CodeBytesEmitted").add(targetMethod.targetCodeSize()); + Debug.metric("SafepointsEmitted").add(targetMethod.safepoints.size()); + Debug.metric("DataPatches").add(targetMethod.dataReferences.size()); + Debug.metric("ExceptionHandlersEmitted").add(targetMethod.exceptionHandlers.size()); + + Debug.log("Finished target method %s, isStub %d", name, isStub); +/* + if (GraalOptions.PrintAssembly && !TTY.isSuppressed() && !isStub) { + Util.printSection("Target Method", Util.SECTION_CHARACTER); + TTY.println("Name: " + name); + TTY.println("Frame size: " + targetMethod.frameSize()); + TTY.println("Register size: " + asm.target.arch.registerReferenceMapBitCount); + + if (GraalOptions.PrintCodeBytes) { + Util.printSection("Code", Util.SUB_SECTION_CHARACTER); + TTY.println("Code: %d bytes", targetMethod.targetCodeSize()); + Util.printBytes(0L, targetMethod.targetCode(), 0, targetMethod.targetCodeSize(), GraalOptions.PrintAssemblyBytesPerLine); + } + + Util.printSection("Disassembly", Util.SUB_SECTION_CHARACTER); + String disassembly = runtime.disassemble(targetMethod); + TTY.println(disassembly); + boolean noDis = disassembly == null || disassembly.length() == 0; + + Util.printSection("Safepoints", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.Safepoint x : targetMethod.safepoints) { + TTY.println(x.toString()); + if (noDis && x.debugInfo != null) { + TTY.println(CiUtil.indent(x.debugInfo.toString(), " ")); + } + } + + Util.printSection("Data Patches", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.DataPatch x : targetMethod.dataReferences) { + TTY.println(x.toString()); + } + + Util.printSection("Marks", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.Mark x : targetMethod.marks) { + TTY.println(x.toString()); + } + + Util.printSection("Exception Handlers", Util.SUB_SECTION_CHARACTER); + for (CiTargetMethod.ExceptionHandler x : targetMethod.exceptionHandlers) { + TTY.println(x.toString()); + } + } +*/ + + return targetMethod; + } + + public void recordExceptionHandlers(int pcOffset, LIRDebugInfo info) { + if (info != null) { + if (info.exceptionEdge != null) { + if (exceptionInfoList == null) { + exceptionInfoList = new ArrayList<>(4); + } + exceptionInfoList.add(new ExceptionInfo(pcOffset, info.exceptionEdge)); + } + } + } + + public void recordImplicitException(int pcOffset, LIRDebugInfo info) { + // record an implicit exception point + if (info != null) { + assert lastSafepointPos < pcOffset : lastSafepointPos + "<" + pcOffset; + lastSafepointPos = pcOffset; + targetMethod.recordSafepoint(pcOffset, info.debugInfo()); + assert info.exceptionEdge == null; + } + } + + public void recordDirectCall(int posBefore, int posAfter, Object callTarget, LIRDebugInfo info) { + CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; + assert lastSafepointPos < posAfter; + lastSafepointPos = posAfter; + targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true); + } + + public void recordIndirectCall(int posBefore, int posAfter, Object callTarget, LIRDebugInfo info) { + CiDebugInfo debugInfo = info != null ? info.debugInfo() : null; + assert lastSafepointPos < posAfter; + lastSafepointPos = posAfter; + targetMethod.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, false); + } + + public void recordSafepoint(int pos, LIRDebugInfo info) { + // safepoints always need debug info + CiDebugInfo debugInfo = info.debugInfo(); + assert lastSafepointPos < pos; + lastSafepointPos = pos; + targetMethod.recordSafepoint(pos, debugInfo); + } + + public CiAddress recordDataReferenceInCode(CiConstant data, int alignment) { + assert data != null; + int pos = asm.codeBuffer.position(); + Debug.log("Data reference in code: pos = %d, data = %s", pos, data.toString()); + targetMethod.recordDataReference(pos, data, alignment); + return CiAddress.Placeholder; + } + + public int lastSafepointPos() { + return lastSafepointPos; + } + + + /** + * Returns the integer value of any constants that can be represented by a 32-bit integer value, + * including long constants that fit into the 32-bit range. + */ + public int asIntConst(CiValue value) { + assert (value.kind.stackKind() == CiKind.Int || value.kind == CiKind.Jsr || value.kind == CiKind.Long) && isConstant(value); + long c = ((CiConstant) value).asLong(); + if (!(NumUtil.isInt(c))) { + throw GraalInternalError.shouldNotReachHere(); + } + return (int) c; + } + + /** + * Returns the address of a float constant that is embedded as a data references into the code. + */ + public CiAddress asFloatConstRef(CiValue value) { + return asFloatConstRef(value, 4); + } + + public CiAddress asFloatConstRef(CiValue value, int alignment) { + assert value.kind == CiKind.Float && isConstant(value); + return recordDataReferenceInCode((CiConstant) value, alignment); + } + + /** + * Returns the address of a double constant that is embedded as a data references into the code. + */ + public CiAddress asDoubleConstRef(CiValue value) { + return asDoubleConstRef(value, 8); + } + + public CiAddress asDoubleConstRef(CiValue value, int alignment) { + assert value.kind == CiKind.Double && isConstant(value); + return recordDataReferenceInCode((CiConstant) value, alignment); + } + + /** + * Returns the address of a long constant that is embedded as a data references into the code. + */ + public CiAddress asLongConstRef(CiValue value) { + assert value.kind == CiKind.Long && isConstant(value); + return recordDataReferenceInCode((CiConstant) value, 8); + } + + public CiAddress asIntAddr(CiValue value) { + assert value.kind == CiKind.Int; + return asAddress(value); + } + + public CiAddress asLongAddr(CiValue value) { + assert value.kind == CiKind.Long; + return asAddress(value); + } + + public CiAddress asObjectAddr(CiValue value) { + assert value.kind == CiKind.Object; + return asAddress(value); + } + + public CiAddress asFloatAddr(CiValue value) { + assert value.kind == CiKind.Float; + return asAddress(value); + } + + public CiAddress asDoubleAddr(CiValue value) { + assert value.kind == CiKind.Double; + return asAddress(value); + } + + public CiAddress asAddress(CiValue value) { + if (isStackSlot(value)) { + CiStackSlot slot = (CiStackSlot) value; + return new CiAddress(slot.kind, frameMap.registerConfig.getFrameRegister().asValue(), frameMap.offsetForStackSlot(slot)); + } + return (CiAddress) value; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/Block.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/Block.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2009, 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.max.graal.lir.cfg; + +import java.util.*; + +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.nodes.*; +import com.oracle.max.graal.nodes.java.*; + +public class Block { + protected int id; + + protected BeginNode beginNode; + protected Node endNode; + protected Loop loop; + protected double probability; + + protected List predecessors; + protected List successors; + + protected Block dominator; + protected List dominated; + protected Block postdominator; + + // Fields that still need to be worked on, try to remove them later. + public List lir; + public boolean align; + public int linearScanNumber; + + public Block() { + id = ControlFlowGraph.BLOCK_ID_INITIAL; + } + + public int getId() { + assert id >= 0; + return id; + } + + public BeginNode getBeginNode() { + return beginNode; + } + + public Node getEndNode() { + return endNode; + } + + public Loop getLoop() { + return loop; + } + + public int getLoopDepth() { + return loop == null ? 0 : loop.depth; + } + + public boolean isLoopHeader() { + return getBeginNode() instanceof LoopBeginNode; + } + + public boolean isLoopEnd() { + return getEndNode() instanceof LoopEndNode; + } + + public boolean isExceptionEntry() { + return getBeginNode().next() instanceof ExceptionObjectNode; + } + + public List getPredecessors() { + return predecessors; + } + + public List getSuccessors() { + return successors; + } + + public Block getDominator() { + return dominator; + } + + public List getDominated() { + if (dominated == null) { + return Collections.emptyList(); + } + return dominated; + } + + public Block getPostdominator() { + return postdominator; + } + + private class NodeIterator implements Iterator { + private Node cur; + + public NodeIterator() { + cur = getBeginNode(); + } + + @Override + public boolean hasNext() { + return cur != null; + } + + @Override + public Node next() { + Node result = cur; + if (cur == getEndNode()) { + cur = null; + } else { + cur = ((FixedWithNextNode) cur).next(); + } + assert !(cur instanceof BeginNode); + return result; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + public Iterable getNodes() { + return new Iterable() { + @Override + public Iterator iterator() { + return new NodeIterator(); + } + }; + } + + public int getFirstLirInstructionId() { + int result = lir.get(0).id(); + assert result >= 0; + return result; + } + + public int getLastLirInstructionId() { + int result = lir.get(lir.size() - 1).id(); + assert result >= 0; + return result; + } + + @Override + public String toString() { + return "B" + id; + } + + +// to be inlined later on + public int numberOfPreds() { + return getPredecessors().size(); + } + + public int numberOfSux() { + return getSuccessors().size(); + } + + public Block predAt(int i) { + return getPredecessors().get(i); + } + + public Block suxAt(int i) { + return getSuccessors().get(i); + } +// end to be inlined later on +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/BlockMap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/BlockMap.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,40 @@ +/* + * 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.max.graal.lir.cfg; + +public class BlockMap { + private final T[] data; + + @SuppressWarnings("unchecked") + public BlockMap(ControlFlowGraph cfg) { + data = (T[]) new Object[cfg.getBlocks().length]; + } + + public T get(Block block) { + return data[block.getId()]; + } + + public void put(Block block, T value) { + data[block.getId()] = value; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/CFGVerifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/CFGVerifier.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,80 @@ +/* + * 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.max.graal.lir.cfg; + +public class CFGVerifier { + public static boolean verify(ControlFlowGraph cfg) { + for (Block block : cfg.getBlocks()) { + assert cfg.getBlocks()[block.getId()] == block; + + for (Block pred : block.getPredecessors()) { + assert pred.getSuccessors().contains(block); + assert pred.getId() < block.getId() || pred.isLoopEnd(); + } + + for (Block sux : block.getSuccessors()) { + assert sux.getPredecessors().contains(block); + assert sux.getId() > block.getId() || sux.isLoopHeader(); + } + + if (block.getDominator() != null) { + assert block.getDominator().getId() < block.getId(); + assert block.getDominator().getDominated().contains(block); + } + for (Block dominated : block.getDominated()) { + assert dominated.getId() > block.getId(); + assert dominated.getDominator() == block; + } + + assert cfg.getLoops() == null || !block.isLoopHeader() || block.getLoop().header == block; + } + + if (cfg.getLoops() != null) { + for (Loop loop : cfg.getLoops()) { + assert loop.header.isLoopHeader(); + + for (Block block : loop.blocks) { + assert block.getId() >= loop.header.getId(); + + Loop blockLoop = block.getLoop(); + while (blockLoop != loop) { + blockLoop = blockLoop.parent; + assert blockLoop != null; + } + } + + for (Block block : loop.exits) { + assert block.getId() >= loop.header.getId(); + + Loop blockLoop = block.getLoop(); + while (blockLoop != null) { + blockLoop = blockLoop.parent; + assert blockLoop != loop; + } + } + } + } + + return true; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/ControlFlowGraph.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/ControlFlowGraph.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2011, 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.max.graal.lir.cfg; + +import java.util.*; + +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.nodes.*; + +public class ControlFlowGraph { + + public final StructuredGraph graph; + + private final NodeMap nodeToBlock; + private Block[] reversePostOrder; + private Loop[] loops; + + public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { + ControlFlowGraph cfg = new ControlFlowGraph(graph); + cfg.identifyBlocks(); + if (connectBlocks || computeLoops || computeDominators || computePostdominators) { + cfg.connectBlocks(); + } + if (computeLoops) { + cfg.computeLoopInformation(); + } + if (computeDominators) { + cfg.computeDominators(); + } + if (computePostdominators) { + cfg.computePostdominators(); + } + assert CFGVerifier.verify(cfg); + return cfg; + } + + protected ControlFlowGraph(StructuredGraph graph) { + this.graph = graph; + this.nodeToBlock = graph.createNodeMap(); + } + + public Block[] getBlocks() { + return reversePostOrder; + } + + public Block getStartBlock() { + return reversePostOrder[0]; + } + + public NodeMap getNodeToBlock() { + return nodeToBlock; + } + + public Block blockFor(Node node) { + return nodeToBlock.get(node); + } + + public Loop[] getLoops() { + return loops; + } + + protected static final int BLOCK_ID_INITIAL = -1; + protected static final int BLOCK_ID_VISITED = -2; + + private void identifyBlocks() { + // Find all block headers + int numBlocks = 0; + for (Node node : graph.getNodes()) { + if (node instanceof BeginNode) { + Block block = new Block(); + numBlocks++; + + block.beginNode = (BeginNode) node; + Node cur = node; + do { + assert !cur.isDeleted(); + block.endNode = cur; + + assert nodeToBlock.get(cur) == null; + nodeToBlock.set(cur, block); + if (cur instanceof MergeNode) { + for (PhiNode phi : ((MergeNode) cur).phis()) { + nodeToBlock.set(phi, block); + } + } + + if (cur instanceof FixedNode) { + double probability = ((FixedNode) cur).probability(); + if (probability > block.probability) { + block.probability = probability; + } + } + + Node next = null; + for (Node sux : cur.successors()) { + if (sux != null && !(sux instanceof BeginNode)) { + assert next == null; + next = sux; + } + } + cur = next; + } while (cur != null); + } + } + + // Compute reverse postorder. + reversePostOrder = new Block[numBlocks]; + int reversePostOrderId = numBlocks - 1; + + ArrayList stack = new ArrayList<>(); + stack.add(blockFor(graph.start())); + + do { + Block block = stack.get(stack.size() - 1); + if (block.id == BLOCK_ID_INITIAL) { + // First time we see this block: push all successors. + for (Node suxNode : block.getEndNode().cfgSuccessors()) { + Block suxBlock = blockFor(suxNode); + assert suxBlock.id != BLOCK_ID_VISITED; + if (suxBlock.id == BLOCK_ID_INITIAL) { + stack.add(suxBlock); + } + } + block.id = BLOCK_ID_VISITED; + } else if (block.id == BLOCK_ID_VISITED) { + // Second time we see this block: All successors haved been processed, so insert block into reverse postorder list. + stack.remove(stack.size() - 1); + reversePostOrder[reversePostOrderId] = block; + block.id = reversePostOrderId; + reversePostOrderId--; + } else { + throw GraalInternalError.shouldNotReachHere(); + } + } while (!stack.isEmpty()); + assert reversePostOrderId == -1; + } + + // Connect blocks (including loop backward edges). + private void connectBlocks() { + for (Block block : reversePostOrder) { + List predecessors = new ArrayList<>(); + for (Node predNode : block.getBeginNode().cfgPredecessors()) { + predecessors.add(nodeToBlock.get(predNode)); + } + if (block.getBeginNode() instanceof LoopBeginNode) { + predecessors.add(nodeToBlock.get(((LoopBeginNode) block.getBeginNode()).loopEnd())); + } + block.predecessors = predecessors; + + List successors = new ArrayList<>(); + for (Node suxNode : block.getEndNode().cfgSuccessors()) { + successors.add(nodeToBlock.get(suxNode)); + } + if (block.getEndNode() instanceof LoopEndNode) { + successors.add(nodeToBlock.get(((LoopEndNode) block.getEndNode()).loopBegin())); + } + block.successors = successors; + } + } + + private void computeLoopInformation() { + List loopsList = 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); + + LoopEndNode end = ((LoopBeginNode) beginNode).loopEnd(); + Block endBlock = nodeToBlock.get(end); + computeLoopBlocks(endBlock, loop); + } + } + loops = loopsList.toArray(new Loop[loopsList.size()]); + + for (Loop loop : loops) { + for (Block block : loop.blocks) { + for (Block sux : block.getSuccessors()) { + if (sux.getLoopDepth() < loop.depth) { + loop.exits.add(sux); + } + } + } + } + } + + private void computeLoopBlocks(Block block, Loop loop) { + if (block.getLoop() == loop) { + return; + } + assert block.loop == loop.parent; + block.loop = loop; + + assert !loop.blocks.contains(block); + loop.blocks.add(block); + + if (block != loop.header) { + for (Block pred : block.getPredecessors()) { + computeLoopBlocks(pred, loop); + } + } + } + + private void computeDominators() { + assert reversePostOrder[0].getPredecessors().size() == 0 : "start block has no predecessor and therefore no dominator"; + for (int i = 1; i < reversePostOrder.length; i++) { + Block block = reversePostOrder[i]; + List predecessors = block.getPredecessors(); + assert predecessors.size() > 0; + + if (block.isLoopHeader()) { + // Loop headers have exactly one non-loop predecessor, and that is the dominator. + setDominator(block, predecessors.get(0)); + continue; + } + + Block dominator = predecessors.get(0); + for (int j = 1; j < predecessors.size(); j++) { + Block pred = predecessors.get(j); + dominator = commonDominator(dominator, pred); + } + setDominator(block, dominator); + } + } + + private static void setDominator(Block block, Block dominator) { + block.dominator = dominator; + if (dominator.dominated == null) { + dominator.dominated = new ArrayList<>(); + } + dominator.dominated.add(block); + } + + public static Block commonDominator(Block a, Block b) { + Block iterA = a; + Block iterB = b; + while (iterA != iterB) { + if (iterA.getId() > iterB.getId()) { + iterA = iterA.getDominator(); + } else { + assert iterB.getId() > iterA.getId(); + iterB = iterB.getDominator(); + } + } + return iterA; + } + + private void computePostdominators() { + for (Block block : reversePostOrder) { + if (block.isLoopEnd()) { + // We do not want the loop header registered as the postdominator of the loop end. + continue; + } + Block postdominator = null; + for (Block sux : block.getSuccessors()) { + if (sux.isExceptionEntry()) { + // We ignore exception handlers. + } else if (postdominator == null) { + postdominator = sux; + } else { + postdominator = commonPostdominator(postdominator, sux); + } + } + block.postdominator = postdominator; + } + } + + private static Block commonPostdominator(Block a, Block b) { + Block iterA = a; + Block iterB = b; + while (iterA != iterB) { + if (iterA.getId() < iterB.getId()) { + iterA = iterA.getPostdominator(); + if (iterA == null) { + return null; + } + } else { + assert iterB.getId() < iterA.getId(); + iterB = iterB.getPostdominator(); + if (iterB == null) { + return null; + } + } + } + return iterA; + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/Loop.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.max.graal.lir/src/com/oracle/max/graal/lir/cfg/Loop.java Thu Feb 09 10:03:21 2012 +0100 @@ -0,0 +1,56 @@ +/* + * 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.max.graal.lir.cfg; + +import java.util.*; + +public class Loop { + 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; + + protected Loop(Loop parent, int index, Block header) { + this.parent = parent; + if (parent != null) { + this.depth = parent.depth + 1; + parent.children.add(this); + } else { + this.depth = 1; + } + this.index = index; + this.header = header; + this.blocks = new ArrayList<>(); + this.children = new ArrayList<>(); + this.exits = new ArrayList<>(); + } + + @Override + public String toString() { + return "loop " + index + " depth " + depth + (parent != null ? " outer " + parent.index : ""); + } +} diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java --- a/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java Thu Feb 09 10:03:21 2012 +0100 @@ -33,15 +33,15 @@ import com.oracle.max.graal.alloc.util.*; import com.oracle.max.graal.compiler.alloc.*; import com.oracle.max.graal.compiler.alloc.Interval.UsePosList; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.graph.Node.Verbosity; import com.oracle.max.graal.graph.NodeClass.NodeClassIterator; import com.oracle.max.graal.graph.NodeClass.Position; import com.oracle.max.graal.java.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.calc.*; @@ -50,7 +50,6 @@ */ class CFGPrinter extends CompilationPrinter { - public final ByteArrayOutputStream buffer; public final CiTarget target; public final RiRuntime runtime; public LIR lir; @@ -61,9 +60,8 @@ * * @param buffer where the output generated via this printer shown be written */ - public CFGPrinter(ByteArrayOutputStream buffer, CiTarget target, RiRuntime runtime) { - super(buffer); - this.buffer = buffer; + public CFGPrinter(OutputStream out, CiTarget target, RiRuntime runtime) { + super(out); this.target = target; this.runtime = runtime; } @@ -347,22 +345,6 @@ begin("IR"); out.println("LIR"); - if (block.phis != null) { - CiValue[] results = block.phis.results(); - for (int i = 0; i < results.length; i++) { - if (i == 0) { - out.printf("nr %4d ", block.getFirstLirInstructionId()).print(COLUMN_END); - } - out.print("instruction PHI ").print(results[i].toString()).print(" = ("); - String sep = ""; - for (Block pred : block.getPredecessors()) { - out.print(sep).print(block.phis.inputs(pred)[i].toString()); - sep = ", "; - } - out.print(")").print(COLUMN_END).println(COLUMN_END); - } - } - for (int i = 0; i < lirInstructions.size(); i++) { LIRInstruction inst = lirInstructions.get(i); out.printf("nr %4d ", inst.id()).print(COLUMN_END); diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java --- a/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java Thu Feb 09 10:03:21 2012 +0100 @@ -27,118 +27,98 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; import com.oracle.max.graal.alloc.util.*; +import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.alloc.*; import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.compiler.schedule.*; -import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.debug.*; import com.oracle.max.graal.java.*; +import com.oracle.max.graal.lir.*; import com.oracle.max.graal.nodes.*; /** * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the C1 Visualizer. */ -public class CFGPrinterObserver implements CompilationObserver { +public class CFGPrinterObserver implements DebugDumpHandler { + + private CFGPrinter cfgPrinter; - /** - * A thread local stack of {@link CFGPrinter}s to support thread-safety and re-entrant compilation. - */ - private ThreadLocal> observations = new ThreadLocal>() { - @Override - protected java.util.LinkedList initialValue() { - return new LinkedList<>(); - } - }; + private GraalCompiler compiler; + private RiResolvedMethod method; + private SchedulePhase schedule; @Override - public void compilationStarted(CompilationEvent event) { - if (TTY.isSuppressed()) { + public void dump(final Object object, final String message) { + Debug.sandbox("CFGPrinter", new Runnable() { + @Override + public void run() { + dumpSandboxed(object, message); + } + }); + } + + private void dumpSandboxed(final Object object, final String message) { + if (object instanceof GraalCompiler) { + compiler = (GraalCompiler) object; + return; + } else if (object instanceof SchedulePhase) { + schedule = (SchedulePhase) object; + return; + } else if (object instanceof LIRGenerator) { + cfgPrinter.lirGenerator = (LIRGenerator) object; return; } - RiRuntime runtime = event.debugObject(RiRuntime.class); - CiTarget target = event.debugObject(CiTarget.class); - CFGPrinter cfgPrinter = new CFGPrinter(new ByteArrayOutputStream(), target, runtime); - cfgPrinter.printCompilation(event.debugObject(RiResolvedMethod.class)); - observations.get().push(cfgPrinter); - } - - @Override - public void compilationEvent(CompilationEvent event) { - if (TTY.isSuppressed()) { - return; - } - CFGPrinter cfgPrinter = observations.get().peek(); if (cfgPrinter == null) { - return; + File file = new File("compilations-" + System.currentTimeMillis() + ".cfg"); + try { + OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); + cfgPrinter = new CFGPrinter(out, compiler.target, compiler.runtime); + } catch (FileNotFoundException e) { + throw new InternalError("Could not open " + file.getAbsolutePath()); + } } RiRuntime runtime = cfgPrinter.runtime; - if (event.debugObject(LIR.class) != null) { - cfgPrinter.lir = event.debugObject(LIR.class); - } - if (event.debugObject(LIRGenerator.class) != null) { - cfgPrinter.lirGenerator = event.debugObject(LIRGenerator.class); + if (object instanceof RiResolvedMethod) { + method = (RiResolvedMethod) object; + cfgPrinter.printCompilation(method); + + cfgPrinter.lir = null; + cfgPrinter.lirGenerator = null; + schedule = null; + + } else if (object instanceof BciBlockMapping) { + BciBlockMapping blockMap = (BciBlockMapping) object; + cfgPrinter.printCFG(message, blockMap); + cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method)); + + } else if (object instanceof LIR) { + cfgPrinter.lir = (LIR) object; + cfgPrinter.printCFG(message, ((LIR) object).codeEmittingOrder(), schedule); + + } else if (object instanceof StructuredGraph) { + SchedulePhase curSchedule = schedule; + if (curSchedule == null) { + try { + curSchedule = new SchedulePhase(); + curSchedule.apply((StructuredGraph) object); + } catch (Throwable ex) { + // ignore + } + } + cfgPrinter.printCFG(message, Arrays.asList(curSchedule.getCFG().getBlocks()), curSchedule); + + } else if (object instanceof CiTargetMethod) { + cfgPrinter.printMachineCode(runtime.disassemble((CiTargetMethod) object), null); + } else if (object instanceof Interval[]) { + cfgPrinter.printIntervals(message, (Interval[]) object); + } else if (object instanceof IntervalPrinter.Interval[]) { + cfgPrinter.printIntervals(message, (IntervalPrinter.Interval[]) object); } - BciBlockMapping blockMap = event.debugObject(BciBlockMapping.class); - Graph graph = event.debugObject(Graph.class); - SchedulePhase schedule = event.debugObject(SchedulePhase.class); - LinearScan allocator = event.debugObject(LinearScan.class); - Interval[] intervals = event.debugObject(Interval[].class); - IntervalPrinter.Interval[] printIntervals = event.debugObject(IntervalPrinter.Interval[].class); - CiTargetMethod targetMethod = event.debugObject(CiTargetMethod.class); - - if (blockMap != null) { - cfgPrinter.printCFG(event.label, blockMap); - cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method)); - } - if (cfgPrinter.lir != null) { - cfgPrinter.printCFG(event.label, cfgPrinter.lir.codeEmittingOrder(), schedule); - if (targetMethod != null) { - cfgPrinter.printMachineCode(runtime.disassemble(targetMethod), null); - } - } else if (graph != null) { - if (schedule == null) { - try { - schedule = new SchedulePhase(); - schedule.apply((StructuredGraph) graph); - } catch (Throwable t) { - // nothing to do here... - } - } - cfgPrinter.printCFG(event.label, Arrays.asList(schedule.getCFG().getBlocks()), schedule); - } - if (allocator != null && intervals != null) { - cfgPrinter.printIntervals(event.label, intervals); - } - if (printIntervals != null) { - cfgPrinter.printIntervals(event.label, printIntervals); - } - } - - @Override - public void compilationFinished(CompilationEvent event) { - if (TTY.isSuppressed()) { - return; - } - CFGPrinter cfgPrinter = observations.get().pop(); cfgPrinter.flush(); - - OutputStream stream = CompilationPrinter.globalOut(); - if (stream != null) { - synchronized (stream) { - try { - stream.write(cfgPrinter.buffer.toByteArray()); - stream.flush(); - } catch (IOException e) { - TTY.println("WARNING: Error writing CFGPrinter output: %s", e); - } - } - } } } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinter.java --- a/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinter.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinter.java Thu Feb 09 10:03:21 2012 +0100 @@ -27,13 +27,13 @@ import java.util.Map.Entry; import com.oracle.max.cri.ri.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.graph.Node.Verbosity; import com.oracle.max.graal.graph.NodeClass.NodeClassIterator; import com.oracle.max.graal.graph.NodeClass.Position; import com.oracle.max.graal.java.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; /** diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/nodes/MathIntrinsicNode.java --- a/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/nodes/MathIntrinsicNode.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/nodes/MathIntrinsicNode.java Thu Feb 09 10:03:21 2012 +0100 @@ -22,13 +22,13 @@ */ package com.oracle.max.graal.snippets.nodes; -import static com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.*; +import static com.oracle.max.graal.lir.amd64.AMD64Arithmetic.*; import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.target.amd64.AMD64Arithmetic.Op2Reg; import com.oracle.max.graal.compiler.target.amd64.*; -import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.amd64.AMD64Arithmetic.Op2Reg; import com.oracle.max.graal.nodes.*; import com.oracle.max.graal.nodes.calc.*; import com.oracle.max.graal.nodes.spi.*; @@ -71,7 +71,7 @@ case SIN: gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.SIN, result, input)); break; case COS: gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.COS, result, input)); break; case TAN: gen.append(new AMD64MathIntrinsicOp(AMD64MathIntrinsicOp.Opcode.TAN, result, input)); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } gen.setResult(this, result); } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/target/amd64/AMD64MathIntrinsicOp.java --- a/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/target/amd64/AMD64MathIntrinsicOp.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/target/amd64/AMD64MathIntrinsicOp.java Thu Feb 09 10:03:21 2012 +0100 @@ -28,10 +28,10 @@ import com.oracle.max.asm.target.amd64.*; import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.target.amd64.*; -import com.oracle.max.graal.compiler.util.*; +import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.*; +import com.oracle.max.graal.lir.amd64.*; +import com.oracle.max.graal.lir.asm.*; public class AMD64MathIntrinsicOp extends AMD64LIRInstruction { public enum Opcode { @@ -57,7 +57,7 @@ case SIN: masm.fsin(asDoubleReg(result), asDoubleReg(input)); break; case COS: masm.fcos(asDoubleReg(result), asDoubleReg(input)); break; case TAN: masm.ftan(asDoubleReg(result), asDoubleReg(input)); break; - default: throw Util.shouldNotReachHere(); + default: throw GraalInternalError.shouldNotReachHere(); } } @@ -68,6 +68,6 @@ } else if (mode == OperandMode.Output && index == 0) { return EnumSet.of(OperandFlag.Register); } - throw Util.shouldNotReachHere(); + throw GraalInternalError.shouldNotReachHere(); } } diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphScheduleTest.java --- a/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphScheduleTest.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphScheduleTest.java Thu Feb 09 10:03:21 2012 +0100 @@ -26,9 +26,9 @@ import org.junit.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.schedule.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; public class GraphScheduleTest extends GraphTest { diff -r 818757f088d3 -r 6dda62bf5be4 graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/NestedLoopTest.java --- a/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/NestedLoopTest.java Thu Feb 09 10:03:00 2012 +0100 +++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/NestedLoopTest.java Thu Feb 09 10:03:21 2012 +0100 @@ -24,9 +24,9 @@ import org.junit.*; -import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.lir.cfg.*; import com.oracle.max.graal.nodes.*; public class NestedLoopTest extends GraphTest { diff -r 818757f088d3 -r 6dda62bf5be4 mx/projects --- a/mx/projects Thu Feb 09 10:03:00 2012 +0100 +++ b/mx/projects Thu Feb 09 10:03:21 2012 +0100 @@ -60,6 +60,24 @@ project@com.oracle.max.graal.debug@sourceDirs=src project@com.oracle.max.graal.debug@checkstyle=com.oracle.max.graal.graph +# graal.lir +project@com.oracle.max.graal.lir@subDir=graal +project@com.oracle.max.graal.lir@sourceDirs=src +project@com.oracle.max.graal.lir@dependencies=com.oracle.max.asm,com.oracle.max.graal.nodes +project@com.oracle.max.graal.lir@checkstyle=com.oracle.max.graal.graph + +# graal.lir.amd64 +project@com.oracle.max.graal.lir.amd64@subDir=graal +project@com.oracle.max.graal.lir.amd64@sourceDirs=src +project@com.oracle.max.graal.lir.amd64@dependencies=com.oracle.max.graal.lir +project@com.oracle.max.graal.lir.amd64@checkstyle=com.oracle.max.graal.graph + +# graal.alloc +project@com.oracle.max.graal.alloc@subDir=graal +project@com.oracle.max.graal.alloc@sourceDirs=src +project@com.oracle.max.graal.alloc@dependencies=com.oracle.max.graal.lir +project@com.oracle.max.graal.alloc@checkstyle=com.oracle.max.graal.graph + # graal.snippets project@com.oracle.max.graal.snippets@subDir=graal project@com.oracle.max.graal.snippets@sourceDirs=src,test @@ -75,7 +93,7 @@ # graal.compiler project@com.oracle.max.graal.compiler@subDir=graal project@com.oracle.max.graal.compiler@sourceDirs=src -project@com.oracle.max.graal.compiler@dependencies=com.oracle.max.asm,com.oracle.max.graal.nodes +project@com.oracle.max.graal.compiler@dependencies=com.oracle.max.graal.lir.amd64,com.oracle.max.graal.alloc project@com.oracle.max.graal.compiler@checkstyle=com.oracle.max.graal.graph # graal.java diff -r 818757f088d3 -r 6dda62bf5be4 src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Thu Feb 09 10:03:00 2012 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Thu Feb 09 10:03:21 2012 +0100 @@ -1126,8 +1126,11 @@ Register receiver, Register mdp, Register reg2, int start_row, Label& done, bool is_virtual_call) { + // change for GRAAL (use counter to indicate polymorphic case instead of failed typechecks) + bool use_counter_for_polymorphic_case = is_virtual_call || UseGraal; + if (TypeProfileWidth == 0) { - if (is_virtual_call) { + if (use_counter_for_polymorphic_case) { increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); } return; @@ -1164,7 +1167,7 @@ testptr(reg2, reg2); if (start_row == last_row) { // The only thing left to do is handle the null case. - if (is_virtual_call) { + if (use_counter_for_polymorphic_case) { jccb(Assembler::zero, found_null); // Receiver did not match any saved receiver and there is no empty row for it. // Increment total counter to indicate polymorphic case. @@ -1297,7 +1300,8 @@ void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { - if (ProfileInterpreter && TypeProfileCasts) { + // changed for GRAAL (use counter to indicate polymorphism instead of failed typechecks) + if (ProfileInterpreter && TypeProfileCasts && !UseGraal) { Label profile_continue; // If no method data exists, go to profile_continue. diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/nbproject/project.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/nbproject/project.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/Bundle.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/FolderNode.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/GraphNode.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.form diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardConfiguration.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/Bundle.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/DiffGraphAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/DiffGraphCookie.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/GraphOpenCookie.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/GraphRemoveCookie.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/ImportAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/OutlineAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/RemoveAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/RemoveAllAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/RemoveCookie.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/SaveAllAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/actions/SaveAsAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/customLeftWsmode.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/images/import.png diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/images/remove.png diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/images/removeall.png diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/images/save.png diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/images/saveall.gif diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/layer.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/NetworkConnection/nbproject/build-impl.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/NetworkConnection/nbproject/genfiles.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/NetworkConnection/nbproject/project.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/NetworkConnection/nbproject/project.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Bundle.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Client.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/Server.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/project.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/nbproject/project.properties diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/nbproject/project.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/color.filter diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/onlyControlFlow.filter diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/register.filter diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/filters/remove.filter diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/layer.xml diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ContextAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/LookupHistory.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/BoundedZoomAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewer.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorInputGraphProvider.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.form diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/ExportCookie.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/ExtendedSatelliteComponent.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/GraphViewerImplementation.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/NodeQuickSearch.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/CustomizablePanAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExportAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/NextDiagramAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/OverviewAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/PanModeAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/PrevDiagramAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/SelectionModeAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ShowAllAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ZoomInAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ZoomOutAction.java diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/images/export.png diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/images/next_diagram.png diff -r 818757f088d3 -r 6dda62bf5be4 src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/images/prev_diagram.png diff -r 818757f088d3 -r 6dda62bf5be4 src/share/vm/graal/graalCompilerToVM.cpp --- a/src/share/vm/graal/graalCompilerToVM.cpp Thu Feb 09 10:03:00 2012 +0100 +++ b/src/share/vm/graal/graalCompilerToVM.cpp Thu Feb 09 10:03:21 2012 +0100 @@ -239,6 +239,13 @@ return getMethodFromHotSpotMethod(hotspot_method)->has_compiled_code(); } +// public native int RiMethod_getCompiledCodeSize(HotSpotMethodResolved method); +JNIEXPORT jint JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiMethod_1getCompiledCodeSize(JNIEnv *env, jobject, jobject hotspot_method) { + TRACE_graal_3("CompilerToVM::RiMethod_getCompiledCodeSize"); + nmethod* code = getMethodFromHotSpotMethod(hotspot_method)->code(); + return code == NULL ? 0 : code->insts_size(); +} + // public RiType RiSignature_lookupType(String returnType, HotSpotTypeResolved accessingClass); JNIEXPORT jobject JNICALL Java_com_oracle_max_graal_hotspot_bridge_CompilerToVMImpl_RiSignature_1lookupType(JNIEnv *env, jobject, jstring jname, jobject accessingClass, jboolean eagerResolve) { TRACE_graal_3("CompilerToVM::RiSignature_lookupType"); @@ -947,6 +954,7 @@ {CC"HotSpotMethodData_isMature", CC"("METHOD_DATA")Z", FN_PTR(HotSpotMethodData_1isMature)}, {CC"RiMethod_invocationCount", CC"("RESOLVED_METHOD")I", FN_PTR(RiMethod_1invocationCount)}, {CC"RiMethod_hasCompiledCode", CC"("RESOLVED_METHOD")Z", FN_PTR(RiMethod_1hasCompiledCode)}, + {CC"RiMethod_getCompiledCodeSize", CC"("RESOLVED_METHOD")I", FN_PTR(RiMethod_1getCompiledCodeSize)}, {CC"RiSignature_lookupType", CC"("STRING RESOLVED_TYPE"Z)"TYPE, FN_PTR(RiSignature_1lookupType)}, {CC"RiConstantPool_lookupConstant", CC"("RESOLVED_TYPE"I)"OBJECT, FN_PTR(RiConstantPool_1lookupConstant)}, {CC"RiConstantPool_lookupMethod", CC"("RESOLVED_TYPE"IB)"METHOD, FN_PTR(RiConstantPool_1lookupMethod)},