# HG changeset patch # User Christian Wimmer # Date 1328757929 28800 # Node ID 681e969888a7b18769aec862452fe0a890cab588 # Parent dcc8f5c6f394681d5132c93aa3aa2638c2dd38b0 Separate LIR and new register allocator into separate projects diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/NumUtil.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,123 +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.LocationUtil.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.alloc.util.*; -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.debug.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,304 +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.LocationUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.cri.ri.*; -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.debug.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,575 +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.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.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.debug.*; -import com.oracle.max.graal.graph.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +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.LocationUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.alloc.util.*; -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.StandardOp.PhiJumpOp; -import com.oracle.max.graal.compiler.lir.StandardOp.PhiLabelOp; -import com.oracle.max.graal.debug.*; -import com.oracle.max.graal.graph.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,468 +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.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.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.debug.*; -import com.oracle.max.graal.graph.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,276 +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.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.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.debug.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.LocationUtil.*; - -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 dcc8f5c6f394 -r 681e969888a7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LocationUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LocationUtil.java Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +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 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,343 +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.LocationUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.alloc.*; -import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.debug.*; -import com.oracle.max.graal.graph.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,250 +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.LocationUtil.*; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -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.debug.*; -import com.oracle.max.graal.graph.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Wed Feb 08 19:25:29 2012 -0800 @@ -31,16 +31,16 @@ import com.oracle.max.cri.xir.*; 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 { diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ComputeLinearScanOrder.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/Interval.java Wed Feb 08 19:25:29 2012 -0800 @@ -29,8 +29,8 @@ 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,280 +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.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.LIR.SlowPath; -import com.oracle.max.graal.debug.*; -import com.oracle.max.graal.graph.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +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 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,307 +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; - } - - 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/DebugInfoBuilder.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.compiler.lir.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.*; 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; diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/PhiResolver.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.compiler.lir.ValueUtil.*; +import static com.oracle.max.graal.lir.ValueUtil.*; import java.util.*; diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.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.*; - -/** - * 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); - } - - private static int roundUp(int number, int mod) { - return ((number + mod - 1) / mod) * mod; - } - - /** - * 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 = 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 = 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +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.graal.compiler.asm.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.debug.*; -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) { - 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.compiler.lir.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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,447 +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.graal.compiler.asm.*; -import com.oracle.max.graal.graph.*; - -/** - * 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,243 +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.compiler.lir.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.graph.*; - -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,211 +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.graph.*; - -/** - * 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 dcc8f5c6f394 -r 681e969888a7 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/ValueUtil.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/ValueUtil.java Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +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 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/FloatingReadPhase.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoweringPhase.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/BlockClosure.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/SchedulePhase.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/Backend.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.graph.*; - -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(); - } - } - - 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 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Backend.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.graph.*; - -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) { - 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.graph.*; - -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); - } - } - - 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 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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.graph.*; - -/** - * 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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,383 +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.graph.*; -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64DeoptimizationStub.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.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 { diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.lir.StandardOp.JumpOp; -import com.oracle.max.graal.compiler.lir.StandardOp.LabelOp; -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.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.*; diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MethodEndStub.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,486 +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.*; -import com.oracle.max.graal.graph.*; - -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(); - } - } - - - 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 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(); - } - } - - - 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 GraalInternalError.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 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 (Util.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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ /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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64XirOp.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.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, diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/target/amd64/AMD64TailcallOp.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.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. diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.*; diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java Wed Feb 08 19:25:29 2012 -0800 @@ -31,10 +31,10 @@ 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.schedule.*; import com.oracle.max.graal.debug.*; import com.oracle.max.graal.java.*; +import com.oracle.max.graal.lir.*; import com.oracle.max.graal.nodes.*; /** diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinter.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/nodes/MathIntrinsicNode.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.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.*; diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/target/amd64/AMD64MathIntrinsicOp.java Wed Feb 08 19:25:29 2012 -0800 @@ -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.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 { diff -r dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphScheduleTest.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 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 Wed Feb 08 18:19:09 2012 -0800 +++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/NestedLoopTest.java Wed Feb 08 19:25:29 2012 -0800 @@ -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 dcc8f5c6f394 -r 681e969888a7 mx/projects --- a/mx/projects Wed Feb 08 18:19:09 2012 -0800 +++ b/mx/projects Wed Feb 08 19:25:29 2012 -0800 @@ -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