# HG changeset patch # User Josef Eisl # Date 1417635630 -3600 # Node ID 6a6291c31657920dec2332614f57c2a3728f4b92 # Parent c7fe48cd80877eab79490d5830dcdcd7d49ef92d Add LocationMarker. diff -r c7fe48cd8087 -r 6a6291c31657 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java --- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Wed Dec 03 19:42:38 2014 +0100 +++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Wed Dec 03 20:40:30 2014 +0100 @@ -158,13 +158,27 @@ } try (Scope s = Debug.scope("Allocator")) { - if (backend.shouldAllocateRegisters()) { LinearScan.allocate(target, lirGenRes); + } else if (!LocationMarker.Options.UseLocationMarker.getValue()) { + // build frame map for targets that do not allocate registers + lirGenRes.buildFrameMap(); } - } catch (Throwable e) { - throw Debug.handle(e); } + if (LocationMarker.Options.UseLocationMarker.getValue()) { + try (Scope s1 = Debug.scope("BuildFrameMap")) { + // build frame map + lirGenRes.buildFrameMap(); + Debug.dump(lir, "After FrameMap building"); + } + try (Scope s1 = Debug.scope("MarkLocations")) { + if (backend.shouldAllocateRegisters()) { + // currently we mark locations only if we do register allocation + LocationMarker.markLocations(lir, lirGenRes.getFrameMap()); + } + } + } + } catch (Throwable e) { throw Debug.handle(e); } diff -r c7fe48cd8087 -r 6a6291c31657 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Dec 03 19:42:38 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Wed Dec 03 20:40:30 2014 +0100 @@ -351,7 +351,7 @@ try (Scope s = Debug.scope("Allocator", nodeLirGen)) { if (backend.shouldAllocateRegisters()) { LinearScan.allocate(target, lirGenRes); - } else { + } else if (!LocationMarker.Options.UseLocationMarker.getValue()) { // build frame map for targets that do not allocate registers lirGenRes.buildFrameMap(); } @@ -359,6 +359,20 @@ throw Debug.handle(e); } + if (LocationMarker.Options.UseLocationMarker.getValue()) { + try (Scope s1 = Debug.scope("BuildFrameMap")) { + // build frame map + lirGenRes.buildFrameMap(); + Debug.dump(lir, "After FrameMap building"); + } + try (Scope s1 = Debug.scope("MarkLocations")) { + if (backend.shouldAllocateRegisters()) { + // currently we mark locations only if we do register allocation + LocationMarker.markLocations(lir, lirGenRes.getFrameMap()); + } + } + } + try (Scope s = Debug.scope("ControlFlowOptimizations")) { EdgeMoveOptimizer.optimize(lir); ControlFlowOptimizer.optimize(lir, codeEmittingOrder); diff -r c7fe48cd8087 -r 6a6291c31657 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 Wed Dec 03 19:42:38 2014 +0100 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java Wed Dec 03 20:40:30 2014 +0100 @@ -1713,6 +1713,9 @@ * @see InstructionValueProcedure#doValue(LIRInstruction, Value, OperandMode, EnumSet) */ private Value debugInfoProcedure(LIRInstruction op, Value operand, OperandMode valueMode, EnumSet flags) { + if (isVirtualStackSlot(operand)) { + return operand; + } int tempOpId = op.id(); OperandMode mode = OperandMode.USE; AbstractBlock block = blockForId(tempOpId); @@ -1742,12 +1745,16 @@ } private void computeDebugInfo(IntervalWalker iw, final LIRInstruction op, LIRFrameState info) { - FrameMap frameMap = res.getFrameMap(); - info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters); - markFrameLocations(iw, op, info, frameMap); + if (!LocationMarker.Options.UseLocationMarker.getValue()) { + FrameMap frameMap = res.getFrameMap(); + info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !callKillsRegisters); + markFrameLocations(iw, op, info, frameMap); + } info.forEachState(op, this::debugInfoProcedure); - info.finish(op, frameMap); + if (!LocationMarker.Options.UseLocationMarker.getValue()) { + info.finish(op, res.getFrameMap()); + } } private void assignLocations(List instructions, final IntervalWalker iw) { @@ -1887,8 +1894,11 @@ // register interval mapper frameMapBuilder.requireMapping(new Mapper()); - // build frame map - res.buildFrameMap(); + + if (!LocationMarker.Options.UseLocationMarker.getValue()) { + // build frame map + res.buildFrameMap(); + } printLir("After FrameMap building", true); diff -r c7fe48cd8087 -r 6a6291c31657 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LocationMarker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LocationMarker.java Wed Dec 03 20:40:30 2014 +0100 @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.compiler.alloc; + +import static com.oracle.graal.api.code.ValueUtil.*; + +import java.util.*; + +import com.oracle.graal.api.code.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.common.cfg.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.lir.*; +import com.oracle.graal.lir.LIRInstruction.OperandFlag; +import com.oracle.graal.lir.LIRInstruction.OperandMode; +import com.oracle.graal.lir.framemap.*; +import com.oracle.graal.options.*; + +public final class LocationMarker { + + public static class Options { + // @formatter:off + @Option(help = "Use decoupled pass for location marking (instead of using LSRA marking)") + public static final OptionValue UseLocationMarker = new OptionValue<>(true); + // @formatter:on + } + + /** + * Mark all live references for a frame state. The frame state use this information to build the + * OOP maps. + */ + public static void markLocations(LIR lir, FrameMap frameMap) { + new LocationMarker(lir, frameMap).build(); + } + + private final LIR lir; + private final FrameMap frameMap; + private final RegisterAttributes[] registerAttributes; + private final BlockMap liveInMap; + private final BlockMap liveOutMap; + + private LocationMarker(LIR lir, FrameMap frameMap) { + this.lir = lir; + this.frameMap = frameMap; + this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap(); + liveInMap = new BlockMap<>(lir.getControlFlowGraph()); + liveOutMap = new BlockMap<>(lir.getControlFlowGraph()); + } + + private void build() { + Deque> worklist = new ArrayDeque<>(); + for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) { + worklist.add(lir.getControlFlowGraph().getBlocks().get(i)); + } + for (AbstractBlock block : lir.getControlFlowGraph().getBlocks()) { + liveInMap.put(block, frameMap.initReferenceMap(true)); + } + while (!worklist.isEmpty()) { + AbstractBlock block = worklist.poll(); + processBlock(block, worklist); + } + // finish states + for (AbstractBlock block : lir.getControlFlowGraph().getBlocks()) { + List instructions = lir.getLIRforBlock(block); + for (int i = instructions.size() - 1; i >= 0; i--) { + LIRInstruction inst = instructions.get(i); + inst.forEachState((op, info) -> info.finish(op, frameMap)); + } + + } + } + + /** + * Merge outSet with in-set of successors. + */ + private boolean updateOutBlock(AbstractBlock block) { + ReferenceMap merged = frameMap.initReferenceMap(true); + block.getSuccessors().forEach(succ -> merged.mergeMaps(liveInMap.get(succ))); + ReferenceMap outSet = liveOutMap.get(block); + // check if changed + if (outSet == null || !merged.equals(outSet)) { + liveOutMap.put(block, merged); + return true; + } + return false; + } + + private void processBlock(AbstractBlock block, Deque> worklist) { + if (updateOutBlock(block)) { + try (Indent indent = Debug.logAndIndent("handle block %s", block)) { + BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone()); + List instructions = lir.getLIRforBlock(block); + for (int i = instructions.size() - 1; i >= 0; i--) { + LIRInstruction inst = instructions.get(i); + closure.processInstructionBottomUp(inst); + } + liveInMap.put(block, closure.getCurrentSet()); + worklist.addAll(block.getPredecessors()); + } + } + } + + private static final EnumSet REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG); + private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object); + + private void forEachDestroyedCallerSavedRegister(LIRInstruction op, ValueConsumer consumer) { + if (op.destroysCallerSavedRegisters()) { + for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) { + consumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET); + } + } + } + + private final class BlockClosure { + private final ReferenceMap currentSet; + + private BlockClosure(ReferenceMap set) { + currentSet = set; + } + + private ReferenceMap getCurrentSet() { + return currentSet; + } + + /** + * Process all values of an instruction bottom-up, i.e. definitions before usages. Values + * that start or end at the current operation are not included. + */ + private void processInstructionBottomUp(LIRInstruction op) { + try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) { + // kills + op.visitEachTemp(this::defConsumer); + op.visitEachOutput(this::defConsumer); + forEachDestroyedCallerSavedRegister(op, this::defConsumer); + + // gen - values that are considered alive for this state + op.visitEachAlive(this::useConsumer); + op.visitEachState(this::useConsumer); + // mark locations + op.forEachState((inst, info) -> markLocation(inst, info, this.getCurrentSet())); + // gen + op.visitEachInput(this::useConsumer); + } + } + + /** + * @see InstructionValueConsumer + * @param operand + * @param mode + * @param flags + */ + private void useConsumer(Value operand, OperandMode mode, EnumSet flags) { + LIRKind kind = operand.getLIRKind(); + if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) { + // no need to insert values and derived reference + Debug.log("set operand: %s", operand); + frameMap.setReference(operand, currentSet); + } + } + + /** + * @see InstructionValueConsumer + * @param operand + * @param mode + * @param flags + */ + private void defConsumer(Value operand, OperandMode mode, EnumSet flags) { + if (shouldProcessValue(operand)) { + Debug.log("clear operand: %s", operand); + frameMap.clearReference(operand, currentSet); + } + } + + protected boolean shouldProcessValue(Value operand) { + return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getKind() != Kind.Illegal; + } + } + + /** + * This method does the actual marking. + */ + private void markLocation(LIRInstruction op, LIRFrameState info, ReferenceMap refMap) { + if (!info.hasDebugInfo()) { + info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved()); + } + info.markLocation(refMap); + } + + /** + * Gets an object describing the attributes of a given register according to this register + * configuration. + * + * @see LinearScan#attributes + */ + private RegisterAttributes attributes(Register reg) { + return registerAttributes[reg.number]; + } +}