# HG changeset patch # User Christian Wimmer # Date 1328744121 28800 # Node ID cf13124efdd9e80a2da534a3971f09199dfdb442 # Parent 333896b40999747a5834aa5f4891f9f26d5eda9d Restructure phi functions in LIR; Re-enabled C1Visualizer output diff -r 333896b40999 -r cf13124efdd9 graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java --- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java Wed Feb 08 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/AbstractAssembler.java Wed Feb 08 15:35:21 2012 -0800 @@ -48,6 +48,10 @@ l.patchInstructions(this); } + public abstract void align(int modulus); + + public abstract void jmp(Label l); + protected abstract void patchJumpTarget(int branch, int jumpTarget); protected final void emitByte(int x) { diff -r 333896b40999 -r cf13124efdd9 graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java --- a/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java Wed Feb 08 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.asm/src/com/oracle/max/asm/target/amd64/AMD64Assembler.java Wed Feb 08 15:35:21 2012 -0800 @@ -759,6 +759,7 @@ } } + @Override public final void jmp(Label l) { if (l.isBound()) { jmp(l.position(), false); @@ -2876,6 +2877,7 @@ testl(AMD64.rax, new CiAddress(Word, r.asValue(Word), 0)); } + @Override public void align(int modulus) { if (codeBuffer.position() % modulus != 0) { nop(modulus - (codeBuffer.position() % modulus)); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/AssignRegisters.java Wed Feb 08 15:35:21 2012 -0800 @@ -53,7 +53,6 @@ for (int i = lir.linearScanOrder().size() - 1; i >= 0; i--) { Block block = lir.linearScanOrder().get(i); assert trace("start block %s", block); - assert block.phis == null : "Register assignment must run after phi functions have been replaced by moves"; curRegisterRefMap = frameMap.initRegisterRefMap(); curFrameRefMap = frameMap.initFrameRefMap(); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java Wed Feb 08 15:35:21 2012 -0800 @@ -35,7 +35,6 @@ import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; public class DataFlowAnalysis { private final LIR lir; @@ -130,10 +129,6 @@ curOpId = 0; for (Block block : blocks()) { - if (block.phis != null) { - block.phis.forEachOutput(defProc); - } - for (LIRInstruction op : block.lir) { op.setId(curOpId); setBlockOf(curOpId, block); @@ -161,11 +156,10 @@ private int curOpId; private void backwardDataFlow() { - ValueProcedure inputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId); } }; - ValueProcedure aliveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId + 1); } }; - PhiValueProcedure phiInputProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, -1); } }; - ValueProcedure tempProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, true); } }; - ValueProcedure outputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, false); } }; + 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(); @@ -182,12 +176,6 @@ assert trace(" sux %s suxLive: %s", sux, suxLive); variableLive.or(suxLive); } - - if (sux.phis != null) { - curOpId = block.getLastLirInstructionId(); - assert trace(" phis %d variableLive: %s", curOpId, variableLive); - sux.phis.forEachInput(block, phiInputProc); - } } assert registerLive.isEmpty() : "no fixed register must be alive before processing a block"; @@ -204,12 +192,6 @@ op.forEachInput(inputProc); } - if (block.phis != null) { - curOpId = block.getFirstLirInstructionId(); - assert trace(" phis %d variableLive: %s registerLive: %s", curOpId, variableLive, registerLive); - block.phis.forEachOutput(outputProc); - } - assert registerLive.isEmpty() : "no fixed register must be alive after processing a block"; assert liveIn(block) == null; setLiveIn(block, variableLive); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/LinearScanAllocator.java Wed Feb 08 15:35:21 2012 -0800 @@ -37,7 +37,6 @@ import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.debug.*; @@ -150,7 +149,7 @@ private CiValue[] curOutRegisterState; private BitSet curLiveIn; private int curOpId; - private Block curPhiBlock; + private boolean curPhiDefs; private LocationMap canonicalSpillLocations; @@ -179,13 +178,13 @@ } private void allocate() { - ValueProcedure recordUseProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return recordUse(value, mode); } }; - ValueProcedure killNonLiveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killNonLive(value); } }; - ValueProcedure unblockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return unblock(value); } }; - ValueProcedure killProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value); } }; - ValueProcedure blockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return block(value); } }; - PhiValueProcedure useProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, mode, flags); } }; + 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); } }; assert trace("==== start linear scan allocation ===="); canonicalSpillLocations = new LocationMap(lir.numVariables()); @@ -207,20 +206,11 @@ } assert traceState(); - if (block.phis != null) { - assert trace(" phis"); - curPhiBlock = block; - curOpId = block.getFirstLirInstructionId(); - block.phis.forEachOutput(defProc); - curOpId = -1; - curPhiBlock = null; - } - - setBeginLocationsFor(block, new LocationMap(curLocations)); - for (int opIdx = 0; opIdx < block.lir.size(); opIdx++) { LIRInstruction op = block.lir.get(opIdx); curOpId = op.id(); + curPhiDefs = opIdx == 0; + assert trace(" op %d %s", op.id(), op); System.arraycopy(curOutRegisterState, 0, curInRegisterState, 0, curOutRegisterState.length); @@ -253,26 +243,18 @@ // 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); -// curInstruction = null; curOpId = -1; } - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - assert trace(" phis of successor %s", sux); - System.arraycopy(curOutRegisterState, 0, curInRegisterState, 0, curOutRegisterState.length); - curOpId = block.getLastLirInstructionId() + 1; - sux.phis.forEachInput(block, useProc); - curOpId = -1; - } - } - assert endLocationsFor(block) == null; setEndLocationsFor(block, curLocations); @@ -343,11 +325,10 @@ } } - private CiValue recordUse(CiValue value, OperandMode mode) { + private CiValue recordUse(CiValue value) { if (isVariable(value)) { - int id = mode == OperandMode.Input ? curOpId : curOpId + 1; - assert lastUseFor(asVariable(value)) <= id; - setLastUseFor(asVariable(value), id); + assert lastUseFor(asVariable(value)) <= curOpId; + setLastUseFor(asVariable(value), curOpId); } return value; @@ -357,7 +338,7 @@ assert mode == OperandMode.Input || mode == OperandMode.Alive; if (isVariable(value)) { // State values are not recorded beforehand because it does not matter if they are spilled. Still, it is necessary to record them as used now. - recordUse(value, mode); + recordUse(value); Location curLoc = curLocations.get(asVariable(value)); if (isStackSlot(curLoc.location) && flags.contains(OperandFlag.Stack)) { @@ -459,13 +440,14 @@ } if (flags.contains(OperandFlag.Stack) && betterSpillCandidate(curLocations.get(variable), bestSpillCandidate)) { - return selectSpillSlot(variable, mode); + return selectSpillSlot(variable); } if (bestSpillCandidate == null) { - if (curPhiBlock != null) { - return selectSpillSlot(variable, mode); + 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"); @@ -479,7 +461,7 @@ private void spill(Location value) { Location newLoc = spillLocation(value.variable); assert trace(" spill %s to %s", value, newLoc); - if (curPhiBlock == null) { + if (!curPhiDefs) { moveResolver.add(value, newLoc); } curLocations.put(newLoc); @@ -542,16 +524,16 @@ } curOutRegisterState[reg.number] = loc; curLocations.put(loc); - recordUse(variable, mode); + recordUse(variable); assert trace(" selected register %s", loc); return loc; } - private Location selectSpillSlot(Variable variable, OperandMode mode) { + private Location selectSpillSlot(Variable variable) { Location loc = spillLocation(variable); curLocations.put(loc); - recordUse(variable, mode); + recordUse(variable); assert trace(" selected spill slot %s", loc); return loc; diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java Wed Feb 08 15:35:21 2012 -0800 @@ -33,7 +33,8 @@ import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.lir.*; import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; +import com.oracle.max.graal.compiler.lir.StandardOp.PhiJumpOp; +import com.oracle.max.graal.compiler.lir.StandardOp.PhiLabelOp; import com.oracle.max.graal.compiler.util.*; public abstract class ResolveDataFlow { @@ -47,16 +48,17 @@ this.dataFlow = dataFlow; } - private Block curToBlock; private LocationMap curFromLocations; public void execute() { - ValueProcedure locMappingProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return locMapping(value); } }; - PhiValueProcedure phiMappingProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue input, CiValue output) { return phiMapping(input, output); } }; + ValueProcedure locMappingProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return locMapping(value); } }; assert trace("==== start resolve data flow ===="); for (Block toBlock : lir.linearScanOrder()) { - curToBlock = toBlock; + PhiLabelOp phiDefs = null; + if (toBlock.lir.get(0) instanceof PhiLabelOp) { + phiDefs = (PhiLabelOp) toBlock.lir.get(0); + } for (Block fromBlock : toBlock.getPredecessors()) { assert trace("start edge %s -> %s", fromBlock, toBlock); @@ -68,16 +70,20 @@ toLocations.forEachLocation(locMappingProc); } - if (toBlock.phis != null) { - toBlock.phis.forEachInput(fromBlock, phiMappingProc); + if (phiDefs != null) { + PhiJumpOp phiInputs = (PhiJumpOp) fromBlock.lir.get(fromBlock.lir.size() - 1); + phiMapping(phiInputs.getPhiInputs(), phiDefs.getPhiDefinitions()); + phiInputs.markResolved(); } moveResolver.resolve(); assert trace("end edge %s -> %s", fromBlock, toBlock); } - // Phi functions are resolved with moves now, so delete them. - toBlock.phis = null; + if (phiDefs != null) { + // Phi functions are resolved with moves now, so delete them. + phiDefs.markResolved(); + } } moveResolver.finish(); assert trace("==== end resolve data flow ===="); @@ -86,17 +92,19 @@ private CiValue locMapping(CiValue value) { Location to = asLocation(value); Location from = curFromLocations.get(to.variable); - if (value != from && dataFlow.liveIn(curToBlock).get(to.variable.index)) { + if (value != from && from != null) { moveResolver.add(from, to); } return value; } - private CiValue phiMapping(CiValue input, CiValue output) { - if (input != output) { - moveResolver.add(input, asLocation(output)); + 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])); + } } - return input; } private void findInsertPos(Block fromBlock, Block toBlock) { diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java Wed Feb 08 15:35:21 2012 -0800 @@ -37,7 +37,6 @@ import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.debug.*; @@ -154,15 +153,14 @@ } private void allocate() { - ValueProcedure killNonLiveProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killNonLive(value); } }; - ValueProcedure killBeginProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, false); } }; - ValueProcedure killEndProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, true); } }; - ValueProcedure killLocationProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killLocation(value); } }; - ValueProcedure blockProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return block(value); } }; - ValueProcedure loadProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return load(value, mode, flags); } }; - ValueProcedure spillProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return spill(value, mode, flags); } }; - PhiValueProcedure useSlotProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value) { return useSlot(value); } }; - ValueProcedure defSlotProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return defSlot(value); } }; + 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); } }; assert trace("==== start spill all allocation ===="); curInRegisterState = new Object[maxRegisterNum()]; @@ -184,11 +182,6 @@ } assert traceState(); - if (block.phis != null) { - assert trace(" phis"); - block.phis.forEachOutput(defSlotProc); - } - for (int opIdx = 0; opIdx < block.lir.size(); opIdx++) { LIRInstruction op = block.lir.get(opIdx); curInstruction = op; @@ -224,15 +217,6 @@ curInstruction = null; } assert checkEmpty(curOutRegisterState); - - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - assert trace(" phis of successor %s", sux); - sux.phis.forEachInput(block, useSlotProc); - } - } - - assert checkEmpty(curOutRegisterState); assert locationsFor(block) == null; setLocationsFor(block, curStackLocations); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/IntervalPrinter.java Wed Feb 08 15:35:21 2012 -0800 @@ -35,26 +35,24 @@ import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; +import com.oracle.max.graal.debug.*; public final class IntervalPrinter { - @SuppressWarnings("unused") public static void printBeforeAllocation(String label, LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow) { - // TODO(tw): Fix printing. -// if (context.isObserved()) { -// IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, null); -// context.observable.fireCompilationEvent(label, lir, printer.execute()); -// } + if (Debug.isDumpEnabled()) { + IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, null); + Debug.dump(lir, label); + Debug.dump(printer.execute(), label); + } } - @SuppressWarnings("unused") public static void printAfterAllocation(String label, LIR lir, RiRegisterConfig registerConfig, DataFlowAnalysis dataFlow, LocationMap[] blockEndLocations) { - // TODO(tw): Fix printing. -// if (context.isObserved()) { -// IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, blockEndLocations); -// context.observable.fireCompilationEvent(label, lir, printer.execute()); -// } + if (Debug.isDumpEnabled()) { + IntervalPrinter printer = new IntervalPrinter(lir, registerConfig, dataFlow, blockEndLocations); + Debug.dump(lir, label); + Debug.dump(printer.execute(), label); + } } @@ -128,16 +126,13 @@ ValueProcedure varProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return var(value); } }; for (Block block : lir.linearScanOrder()) { - if (block.phis != null) { - block.phis.forEachOutput(varProc); - } for (LIRInstruction op : block.lir) { op.forEachOutput(varProc); } } - PhiValueProcedure useProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, flags); } }; + 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")); @@ -157,13 +152,6 @@ } } - curOpId = block.getLastLirInstructionId() + 1; - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - sux.phis.forEachInput(block, useProc); - } - } - for (int j = block.lir.size() - 1; j >= 0; j--) { LIRInstruction op = block.lir.get(j); if (op.id() >= 0) { @@ -188,11 +176,6 @@ } } - if (block.phis != null) { - curOpId = block.getFirstLirInstructionId() + 1; - block.phis.forEachOutput(defProc); - } - for (Interval interval : intervals.values()) { if (interval.lastTo != 0) { interval.ranges.add(new Range(block.getFirstLirInstructionId(), interval.lastTo)); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/MoveResolver.java Wed Feb 08 15:35:21 2012 -0800 @@ -83,6 +83,10 @@ assert checkValid(); } + public boolean hasMappings() { + return mappingFrom.size() > 0; + } + public void resolve() { assert checkValid(); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/RegisterVerifier.java Wed Feb 08 15:35:21 2012 -0800 @@ -97,7 +97,6 @@ assert trace("==== start verify register allocation ===="); do { Block block = workList.remove(0); - assert block.phis == null : "phi functions must have been resolved with moves"; // Must copy state because it is modified. curInputState = copy(stateFor(block)); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java Wed Feb 08 15:35:21 2012 -0800 @@ -81,6 +81,9 @@ if (osrBCI != -1) { throw new CiBailout("No OSR supported"); } + Debug.dump(this, "compiler"); + Debug.dump(method, "method"); + return Debug.scope(createScopeName(method), new Callable() { public CiTargetMethod call() { final CiAssumptions assumptions = GraalOptions.OptAssumptions ? new CiAssumptions() : null; @@ -189,6 +192,7 @@ final SchedulePhase schedule = new SchedulePhase(); schedule.apply(graph); + Debug.dump(schedule, "final schedule"); final Block[] blocks = schedule.getCFG().getBlocks(); final Block startBlock = schedule.getCFG().getStartBlock(); @@ -219,6 +223,7 @@ public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final RiResolvedMethod method) { final FrameMap frameMap = backend.newFrameMap(runtime.getRegisterConfig(method)); final LIRGenerator lirGenerator = backend.newLIRGenerator(graph, frameMap, method, lir, xir); + Debug.dump(lirGenerator, "LIRGenerator"); Debug.scope("LIRGen", new Runnable() { public void run() { @@ -226,13 +231,7 @@ lirGenerator.doBlock(b); } - for (Block b : lir.linearScanOrder()) { - if (b.phis != null) { - b.phis.fillInputs(lirGenerator); - } - } - - Debug.dump(lirGenerator, "After LIR generation"); + Debug.dump(lir, "After LIR generation"); if (GraalOptions.PrintLIR && !TTY.isSuppressed()) { LIR.printLIR(lir.linearScanOrder()); } @@ -269,6 +268,7 @@ targetMethod.setAssumptions(assumptions); } + Debug.dump(lir, "After code generation"); Debug.dump(targetMethod, "After code generation"); return targetMethod; } diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/Block.java Wed Feb 08 15:35:21 2012 -0800 @@ -45,14 +45,12 @@ protected Block postdominator; // Fields that still need to be worked on, try to remove them later. - public FrameState lastState; public List lir; public boolean align; public int linearScanNumber; - public LIRPhiMapping phis; public Block() { - id = -1; + id = ControlFlowGraph.BLOCK_ID_INITIAL; } public int getId() { diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/cfg/ControlFlowGraph.java Wed Feb 08 15:35:21 2012 -0800 @@ -24,6 +24,7 @@ import java.util.*; +import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.graph.*; import com.oracle.max.graal.nodes.*; @@ -79,6 +80,9 @@ 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; @@ -129,22 +133,24 @@ do { Block block = stack.get(stack.size() - 1); - if (block.id == -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); - if (suxBlock.id < 0) { + assert suxBlock.id != BLOCK_ID_VISITED; + if (suxBlock.id == BLOCK_ID_INITIAL) { stack.add(suxBlock); } } - block.id = -2; - } else { + 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. - assert block.id == -2; stack.remove(stack.size() - 1); + reversePostOrder[reversePostOrderId] = block; block.id = reversePostOrderId; - reversePostOrder[reversePostOrderId] = block; reversePostOrderId--; + } else { + throw Util.shouldNotReachHere(); } } while (!stack.isEmpty()); assert reversePostOrderId == -1; diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java Wed Feb 08 15:35:21 2012 -0800 @@ -48,7 +48,7 @@ import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.cfg.*; import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.lir.StandardOp.ParametersOp; +import com.oracle.max.graal.compiler.lir.StandardOp.*; import com.oracle.max.graal.compiler.util.*; import com.oracle.max.graal.debug.*; import com.oracle.max.graal.graph.*; @@ -130,7 +130,9 @@ /** * Mapping from blocks to the lock state at the end of the block, indexed by the id number of the block. */ - private LockScope[] blockLocks; + private BlockMap blockLocks; + + private BlockMap blockLastState; /** * The list of currently locked monitors. @@ -149,7 +151,8 @@ this.xir = xir; this.xirSupport = new XirSupport(); this.debugInfoBuilder = new DebugInfoBuilder(nodeOperands); - this.blockLocks = new LockScope[lir.linearScanOrder().size()]; + this.blockLocks = new BlockMap<>(lir.cfg); + this.blockLastState = new BlockMap<>(lir.cfg); } @Override @@ -157,14 +160,6 @@ return target; } - private LockScope locksFor(Block block) { - return blockLocks[block.getId()]; - } - - private void setLocksFor(Block block, LockScope locks) { - blockLocks[block.getId()] = locks; - } - /** * Returns the operand that has been previously initialized by {@link #setResult()} * with the result of an instruction. @@ -300,7 +295,21 @@ assert block.lir == null : "LIR list already computed for this block"; block.lir = new ArrayList<>(); - emitLabel(new Label(), block.align); + if (GraalOptions.AllocSSA && block.getBeginNode() instanceof MergeNode) { + assert phiValues.isEmpty(); + MergeNode merge = (MergeNode) block.getBeginNode(); + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value) { + CiValue phiValue = newVariable(phi.kind()); + setResult(phi, phiValue); + phiValues.add(phiValue); + } + } + append(new PhiLabelOp(new Label(), block.align, phiValues.toArray(new CiValue[phiValues.size()]))); + phiValues.clear(); + } else { + append(new LabelOp(new Label(), block.align)); + } if (GraalOptions.TraceLIRGeneratorLevel >= 1) { TTY.println("BEGIN Generating LIR for block B" + block.getId()); @@ -308,7 +317,7 @@ curLocks = null; for (Block pred : block.getPredecessors()) { - LockScope predLocks = locksFor(pred); + LockScope predLocks = blockLocks.get(pred); if (curLocks == null) { curLocks = predLocks; } else if (curLocks != predLocks && (!pred.isLoopEnd() || predLocks != null)) { @@ -326,8 +335,8 @@ for (Block pred : block.getPredecessors()) { if (fs == null) { - fs = pred.lastState; - } else if (fs != pred.lastState) { + fs = blockLastState.get(pred); + } else if (fs != blockLastState.get(pred)) { fs = null; break; } @@ -345,10 +354,6 @@ lastState = fs; } - if (GraalOptions.AllocSSA && block.getBeginNode() instanceof MergeNode) { - block.phis = new LIRPhiMapping(block, this); - } - List nodes = lir.nodesFor(block); for (int i = 0; i < nodes.size(); i++) { Node instr = nodes.get(i); @@ -406,8 +411,8 @@ TTY.println("END Generating LIR for block B" + block.getId()); } - setLocksFor(currentBlock, curLocks); - block.lastState = lastState; + blockLocks.put(currentBlock, curLocks); + blockLastState.put(block, lastState); currentBlock = null; if (GraalOptions.PrintIRWithLIR) { @@ -665,27 +670,65 @@ @Override public void visitMerge(MergeNode x) { - if (x.next() instanceof LoopBeginNode) { - moveToPhi((LoopBeginNode) x.next(), x); - } } @Override public void visitEndNode(EndNode end) { - assert end.merge() != null; moveToPhi(end.merge(), end); - emitJump(getLIRBlock(end.merge()), null); } @Override public void visitLoopEnd(LoopEndNode x) { - moveToPhi(x.loopBegin(), x); if (GraalOptions.GenLoopSafepoints && x.hasSafepointPolling()) { emitSafepointPoll(x); } - emitJump(getLIRBlock(x.loopBegin()), null); + moveToPhi(x.loopBegin(), x); } + private ArrayList phiValues = new ArrayList<>(); + + private void moveToPhi(MergeNode merge, FixedNode pred) { + if (GraalOptions.AllocSSA) { + assert phiValues.isEmpty(); + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value) { + phiValues.add(operand(phi.valueAt(pred))); + } + } + append(new PhiJumpOp(getLIRBlock(merge), phiValues.toArray(new CiValue[phiValues.size()]))); + phiValues.clear(); + return; + } + + if (GraalOptions.TraceLIRGeneratorLevel >= 1) { + TTY.println("MOVE TO PHI from " + pred + " to " + merge); + } + PhiResolver resolver = new PhiResolver(this); + for (PhiNode phi : merge.phis()) { + if (phi.type() == PhiType.Value) { + ValueNode curVal = phi.valueAt(pred); + resolver.move(operand(curVal), operandForPhi(phi)); + } + } + resolver.dispose(); + + append(new JumpOp(getLIRBlock(merge), null)); + } + + private CiValue operandForPhi(PhiNode phi) { + assert phi.type() == PhiType.Value : "wrong phi type: " + phi; + CiValue result = operand(phi); + if (result == null) { + // allocate a variable for this phi + Variable newOperand = newVariable(phi.kind()); + setResult(phi, newOperand); + return newOperand; + } else { + return result; + } + } + + public void emitSafepointPoll(FixedNode x) { if (!lastState.method().noSafepointPolls()) { XirSnippet snippet = xir.genSafepointPoll(site(x)); @@ -1127,40 +1170,6 @@ } - - private void moveToPhi(MergeNode merge, FixedNode pred) { - if (GraalOptions.AllocSSA) { - return; - } - - if (GraalOptions.TraceLIRGeneratorLevel >= 1) { - TTY.println("MOVE TO PHI from " + pred + " to " + merge); - } - PhiResolver resolver = new PhiResolver(this); - for (PhiNode phi : merge.phis()) { - if (phi.type() == PhiType.Value) { - ValueNode curVal = phi.valueAt(pred); - resolver.move(operand(curVal), operandForPhi(phi)); - } - } - resolver.dispose(); - } - - private CiValue operandForPhi(PhiNode phi) { - assert phi.type() == PhiType.Value : "wrong phi type: " + phi; - CiValue result = operand(phi); - if (result == null) { - // allocate a variable for this phi - Variable newOperand = newVariable(phi.kind()); - setResult(phi, newOperand); - return newOperand; - } else { - return result; - } - } - - - protected XirArgument toXirArgument(CiValue v) { if (v == null) { return null; diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java Wed Feb 08 15:35:21 2012 -0800 @@ -162,22 +162,22 @@ /** * The output operands for this instruction (modified by the register allocator). */ - protected final CiValue[] outputs; + protected CiValue[] outputs; /** * The input operands for this instruction (modified by the register allocator). */ - protected final CiValue[] inputs; + protected CiValue[] inputs; /** * The alive operands for this instruction (modified by the register allocator). */ - protected final CiValue[] alives; + protected CiValue[] alives; /** * The temp operands for this instruction (modified by the register allocator). */ - protected final CiValue[] temps; + protected CiValue[] temps; /** * Used to emit debug information. diff -r 333896b40999 -r cf13124efdd9 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRPhiMapping.java --- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRPhiMapping.java Wed Feb 08 17:40:55 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.max.graal.compiler.lir; - -import java.util.*; - -import com.oracle.max.cri.ci.*; -import com.oracle.max.graal.compiler.cfg.*; -import com.oracle.max.graal.compiler.gen.*; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; -import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; -import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.nodes.*; -import com.oracle.max.graal.nodes.PhiNode.*; - -public class LIRPhiMapping { - private final Block block; - - private CiValue[][] inputs; - private CiValue[] results; - - public LIRPhiMapping(Block block, LIRGenerator gen) { - this.block = block; - - assert block.getBeginNode() instanceof MergeNode : "phi functions are only present at control flow merges"; - MergeNode mergeNode = (MergeNode) block.getBeginNode(); - List phis = mergeNode.phis().snapshot(); - - for (int i = 0; i < phis.size(); i++) { - PhiNode phi = phis.get(i); - if (phi.type() == PhiType.Value) { - gen.setResult(phi, gen.newVariable(phi.kind())); - } - } - } - - public void fillInputs(LIRGenerator gen) { - assert block.getBeginNode() instanceof MergeNode : "phi functions are only present at control flow merges"; - MergeNode mergeNode = (MergeNode) block.getBeginNode(); - List phis = mergeNode.phis().snapshot(); - - int numPhis = 0; - for (int i = 0; i < phis.size(); i++) { - if (phis.get(i).type() == PhiType.Value) { - numPhis++; - } - } - int numPreds = block.numberOfPreds(); - - results = new CiValue[numPhis]; - inputs = new CiValue[numPreds][numPhis]; - - int phiIdx = 0; - for (int i = 0; i < phis.size(); i++) { - PhiNode phi = phis.get(i); - if (phi.type() == PhiType.Value) { - results[phiIdx] = gen.operand(phi); - for (int j = 0; j < numPreds; j++) { - assert j == mergeNode.phiPredecessorIndex((FixedNode) block.predAt(j).getEndNode()) : "block predecessors and node predecessors must have same order"; - inputs[j][phiIdx] = gen.operand(phi.valueAt(j)); - } - phiIdx++; - } - } - assert phiIdx == numPhis; - } - - public CiValue[] results() { - return results; - } - - public CiValue[] inputs(Block pred) { - assert pred.numberOfSux() == 1 && pred.suxAt(0) == block; - return inputs[block.getPredecessors().indexOf(pred)]; - } - - private static final EnumSet INPUT_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant); - private static final EnumSet OUTPUT_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack); - - public void forEachInput(Block pred, PhiValueProcedure proc) { - CiValue[] predInputs = inputs(pred); - for (int i = 0; i < predInputs.length; i++) { - predInputs[i] = proc.doValue(predInputs[i], results[i]); - } - } - - public void forEachOutput(ValueProcedure proc) { - for (int i = 0; i < results.length; i++) { - results[i] = proc.doValue(results[i], OperandMode.Output, OUTPUT_FLAGS); - } - } - - public abstract static class PhiValueProcedure extends ValueProcedure { - /** - * Iterator method to be overwritten. This version of the iterator has both the input and output of the phi function as parameters. - * to keep the signature short. - * - * @param input The input value that is iterated. - * @param output The output value that is iterated. - * @return The new value to replace the input value that was passed in. - */ - protected CiValue doValue(CiValue input, CiValue output) { - return doValue(input, OperandMode.Input, INPUT_FLAGS); - } - } - - @Override - public String toString() { - return "PhiMapping for " + block + ": " + Arrays.toString(results); - } -} diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRVerifier.java Wed Feb 08 15:35:21 2012 -0800 @@ -33,7 +33,6 @@ import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag; import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode; import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure; -import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure; import com.oracle.max.graal.compiler.util.*; public final class LIRVerifier { @@ -96,8 +95,8 @@ private BitSet curRegistersDefined; private void verify() { - PhiValueProcedure useProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return use(value, mode, flags); } }; - ValueProcedure defProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet flags) { return def(value, mode, flags); } }; + 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()) { @@ -109,13 +108,24 @@ curVariablesLive.or(liveOutFor(block.getDominator())); } - if (block.phis != null) { - assert beforeRegisterAllocation; - curInstruction = block.phis; - block.phis.forEachOutput(defProc); + assert block.lir.get(0) instanceof StandardOp.LabelOp : "block must start with label"; + if (block.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; + } + } } - assert block.lir.get(0) instanceof StandardOp.LabelOp : "block must start with label"; if (block.numberOfSux() > 0) { LIRInstruction last = block.lir.get(block.lir.size() - 1); assert last instanceof StandardOp.JumpOp || last instanceof LIRXirInstruction : "block with successor must end with unconditional jump"; @@ -139,14 +149,6 @@ curInstruction = null; } - for (Block sux : block.getSuccessors()) { - if (sux.phis != null) { - assert beforeRegisterAllocation; - curInstruction = sux.phis; - sux.phis.forEachInput(block, useProc); - } - } - setLiveOutFor(block, curVariablesLive); } } diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/StandardOp.java Wed Feb 08 15:35:21 2012 -0800 @@ -35,23 +35,130 @@ */ public class StandardOp { + private static CiValue[] EMPTY = new CiValue[0]; + /** - * Marker interface for a LIR operation that defines the position of a label. + * LIR operation that defines the position of a label. * The first operation of every block must implement this interface. */ - public interface LabelOp { - Label getLabel(); + 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 Util.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 Util.shouldNotReachHere(); + } + + public void markResolved() { + outputs = EMPTY; + } + + public CiValue[] getPhiDefinitions() { + return outputs; + } } /** - * Marker interface for a LIR operation that is an unconditional jump to {@link #destination()}. + * LIR operation that is an unconditional jump to {@link #destination()}. * When the LIR is constructed, the last operation of every block must implement this interface. After * register allocation, unnecessary jumps can be deleted. * * TODO Currently, a block can also end with an XIR operation. */ - public interface JumpOp { - LabelRef destination(); + 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 Util.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 Util.shouldNotReachHere(); + } + + public void markResolved() { + alives = EMPTY; + } + + public CiValue[] getPhiInputs() { + return alives; + } } /** diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ControlFlow.java Wed Feb 08 15:35:21 2012 -0800 @@ -39,41 +39,6 @@ public class AMD64ControlFlow { - public static class LabelOp extends AMD64LIRInstruction implements StandardOp.LabelOp { - private final Label label; - private final boolean align; - - public LabelOp(Label label, boolean align) { - super("LABEL", LIRInstruction.NO_OPERANDS, null, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.label = label; - this.align = align; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - if (align) { - masm.align(tasm.target.wordSize); - } - masm.bind(label); - } - - @Override - public String operationString() { - return label.toString(); - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - throw Util.shouldNotReachHere(); - } - - @Override - public Label getLabel() { - return label; - } - } - - public static class ReturnOp extends AMD64LIRInstruction { public ReturnOp(CiValue input) { super("RETURN", LIRInstruction.NO_OPERANDS, null, new CiValue[] {input}, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); @@ -94,36 +59,6 @@ } - public static class JumpOp extends AMD64LIRInstruction implements StandardOp.JumpOp { - private final LabelRef destination; - - public JumpOp(LabelRef destination, LIRDebugInfo info) { - super("JUMP", LIRInstruction.NO_OPERANDS, info, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS); - this.destination = destination; - } - - @Override - public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) { - masm.jmp(destination.label()); - } - - @Override - public LabelRef destination() { - return destination; - } - - @Override - public String operationString() { - return "[" + destination + "]"; - } - - @Override - protected EnumSet flagsFor(OperandMode mode, int index) { - throw Util.shouldNotReachHere(); - } - } - - public static class BranchOp extends AMD64LIRInstruction implements StandardOp.BranchOp { protected Condition condition; protected LabelRef destination; diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java Wed Feb 08 15:35:21 2012 -0800 @@ -39,6 +39,8 @@ 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; @@ -52,8 +54,6 @@ import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.CondMoveOp; import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.FloatBranchOp; import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.FloatCondMoveOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.JumpOp; -import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.LabelOp; import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.ReturnOp; import com.oracle.max.graal.compiler.target.amd64.AMD64ControlFlow.TableSwitchOp; import com.oracle.max.graal.compiler.target.amd64.AMD64Move.CompareAndSwapOp; diff -r 333896b40999 -r cf13124efdd9 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java Wed Feb 08 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/HotSpotDebugConfig.java Wed Feb 08 15:35:21 2012 -0800 @@ -49,6 +49,7 @@ this.dumpFilter = dumpFilter; this.methodFilter = methodFilter; dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort)); + dumpHandlers.add(new CFGPrinterObserver()); } public boolean isLogEnabled() { diff -r 333896b40999 -r cf13124efdd9 graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java --- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java Wed Feb 08 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java Wed Feb 08 15:35:21 2012 -0800 @@ -1173,7 +1173,7 @@ private SimpleTemplates typeCheckTemplates = new SimpleTemplates(NULL_CHECK) { @Override protected XirTemplate create(CiXirAssembler asm, long flags) { - asm.restart(); + asm.restart(CiKind.Void); XirParameter objHub = asm.createInputParameter("objectHub", CiKind.Object); XirOperand hub = asm.createConstantInputParameter("hub", CiKind.Object); XirLabel falseSucc = asm.createInlineLabel(XirLabel.FalseSuccessor); @@ -1188,7 +1188,7 @@ // if we get an exact match: continue asm.jneq(falseSucc, objHub, checkHub); - return asm.finishTemplate(objHub, "typeCheck"); + return asm.finishTemplate("typeCheck"); } }; diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java Wed Feb 08 15:35:21 2012 -0800 @@ -50,7 +50,6 @@ */ class CFGPrinter extends CompilationPrinter { - public final ByteArrayOutputStream buffer; public final CiTarget target; public final RiRuntime runtime; public LIR lir; @@ -61,9 +60,8 @@ * * @param buffer where the output generated via this printer shown be written */ - public CFGPrinter(ByteArrayOutputStream buffer, CiTarget target, RiRuntime runtime) { - super(buffer); - this.buffer = buffer; + public CFGPrinter(OutputStream out, CiTarget target, RiRuntime runtime) { + super(out); this.target = target; this.runtime = runtime; } @@ -347,22 +345,6 @@ begin("IR"); out.println("LIR"); - if (block.phis != null) { - CiValue[] results = block.phis.results(); - for (int i = 0; i < results.length; i++) { - if (i == 0) { - out.printf("nr %4d ", block.getFirstLirInstructionId()).print(COLUMN_END); - } - out.print("instruction PHI ").print(results[i].toString()).print(" = ("); - String sep = ""; - for (Block pred : block.getPredecessors()) { - out.print(sep).print(block.phis.inputs(pred)[i].toString()); - sep = ", "; - } - out.print(")").print(COLUMN_END).println(COLUMN_END); - } - } - for (int i = 0; i < lirInstructions.size(); i++) { LIRInstruction inst = lirInstructions.get(i); out.printf("nr %4d ", inst.id()).print(COLUMN_END); diff -r 333896b40999 -r cf13124efdd9 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 17:40:55 2012 +0100 +++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java Wed Feb 08 15:35:21 2012 -0800 @@ -27,14 +27,13 @@ import com.oracle.max.cri.ci.*; import com.oracle.max.cri.ri.*; -import com.oracle.max.criutils.*; import com.oracle.max.graal.alloc.util.*; +import com.oracle.max.graal.compiler.*; import com.oracle.max.graal.compiler.alloc.*; import com.oracle.max.graal.compiler.gen.*; import com.oracle.max.graal.compiler.lir.*; -import com.oracle.max.graal.compiler.observer.*; import com.oracle.max.graal.compiler.schedule.*; -import com.oracle.max.graal.graph.*; +import com.oracle.max.graal.debug.*; import com.oracle.max.graal.java.*; import com.oracle.max.graal.nodes.*; @@ -42,103 +41,84 @@ * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the C1 Visualizer. */ -public class CFGPrinterObserver implements CompilationObserver { +public class CFGPrinterObserver implements DebugDumpHandler { + + private CFGPrinter cfgPrinter; - /** - * A thread local stack of {@link CFGPrinter}s to support thread-safety and re-entrant compilation. - */ - private ThreadLocal> observations = new ThreadLocal>() { - @Override - protected java.util.LinkedList initialValue() { - return new LinkedList<>(); - } - }; + private GraalCompiler compiler; + private RiResolvedMethod method; + private SchedulePhase schedule; @Override - public void compilationStarted(CompilationEvent event) { - if (TTY.isSuppressed()) { + public void dump(final Object object, final String message) { + Debug.sandbox("CFGPrinter", new Runnable() { + @Override + public void run() { + dumpSandboxed(object, message); + } + }); + } + + private void dumpSandboxed(final Object object, final String message) { + if (object instanceof GraalCompiler) { + compiler = (GraalCompiler) object; + return; + } else if (object instanceof SchedulePhase) { + schedule = (SchedulePhase) object; + return; + } else if (object instanceof LIRGenerator) { + cfgPrinter.lirGenerator = (LIRGenerator) object; return; } - RiRuntime runtime = event.debugObject(RiRuntime.class); - CiTarget target = event.debugObject(CiTarget.class); - CFGPrinter cfgPrinter = new CFGPrinter(new ByteArrayOutputStream(), target, runtime); - cfgPrinter.printCompilation(event.debugObject(RiResolvedMethod.class)); - observations.get().push(cfgPrinter); - } - - @Override - public void compilationEvent(CompilationEvent event) { - if (TTY.isSuppressed()) { - return; - } - CFGPrinter cfgPrinter = observations.get().peek(); if (cfgPrinter == null) { - return; + File file = new File("compilations-" + System.currentTimeMillis() + ".cfg"); + try { + OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); + cfgPrinter = new CFGPrinter(out, compiler.target, compiler.runtime); + } catch (FileNotFoundException e) { + throw new InternalError("Could not open " + file.getAbsolutePath()); + } } RiRuntime runtime = cfgPrinter.runtime; - if (event.debugObject(LIR.class) != null) { - cfgPrinter.lir = event.debugObject(LIR.class); - } - if (event.debugObject(LIRGenerator.class) != null) { - cfgPrinter.lirGenerator = event.debugObject(LIRGenerator.class); + if (object instanceof RiResolvedMethod) { + method = (RiResolvedMethod) object; + cfgPrinter.printCompilation(method); + + cfgPrinter.lir = null; + cfgPrinter.lirGenerator = null; + schedule = null; + + } else if (object instanceof BciBlockMapping) { + BciBlockMapping blockMap = (BciBlockMapping) object; + cfgPrinter.printCFG(message, blockMap); + cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method)); + + } else if (object instanceof LIR) { + cfgPrinter.lir = (LIR) object; + cfgPrinter.printCFG(message, ((LIR) object).codeEmittingOrder(), schedule); + + } else if (object instanceof StructuredGraph) { + SchedulePhase curSchedule = schedule; + if (curSchedule == null) { + try { + curSchedule = new SchedulePhase(); + curSchedule.apply((StructuredGraph) object); + } catch (Throwable ex) { + // ignore + } + } + cfgPrinter.printCFG(message, Arrays.asList(curSchedule.getCFG().getBlocks()), curSchedule); + + } else if (object instanceof CiTargetMethod) { + cfgPrinter.printMachineCode(runtime.disassemble((CiTargetMethod) object), null); + } else if (object instanceof Interval[]) { + cfgPrinter.printIntervals(message, (Interval[]) object); + } else if (object instanceof IntervalPrinter.Interval[]) { + cfgPrinter.printIntervals(message, (IntervalPrinter.Interval[]) object); } - BciBlockMapping blockMap = event.debugObject(BciBlockMapping.class); - Graph graph = event.debugObject(Graph.class); - SchedulePhase schedule = event.debugObject(SchedulePhase.class); - LinearScan allocator = event.debugObject(LinearScan.class); - Interval[] intervals = event.debugObject(Interval[].class); - IntervalPrinter.Interval[] printIntervals = event.debugObject(IntervalPrinter.Interval[].class); - CiTargetMethod targetMethod = event.debugObject(CiTargetMethod.class); - - if (blockMap != null) { - cfgPrinter.printCFG(event.label, blockMap); - cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method)); - } - if (cfgPrinter.lir != null) { - cfgPrinter.printCFG(event.label, cfgPrinter.lir.codeEmittingOrder(), schedule); - if (targetMethod != null) { - cfgPrinter.printMachineCode(runtime.disassemble(targetMethod), null); - } - } else if (graph != null) { - if (schedule == null) { - try { - schedule = new SchedulePhase(); - schedule.apply((StructuredGraph) graph); - } catch (Throwable t) { - // nothing to do here... - } - } - cfgPrinter.printCFG(event.label, Arrays.asList(schedule.getCFG().getBlocks()), schedule); - } - if (allocator != null && intervals != null) { - cfgPrinter.printIntervals(event.label, intervals); - } - if (printIntervals != null) { - cfgPrinter.printIntervals(event.label, printIntervals); - } - } - - @Override - public void compilationFinished(CompilationEvent event) { - if (TTY.isSuppressed()) { - return; - } - CFGPrinter cfgPrinter = observations.get().pop(); cfgPrinter.flush(); - - OutputStream stream = CompilationPrinter.globalOut(); - if (stream != null) { - synchronized (stream) { - try { - stream.write(cfgPrinter.buffer.toByteArray()); - stream.flush(); - } catch (IOException e) { - TTY.println("WARNING: Error writing CFGPrinter output: %s", e); - } - } - } } }