changeset 18610:6a6291c31657

Add LocationMarker.
author Josef Eisl <josef.eisl@jku.at>
date Wed, 03 Dec 2014 20:40:30 +0100
parents c7fe48cd8087
children 20e498cfa409 4a88dacfcb17
files graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LocationMarker.java
diffstat 4 files changed, 266 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- 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);
             }
--- 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);
--- 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<OperandFlag> 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<LIRInstruction> 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);
 
--- /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<Boolean> 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<ReferenceMap> liveInMap;
+    private final BlockMap<ReferenceMap> 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<AbstractBlock<?>> 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<LIRInstruction> 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<AbstractBlock<?>> worklist) {
+        if (updateOutBlock(block)) {
+            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
+                List<LIRInstruction> 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<OperandFlag> 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<OperandFlag> 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<OperandFlag> 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];
+    }
+}