# HG changeset patch # User Doug Simon # Date 1396003302 -3600 # Node ID 667710021ea1c0b881746f2265b917f64d255643 # Parent a8dce92315a221501f5ea10be68feb86d9e0d8cd removed methods in Indent that are redundant with those in Debug diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java Fri Mar 28 11:41:42 2014 +0100 @@ -506,10 +506,10 @@ } public void processBlock(BciBlock block) { - Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader); - currentBlock = block; - iterateBytecodesForBlock(block); - indent.outdent(); + try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader)) { + currentBlock = block; + iterateBytecodesForBlock(block); + } } private void createExceptionDispatch(ExceptionDispatchBlock block) { diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Fri Mar 28 11:41:42 2014 +0100 @@ -279,7 +279,7 @@ /** * Creates a new interval. - * + * * @param operand the operand for the interval * @return the created interval */ @@ -295,7 +295,7 @@ /** * Creates an interval as a result of splitting or spilling another interval. - * + * * @param source an interval being split of spilled * @return a new interval derived from {@code source} */ @@ -376,7 +376,7 @@ /** * Retrieves the {@link LIRInstruction} based on its {@linkplain LIRInstruction#id id}. - * + * * @param opId an instruction {@linkplain LIRInstruction#id id} * @return the instruction whose {@linkplain LIRInstruction#id} {@code == id} */ @@ -389,7 +389,7 @@ /** * Gets the block containing a given instruction. - * + * * @param opId an instruction {@linkplain LIRInstruction#id id} * @return the block containing the instruction denoted by {@code opId} */ @@ -408,7 +408,7 @@ /** * Determines if an {@link LIRInstruction} destroys all caller saved registers. - * + * * @param opId an instruction {@linkplain LIRInstruction#id id} * @return {@code true} if the instruction denoted by {@code id} destroys all caller saved * registers. @@ -505,79 +505,82 @@ // called once before assignment of register numbers void eliminateSpillMoves() { - Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves"); + try (Indent indent = Debug.logAndIndent("Eliminating unnecessary spill moves")) { + + // collect all intervals that must be stored after their definition. + // the list is sorted by Interval.spillDefinitionPos + Interval interval; + interval = createUnhandledLists(mustStoreAtDefinition, null).first; + if (DetailedAsserts.getValue()) { + checkIntervals(interval); + } + + LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); + for (AbstractBlock block : sortedBlocks) { + List instructions = ir.getLIRforBlock(block); + int numInst = instructions.size(); - // collect all intervals that must be stored after their definition. - // the list is sorted by Interval.spillDefinitionPos - Interval interval; - interval = createUnhandledLists(mustStoreAtDefinition, null).first; - if (DetailedAsserts.getValue()) { - checkIntervals(interval); - } + // iterate all instructions of the block. skip the first + // because it is always a label + for (int j = 1; j < numInst; j++) { + LIRInstruction op = instructions.get(j); + int opId = op.id(); - LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer(); - for (AbstractBlock block : sortedBlocks) { - List instructions = ir.getLIRforBlock(block); - int numInst = instructions.size(); + if (opId == -1) { + MoveOp move = (MoveOp) op; + // remove move from register to stack if the stack slot is guaranteed to be + // correct. + // only moves that have been inserted by LinearScan can be removed. + assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables"; + + Interval curInterval = intervalFor(move.getResult()); - // iterate all instructions of the block. skip the first because it is always a label - for (int j = 1; j < numInst; j++) { - LIRInstruction op = instructions.get(j); - int opId = op.id(); + if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) { + // move target is a stack slot that is always correct, so eliminate + // instruction + if (Debug.isLogEnabled()) { + Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult())); + } + // null-instructions are deleted by assignRegNum + instructions.set(j, null); + } + + } else { + // insert move from register to stack just after + // the beginning of the interval + assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; + assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; - if (opId == -1) { - MoveOp move = (MoveOp) op; - // remove move from register to stack if the stack slot is guaranteed to be - // correct. - // only moves that have been inserted by LinearScan can be removed. - assert isVariable(move.getResult()) : "LinearScan inserts only moves to variables"; + while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { + if (!interval.canMaterialize()) { + if (!insertionBuffer.initialized()) { + // prepare insertion buffer (appended when all instructions in + // the block are processed) + insertionBuffer.init(instructions); + } - Interval curInterval = intervalFor(move.getResult()); + AllocatableValue fromLocation = interval.location(); + AllocatableValue toLocation = canonicalSpillOpr(interval); + + assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); + assert isStackSlot(toLocation) : "to operand must be a stack slot"; - if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) { - // move target is a stack slot that is always correct, so eliminate - // instruction - if (Debug.isLogEnabled()) { - Debug.log("eliminating move from interval %d to %d", operandNumber(move.getInput()), operandNumber(move.getResult())); + insertionBuffer.append(j + 1, ir.getSpillMoveFactory().createMove(toLocation, fromLocation)); + + Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId); + } + interval = interval.next; } - instructions.set(j, null); // null-instructions are deleted by assignRegNum } - - } else { - // insert move from register to stack just after the beginning of the interval - assert interval == Interval.EndMarker || interval.spillDefinitionPos() >= opId : "invalid order"; - assert interval == Interval.EndMarker || (interval.isSplitParent() && interval.spillState() == SpillState.StoreAtDefinition) : "invalid interval"; - - while (interval != Interval.EndMarker && interval.spillDefinitionPos() == opId) { - if (!interval.canMaterialize()) { - if (!insertionBuffer.initialized()) { - // prepare insertion buffer (appended when all instructions of the - // block are processed) - insertionBuffer.init(instructions); - } - - AllocatableValue fromLocation = interval.location(); - AllocatableValue toLocation = canonicalSpillOpr(interval); + } // end of instruction iteration - assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState(); - assert isStackSlot(toLocation) : "to operand must be a stack slot"; - - insertionBuffer.append(j + 1, ir.getSpillMoveFactory().createMove(toLocation, fromLocation)); - - Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId); - } - interval = interval.next; - } + if (insertionBuffer.initialized()) { + insertionBuffer.finish(); } - } // end of instruction iteration + } // end of block iteration - if (insertionBuffer.initialized()) { - insertionBuffer.finish(); - } - } // end of block iteration - - assert interval == Interval.EndMarker : "missed an interval"; - indent.outdent(); + assert interval == Interval.EndMarker : "missed an interval"; + } } private static void checkIntervals(Interval interval) { @@ -676,95 +679,95 @@ // iterate all blocks for (final AbstractBlock block : sortedBlocks) { - Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId()); + try (Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId())) { + + final BitSet liveGen = new BitSet(liveSize); + final BitSet liveKill = new BitSet(liveSize); - final BitSet liveGen = new BitSet(liveSize); - final BitSet liveKill = new BitSet(liveSize); + List instructions = ir.getLIRforBlock(block); + int numInst = instructions.size(); - List instructions = ir.getLIRforBlock(block); - int numInst = instructions.size(); + // iterate all instructions of the block + for (int j = 0; j < numInst; j++) { + final LIRInstruction op = instructions.get(j); + + ValueProcedure useProc = new ValueProcedure() { - // iterate all instructions of the block - for (int j = 0; j < numInst; j++) { - final LIRInstruction op = instructions.get(j); + @Override + protected Value doValue(Value operand) { + if (isVariable(operand)) { + int operandNum = operandNumber(operand); + if (!liveKill.get(operandNum)) { + liveGen.set(operandNum); + Debug.log("liveGen for operand %d", operandNum); + } + if (block.getLoop() != null) { + intervalInLoop.setBit(operandNum, block.getLoop().index); + } + } - ValueProcedure useProc = new ValueProcedure() { + if (DetailedAsserts.getValue()) { + verifyInput(block, liveKill, operand); + } + return operand; + } + }; + ValueProcedure stateProc = new ValueProcedure() { - @Override - protected Value doValue(Value operand) { - if (isVariable(operand)) { + @Override + public Value doValue(Value operand) { int operandNum = operandNumber(operand); if (!liveKill.get(operandNum)) { liveGen.set(operandNum); - Debug.log("liveGen for operand %d", operandNum); - } - if (block.getLoop() != null) { - intervalInLoop.setBit(operandNum, block.getLoop().index); + Debug.log("liveGen in state for operand %d", operandNum); } - } - - if (DetailedAsserts.getValue()) { - verifyInput(block, liveKill, operand); + return operand; } - return operand; - } - }; - ValueProcedure stateProc = new ValueProcedure() { + }; + ValueProcedure defProc = new ValueProcedure() { - @Override - public Value doValue(Value operand) { - int operandNum = operandNumber(operand); - if (!liveKill.get(operandNum)) { - liveGen.set(operandNum); - Debug.log("liveGen in state for operand %d", operandNum); - } - return operand; - } - }; - ValueProcedure defProc = new ValueProcedure() { + @Override + public Value doValue(Value operand) { + if (isVariable(operand)) { + int varNum = operandNumber(operand); + liveKill.set(varNum); + Debug.log("liveKill for operand %d", varNum); + if (block.getLoop() != null) { + intervalInLoop.setBit(varNum, block.getLoop().index); + } + } - @Override - public Value doValue(Value operand) { - if (isVariable(operand)) { - int varNum = operandNumber(operand); - liveKill.set(varNum); - Debug.log("liveKill for operand %d", varNum); - if (block.getLoop() != null) { - intervalInLoop.setBit(varNum, block.getLoop().index); + if (DetailedAsserts.getValue()) { + // fixed intervals are never live at block boundaries, so + // they need not be processed in live sets + // process them only in debug mode so that this can be checked + verifyTemp(liveKill, operand); } + return operand; } - - if (DetailedAsserts.getValue()) { - // fixed intervals are never live at block boundaries, so - // they need not be processed in live sets - // process them only in debug mode so that this can be checked - verifyTemp(liveKill, operand); - } - return operand; - } - }; + }; - try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) { - op.forEachInput(useProc); - op.forEachAlive(useProc); - // Add uses of live locals from interpreter's point of view for proper debug - // information generation - op.forEachState(stateProc); - op.forEachTemp(defProc); - op.forEachOutput(defProc); - } - } // end of instruction iteration + try (Indent indent2 = Debug.logAndIndent("handle op %d", op.id())) { + op.forEachInput(useProc); + op.forEachAlive(useProc); + // Add uses of live locals from interpreter's point of view for proper debug + // information generation + op.forEachState(stateProc); + op.forEachTemp(defProc); + op.forEachOutput(defProc); + } + } // end of instruction iteration - BlockData blockSets = blockData.get(block); - blockSets.liveGen = liveGen; - blockSets.liveKill = liveKill; - blockSets.liveIn = new BitSet(liveSize); - blockSets.liveOut = new BitSet(liveSize); + BlockData blockSets = blockData.get(block); + blockSets.liveGen = liveGen; + blockSets.liveKill = liveKill; + blockSets.liveIn = new BitSet(liveSize); + blockSets.liveOut = new BitSet(liveSize); - Debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); - Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill); + Debug.log("liveGen B%d %s", block.getId(), blockSets.liveGen); + Debug.log("liveKill B%d %s", block.getId(), blockSets.liveKill); - indent.outdent(); + } } // end of block iteration } @@ -797,87 +800,88 @@ * {@link BlockData#liveIn} and {@link BlockData#liveOut}) for each block. */ void computeGlobalLiveSets() { - Indent indent = Debug.logAndIndent("compute global live sets"); - int numBlocks = blockCount(); - boolean changeOccurred; - boolean changeOccurredInBlock; - int iterationCount = 0; - BitSet liveOut = new BitSet(liveSetSize()); // scratch set for calculations + try (Indent indent = Debug.logAndIndent("compute global live sets")) { + int numBlocks = blockCount(); + boolean changeOccurred; + boolean changeOccurredInBlock; + int iterationCount = 0; + BitSet liveOut = new BitSet(liveSetSize()); // scratch set for calculations - // Perform a backward dataflow analysis to compute liveOut and liveIn for each block. - // The loop is executed until a fixpoint is reached (no changes in an iteration) - do { - changeOccurred = false; + // Perform a backward dataflow analysis to compute liveOut and liveIn for each block. + // The loop is executed until a fixpoint is reached (no changes in an iteration) + do { + changeOccurred = false; - Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount); + try (Indent indent2 = Debug.logAndIndent("new iteration %d", iterationCount)) { - // iterate all blocks in reverse order - for (int i = numBlocks - 1; i >= 0; i--) { - AbstractBlock block = blockAt(i); - BlockData blockSets = blockData.get(block); + // iterate all blocks in reverse order + for (int i = numBlocks - 1; i >= 0; i--) { + AbstractBlock block = blockAt(i); + BlockData blockSets = blockData.get(block); - changeOccurredInBlock = false; + changeOccurredInBlock = false; - // liveOut(block) is the union of liveIn(sux), for successors sux of block - int n = block.getSuccessorCount(); - if (n > 0) { - // block has successors - if (n > 0) { - liveOut.clear(); - for (AbstractBlock successor : block.getSuccessors()) { - liveOut.or(blockData.get(successor).liveIn); + // liveOut(block) is the union of liveIn(sux), for successors sux of block + int n = block.getSuccessorCount(); + if (n > 0) { + // block has successors + if (n > 0) { + liveOut.clear(); + for (AbstractBlock successor : block.getSuccessors()) { + liveOut.or(blockData.get(successor).liveIn); + } + } else { + liveOut.clear(); + } + + if (!blockSets.liveOut.equals(liveOut)) { + // A change occurred. Swap the old and new live out + // sets to avoid copying. + BitSet temp = blockSets.liveOut; + blockSets.liveOut = liveOut; + liveOut = temp; + + changeOccurred = true; + changeOccurredInBlock = true; + } } - } else { - liveOut.clear(); - } - if (!blockSets.liveOut.equals(liveOut)) { - // A change occurred. Swap the old and new live out sets to avoid copying. - BitSet temp = blockSets.liveOut; - blockSets.liveOut = liveOut; - liveOut = temp; + if (iterationCount == 0 || changeOccurredInBlock) { + // liveIn(block) is the union of liveGen(block) with (liveOut(block) & + // !liveKill(block)) + // note: liveIn has to be computed only in first iteration + // or if liveOut has changed! + BitSet liveIn = blockSets.liveIn; + liveIn.clear(); + liveIn.or(blockSets.liveOut); + liveIn.andNot(blockSets.liveKill); + liveIn.or(blockSets.liveGen); - changeOccurred = true; - changeOccurredInBlock = true; + Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); + } + } + iterationCount++; + + if (changeOccurred && iterationCount > 50) { + throw new BailoutException("too many iterations in computeGlobalLiveSets"); } } + } while (changeOccurred); - if (iterationCount == 0 || changeOccurredInBlock) { - // liveIn(block) is the union of liveGen(block) with (liveOut(block) & - // !liveKill(block)) - // note: liveIn has to be computed only in first iteration or if liveOut has - // changed! - BitSet liveIn = blockSets.liveIn; - liveIn.clear(); - liveIn.or(blockSets.liveOut); - liveIn.andNot(blockSets.liveKill); - liveIn.or(blockSets.liveGen); - - Debug.log("block %d: livein = %s, liveout = %s", block.getId(), liveIn, blockSets.liveOut); - } + if (DetailedAsserts.getValue()) { + verifyLiveness(); } - iterationCount++; - if (changeOccurred && iterationCount > 50) { - throw new BailoutException("too many iterations in computeGlobalLiveSets"); + // check that the liveIn set of the first block is empty + AbstractBlock startBlock = ir.getControlFlowGraph().getStartBlock(); + if (blockData.get(startBlock).liveIn.cardinality() != 0) { + if (DetailedAsserts.getValue()) { + reportFailure(numBlocks); + } + // bailout if this occurs in product mode. + throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn); } - indent2.outdent(); - } while (changeOccurred); - - if (DetailedAsserts.getValue()) { - verifyLiveness(); } - - // check that the liveIn set of the first block is empty - AbstractBlock startBlock = ir.getControlFlowGraph().getStartBlock(); - if (blockData.get(startBlock).liveIn.cardinality() != 0) { - if (DetailedAsserts.getValue()) { - reportFailure(numBlocks); - } - // bailout if this occurs in product mode. - throw new GraalInternalError("liveIn set of first block must be empty: " + blockData.get(startBlock).liveIn); - } - indent.outdent(); } private static NodeLIRGenerator getNodeLIRGeneratorFromDebugContext() { @@ -899,76 +903,76 @@ private void reportFailure(int numBlocks) { try (Scope s = Debug.forceLog()) { - Indent indent = Debug.logAndIndent("report failure"); + try (Indent indent = Debug.logAndIndent("report failure")) { - BitSet startBlockLiveIn = blockData.get(ir.getControlFlowGraph().getStartBlock()).liveIn; - try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { + BitSet startBlockLiveIn = blockData.get(ir.getControlFlowGraph().getStartBlock()).liveIn; + try (Indent indent2 = Debug.logAndIndent("Error: liveIn set of first block must be empty (when this fails, variables are used before they are defined):")) { + for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { + Value operand = operandFor(operandNum); + Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand)); + } + } + + // print some additional information to simplify debugging for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { Value operand = operandFor(operandNum); - Debug.log("var %d; operand=%s; node=%s", operandNum, operand, getValueForOperandFromDebugContext(operand)); - } - } + try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand))) { - // print some additional information to simplify debugging - for (int operandNum = startBlockLiveIn.nextSetBit(0); operandNum >= 0; operandNum = startBlockLiveIn.nextSetBit(operandNum + 1)) { - Value operand = operandFor(operandNum); - final Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, getValueForOperandFromDebugContext(operand)); + Deque> definedIn = new ArrayDeque<>(); + HashSet> usedIn = new HashSet<>(); + for (AbstractBlock block : sortedBlocks) { + if (blockData.get(block).liveGen.get(operandNum)) { + usedIn.add(block); + try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { + for (LIRInstruction ins : ir.getLIRforBlock(block)) { + try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { + ins.forEachState(new ValueProcedure() { - Deque> definedIn = new ArrayDeque<>(); - HashSet> usedIn = new HashSet<>(); - for (AbstractBlock block : sortedBlocks) { - if (blockData.get(block).liveGen.get(operandNum)) { - usedIn.add(block); - try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) { - for (LIRInstruction ins : ir.getLIRforBlock(block)) { - try (Indent indent4 = Debug.logAndIndent("%d: %s", ins.id(), ins)) { - ins.forEachState(new ValueProcedure() { - - @Override - public Value doValue(Value liveStateOperand) { - Debug.log("operand=%s", liveStateOperand); - return liveStateOperand; + @Override + public Value doValue(Value liveStateOperand) { + Debug.log("operand=%s", liveStateOperand); + return liveStateOperand; + } + }); } - }); + } + } + } + if (blockData.get(block).liveKill.get(operandNum)) { + definedIn.add(block); + try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { + for (LIRInstruction ins : ir.getLIRforBlock(block)) { + Debug.log("%d: %s", ins.id(), ins); + } } } } - } - if (blockData.get(block).liveKill.get(operandNum)) { - definedIn.add(block); - try (Indent indent3 = Debug.logAndIndent("defined in block B%d", block.getId())) { - for (LIRInstruction ins : ir.getLIRforBlock(block)) { - Debug.log("%d: %s", ins.id(), ins); + + int[] hitCount = new int[numBlocks]; + + while (!definedIn.isEmpty()) { + AbstractBlock block = definedIn.removeFirst(); + usedIn.remove(block); + for (AbstractBlock successor : block.getSuccessors()) { + if (successor.isLoopHeader()) { + if (!block.isLoopEnd()) { + definedIn.add(successor); + } + } else { + if (++hitCount[successor.getId()] == successor.getPredecessorCount()) { + definedIn.add(successor); + } + } + } + } + try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) { + for (AbstractBlock block : usedIn) { + Debug.log("B%d", block.getId()); } } } } - - int[] hitCount = new int[numBlocks]; - - while (!definedIn.isEmpty()) { - AbstractBlock block = definedIn.removeFirst(); - usedIn.remove(block); - for (AbstractBlock successor : block.getSuccessors()) { - if (successor.isLoopHeader()) { - if (!block.isLoopEnd()) { - definedIn.add(successor); - } - } else { - if (++hitCount[successor.getId()] == successor.getPredecessorCount()) { - definedIn.add(successor); - } - } - } - } - try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) { - for (AbstractBlock block : usedIn) { - Debug.log("B%d", block.getId()); - } - } - indent2.outdent(); } - indent.outdent(); } } @@ -1147,140 +1151,142 @@ void buildIntervals() { - Indent indent = Debug.logAndIndent("build intervals"); + try (Indent indent = Debug.logAndIndent("build intervals")) { - intervalsSize = operandSize(); - intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY]; + intervalsSize = operandSize(); + intervals = new Interval[intervalsSize + INITIAL_SPLIT_INTERVALS_CAPACITY]; - // create a list with all caller-save registers (cpu, fpu, xmm) - Register[] callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters(); + // create a list with all caller-save registers (cpu, fpu, xmm) + Register[] callerSaveRegs = frameMap.registerConfig.getCallerSaveRegisters(); - // iterate all blocks in reverse order - for (int i = blockCount() - 1; i >= 0; i--) { - - AbstractBlock block = blockAt(i); - Indent indent2 = Debug.logAndIndent("handle block %d", block.getId()); + // iterate all blocks in reverse order + for (int i = blockCount() - 1; i >= 0; i--) { - List instructions = ir.getLIRforBlock(block); - final int blockFrom = getFirstLirInstructionId(block); - int blockTo = getLastLirInstructionId(block); + AbstractBlock block = blockAt(i); + try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) { - assert blockFrom == instructions.get(0).id(); - assert blockTo == instructions.get(instructions.size() - 1).id(); + List instructions = ir.getLIRforBlock(block); + final int blockFrom = getFirstLirInstructionId(block); + int blockTo = getLastLirInstructionId(block); - // Update intervals for operands live at the end of this block; - BitSet live = blockData.get(block).liveOut; - for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { - assert live.get(operandNum) : "should not stop here otherwise"; - AllocatableValue operand = operandFor(operandNum); - Debug.log("live in %d: %s", operandNum, operand); - - addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal); + assert blockFrom == instructions.get(0).id(); + assert blockTo == instructions.get(instructions.size() - 1).id(); - // add special use positions for loop-end blocks when the - // interval is used anywhere inside this loop. It's possible - // that the block was part of a non-natural loop, so it might - // have an invalid loop index. - if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().index)) { - intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); - } - } + // Update intervals for operands live at the end of this block; + BitSet live = blockData.get(block).liveOut; + for (int operandNum = live.nextSetBit(0); operandNum >= 0; operandNum = live.nextSetBit(operandNum + 1)) { + assert live.get(operandNum) : "should not stop here otherwise"; + AllocatableValue operand = operandFor(operandNum); + Debug.log("live in %d: %s", operandNum, operand); - // iterate all instructions of the block in reverse order. - // definitions of intervals are processed before uses - for (int j = instructions.size() - 1; j >= 0; j--) { - final LIRInstruction op = instructions.get(j); - final int opId = op.id(); + addUse(operand, blockFrom, blockTo + 2, RegisterPriority.None, Kind.Illegal); - Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op); - - // add a temp range for each register if operation destroys caller-save registers - if (op.destroysCallerSavedRegisters()) { - for (Register r : callerSaveRegs) { - if (attributes(r).isAllocatable()) { - addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal); + // add special use positions for loop-end blocks when the + // interval is used anywhere inside this loop. It's possible + // that the block was part of a non-natural loop, so it might + // have an invalid loop index. + if (block.isLoopEnd() && block.getLoop() != null && isIntervalInLoop(operandNum, block.getLoop().index)) { + intervalFor(operand).addUsePos(blockTo + 1, RegisterPriority.LiveAtLoopEnd); } } - Debug.log("operation destroys all caller-save registers"); - } - op.forEachOutput(new ValueProcedure() { + // iterate all instructions of the block in reverse order. + // definitions of intervals are processed before uses + for (int j = instructions.size() - 1; j >= 0; j--) { + final LIRInstruction op = instructions.get(j); + final int opId = op.id(); + + try (Indent indent3 = Debug.logAndIndent("handle inst %d: %s", opId, op)) { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, true); - } - return operand; - } - }); - op.forEachTemp(new ValueProcedure() { + // add a temp range for each register if operation destroys + // caller-save registers + if (op.destroysCallerSavedRegisters()) { + for (Register r : callerSaveRegs) { + if (attributes(r).isAllocatable()) { + addTemp(r.asValue(), opId, RegisterPriority.None, Kind.Illegal); + } + } + Debug.log("operation destroys all caller-save registers"); + } + + op.forEachOutput(new ValueProcedure() { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, false); - } - return operand; - } - }); - op.forEachAlive(new ValueProcedure() { + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + addDef((AllocatableValue) operand, op, registerPriorityOfOutputOperand(op), operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, true); + } + return operand; + } + }); + op.forEachTemp(new ValueProcedure() { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, false); - } - return operand; - } - }); - op.forEachInput(new ValueProcedure() { + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + addTemp((AllocatableValue) operand, opId, RegisterPriority.MustHaveRegister, operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, false); + } + return operand; + } + }); + op.forEachAlive(new ValueProcedure() { - @Override - public Value doValue(Value operand, OperandMode mode, EnumSet flags) { - if (isVariableOrRegister(operand)) { - RegisterPriority p = registerPriorityOfInputOperand(flags); - addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind()); - addRegisterHint(op, operand, mode, flags, false); - } - return operand; - } - }); + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + RegisterPriority p = registerPriorityOfInputOperand(flags); + addUse((AllocatableValue) operand, blockFrom, opId + 1, p, operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, false); + } + return operand; + } + }); + op.forEachInput(new ValueProcedure() { - // Add uses of live locals from interpreter's point of view for proper - // debug information generation - // Treat these operands as temp values (if the live range is extended - // to a call site, the value would be in a register at the call otherwise) - op.forEachState(new ValueProcedure() { + @Override + public Value doValue(Value operand, OperandMode mode, EnumSet flags) { + if (isVariableOrRegister(operand)) { + RegisterPriority p = registerPriorityOfInputOperand(flags); + addUse((AllocatableValue) operand, blockFrom, opId, p, operand.getPlatformKind()); + addRegisterHint(op, operand, mode, flags, false); + } + return operand; + } + }); - @Override - public Value doValue(Value operand) { - addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind()); - return operand; - } - }); + // Add uses of live locals from interpreter's point of view for proper + // debug information generation + // Treat these operands as temp values (if the live range is extended + // to a call site, the value would be in a register at + // the call otherwise) + op.forEachState(new ValueProcedure() { - // special steps for some instructions (especially moves) - handleMethodArguments(op); + @Override + public Value doValue(Value operand) { + addUse((AllocatableValue) operand, blockFrom, opId + 1, RegisterPriority.None, operand.getPlatformKind()); + return operand; + } + }); - indent3.outdent(); + // special steps for some instructions (especially moves) + handleMethodArguments(op); - } // end of instruction iteration - indent2.outdent(); - } // end of block iteration + } - // add the range [0, 1] to all fixed intervals. - // the register allocator need not handle unhandled fixed intervals - for (Interval interval : intervals) { - if (interval != null && isRegister(interval.operand)) { - interval.addRange(0, 1); + } // end of instruction iteration + } + } // end of block iteration + + // add the range [0, 1] to all fixed intervals. + // the register allocator need not handle unhandled fixed intervals + for (Interval interval : intervals) { + if (interval != null && isRegister(interval.operand)) { + interval.addRange(0, 1); + } } } - indent.outdent(); } // * Phase 5: actual register allocation @@ -1432,19 +1438,19 @@ }; public void allocateRegisters() { - Indent indent = Debug.logAndIndent("allocate registers"); - Interval precoloredIntervals; - Interval notPrecoloredIntervals; + try (Indent indent = Debug.logAndIndent("allocate registers")) { + Interval precoloredIntervals; + Interval notPrecoloredIntervals; - Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL); - precoloredIntervals = result.first; - notPrecoloredIntervals = result.second; + Interval.Pair result = createUnhandledLists(IS_PRECOLORED_INTERVAL, IS_VARIABLE_INTERVAL); + precoloredIntervals = result.first; + notPrecoloredIntervals = result.second; - // allocate cpu registers - LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); - lsw.walk(); - lsw.finishAllocation(); - indent.outdent(); + // allocate cpu registers + LinearScanWalker lsw = new LinearScanWalker(this, precoloredIntervals, notPrecoloredIntervals); + lsw.walk(); + lsw.finishAllocation(); + } } // * Phase 6: resolve data flow @@ -1543,69 +1549,71 @@ * have been split. */ void resolveDataFlow() { - Indent indent = Debug.logAndIndent("resolve data flow"); + try (Indent indent = Debug.logAndIndent("resolve data flow")) { - int numBlocks = blockCount(); - MoveResolver moveResolver = new MoveResolver(this); - BitSet blockCompleted = new BitSet(numBlocks); - BitSet alreadyResolved = new BitSet(numBlocks); + int numBlocks = blockCount(); + MoveResolver moveResolver = new MoveResolver(this); + BitSet blockCompleted = new BitSet(numBlocks); + BitSet alreadyResolved = new BitSet(numBlocks); + + for (AbstractBlock block : sortedBlocks) { - for (AbstractBlock block : sortedBlocks) { + // check if block has only one predecessor and only one successor + if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) { + List instructions = ir.getLIRforBlock(block); + assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; + assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; - // check if block has only one predecessor and only one successor - if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) { - List instructions = ir.getLIRforBlock(block); - assert instructions.get(0) instanceof StandardOp.LabelOp : "block must start with label"; - assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "block with successor must end with unconditional jump"; + // check if block is empty (only label and branch) + if (instructions.size() == 2) { + AbstractBlock pred = block.getPredecessors().iterator().next(); + AbstractBlock sux = block.getSuccessors().iterator().next(); + + // prevent optimization of two consecutive blocks + if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) { + Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId()); + + blockCompleted.set(block.getLinearScanNumber()); - // check if block is empty (only label and branch) - if (instructions.size() == 2) { - AbstractBlock pred = block.getPredecessors().iterator().next(); - AbstractBlock sux = block.getSuccessors().iterator().next(); - - // prevent optimization of two consecutive blocks - if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) { - Debug.log(" optimizing empty block B%d (pred: B%d, sux: B%d)", block.getId(), pred.getId(), sux.getId()); + // directly resolve between pred and sux (without looking + // at the empty block + // between) + resolveCollectMappings(pred, sux, moveResolver); + if (moveResolver.hasMappings()) { + moveResolver.setInsertPosition(instructions, 1); + moveResolver.resolveAndAppendMoves(); + } + } + } + } + } - blockCompleted.set(block.getLinearScanNumber()); + for (AbstractBlock fromBlock : sortedBlocks) { + if (!blockCompleted.get(fromBlock.getLinearScanNumber())) { + alreadyResolved.clear(); + alreadyResolved.or(blockCompleted); + + for (AbstractBlock toBlock : fromBlock.getSuccessors()) { - // directly resolve between pred and sux (without looking at the empty block - // between) - resolveCollectMappings(pred, sux, moveResolver); - if (moveResolver.hasMappings()) { - moveResolver.setInsertPosition(instructions, 1); - moveResolver.resolveAndAppendMoves(); + // check for duplicate edges between the same blocks (can happen with switch + // blocks) + if (!alreadyResolved.get(toBlock.getLinearScanNumber())) { + Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId()); + + alreadyResolved.set(toBlock.getLinearScanNumber()); + + // collect all intervals that have been split between + // fromBlock and toBlock + resolveCollectMappings(fromBlock, toBlock, moveResolver); + if (moveResolver.hasMappings()) { + resolveFindInsertPos(fromBlock, toBlock, moveResolver); + moveResolver.resolveAndAppendMoves(); + } } } } } } - - for (AbstractBlock fromBlock : sortedBlocks) { - if (!blockCompleted.get(fromBlock.getLinearScanNumber())) { - alreadyResolved.clear(); - alreadyResolved.or(blockCompleted); - - for (AbstractBlock toBlock : fromBlock.getSuccessors()) { - - // check for duplicate edges between the same blocks (can happen with switch - // blocks) - if (!alreadyResolved.get(toBlock.getLinearScanNumber())) { - Debug.log("processing edge between B%d and B%d", fromBlock.getId(), toBlock.getId()); - - alreadyResolved.set(toBlock.getLinearScanNumber()); - - // collect all intervals that have been split between fromBlock and toBlock - resolveCollectMappings(fromBlock, toBlock, moveResolver); - if (moveResolver.hasMappings()) { - resolveFindInsertPos(fromBlock, toBlock, moveResolver); - moveResolver.resolveAndAppendMoves(); - } - } - } - } - } - indent.outdent(); } // * Phase 7: assign register numbers back to LIR @@ -1618,7 +1626,7 @@ /** * Assigns the allocated location for an LIR instruction operand back into the instruction. - * + * * @param operand an LIR instruction operand * @param opId the id of the LIR instruction using {@code operand} * @param mode the usage mode for {@code operand} by the instruction @@ -1857,57 +1865,57 @@ /* * This is the point to enable debug logging for the whole register allocation. */ - Indent indent = Debug.logAndIndent("LinearScan allocate"); - - try (Scope s = Debug.scope("LifetimeAnalysis")) { - numberInstructions(); - printLir("Before register allocation", true); - computeLocalLiveSets(); - computeGlobalLiveSets(); - buildIntervals(); - sortIntervalsBeforeAllocation(); - } catch (Throwable e) { - throw Debug.handle(e); - } + try (Indent indent = Debug.logAndIndent("LinearScan allocate")) { - try (Scope s = Debug.scope("RegisterAllocation")) { - printIntervals("Before register allocation"); - allocateRegisters(); - } catch (Throwable e) { - throw Debug.handle(e); - } + try (Scope s = Debug.scope("LifetimeAnalysis")) { + numberInstructions(); + printLir("Before register allocation", true); + computeLocalLiveSets(); + computeGlobalLiveSets(); + buildIntervals(); + sortIntervalsBeforeAllocation(); + } catch (Throwable e) { + throw Debug.handle(e); + } - try (Scope s = Debug.scope("ResolveDataFlow")) { - resolveDataFlow(); - } catch (Throwable e) { - throw Debug.handle(e); - } + try (Scope s = Debug.scope("RegisterAllocation")) { + printIntervals("Before register allocation"); + allocateRegisters(); + } catch (Throwable e) { + throw Debug.handle(e); + } - try (Scope s = Debug.scope("DebugInfo")) { - frameMap.finish(); - - printIntervals("After register allocation"); - printLir("After register allocation", true); - - sortIntervalsAfterAllocation(); - - if (DetailedAsserts.getValue()) { - verify(); + try (Scope s = Debug.scope("ResolveDataFlow")) { + resolveDataFlow(); + } catch (Throwable e) { + throw Debug.handle(e); } - eliminateSpillMoves(); - assignLocations(); + try (Scope s = Debug.scope("DebugInfo")) { + frameMap.finish(); + + printIntervals("After register allocation"); + printLir("After register allocation", true); + + sortIntervalsAfterAllocation(); - if (DetailedAsserts.getValue()) { - verifyIntervals(); + if (DetailedAsserts.getValue()) { + verify(); + } + + eliminateSpillMoves(); + assignLocations(); + + if (DetailedAsserts.getValue()) { + verifyIntervals(); + } + } catch (Throwable e) { + throw Debug.handle(e); } - } catch (Throwable e) { - throw Debug.handle(e); - } - printLir("After register number assignment", true); + printLir("After register number assignment", true); - indent.outdent(); + } } void printIntervals(String label) { @@ -2114,7 +2122,7 @@ /** * Returns a value for a interval definition, which can be used for re-materialization. - * + * * @param op An instruction which defines a value * @param operand The destination operand of the instruction * @param interval The interval for this defined value. diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScanWalker.java Fri Mar 28 11:41:42 2014 +0100 @@ -450,82 +450,82 @@ int maxSplitPos = currentPosition; int minSplitPos = Math.max(interval.previousUsage(RegisterPriority.ShouldHaveRegister, maxSplitPos) + 1, interval.from()); - Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos); + try (Indent indent = Debug.logAndIndent("splitting and spilling interval %s between %d and %d", interval, minSplitPos, maxSplitPos)) { - assert interval.state == State.Active : "why spill interval that is not active?"; - assert interval.from() <= minSplitPos : "cannot split before start of interval"; - assert minSplitPos <= maxSplitPos : "invalid order"; - assert maxSplitPos < interval.to() : "cannot split at end end of interval"; - assert currentPosition < interval.to() : "interval must not end before current position"; + assert interval.state == State.Active : "why spill interval that is not active?"; + assert interval.from() <= minSplitPos : "cannot split before start of interval"; + assert minSplitPos <= maxSplitPos : "invalid order"; + assert maxSplitPos < interval.to() : "cannot split at end end of interval"; + assert currentPosition < interval.to() : "interval must not end before current position"; + + if (minSplitPos == interval.from()) { + // the whole interval is never used, so spill it entirely to memory - if (minSplitPos == interval.from()) { - // the whole interval is never used, so spill it entirely to memory + try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) { - try (Indent indent2 = Debug.logAndIndent("spilling entire interval because split pos is at beginning of interval (use positions: %d)", interval.usePosList().size())) { + assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition"; + + allocator.assignSpillSlot(interval); + allocator.changeSpillState(interval, minSplitPos); - assert interval.firstUsage(RegisterPriority.ShouldHaveRegister) > currentPosition : "interval must not have use position before currentPosition"; - - allocator.assignSpillSlot(interval); - allocator.changeSpillState(interval, minSplitPos); + // Also kick parent intervals out of register to memory when they have no use + // position. This avoids short interval in register surrounded by intervals in + // memory . avoid useless moves from memory to register and back + Interval parent = interval; + while (parent != null && parent.isSplitChild()) { + parent = parent.getSplitChildBeforeOpId(parent.from()); - // Also kick parent intervals out of register to memory when they have no use - // position. This avoids short interval in register surrounded by intervals in - // memory . avoid useless moves from memory to register and back - Interval parent = interval; - while (parent != null && parent.isSplitChild()) { - parent = parent.getSplitChildBeforeOpId(parent.from()); + if (isRegister(parent.location())) { + if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) { + // parent is never used, so kick it out of its assigned register + Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber); + allocator.assignSpillSlot(parent); + } else { + // do not go further back because the register is actually used by + // the interval + parent = null; + } + } + } + } + + } else { + // search optimal split pos, split interval and spill only the right hand part + int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false); + + assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; + assert optimalSplitPos < interval.to() : "cannot split at end of interval"; + assert optimalSplitPos >= interval.from() : "cannot split before start of interval"; - if (isRegister(parent.location())) { - if (parent.firstUsage(RegisterPriority.ShouldHaveRegister) == Integer.MAX_VALUE) { - // parent is never used, so kick it out of its assigned register - Debug.log("kicking out interval %d out of its register because it is never used", parent.operandNumber); - allocator.assignSpillSlot(parent); - } else { - // do not go further back because the register is actually used by - // the interval - parent = null; - } + if (!allocator.isBlockBegin(optimalSplitPos)) { + // move position before actual instruction (odd opId) + optimalSplitPos = (optimalSplitPos - 1) | 1; + } + + try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) { + assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary"; + assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary"; + + Interval spilledPart = interval.split(optimalSplitPos, allocator); + allocator.assignSpillSlot(spilledPart); + allocator.changeSpillState(spilledPart, optimalSplitPos); + + if (!allocator.isBlockBegin(optimalSplitPos)) { + Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber); + insertMove(optimalSplitPos, interval, spilledPart); + } + + // the currentSplitChild is needed later when moves are inserted for reloading + assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild"; + spilledPart.makeCurrentSplitChild(); + + if (Debug.isLogEnabled()) { + Debug.log("left interval: %s", interval.logString(allocator)); + Debug.log("spilled interval : %s", spilledPart.logString(allocator)); } } } - - } else { - // search optimal split pos, split interval and spill only the right hand part - int optimalSplitPos = findOptimalSplitPos(interval, minSplitPos, maxSplitPos, false); - - assert minSplitPos <= optimalSplitPos && optimalSplitPos <= maxSplitPos : "out of range"; - assert optimalSplitPos < interval.to() : "cannot split at end of interval"; - assert optimalSplitPos >= interval.from() : "cannot split before start of interval"; - - if (!allocator.isBlockBegin(optimalSplitPos)) { - // move position before actual instruction (odd opId) - optimalSplitPos = (optimalSplitPos - 1) | 1; - } - - try (Indent indent2 = Debug.logAndIndent("splitting at position %d", optimalSplitPos)) { - assert allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 1) : "split pos must be odd when not on block boundary"; - assert !allocator.isBlockBegin(optimalSplitPos) || ((optimalSplitPos & 1) == 0) : "split pos must be even on block boundary"; - - Interval spilledPart = interval.split(optimalSplitPos, allocator); - allocator.assignSpillSlot(spilledPart); - allocator.changeSpillState(spilledPart, optimalSplitPos); - - if (!allocator.isBlockBegin(optimalSplitPos)) { - Debug.log("inserting move from interval %d to %d", interval.operandNumber, spilledPart.operandNumber); - insertMove(optimalSplitPos, interval, spilledPart); - } - - // the currentSplitChild is needed later when moves are inserted for reloading - assert spilledPart.currentSplitChild() == interval : "overwriting wrong currentSplitChild"; - spilledPart.makeCurrentSplitChild(); - - if (Debug.isLogEnabled()) { - Debug.log("left interval: %s", interval.logString(allocator)); - Debug.log("spilled interval : %s", spilledPart.logString(allocator)); - } - } } - indent.outdent(); } void splitStackInterval(Interval interval) { @@ -840,52 +840,52 @@ Interval interval = currentInterval; boolean result = true; - Indent indent = Debug.logAndIndent("activating interval %s, splitParent: %d", interval, interval.splitParent().operandNumber); + try (Indent indent = Debug.logAndIndent("activating interval %s, splitParent: %d", interval, interval.splitParent().operandNumber)) { - final Value operand = interval.operand; - if (interval.location() != null && isStackSlot(interval.location())) { - // activating an interval that has a stack slot assigned . split it at first use - // position - // used for method parameters - Debug.log("interval has spill slot assigned (method parameter) . split it before first use"); - splitStackInterval(interval); - result = false; + final Value operand = interval.operand; + if (interval.location() != null && isStackSlot(interval.location())) { + // activating an interval that has a stack slot assigned . split it at first use + // position + // used for method parameters + Debug.log("interval has spill slot assigned (method parameter) . split it before first use"); + splitStackInterval(interval); + result = false; - } else { - if (interval.location() == null) { - // interval has not assigned register . normal allocation - // (this is the normal case for most intervals) - Debug.log("normal allocation of register"); + } else { + if (interval.location() == null) { + // interval has not assigned register . normal allocation + // (this is the normal case for most intervals) + Debug.log("normal allocation of register"); - // assign same spill slot to non-intersecting intervals - combineSpilledIntervals(interval); + // assign same spill slot to non-intersecting intervals + combineSpilledIntervals(interval); - initVarsForAlloc(interval); - if (noAllocationPossible(interval) || !allocFreeRegister(interval)) { - // no empty register available. - // split and spill another interval so that this interval gets a register - allocLockedRegister(interval); - } + initVarsForAlloc(interval); + if (noAllocationPossible(interval) || !allocFreeRegister(interval)) { + // no empty register available. + // split and spill another interval so that this interval gets a register + allocLockedRegister(interval); + } - // spilled intervals need not be move to active-list - if (!isRegister(interval.location())) { - result = false; + // spilled intervals need not be move to active-list + if (!isRegister(interval.location())) { + result = false; + } } } - } - // load spilled values that become active from stack slot to register - if (interval.insertMoveWhenActivated()) { - assert interval.isSplitChild(); - assert interval.currentSplitChild() != null; - assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval"; - Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); + // load spilled values that become active from stack slot to register + if (interval.insertMoveWhenActivated()) { + assert interval.isSplitChild(); + assert interval.currentSplitChild() != null; + assert !interval.currentSplitChild().operand.equals(operand) : "cannot insert move between same interval"; + Debug.log("Inserting move from interval %d to %d because insertMoveWhenActivated is set", interval.currentSplitChild().operandNumber, interval.operandNumber); - insertMove(interval.from(), interval.currentSplitChild(), interval); + insertMove(interval.from(), interval.currentSplitChild(), interval); + } + interval.makeCurrentSplitChild(); + } - interval.makeCurrentSplitChild(); - - indent.outdent(); return result; // true = interval is moved to active list } diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRGenerator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRGenerator.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRGenerator.java Fri Mar 28 11:41:42 2014 +0100 @@ -334,7 +334,7 @@ int start = nodes.indexOf(access); int end = nodes.indexOf(operation); for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) { - indent.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); + Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); } } return 0; @@ -349,7 +349,7 @@ int start = nodes.indexOf(access); int end = nodes.indexOf(operation); for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) { - indent.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); + Debug.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1)); } } } diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java Fri Mar 28 11:41:42 2014 +0100 @@ -371,8 +371,8 @@ } /** - * This override exists the catch cases when log is called with one argument from a method which - * is vararg. It will bind to this method instead of the single arg variant and produce a + * This override exists to catch cases when log is called with one argument bound to a varargs + * method parameter. It will bind to this method instead of the single arg variant and produce a * deprecation warning instead of silently wrapping the Object[] inside of another Object[]. */ @Deprecated @@ -396,64 +396,99 @@ } } - private static final class NoLogger implements Indent { - - @Override - public void log(String msg, Object... args) { - } - - @Override - public Indent indent() { - return this; - } - - @Override - public Indent logAndIndent(String msg, Object... args) { - return this; - } - - @Override - public Indent outdent() { - return this; - } - - @Override - public void close() { - } - } - - private static final NoLogger noLoggerInstance = new NoLogger(); - /** - * Creates a new indentation level (by adding some spaces) based on the last used Indent of the - * current DebugScope. + * Opens a new indentation level (by adding some spaces) based on the current indentation level. + * This should be used in a {@linkplain Indent try-with-resources} pattern. * - * @return The new indentation level - * @see Indent#indent + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + * @see #logAndIndent(String) + * @see #logAndIndent(String, Object) */ public static Indent indent() { if (ENABLED) { DebugScope scope = DebugScope.getInstance(); return scope.pushIndentLogger(); } - return noLoggerInstance; + return null; + } + + /** + * A convenience function which combines {@link #log(String)} and {@link #indent()}. + * + * @param msg the message to log + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logAndIndent(String msg) { + if (ENABLED) { + return logvAndIndent(msg); + } + return null; + } + + /** + * A convenience function which combines {@link #log(String, Object)} and {@link #indent()}. + * + * @param format a format string + * @param arg the argument referenced by the format specifiers in {@code format} + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled + */ + public static Indent logAndIndent(String format, Object arg) { + if (ENABLED) { + return logvAndIndent(format, arg); + } + return null; } /** - * A convenience function which combines {@link #log} and {@link #indent()}. + * @see #logAndIndent(String, Object) + */ + public static Indent logAndIndent(String format, Object arg1, Object arg2) { + if (ENABLED) { + return logvAndIndent(format, arg1, arg2); + } + return null; + } + + /** + * @see #logAndIndent(String, Object) + */ + public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) { + if (ENABLED) { + return logvAndIndent(format, arg1, arg2, arg3); + } + return null; + } + + /** + * A convenience function which combines {@link #logv(String, Object...)} and {@link #indent()}. * - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @return The new indentation level - * @see Indent#logAndIndent + * @param format a format string + * @param args the arguments referenced by the format specifiers in {@code format} + * @return an object that reverts to the current indentation level when + * {@linkplain Indent#close() closed} or null if debugging is disabled */ - public static Indent logAndIndent(String msg, Object... args) { + public static Indent logvAndIndent(String format, Object... args) { if (ENABLED) { DebugScope scope = DebugScope.getInstance(); - scope.log(msg, args); + scope.log(format, args); return scope.pushIndentLogger(); } - return noLoggerInstance; + throw new InternalError("Use of Debug.logvAndIndent() must be guarded by a test of Debug.isEnabled()"); + } + + /** + * This override exists to catch cases when {@link #logAndIndent(String, Object)} is called with + * one argument bound to a varargs method parameter. It will bind to this method instead of the + * single arg variant and produce a deprecation warning instead of silently wrapping the + * Object[] inside of another Object[]. + */ + @Deprecated + public static void logAndIndent(String format, Object[] args) { + assert false : "shouldn't use this"; + logvAndIndent(format, args); } public static Iterable context() { diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Indent.java Fri Mar 28 11:41:42 2014 +0100 @@ -23,80 +23,29 @@ package com.oracle.graal.debug; /** - * Represents an indentation level for logging. - *

- * Note that calling the logging/indent/outdent methods of this interface updates the last used - * Indent of the current DebugScope. If no instance of Indent is available (e.g. at the beginning of - * a method), then the corresponding static methods of the Debug class should be used. They perform - * logging and indentation based on the last used Indent of the current DebugScope. + * Object used to close a debug {@link Debug#indent() indentation} scope. *

* Example usage: - * + * *

- *      void method() {
- *      
- *          Indent in = Debug.logIndent("header message");
+ *
+ *      try (Indent i1 = Debug.logAndIndent("header message")) {
  *          ...
- *          in.log("message");
- *          ...
- *          Indent in2 = in.logIndent("sub-header message");
- *          ...
- *          {
- *              in2.log("inner message");
- *          }
+ *          Debug.log("message");
  *          ...
- *          in.outdent();
+ *          try (Indent i2 = Debug.logAndIndent(sub-header message")) {
+ *              ...
+ *              Debug.log("inner message");
+ *              ...
+ *          }
  *      }
- * 
- * - * Example usage with try-with-resources: - * - *
- * 
- *      try (Indent in = Debug.logIndent("header message")) {
- *          ...
- *          in.log("message");
- *          ...
- *      }
- * 
+ *
  * 
*/ public interface Indent extends AutoCloseable { /** - * Prints an indented message to the DebugLevel's logging stream if logging is enabled. - * - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @see Debug#log - */ - void log(String msg, Object... args); - - /** - * Creates a new indentation level (by adding some spaces). - * - * @return The new indentation level - * @see Debug#indent + * Closes the current indentation scope. */ - Indent indent(); - - /** - * A convenience function which combines {@link #log} and {@link #indent}. - * - * @param msg The format string of the log message - * @param args The arguments referenced by the log message string - * @return The new indentation level - * @see Debug#logAndIndent - */ - Indent logAndIndent(String msg, Object... args); - - /** - * Restores the previous indent level. Calling this method is important to restore the correct - * last used Indent in the current DebugScope. - * - * @return The indent level from which this Indent was created. - */ - Indent outdent(); - void close(); } diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java --- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugScope.java Fri Mar 28 11:41:42 2014 +0100 @@ -52,7 +52,6 @@ } } - @Override public void log(String msg, Object... args) { if (isLogEnabled()) { printScopeName(); @@ -61,29 +60,16 @@ } } - @Override - public Indent indent() { + IndentImpl indent() { lastUsedIndent = new IndentImpl(this); return lastUsedIndent; } @Override - public Indent logAndIndent(String msg, Object... args) { - log(msg, args); - return indent(); - } - - @Override - public Indent outdent() { + public void close() { if (parentIndent != null) { lastUsedIndent = parentIndent; } - return lastUsedIndent; - } - - @Override - public void close() { - outdent(); } } @@ -224,7 +210,7 @@ /** * Creates and enters a new debug scope which is either a child of the current scope or a * disjoint top level scope. - * + * * @param name the name of the new scope * @param sandboxConfig the configuration to use for a new top level scope, or null if the new * scope should be a child scope @@ -387,7 +373,7 @@ } public Indent pushIndentLogger() { - lastUsedIndent = (IndentImpl) lastUsedIndent.indent(); + lastUsedIndent = lastUsedIndent.indent(); return lastUsedIndent; } } diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java --- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri Mar 28 11:41:42 2014 +0100 @@ -224,68 +224,68 @@ TTY.println(MetaUtil.indent(MetaUtil.profileToString(profilingInfo, method, CodeUtil.NEW_LINE), " ")); } - Indent indent = Debug.logAndIndent("build graph for %s", method); + try (Indent indent = Debug.logAndIndent("build graph for %s", method)) { - // compute the block map, setup exception handlers and get the entrypoint(s) - BciBlockMapping blockMap = BciBlockMapping.create(method); - loopHeaders = blockMap.loopHeaders; - liveness = blockMap.liveness; + // compute the block map, setup exception handlers and get the entrypoint(s) + BciBlockMapping blockMap = BciBlockMapping.create(method); + loopHeaders = blockMap.loopHeaders; + liveness = blockMap.liveness; - lastInstr = currentGraph.start(); - if (isSynchronized(method.getModifiers())) { - // add a monitor enter to the start block - currentGraph.start().setStateAfter(frameState.create(FrameState.BEFORE_BCI)); - methodSynchronizedObject = synchronizedObject(frameState, method); - lastInstr = genMonitorEnter(methodSynchronizedObject); - } - frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true); - ((StateSplit) lastInstr).setStateAfter(frameState.create(0)); - finishPrepare(lastInstr); + lastInstr = currentGraph.start(); + if (isSynchronized(method.getModifiers())) { + // add a monitor enter to the start block + currentGraph.start().setStateAfter(frameState.create(FrameState.BEFORE_BCI)); + methodSynchronizedObject = synchronizedObject(frameState, method); + lastInstr = genMonitorEnter(methodSynchronizedObject); + } + frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true); + ((StateSplit) lastInstr).setStateAfter(frameState.create(0)); + finishPrepare(lastInstr); - if (graphBuilderConfig.eagerInfopointMode()) { - InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0))); - lastInstr.setNext(ipn); - lastInstr = ipn; - } + if (graphBuilderConfig.eagerInfopointMode()) { + InfopointNode ipn = currentGraph.add(new InfopointNode(InfopointReason.METHOD_START, frameState.create(0))); + lastInstr.setNext(ipn); + lastInstr = ipn; + } - currentBlock = blockMap.startBlock; - blockMap.startBlock.entryState = frameState; - if (blockMap.startBlock.isLoopHeader) { - /* - * TODO(lstadler,gduboscq) createTarget might not be safe at this position, since it - * expects currentBlock, etc. to be set up correctly. A better solution to this - * problem of start blocks that are loop headers would be to create a dummy block in - * BciBlockMapping. - */ - appendGoto(createTarget(blockMap.startBlock, frameState)); - } else { - blockMap.startBlock.firstInstruction = lastInstr; - } + currentBlock = blockMap.startBlock; + blockMap.startBlock.entryState = frameState; + if (blockMap.startBlock.isLoopHeader) { + /* + * TODO(lstadler,gduboscq) createTarget might not be safe at this position, + * since it expects currentBlock, etc. to be set up correctly. A better solution + * to this problem of start blocks that are loop headers would be to create a + * dummy block in BciBlockMapping. + */ + appendGoto(createTarget(blockMap.startBlock, frameState)); + } else { + blockMap.startBlock.firstInstruction = lastInstr; + } - for (BciBlock block : blockMap.blocks) { - processBlock(block); - } - processBlock(unwindBlock); + for (BciBlock block : blockMap.blocks) { + processBlock(block); + } + processBlock(unwindBlock); - Debug.dump(currentGraph, "After bytecode parsing"); + Debug.dump(currentGraph, "After bytecode parsing"); + + connectLoopEndToBegin(); - connectLoopEndToBegin(); + // remove Placeholders + for (BlockPlaceholderNode n = placeholders; n != null; n = n.nextPlaceholder()) { + if (!n.isDeleted()) { + currentGraph.removeFixed(n); + } + } + placeholders = null; - // remove Placeholders - for (BlockPlaceholderNode n = placeholders; n != null; n = n.nextPlaceholder()) { - if (!n.isDeleted()) { - currentGraph.removeFixed(n); + // remove dead FrameStates + for (Node n : currentGraph.getNodes(FrameState.class)) { + if (n.usages().isEmpty() && n.predecessor() == null) { + n.safeDelete(); + } } } - placeholders = null; - - // remove dead FrameStates - for (Node n : currentGraph.getNodes(FrameState.class)) { - if (n.usages().isEmpty() && n.predecessor() == null) { - n.safeDelete(); - } - } - indent.outdent(); } /** @@ -1613,32 +1613,32 @@ Debug.log("Ignoring block %s", block); return; } - Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader); + try (Indent indent = Debug.logAndIndent("Parsing block %s firstInstruction: %s loopHeader: %b", block, block.firstInstruction, block.isLoopHeader)) { + + lastInstr = block.firstInstruction; + frameState = block.entryState; + parseHelper.setCurrentFrameState(frameState); + currentBlock = block; - lastInstr = block.firstInstruction; - frameState = block.entryState; - parseHelper.setCurrentFrameState(frameState); - currentBlock = block; - - frameState.cleanupDeletedPhis(); - if (lastInstr instanceof MergeNode) { - int bci = block.startBci; - if (block instanceof ExceptionDispatchBlock) { - bci = ((ExceptionDispatchBlock) block).deoptBci; + frameState.cleanupDeletedPhis(); + if (lastInstr instanceof MergeNode) { + int bci = block.startBci; + if (block instanceof ExceptionDispatchBlock) { + bci = ((ExceptionDispatchBlock) block).deoptBci; + } + ((MergeNode) lastInstr).setStateAfter(frameState.create(bci)); } - ((MergeNode) lastInstr).setStateAfter(frameState.create(bci)); + + if (block == unwindBlock) { + frameState.setRethrowException(false); + createUnwind(); + } else if (block instanceof ExceptionDispatchBlock) { + createExceptionDispatch((ExceptionDispatchBlock) block); + } else { + frameState.setRethrowException(false); + iterateBytecodesForBlock(block); + } } - - if (block == unwindBlock) { - frameState.setRethrowException(false); - createUnwind(); - } else if (block instanceof ExceptionDispatchBlock) { - createExceptionDispatch((ExceptionDispatchBlock) block); - } else { - frameState.setRethrowException(false); - iterateBytecodesForBlock(block); - } - indent.outdent(); } private void connectLoopEndToBegin() { diff -r a8dce92315a2 -r 667710021ea1 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java Fri Mar 28 09:47:42 2014 +0100 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java Fri Mar 28 11:41:42 2014 +0100 @@ -50,7 +50,7 @@ * instruction. Note that because instructions can have multiple outputs it is not possible to * use the instruction id for value numbering. In addition, the result of merging at block * entries (= phi values) get unique value numbers. - * + * * The value numbers also contain information if it is an object kind value or not: if the * number is negative it is an object kind value. */ @@ -176,100 +176,101 @@ /** * Calculates the entry and exit states for all basic blocks. - * + * * @return Returns true on success and false if the the control flow is too complex. */ private boolean solveDataFlow(LIR lir) { - Indent indent = Debug.logAndIndent("solve data flow"); + try (Indent indent = Debug.logAndIndent("solve data flow")) { - List> blocks = lir.linearScanOrder(); + List> blocks = lir.linearScanOrder(); - int numIter = 0; + int numIter = 0; - /* - * Iterate until there are no more changes. - */ - int currentValueNum = 1; - boolean firstRound = true; - boolean changed; - do { - changed = false; - Indent indent2 = indent.logAndIndent("new iteration"); + /* + * Iterate until there are no more changes. + */ + int currentValueNum = 1; + boolean firstRound = true; + boolean changed; + do { + changed = false; + try (Indent indent2 = Debug.logAndIndent("new iteration")) { + + for (AbstractBlock block : blocks) { - for (AbstractBlock block : blocks) { + BlockData data = blockData.get(block); + /* + * Initialize the number for global value numbering for this block. It is + * essential that the starting number for a block is consistent at all + * iterations and also in eliminateMoves(). + */ + if (firstRound) { + data.entryValueNum = currentValueNum; + } + int valueNum = data.entryValueNum; + assert valueNum > 0; + boolean newState = false; - BlockData data = blockData.get(block); - /* - * Initialize the number for global value numbering for this block. It is essential - * that the starting number for a block is consistent at all iterations and also in - * eliminateMoves(). - */ - if (firstRound) { - data.entryValueNum = currentValueNum; - } - int valueNum = data.entryValueNum; - assert valueNum > 0; - boolean newState = false; + if (block == blocks.get(0) || block.isExceptionEntry()) { + /* + * The entry block has undefined values. And also exception handler + * blocks: the LinearScan can insert moves at the end of an exception + * handler predecessor block (after the invoke, which throws the + * exception), and in reality such moves are not in the control flow in + * case of an exception. So we assume a save default for exception + * handler blocks. + */ + Debug.log("kill all values at entry of block %d", block.getId()); + clearValues(data.entryState, valueNum); + } else { + /* + * Merge the states of predecessor blocks + */ + for (AbstractBlock predecessor : block.getPredecessors()) { + BlockData predData = blockData.get(predecessor); + newState |= mergeState(data.entryState, predData.exitState, valueNum); + } + } + // Advance by the value numbers which are "consumed" by + // clearValues and mergeState + valueNum += data.entryState.length; - if (block == blocks.get(0) || block.isExceptionEntry()) { + if (newState || firstRound) { + try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) { + + /* + * Derive the exit state from the entry state by iterating through + * all instructions of the block. + */ + int[] iterState = data.exitState; + copyState(iterState, data.entryState); + List instructions = lir.getLIRforBlock(block); + + for (LIRInstruction op : instructions) { + valueNum = updateState(iterState, op, valueNum); + } + changed = true; + } + } + if (firstRound) { + currentValueNum = valueNum; + } + } + firstRound = false; + } + numIter++; + + if (numIter > 5) { /* - * The entry block has undefined values. And also exception handler blocks: the - * LinearScan can insert moves at the end of an exception handler predecessor - * block (after the invoke, which throws the exception), and in reality such - * moves are not in the control flow in case of an exception. So we assume a - * save default for exception handler blocks. - */ - indent2.log("kill all values at entry of block %d", block.getId()); - clearValues(data.entryState, valueNum); - } else { - /* - * Merge the states of predecessor blocks + * This is _very_ seldom. */ - for (AbstractBlock predecessor : block.getPredecessors()) { - BlockData predData = blockData.get(predecessor); - newState |= mergeState(data.entryState, predData.exitState, valueNum); - } + return false; } - // Advance by the value numbers which are "consumed" by clearValues and mergeState - valueNum += data.entryState.length; - - if (newState || firstRound) { - - Indent indent3 = indent2.logAndIndent("update block %d", block.getId()); - - /* - * Derive the exit state from the entry state by iterating through all - * instructions of the block. - */ - int[] iterState = data.exitState; - copyState(iterState, data.entryState); - List instructions = lir.getLIRforBlock(block); - for (LIRInstruction op : instructions) { - valueNum = updateState(iterState, op, valueNum); - } - changed = true; - indent3.outdent(); - } - if (firstRound) { - currentValueNum = valueNum; - } - } - firstRound = false; - indent2.outdent(); - numIter++; + } while (changed); - if (numIter > 5) { - /* - * This is _very_ seldom. - */ - return false; - } - - } while (changed); - - indent.outdent(); + } return true; } @@ -279,47 +280,48 @@ */ private void eliminateMoves(LIR lir) { - Indent indent = Debug.logAndIndent("eliminate moves"); + try (Indent indent = Debug.logAndIndent("eliminate moves")) { + + List> blocks = lir.linearScanOrder(); - List> blocks = lir.linearScanOrder(); + for (AbstractBlock block : blocks) { - for (AbstractBlock block : blocks) { + try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) { - Indent indent2 = indent.logAndIndent("eliminate moves in block %d", block.getId()); + List instructions = lir.getLIRforBlock(block); + BlockData data = blockData.get(block); + boolean hasDead = false; - List instructions = lir.getLIRforBlock(block); - BlockData data = blockData.get(block); - boolean hasDead = false; + // Reuse the entry state for iteration, we don't need it later. + int[] iterState = data.entryState; - // Reuse the entry state for iteration, we don't need it later. - int[] iterState = data.entryState; + // Add the values which are "consumed" by clearValues and + // mergeState in solveDataFlow + int valueNum = data.entryValueNum + data.entryState.length; - // Add the values which are "consumed" by clearValues and mergeState in solveDataFlow - int valueNum = data.entryValueNum + data.entryState.length; - - int numInsts = instructions.size(); - for (int idx = 0; idx < numInsts; idx++) { - LIRInstruction op = instructions.get(idx); - if (isEligibleMove(op)) { - MoveOp moveOp = (MoveOp) op; - int sourceIdx = getStateIdx(moveOp.getInput()); - int destIdx = getStateIdx(moveOp.getResult()); - if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) { - assert iterState[sourceIdx] != INIT_VALUE; - indent2.log("delete move %s", op); - instructions.set(idx, null); - hasDead = true; + int numInsts = instructions.size(); + for (int idx = 0; idx < numInsts; idx++) { + LIRInstruction op = instructions.get(idx); + if (isEligibleMove(op)) { + MoveOp moveOp = (MoveOp) op; + int sourceIdx = getStateIdx(moveOp.getInput()); + int destIdx = getStateIdx(moveOp.getResult()); + if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) { + assert iterState[sourceIdx] != INIT_VALUE; + Debug.log("delete move %s", op); + instructions.set(idx, null); + hasDead = true; + } + } + // It doesn't harm if updateState is also called for a deleted move + valueNum = updateState(iterState, op, valueNum); + } + if (hasDead) { + instructions.removeAll(Collections.singleton(null)); } } - // It doesn't harm if updateState is also called for a deleted move - valueNum = updateState(iterState, op, valueNum); } - if (hasDead) { - instructions.removeAll(Collections.singleton(null)); - } - indent2.outdent(); } - indent.outdent(); } /** @@ -338,7 +340,7 @@ if (sourceIdx >= 0 && destIdx >= 0) { assert isObjectValue(state[sourceIdx]) || (moveOp.getInput().getKind() != Kind.Object) : "move op moves object but input is not defined as object"; state[destIdx] = state[sourceIdx]; - indent.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx); + Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx); return initValueNum; } } @@ -346,7 +348,7 @@ int valueNum = initValueNum; if (op.destroysCallerSavedRegisters()) { - indent.log("kill all caller save regs"); + Debug.log("kill all caller save regs"); for (Register reg : callerSaveRegs) { if (reg.number < numRegs) { @@ -375,7 +377,7 @@ * Assign a unique number to the output or temp location. */ state[stateIdx] = encodeValueNum(opValueNum++, operand.getKind() == Kind.Object); - indent.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]); + Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]); } return operand; } @@ -395,12 +397,11 @@ /* * All instructions with framestates (mostly method calls), may do garbage * collection. GC will rewrite all object references which are live at this point. - * So we can't rely on their values. - * - * It would be sufficient to just kill all values which are referenced in the state - * (or all values which are not), but for simplicity we kill all values. + * So we can't rely on their values. It would be sufficient to just kill all values + * which are referenced in the state (or all values which are not), but for + * simplicity we kill all values. */ - indent.log("kill all object values"); + Debug.log("kill all object values"); clearValuesOfKindObject(state, valueNum); valueNum += state.length; }