changeset 4245:75c620f90ab9

Support stack-operands and register hints in new register allocator API
author Christian Wimmer <Christian.Wimmer@Oracle.com>
date Sat, 07 Jan 2012 16:04:22 -0800
parents 30b6720604d2
children b019b2ebe03e
files graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiValueUtil.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LIRVerifier.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LocationMap.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/MoveResolver.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRCall.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRDebugInfo.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRPhiMapping.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/MoveInstruction.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/StandardOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ArithmeticOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64CompareOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ControlFlowOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ConvertOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LogicFloatOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MoveOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MulOpcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Op1Opcode.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ShiftOpcode.java
diffstat 31 files changed, 815 insertions(+), 571 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiValueUtil.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiValueUtil.java	Sat Jan 07 16:04:22 2012 -0800
@@ -47,6 +47,11 @@
         return value instanceof CiConstant;
     }
 
+    public static CiConstant asConstant(CiValue value) {
+        assert value != null;
+        return (CiConstant) value;
+    }
+
 
     public static boolean isStackSlot(CiValue value) {
         assert value != null;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/DataFlowAnalysis.java	Sat Jan 07 16:04:22 2012 -0800
@@ -22,6 +22,7 @@
  */
 package com.oracle.max.graal.alloc.simple;
 
+import static com.oracle.max.graal.compiler.lir.LIRPhiMapping.*;
 import static com.oracle.max.graal.alloc.util.ValueUtil.*;
 
 import java.util.*;
@@ -98,13 +99,13 @@
         if (entry == null) {
             // Nothing to do
         } else if (entry instanceof CiValue) {
-            CiValue newValue = proc.doValue((CiValue) entry);
+            CiValue newValue = proc.doValue((CiValue) entry, null, null);
             assert newValue == entry : "procedure does not allow to change values";
         } else {
             CiValue[] values = (CiValue[]) entry;
             for (int i = 0; i < values.length; i++) {
                 if (values[i] != null) {
-                    CiValue newValue = proc.doValue(values[i]);
+                    CiValue newValue = proc.doValue(values[i], null, null);
                     assert newValue == values[i] : "procedure does not allow to change values";
                 }
             }
@@ -161,11 +162,11 @@
     private int curOpId;
 
     private void backwardDataFlow() {
-        ValueProcedure inputProc =    new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId); } };
-        ValueProcedure aliveProc =    new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, curOpId + 1); } };
-        ValueProcedure phiInputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, -1); } };
-        ValueProcedure tempProc =     new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, true); } };
-        ValueProcedure outputProc =   new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, false); } };
+        ValueProcedure inputProc =       new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return use(value, curOpId); } };
+        ValueProcedure aliveProc =       new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return use(value, curOpId + 1); } };
+        PhiValueProcedure phiInputProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value, -1); } };
+        ValueProcedure tempProc =        new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return def(value, true); } };
+        ValueProcedure outputProc =      new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return def(value, false); } };
 
         blockLiveIn = new BitSet[blocks().size()];
         registerLive = new BitSet();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/ResolveDataFlow.java	Sat Jan 07 16:04:22 2012 -0800
@@ -48,7 +48,7 @@
 
     public void execute() {
         ValueProcedure locMappingProc =    new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return locMapping(value); } };
-        PhiValueProcedure phiMappingProc = new PhiValueProcedure() { @Override public void doValue(CiValue input, CiValue output) { phiMapping(input, output); } };
+        PhiValueProcedure phiMappingProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue input, CiValue output) { return phiMapping(input, output); } };
 
         trace(1, "==== start resolve data flow ====");
         for (LIRBlock toBlock : lir.linearScanOrder()) {
@@ -86,11 +86,12 @@
         return value;
     }
 
-    private void phiMapping(CiValue input, CiValue output) {
+    private CiValue phiMapping(CiValue input, CiValue output) {
         Location to = asLocation(output);
         if (input != to) {
             moveResolver.add(input, to);
         }
+        return input;
     }
 
     private void findInsertPos(LIRBlock fromBlock, LIRBlock toBlock) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/simple/SpillAllAllocator.java	Sat Jan 07 16:04:22 2012 -0800
@@ -22,6 +22,7 @@
  */
 package com.oracle.max.graal.alloc.simple;
 
+import static com.oracle.max.graal.compiler.lir.LIRPhiMapping.*;
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 import static com.oracle.max.graal.alloc.util.ValueUtil.*;
 
@@ -34,7 +35,7 @@
 import com.oracle.max.graal.alloc.util.*;
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.lir.*;
-import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure;
+import com.oracle.max.graal.compiler.lir.LIRInstruction.*;
 import com.oracle.max.graal.compiler.schedule.*;
 import com.oracle.max.graal.compiler.util.*;
 
@@ -134,40 +135,34 @@
         assert LIRVerifier.verify(true, lir, frameMap, registerConfig);
 
         dataFlow.execute();
-
         allocate();
+        frameMap.finish();
 
         context.observable.fireCompilationEvent("After spill all allocation", lir);
 
-        frameMap.finish();
-
         ResolveDataFlow resolveDataFlow = new ResolveDataFlowImpl(lir, moveResolver);
         resolveDataFlow.execute();
 
         context.observable.fireCompilationEvent("After resolve data flow", lir);
-
         assert RegisterVerifier.verify(lir, frameMap, registerConfig);
 
         AssignRegisters assignRegisters = new AssignRegistersImpl(lir, frameMap);
         assignRegisters.execute();
 
         context.observable.fireCompilationEvent("After register asignment", lir);
-
         assert LIRVerifier.verify(true, lir, frameMap, registerConfig);
     }
 
     private void allocate() {
-        ValueProcedure killNonLiveProc =  new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killNonLive(value); } };
-        ValueProcedure killBeginProc =    new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, false); } };
-        ValueProcedure killEndProc =      new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return kill(value, true); } };
-        ValueProcedure killLocationProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return killLocation(value); } };
-        ValueProcedure blockProc =        new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return block(value); } };
-        ValueProcedure inputProc =        new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return load(value, false); } };
-        ValueProcedure aliveProc =        new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return load(value, true); } };
-        ValueProcedure tempProc =         new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return spill(value, true); } };
-        ValueProcedure outputProc =       new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return spill(value, false); } };
-        ValueProcedure useSlotProc =      new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return useSlot(value); } };
-        ValueProcedure defSlotProc =      new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return defSlot(value); } };
+        ValueProcedure killNonLiveProc =  new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return killNonLive(value); } };
+        ValueProcedure killBeginProc =    new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return kill(value, false); } };
+        ValueProcedure killEndProc =      new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return kill(value, true); } };
+        ValueProcedure killLocationProc = new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return killLocation(value); } };
+        ValueProcedure blockProc =        new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return block(value); } };
+        ValueProcedure loadProc =         new ValueProcedure() {    @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) { return load(value, mode, flags); } };
+        ValueProcedure spillProc =        new ValueProcedure() {    @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) { return spill(value, mode, flags); } };
+        PhiValueProcedure useSlotProc =   new PhiValueProcedure() { @Override public CiValue doValue(CiValue value) { return useSlot(value); } };
+        ValueProcedure defSlotProc =      new ValueProcedure() {    @Override public CiValue doValue(CiValue value) { return defSlot(value); } };
 
         trace(1, "==== start spill all allocation ====");
         curInRegisterState = new Object[maxRegisterNum()];
@@ -209,8 +204,8 @@
 
                 moveResolver.init(block.lir(), opIdx);
                 // Process Alive before Input because they are more restricted and the same variable can be Alive and Input.
-                op.forEachAlive(aliveProc);
-                op.forEachInput(inputProc);
+                op.forEachAlive(loadProc);
+                op.forEachInput(loadProc);
                 moveResolver.resolve();
                 op.forEachState(useSlotProc);
 
@@ -218,8 +213,8 @@
                 assert !op.hasCall() || checkNoCallerSavedRegister() : "caller saved register in use accross call site";
 
                 moveResolver.init(block.lir(), opIdx + 1);
-                op.forEachTemp(tempProc);
-                op.forEachOutput(outputProc);
+                op.forEachTemp(spillProc);
+                op.forEachOutput(spillProc);
                 moveResolver.resolve();
 
                 dataFlow.forEachKilled(op, true, killEndProc);
@@ -315,7 +310,11 @@
         return value;
     }
 
-    private CiValue load(CiValue value, boolean isAlive) {
+    private CiValue load(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        assert mode == OperandMode.Input || mode == OperandMode.Alive;
+        if (flags.contains(OperandFlag.Stack)) {
+            return useSlot(value);
+        }
         if (isVariable(value)) {
             trace(3, "    load %s", value);
             Location regLoc = curRegisterLocations.get(asVariable(value));
@@ -323,7 +322,7 @@
                 // This variable has already been processed before.
                 trace(3, "      found location %s", regLoc);
             } else {
-                regLoc = allocateRegister(asVariable(value), curInRegisterState, isAlive ? curOutRegisterState : null);
+                regLoc = allocateRegister(asVariable(value), curInRegisterState, mode == OperandMode.Alive ? curOutRegisterState : null, mode, flags);
                 Location stackLoc = curStackLocations.get(asVariable(value));
                 assert stackLoc != null;
                 moveResolver.add(stackLoc, regLoc);
@@ -335,12 +334,16 @@
         }
     }
 
-    private CiValue spill(CiValue value, boolean isTemp) {
+    private CiValue spill(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        assert mode == OperandMode.Temp || mode == OperandMode.Output;
+        if (flags.contains(OperandFlag.Stack)) {
+            return defSlot(value);
+        }
         if (isVariable(value)) {
             trace(3, "    spill %s", value);
             assert curStackLocations.get(asVariable(value)) == null;
-            Location regLoc = allocateRegister(asVariable(value), null, curOutRegisterState);
-            if (!isTemp) {
+            Location regLoc = allocateRegister(asVariable(value), null, curOutRegisterState, mode, flags);
+            if (mode == OperandMode.Output) {
                 Location stackLoc = new Location(asVariable(value), frameMap.allocateSpillSlot(value.kind));
                 curStackLocations.put(stackLoc);
                 moveResolver.add(regLoc, stackLoc);
@@ -377,28 +380,59 @@
         }
     }
 
-    private Location allocateRegister(Variable variable, Object[] inRegisterState, Object[] outRegisterState) {
+    private Location allocateRegister(final Variable variable, final Object[] inRegisterState, final Object[] outRegisterState, OperandMode mode, EnumSet<OperandFlag> flags) {
+        if (flags.contains(OperandFlag.RegisterHint)) {
+            CiValue result = curInstruction.forEachRegisterHint(variable, mode, new ValueProcedure() {
+                @Override
+                public CiValue doValue(CiValue registerHint) {
+                    trace(3, "      registerHint %s", registerHint);
+                    CiRegister hint = null;
+                    if (isRegister(registerHint)) {
+                        hint = asRegister(registerHint);
+                    } else if (isLocation(registerHint) && isRegister(asLocation(registerHint).location)) {
+                        hint = asRegister(asLocation(registerHint).location);
+                    }
+                    if (hint != null && hint.isSet(variable.flag) && isFree(hint, inRegisterState, outRegisterState)) {
+                        return selectRegister(hint, variable, inRegisterState, outRegisterState);
+                    }
+                    return null;
+                }
+            });
+
+            if (result != null) {
+                return asLocation(result);
+            }
+        }
+
         EnumMap<RegisterFlag, CiRegister[]> categorizedRegs = registerConfig.getCategorizedAllocatableRegisters();
         CiRegister[] availableRegs = categorizedRegs.get(variable.flag);
 
         for (CiRegister reg : availableRegs) {
-            if ((inRegisterState == null || inRegisterState[reg.number] == null) && (outRegisterState == null || outRegisterState[reg.number] == null)) {
-                Location loc = new Location(variable, reg.asValue(variable.kind));
-                if (inRegisterState != null) {
-                    inRegisterState[reg.number] = loc;
-                }
-                if (outRegisterState != null) {
-                    outRegisterState[reg.number] = loc;
-                }
-                assert curRegisterLocations.get(variable) == null;
-                curRegisterLocations.put(loc);
-                trace(3, "      selected register %s", loc);
-                return loc;
+            if (isFree(reg, inRegisterState, outRegisterState)) {
+                return selectRegister(reg, variable, inRegisterState, outRegisterState);
             }
+
         }
         throw new CiBailout("No register found");
     }
 
+    private static boolean isFree(CiRegister reg, Object[] inRegisterState, Object[] outRegisterState) {
+        return (inRegisterState == null || inRegisterState[reg.number] == null) && (outRegisterState == null || outRegisterState[reg.number] == null);
+    }
+
+    private Location selectRegister(CiRegister reg, Variable variable, Object[] inRegisterState, Object[] outRegisterState) {
+        Location loc = new Location(variable, reg.asValue(variable.kind));
+        if (inRegisterState != null) {
+            inRegisterState[reg.number] = loc;
+        }
+        if (outRegisterState != null) {
+            outRegisterState[reg.number] = loc;
+        }
+        assert curRegisterLocations.get(variable) == null;
+        curRegisterLocations.put(loc);
+        trace(3, "      selected register %s", loc);
+        return loc;
+    }
 
     private boolean checkInputState(final LIRBlock block) {
         final BitSet liveState = new BitSet();
@@ -422,19 +456,9 @@
         return true;
     }
 
-//    private boolean checkBlocked(CiValue value, Object[] inRegisterState, Object[] outRegisterState) {
-//        if (isAllocatableRegister(value)) {
-//            int regNum = asRegister(value).number;
-//            assert inRegisterState == null || inRegisterState[regNum] instanceof LIRInstruction;
-//        }
-//        return !isAllocatableRegister(value) || asRegister(curRegisterState[asRegister(value).number]) == asRegister(value);
-//    }
-//
     private boolean checkNoCallerSavedRegister() {
         for (CiRegister reg : registerConfig.getCallerSaveRegisters()) {
             assert curOutRegisterState[reg.number] == null || curOutRegisterState[reg.number] == curInstruction : "caller saved register in use accross call site";
-            // TODO check if that assertion holds, otherwise the code below is necessary (outside of an assertion!)
-            // curRegisterState[reg.number] = null;
         }
         return true;
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LIRVerifier.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LIRVerifier.java	Sat Jan 07 16:04:22 2012 -0800
@@ -31,7 +31,10 @@
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.criutils.*;
 import com.oracle.max.graal.compiler.lir.*;
+import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag;
+import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode;
 import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure;
+import com.oracle.max.graal.compiler.lir.LIRPhiMapping.PhiValueProcedure;
 import com.oracle.max.graal.compiler.schedule.*;
 import com.oracle.max.graal.compiler.util.*;
 
@@ -60,6 +63,16 @@
         return isRegister(value) && registerConfig.getAttributesMap()[asRegister(value).number].isAllocatable;
     }
 
+    public static boolean verify(final LIRInstruction op) {
+        ValueProcedure allowedProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) { return allowed(op, value, mode, flags); } };
+
+        op.forEachInput(allowedProc);
+        op.forEachAlive(allowedProc);
+        op.forEachState(allowedProc);
+        op.forEachTemp(allowedProc);
+        op.forEachOutput(allowedProc);
+        return true;
+    }
 
     public static boolean verify(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap, RiRegisterConfig registerConfig) {
         LIRVerifier verifier = new LIRVerifier(beforeRegisterAllocation, lir, frameMap, registerConfig);
@@ -67,6 +80,7 @@
         return true;
     }
 
+
     private LIRVerifier(boolean beforeRegisterAllocation, LIR lir, FrameMap frameMap, RiRegisterConfig registerConfig) {
         this.beforeRegisterAllocation = beforeRegisterAllocation;
         this.lir = lir;
@@ -83,9 +97,8 @@
     private Object curInstruction;
 
     private void verify() {
-        ValueProcedure useProc =    new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return use(value); } };
-        ValueProcedure tempProc =   new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, true); } };
-        ValueProcedure outputProc = new ValueProcedure() { @Override public CiValue doValue(CiValue value) { return def(value, false); } };
+        PhiValueProcedure useProc = new PhiValueProcedure() { @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) { return use(value, mode, flags); } };
+        ValueProcedure defProc =    new ValueProcedure() {    @Override public CiValue doValue(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) { return def(value, mode, flags); } };
 
         for (LIRBlock block : lir.linearScanOrder()) {
             curBlock = block;
@@ -96,13 +109,10 @@
                 curVariablesLive.or(liveOutFor(block.dominator()));
             }
 
-            if (beforeRegisterAllocation) {
-                if (block.phis != null) {
-                    curInstruction = block.phis;
-                    block.phis.forEachOutput(outputProc);
-                }
-            } else {
-                assert block.phis == null;
+            if (block.phis != null) {
+                assert beforeRegisterAllocation;
+                curInstruction = block.phis;
+                block.phis.forEachOutput(defProc);
             }
 
             for (LIRInstruction op : block.lir()) {
@@ -116,17 +126,27 @@
                 }
                 op.forEachAlive(useProc);
                 op.forEachState(useProc);
-                op.forEachTemp(tempProc);
-                op.forEachOutput(outputProc);
+                op.forEachTemp(defProc);
+                op.forEachOutput(defProc);
 
                 curInstruction = null;
             }
 
+            for (LIRBlock sux : block.getLIRSuccessors()) {
+                if (sux.phis != null) {
+                    assert beforeRegisterAllocation;
+                    curInstruction = sux.phis;
+                    sux.phis.forEachInput(block, useProc);
+                }
+            }
+
             setLiveOutFor(block, curVariablesLive);
         }
     }
 
-    private CiValue use(CiValue value) {
+    private CiValue use(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        allowed(curInstruction, value, mode, flags);
+
         if (beforeRegisterAllocation && isVariable(value)) {
             int variableIdx = asVariable(value).index;
             if (!curVariablesLive.get(variableIdx)) {
@@ -147,23 +167,13 @@
                 TTY.println("ERROR: Use of fixed register %s that is not defined in this block", value);
                 throw Util.shouldNotReachHere();
             }
-        } else if (isRegister(value)) {
-            // Register usage cannot be checked.
-        } else if (isStackSlot(value)) {
-            // TODO check if stack slot is allowed for this operand.
-        } else if (isConstant(value)) {
-            // TODO check if constant is allowed for this operand.
-        } else if (value == CiValue.IllegalValue) {
-            // TODO check if illegal is allowed for this operand.
-        } else {
-            TTY.println("block %s  instruction %s", curBlock, curInstruction);
-            TTY.println("Unexpected value: %s %s", value.getClass().getSimpleName(), value);
-            throw Util.shouldNotReachHere();
         }
         return value;
     }
 
-    private CiValue def(CiValue value, boolean isTemp) {
+    private CiValue def(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        allowed(curInstruction, value, mode, flags);
+
         if (beforeRegisterAllocation && isVariable(value)) {
             int variableIdx = asVariable(value).index;
             if (variableDefinitions[variableIdx] != null) {
@@ -176,26 +186,32 @@
             assert curInstruction != null;
             variableDefinitions[variableIdx] = curInstruction;
             assert !curVariablesLive.get(variableIdx);
-            if (!isTemp) {
+            if (mode == OperandMode.Output) {
                 curVariablesLive.set(variableIdx);
             }
 
         } else if (beforeRegisterAllocation && isAllocatableRegister(value)) {
             int regNum = asRegister(value).number;
-            if (isTemp) {
+            if (mode == OperandMode.Output) {
+                curRegistersLive[regNum] = value;
+            } else {
                 curRegistersLive[regNum] = null;
-            } else {
-                curRegistersLive[regNum] = value;
             }
-        } else if (isRegister(value)) {
-            // Register definition cannot be checked.
-        } else if (isStackSlot(value)) {
-            // TODO check if stack slot is allowed for this operand.
-        } else {
-            TTY.println("block %s  instruction %s", curBlock, curInstruction);
-            TTY.println("Unexpected value: %s %s", value.getClass().getSimpleName(), value);
-            throw Util.shouldNotReachHere();
         }
         return value;
     }
+
+    private static CiValue allowed(Object op, CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) {
+        if ((isVariable(value)  && flags.contains(OperandFlag.Register)) ||
+            (isRegister(value)  && flags.contains(OperandFlag.Register)) ||
+            (isStackSlot(value) && flags.contains(OperandFlag.Stack)) ||
+            (isConstant(value)  && flags.contains(OperandFlag.Constant) && mode != OperandMode.Output) ||
+            (isIllegal(value)   && flags.contains(OperandFlag.Illegal))) {
+            return value;
+        }
+        TTY.println("instruction %s", op);
+        TTY.println("mode: %s  flags: %s", mode, flags);
+        TTY.println("Unexpected value: %s %s", value.getClass().getSimpleName(), value);
+        throw Util.shouldNotReachHere();
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LocationMap.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/LocationMap.java	Sat Jan 07 16:04:22 2012 -0800
@@ -57,7 +57,7 @@
     public void forEachLocation(ValueProcedure proc) {
         for (int i = 0; i < locations.length; i++) {
             if (locations[i] != null) {
-                CiValue newValue = proc.doValue(locations[i]);
+                CiValue newValue = proc.doValue(locations[i], null, null);
                 assert newValue == null || asLocation(newValue).variable == locations[i].variable;
                 locations[i] = (Location) newValue;
             }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/MoveResolver.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/alloc/util/MoveResolver.java	Sat Jan 07 16:04:22 2012 -0800
@@ -292,14 +292,14 @@
 
         } else {
             trace(3, "mr      MOV %s -> %s", src, dst);
-            insertionBuffer.append(insertPos, StandardOpcode.MOVE.create(dst,  src));
+            insertionBuffer.append(insertPos, StandardOpcode.SPILL_MOVE.create(dst,  src));
         }
     }
 
     /**
-     * Provides a register that can be used by the move resolver. If the returned value is a 
+     * Provides a register that can be used by the move resolver. If the returned value is a
      * {@link CiRegisterValue}, the register can be overwritten without precautions. If the
-     * returned value is a {@link Location}, it needs to be spilled and rescued itself. 
+     * returned value is a {@link Location}, it needs to be spilled and rescued itself.
      */
     protected abstract CiValue scratchRegister(Variable spilled);
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/ControlFlowOptimizer.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.lir.*;
 import com.oracle.max.graal.compiler.schedule.*;
@@ -45,7 +44,7 @@
         //optimizer.reorderShortLoops(code);
         optimizer.deleteEmptyBlocks(code);
         ControlFlowOptimizer.deleteUnnecessaryJumps(code);
-        ControlFlowOptimizer.deleteJumpsToReturn(code);
+        //ControlFlowOptimizer.deleteJumpsToReturn(code);
     }
 
     private final LIR ir;
@@ -175,6 +174,7 @@
         assert verify(code);
     }
 
+/*
     private static void deleteJumpsToReturn(List<LIRBlock> code) {
         for (int i = code.size() - 1; i >= 0; i--) {
             LIRBlock block = code.get(i);
@@ -212,6 +212,7 @@
             }
         }
     }
+*/
 
     private static boolean verify(List<LIRBlock> code) {
         for (LIRBlock block : code) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java	Sat Jan 07 16:04:22 2012 -0800
@@ -88,8 +88,10 @@
         assert op1 != null;
         assert op2 != null;
 
-        if (op1.code == StandardOpcode.MOVE && op2.code == StandardOpcode.MOVE) {
-            if (op1.info == op2.info && op1.input(0).equals(op2.input(0)) && op1.output(0).equals(op2.output(0))) {
+        if (op1 instanceof MoveInstruction && op2 instanceof MoveInstruction) {
+            MoveInstruction move1 = (MoveInstruction) op1;
+            MoveInstruction move2 = (MoveInstruction) op2;
+            if (move1.getSource() == move2.getSource() && move1.getDest() == move2.getDest()) {
                 // these moves are exactly equal and can be optimized
                 return true;
             }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Sat Jan 07 16:04:22 2012 -0800
@@ -37,8 +37,7 @@
 import com.oracle.max.graal.compiler.alloc.Interval.SpillState;
 import com.oracle.max.graal.compiler.gen.*;
 import com.oracle.max.graal.compiler.lir.*;
-import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode;
-import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure;
+import com.oracle.max.graal.compiler.lir.LIRInstruction.*;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.graph.*;
 
@@ -464,18 +463,17 @@
                 int opId = op.id();
 
                 if (opId == -1) {
-                    CiValue resultOperand = op.output(0);
+                    MoveInstruction move = (MoveInstruction) 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 op.code == StandardOpcode.MOVE : "only moves can have a opId of -1";
-                    assert isVariable(resultOperand) : "LinearScan inserts only moves to variables";
+                    assert isVariable(move.getDest()) : "LinearScan inserts only moves to variables";
 
-                    Interval curInterval = intervalFor(resultOperand);
+                    Interval curInterval = intervalFor(move.getDest());
 
                     if (!isRegister(curInterval.location()) && curInterval.alwaysInMemory()) {
                         // move target is a stack slot that is always correct, so eliminate instruction
                         if (GraalOptions.TraceLinearScanLevel >= 4) {
-                            TTY.println("eliminating move from interval %d to %d", operandNumber(op.input(0)), operandNumber(op.output(0)));
+                            TTY.println("eliminating move from interval %d to %d", operandNumber(move.getSource()), operandNumber(move.getDest()));
                         }
                         instructions.set(j, null); // null-instructions are deleted by assignRegNum
                     }
@@ -497,7 +495,7 @@
                         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, StandardOpcode.MOVE.create(toLocation, fromLocation));
+                        insertionBuffer.append(j + 1, StandardOpcode.SPILL_MOVE.create(toLocation, fromLocation));
 
                         if (GraalOptions.TraceLinearScanLevel >= 4) {
                             CiStackSlot slot = interval.spillSlot();
@@ -613,11 +611,11 @@
         int numBlocks = blockCount();
         int liveSize = liveSetSize();
 
-        BitMap2D localIntervalInLoop = new BitMap2D(operandSize(), numLoops());
+        intervalInLoop = new BitMap2D(operandSize(), numLoops());
 
         // iterate all blocks
         for (int i = 0; i < numBlocks; i++) {
-            LIRBlock block = blockAt(i);
+            final LIRBlock block = blockAt(i);
             final BitMap liveGen = new BitMap(liveSize);
             final BitMap liveKill = new BitMap(liveSize);
 
@@ -629,107 +627,68 @@
             for (int j = 1; j < numInst; j++) {
                 final LIRInstruction op = instructions.get(j);
 
-                // iterate input operands of instruction
-                int n = op.operandCount(LIRInstruction.OperandMode.Input);
-                for (int k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, k);
-
-                    if (isVariable(operand)) {
-                        int operandNum = operandNumber(operand);
-                        if (!liveKill.get(operandNum)) {
-                            liveGen.set(operandNum);
-                            if (GraalOptions.TraceLinearScanLevel >= 4) {
-                                TTY.println("  Setting liveGen for operand %d at instruction %d", operandNum, op.id());
+                ValueProcedure useProc = new ValueProcedure() {
+                    @Override
+                    protected CiValue doValue(CiValue operand) {
+                        if (isVariable(operand)) {
+                            int operandNum = operandNumber(operand);
+                            if (!liveKill.get(operandNum)) {
+                                liveGen.set(operandNum);
+                                if (GraalOptions.TraceLinearScanLevel >= 4) {
+                                    TTY.println("  Setting liveGen for operand %d at instruction %d", operandNum, op.id());
+                                }
+                            }
+                            if (block.loopIndex() >= 0) {
+                                intervalInLoop.setBit(operandNum, block.loopIndex());
                             }
                         }
-                        if (block.loopIndex() >= 0) {
-                            localIntervalInLoop.setBit(operandNum, block.loopIndex());
+
+                        if (GraalOptions.DetailedAsserts) {
+                            verifyInput(block, liveKill, operand);
                         }
-                    }
-
-                    if (GraalOptions.DetailedAsserts) {
-                        verifyInput(block, liveKill, operand);
+                        return operand;
                     }
-                }
-
-                n = op.operandCount(LIRInstruction.OperandMode.Alive);
-                for (int k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Alive, k);
-
-                    if (isVariable(operand)) {
+                };
+                ValueProcedure stateProc = new ValueProcedure() {
+                    @Override
+                    public CiValue doValue(CiValue operand) {
                         int operandNum = operandNumber(operand);
                         if (!liveKill.get(operandNum)) {
                             liveGen.set(operandNum);
                             if (GraalOptions.TraceLinearScanLevel >= 4) {
-                                TTY.println("  Setting liveGen for operand %d at instruction %d", operandNum, op.id());
+                                TTY.println("  Setting liveGen for LIR opId %d, operand %d because of state for %s", op.id(), operandNum, op);
+                            }
+                        }
+                        return operand;
+                    }
+                };
+                ValueProcedure defProc = new ValueProcedure() {
+                    @Override
+                    public CiValue doValue(CiValue operand) {
+                        if (isVariable(operand)) {
+                            int varNum = operandNumber(operand);
+                            liveKill.set(varNum);
+                            if (block.loopIndex() >= 0) {
+                                intervalInLoop.setBit(varNum, block.loopIndex());
                             }
                         }
-                        if (block.loopIndex() >= 0) {
-                            localIntervalInLoop.setBit(operandNum, block.loopIndex());
-                        }
-                    }
-
-                    if (GraalOptions.DetailedAsserts) {
-                        verifyInput(block, liveKill, operand);
-                    }
-                }
-
-                // Add uses of live locals from interpreter's point of view for proper debug information generation
-                LIRDebugInfo info = op.info;
-                if (info != null) {
-                    info.forEachState(new ValueProcedure() {
-                        @Override
-                        public CiValue doValue(CiValue operand) {
-                            int operandNum = operandNumber(operand);
-                            if (!liveKill.get(operandNum)) {
-                                liveGen.set(operandNum);
-                                if (GraalOptions.TraceLinearScanLevel >= 4) {
-                                    TTY.println("  Setting liveGen for LIR opId %d, operand %d because of state for %s", op.id(), operandNum, op);
-                                }
-                            }
-                            return operand;
-                        }
-                    });
-                }
-
-                // iterate temp operands of instruction
-                n = op.operandCount(LIRInstruction.OperandMode.Temp);
-                for (int k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, k);
 
-                    if (isVariable(operand)) {
-                        int varNum = operandNumber(operand);
-                        liveKill.set(varNum);
-                        if (block.loopIndex() >= 0) {
-                            localIntervalInLoop.setBit(varNum, block.loopIndex());
+                        if (GraalOptions.DetailedAsserts) {
+                            // 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 (GraalOptions.DetailedAsserts) {
-                        verifyTemp(liveKill, operand);
-                    }
-                }
+                };
 
-                // iterate output operands of instruction
-                n = op.operandCount(LIRInstruction.OperandMode.Output);
-                for (int k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, k);
-
-                    if (isVariable(operand)) {
-                        int varNum = operandNumber(operand);
-                        liveKill.set(varNum);
-                        if (block.loopIndex() >= 0) {
-                            localIntervalInLoop.setBit(varNum, block.loopIndex());
-                        }
-                    }
-
-                    if (GraalOptions.DetailedAsserts) {
-                        // 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);
-                    }
-                }
+                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
 
             block.liveGen = liveGen;
@@ -742,8 +701,6 @@
                 TTY.println("liveKill B%d %s", block.blockID(), block.liveKill);
             }
         } // end of block iteration
-
-        intervalInLoop = localIntervalInLoop;
     }
 
     private void verifyTemp(BitMap liveKill, CiValue operand) {
@@ -877,6 +834,7 @@
                             LIRDebugInfo info = ins.info;
                             if (info != null) {
                                 info.forEachState(new ValueProcedure() {
+                                    @Override
                                     public CiValue doValue(CiValue liveStateOperand) {
                                         TTY.println("   operand=" + liveStateOperand);
                                         return liveStateOperand;
@@ -944,6 +902,9 @@
         if (!isProcessed(operand)) {
             return;
         }
+        if (GraalOptions.TraceLinearScanLevel >= 2) {
+            TTY.println(" temp %s tempPos %d (%s)", operand, tempPos, RegisterPriority.MustHaveRegister.name());
+        }
         Interval interval = intervalFor(operand);
         if (interval == null) {
             interval = createInterval(operand);
@@ -1019,8 +980,9 @@
      * Determines the register priority for an instruction's output/result operand.
      */
     static RegisterPriority registerPriorityOfOutputOperand(LIRInstruction op) {
-        if (op.code == StandardOpcode.MOVE) {
-            if (isStackSlot(op.input(0)) && op.input(0).kind != CiKind.Object) {
+        if (op instanceof MoveInstruction) {
+            MoveInstruction move = (MoveInstruction) op;
+            if (isStackSlot(move.getSource()) && move.getSource().kind != CiKind.Object) {
                 // method argument (condition must be equal to handleMethodArguments)
                 return RegisterPriority.None;
             }
@@ -1033,16 +995,8 @@
     /**
      * Determines the priority which with an instruction's input operand will be allocated a register.
      */
-    static RegisterPriority registerPriorityOfInputOperand(LIRInstruction op, int operandIndex) {
-        if (op.code == StandardOpcode.MOVE) {
-            if (isVariableOrRegister(op.input(0)) && isVariableOrRegister(op.output(0))) {
-                // The input operand is not forced to a register (moves from stack to register are allowed),
-                // but it is faster if the input operand is in a register
-                return RegisterPriority.ShouldHaveRegister;
-            }
-        }
-
-        if (op.inputCanBeMemory(operandIndex)) {
+    static RegisterPriority registerPriorityOfInputOperand(EnumSet<OperandFlag> flags) {
+        if (flags.contains(OperandFlag.Stack)) {
             return RegisterPriority.ShouldHaveRegister;
         }
         // all other operands require a register
@@ -1056,41 +1010,47 @@
      * spill slot.
      */
     void handleMethodArguments(LIRInstruction op) {
-        if (op.code == StandardOpcode.MOVE) {
-            if (isStackSlot(op.input(0)) && op.input(0).kind != CiKind.Object) {
-                CiStackSlot slot = (CiStackSlot) op.input(0);
+        if (op instanceof MoveInstruction) {
+            MoveInstruction move = (MoveInstruction) op;
+            if (isStackSlot(move.getSource()) && move.getSource().kind != CiKind.Object) {
+                CiStackSlot slot = (CiStackSlot) move.getSource();
                 if (GraalOptions.DetailedAsserts) {
-                    assert op.id() > 0 : "invalid id";
-                    assert blockForId(op.id()).numberOfPreds() == 0 : "move from stack must be in first block";
-                    assert isVariable(op.output(0)) : "result of move must be a variable";
+                    assert move.id() > 0 : "invalid id";
+                    assert blockForId(move.id()).numberOfPreds() == 0 : "move from stack must be in first block";
+                    assert isVariable(move.getDest()) : "result of move must be a variable";
 
                     if (GraalOptions.TraceLinearScanLevel >= 4) {
-                        TTY.println("found move from stack slot %s to %s", slot, op.output(0));
+                        TTY.println("found move from stack slot %s to %s", slot, move.getDest());
                     }
                 }
 
-                Interval interval = intervalFor(op.output(0));
+                Interval interval = intervalFor(move.getDest());
                 interval.setSpillSlot(slot);
                 interval.assignLocation(slot);
             }
         }
     }
 
-    void addRegisterHints(LIRInstruction op) {
-        CiValue moveFrom = op.registerHint();
-        if (moveFrom != null) {
-            CiValue moveTo = op.output(0);
+    void addRegisterHint(final LIRInstruction op, final CiValue target, OperandMode mode, EnumSet<OperandFlag> flags) {
+        if (flags.contains(OperandFlag.RegisterHint) && isVariableOrRegister(target)) {
 
-            if (isVariableOrRegister(moveTo) && isVariableOrRegister(moveFrom)) {
-                Interval from = intervalFor(moveFrom);
-                Interval to = intervalFor(moveTo);
-                if (from != null && to != null) {
-                    to.setLocationHint(from);
-                    if (GraalOptions.TraceLinearScanLevel >= 4) {
-                        TTY.println("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
+            op.forEachRegisterHint(target, mode, new ValueProcedure() {
+                @Override
+                protected CiValue doValue(CiValue registerHint) {
+                    if (isVariableOrRegister(registerHint)) {
+                        Interval from = intervalFor(registerHint);
+                        Interval to = intervalFor(target);
+                        if (from != null && to != null) {
+                            to.setLocationHint(from);
+                            if (GraalOptions.TraceLinearScanLevel >= 4) {
+                                TTY.println("operation at opId %d: added hint from interval %d to %d", op.id(), from.operandNumber, to.operandNumber);
+                            }
+                            return registerHint;
+                        }
                     }
+                    return null;
                 }
-            }
+            });
         }
     }
 
@@ -1137,7 +1097,7 @@
             // definitions of intervals are processed before uses
             assert !instructions.get(0).hasOperands() : "first operation must always be a label";
             for (int j = instructions.size() - 1; j >= 1; j--) {
-                LIRInstruction op = instructions.get(j);
+                final LIRInstruction op = instructions.get(j);
                 final int opId = op.id();
 
                 // add a temp range for each register if operation destroys caller-save registers
@@ -1152,63 +1112,63 @@
                     }
                 }
 
-                // visit definitions (output and temp operands)
-                int k;
-                int n;
-                n = op.operandCount(LIRInstruction.OperandMode.Output);
-                for (k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, k);
-                    if (isVariableOrRegister(operand)) {
-                        addDef(operand, opId, registerPriorityOfOutputOperand(op), operand.kind.stackKind());
+                op.forEachOutput(new ValueProcedure() {
+                    @Override
+                    public CiValue doValue(CiValue operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        if (isVariableOrRegister(operand)) {
+                            addDef(operand, opId, registerPriorityOfOutputOperand(op), operand.kind.stackKind());
+                            addRegisterHint(op, operand, mode, flags);
+                        }
+                        return operand;
                     }
-                }
-
-                n = op.operandCount(LIRInstruction.OperandMode.Temp);
-                for (k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, k);
-                    if (isVariableOrRegister(operand)) {
-                        if (GraalOptions.TraceLinearScanLevel >= 2) {
-                            TTY.println(" temp %s tempPos %d (%s)", operand, opId, RegisterPriority.MustHaveRegister.name());
+                });
+                op.forEachTemp(new ValueProcedure() {
+                    @Override
+                    public CiValue doValue(CiValue operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        if (isVariableOrRegister(operand)) {
+                            addTemp(operand, opId, RegisterPriority.MustHaveRegister, operand.kind.stackKind());
+                            addRegisterHint(op, operand, mode, flags);
                         }
-                        addTemp(operand, opId, RegisterPriority.MustHaveRegister, operand.kind.stackKind());
+                        return operand;
                     }
-                }
-
-                n = op.operandCount(LIRInstruction.OperandMode.Alive);
-                for (k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Alive, k);
-                    if (isVariableOrRegister(operand)) {
-                        addUse(operand, blockFrom, opId + 1, RegisterPriority.MustHaveRegister, operand.kind.stackKind());
+                });
+                op.forEachAlive(new ValueProcedure() {
+                    @Override
+                    public CiValue doValue(CiValue operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        if (isVariableOrRegister(operand)) {
+                            RegisterPriority p = registerPriorityOfInputOperand(flags);
+                            addUse(operand, blockFrom, opId + 1, p, operand.kind.stackKind());
+                            addRegisterHint(op, operand, mode, flags);
+                        }
+                        return operand;
                     }
-                }
-
-                // visit uses (input operands)
-                n = op.operandCount(LIRInstruction.OperandMode.Input);
-                for (k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, k);
-                    if (isVariableOrRegister(operand)) {
-                        RegisterPriority p = registerPriorityOfInputOperand(op, k);
-                        addUse(operand, blockFrom, opId, p, operand.kind.stackKind());
+                });
+                op.forEachInput(new ValueProcedure() {
+                    @Override
+                    public CiValue doValue(CiValue operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        if (isVariableOrRegister(operand)) {
+                            RegisterPriority p = registerPriorityOfInputOperand(flags);
+                            addUse(operand, blockFrom, opId, p, operand.kind.stackKind());
+                            addRegisterHint(op, operand, mode, flags);
+                        }
+                        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)
-                LIRDebugInfo info = op.info;
-                if (info != null) {
-                    info.forEachState(new ValueProcedure() {
-                        public CiValue doValue(CiValue operand) {
-                            addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, operand.kind.stackKind());
-                            return operand;
-                        }
-                    });
-                }
+                op.forEachState(new ValueProcedure() {
+                    @Override
+                    public CiValue doValue(CiValue operand) {
+                        addUse(operand, blockFrom, opId + 1, RegisterPriority.None, operand.kind.stackKind());
+                        return operand;
+                    }
+                });
 
                 // special steps for some instructions (especially moves)
                 handleMethodArguments(op);
-                addRegisterHints(op);
 
             } // end of instruction iteration
         } // end of block iteration
@@ -1760,22 +1720,26 @@
         boolean hasDead = false;
 
         for (int j = 0; j < numInst; j++) {
-            LIRInstruction op = instructions.get(j);
+            final LIRInstruction op = instructions.get(j);
             if (op == null) { // this can happen when spill-moves are removed in eliminateSpillMoves
                 hasDead = true;
                 continue;
             }
 
-            // iterate all modes of the visitor and process all virtual operands
-            for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) {
-                int n = op.operandCount(mode);
-                for (int k = 0; k < n; k++) {
-                    CiValue operand = op.operandAt(mode, k);
+            ValueProcedure assignProc = new ValueProcedure() {
+                @Override
+                public CiValue doValue(CiValue operand, OperandMode mode, EnumSet<OperandFlag> flags) {
                     if (isVariable(operand)) {
-                        op.setOperandAt(mode, k, colorLirOperand((Variable) operand, op.id(), mode));
+                        return colorLirOperand((Variable) operand, op.id(), mode);
                     }
+                    return operand;
                 }
-            }
+            };
+
+            op.forEachInput(assignProc);
+            op.forEachAlive(assignProc);
+            op.forEachTemp(assignProc);
+            op.forEachOutput(assignProc);
 
             if (op.info != null) {
                 // compute reference map and debug information
@@ -1783,11 +1747,9 @@
             }
 
             // remove useless moves
-            if (op.code == StandardOpcode.MOVE) {
-                CiValue src = op.input(0);
-                CiValue dst = op.output(0);
-                if (dst == src || src.equals(dst)) {
-                    // TODO: what about o.f = o.f and exceptions?
+            if (op instanceof MoveInstruction) {
+                MoveInstruction move = (MoveInstruction) op;
+                if (move.getSource() == move.getDest()) {
                     instructions.set(j, null);
                     hasDead = true;
                 }
@@ -2035,7 +1997,24 @@
         }
     }
 
+    class CheckProcedure extends ValueProcedure {
+        boolean ok;
+        Interval curInterval;
+
+        @Override
+        protected CiValue doValue(CiValue operand) {
+            if (isRegister(operand)) {
+                if (intervalFor(operand) == curInterval) {
+                    ok = true;
+                }
+            }
+            return operand;
+        }
+    }
+
     void verifyNoOopsInFixedIntervals() {
+        CheckProcedure checkProc = new CheckProcedure();
+
         Interval fixedIntervals;
         Interval otherIntervals;
         fixedIntervals = createUnhandledLists(IS_PRECOLORED_INTERVAL, null).first;
@@ -2065,20 +2044,15 @@
                                 // This interval is live out of this op so make sure
                                 // that this interval represents some value that's
                                 // referenced by this op either as an input or output.
-                                boolean ok = false;
-                                for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) {
-                                    int n = op.operandCount(mode);
-                                    for (int k = 0; k < n; k++) {
-                                        CiValue operand = op.operandAt(mode, k);
-                                        if (isRegister(operand)) {
-                                            if (intervalFor(operand) == interval) {
-                                                ok = true;
-                                                break;
-                                            }
-                                        }
-                                    }
-                                }
-                                assert ok : "fixed intervals should never be live across an oopmap point";
+                                checkProc.curInterval = interval;
+                                checkProc.ok = false;
+
+                                op.forEachInput(checkProc);
+                                op.forEachAlive(checkProc);
+                                op.forEachTemp(checkProc);
+                                op.forEachOutput(checkProc);
+
+                                assert checkProc.ok : "fixed intervals should never be live across an oopmap point";
                             }
                         }
                     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java	Sat Jan 07 16:04:22 2012 -0800
@@ -820,13 +820,11 @@
     }
 
     static boolean isMove(LIRInstruction op, Interval from, Interval to) {
-        if (op.code != StandardOpcode.MOVE) {
-            return false;
+        if (op instanceof MoveInstruction) {
+            MoveInstruction move = (MoveInstruction) op;
+            return isVariable(move.getSource()) && isVariable(move.getDest()) && move.getSource() == from.operand && move.getDest() == to.operand;
         }
-
-        CiValue input = op.input(0);
-        CiValue result = op.output(0);
-        return isVariable(input) && isVariable(result) && input == from.operand && result == to.operand;
+        return false;
     }
 
     // optimization (especially for phi functions of nested loops):
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/MoveResolver.java	Sat Jan 07 16:04:22 2012 -0800
@@ -199,7 +199,7 @@
         CiValue fromOpr = fromInterval.operand;
         CiValue toOpr = toInterval.operand;
 
-        insertionBuffer.append(insertIdx, StandardOpcode.MOVE.create(toOpr, fromOpr));
+        insertionBuffer.append(insertIdx, StandardOpcode.SPILL_MOVE.create(toOpr, fromOpr));
 
         if (GraalOptions.TraceLinearScanLevel >= 4) {
             TTY.println("MoveResolver: inserted move from %d (%s) to %d (%s)", fromInterval.operandNumber, fromInterval.location(), toInterval.operandNumber, toInterval.location());
@@ -211,7 +211,7 @@
         assert insertIdx != -1 : "must setup insert position first";
 
         CiValue toOpr = toInterval.operand;
-        insertionBuffer.append(insertIdx, StandardOpcode.MOVE.create(toOpr, fromOpr));
+        insertionBuffer.append(insertIdx, StandardOpcode.SPILL_MOVE.create(toOpr, fromOpr));
 
         if (GraalOptions.TraceLinearScanLevel >= 4) {
             TTY.print("MoveResolver: inserted move from constant %s to %d (%s)", fromOpr, toInterval.operandNumber, toInterval.location());
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java	Sat Jan 07 16:04:22 2012 -0800
@@ -30,6 +30,7 @@
 import com.oracle.max.criutils.*;
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.lir.*;
+import com.oracle.max.graal.compiler.lir.LIRInstruction.*;
 import com.oracle.max.graal.compiler.util.*;
 
 /**
@@ -205,76 +206,58 @@
         return true;
     }
 
-    void processOperations(List<LIRInstruction> ops, Interval[] inputState) {
+    void processOperations(List<LIRInstruction> ops, final Interval[] inputState) {
         // visit all instructions of the block
         for (int i = 0; i < ops.size(); i++) {
-            LIRInstruction op = ops.get(i);
+            final LIRInstruction op = ops.get(i);
 
             if (GraalOptions.TraceLinearScanLevel >= 4) {
                 TTY.println(op.toStringWithIdPrefix());
             }
 
-            // check if input operands are correct
-            int n = op.operandCount(LIRInstruction.OperandMode.Input);
-            for (int j = 0; j < n; j++) {
-                CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, j);
-                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                    Interval interval = intervalAt(operand);
-                    if (op.id() != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Input, allocator);
+            ValueProcedure useProc = new ValueProcedure() {
+                @Override
+                public CiValue doValue(CiValue operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                        Interval interval = intervalAt(operand);
+                        if (op.id() != -1) {
+                            interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                        }
+
+                        assert checkState(inputState, interval.location(), interval.splitParent());
                     }
-
-                    assert checkState(inputState, interval.location(), interval.splitParent());
+                    return operand;
                 }
-            }
-            n = op.operandCount(LIRInstruction.OperandMode.Alive);
-            for (int j = 0; j < n; j++) {
-                CiValue operand = op.operandAt(LIRInstruction.OperandMode.Alive, j);
-                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                    Interval interval = intervalAt(operand);
-                    if (op.id() != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Input, allocator);
+            };
+
+            ValueProcedure defProc = new ValueProcedure() {
+                @Override
+                public CiValue doValue(CiValue operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
+                        Interval interval = intervalAt(operand);
+                        if (op.id() != -1) {
+                            interval = interval.getSplitChildAtOpId(op.id(), mode, allocator);
+                        }
+
+                        statePut(inputState, interval.location(), interval.splitParent());
                     }
-
-                    assert checkState(inputState, interval.location(), interval.splitParent());
+                    return operand;
                 }
-            }
+            };
 
+            // check if input operands are correct
+            op.forEachInput(useProc);
             // invalidate all caller save registers at calls
             if (op.hasCall()) {
                 for (CiRegister r : allocator.compilation.registerConfig.getCallerSaveRegisters()) {
                     statePut(inputState, r.asValue(), null);
                 }
             }
-
+            op.forEachAlive(useProc);
             // set temp operands (some operations use temp operands also as output operands, so can't set them null)
-            n = op.operandCount(LIRInstruction.OperandMode.Temp);
-            for (int j = 0; j < n; j++) {
-                CiValue operand = op.operandAt(LIRInstruction.OperandMode.Temp, j);
-                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                    Interval interval = intervalAt(operand);
-                    assert interval != null : "Could not find interval for operand " + operand;
-                    if (op.id() != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Temp, allocator);
-                    }
-
-                    statePut(inputState, interval.location(), interval.splitParent());
-                }
-            }
-
+            op.forEachTemp(defProc);
             // set output operands
-            n = op.operandCount(LIRInstruction.OperandMode.Output);
-            for (int j = 0; j < n; j++) {
-                CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, j);
-                if (LinearScan.isVariableOrRegister(operand) && allocator.isProcessed(operand)) {
-                    Interval interval = intervalAt(operand);
-                    if (op.id() != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Output, allocator);
-                    }
-
-                    statePut(inputState, interval.location(), interval.splitParent());
-                }
-            }
+            op.forEachOutput(defProc);
         }
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Sat Jan 07 16:04:22 2012 -0800
@@ -44,6 +44,7 @@
 import com.oracle.max.cri.xir.CiXirAssembler.XirTemp;
 import com.oracle.max.cri.xir.*;
 import com.oracle.max.criutils.*;
+import com.oracle.max.graal.alloc.util.*;
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.lir.*;
 import com.oracle.max.graal.compiler.schedule.*;
@@ -258,6 +259,7 @@
 
 
     public void append(LIRInstruction op) {
+        assert LIRVerifier.verify(op);
         if (GraalOptions.PrintIRWithLIR && !TTY.isSuppressed()) {
             if (currentInstruction != null && lastInstructionPrinted != currentInstruction) {
                 lastInstructionPrinted = currentInstruction;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRCall.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRCall.java	Sat Jan 07 16:04:22 2012 -0800
@@ -30,6 +30,7 @@
 import com.oracle.max.cri.ci.CiTargetMethod.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.cri.xir.CiXirAssembler.*;
+import com.oracle.max.graal.compiler.util.*;
 
 /**
  * This class represents a call instruction; either to a {@linkplain CiRuntimeCall runtime method},
@@ -91,4 +92,14 @@
         }
         return null;
     }
+
+    @Override
+    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+        if (mode == OperandMode.Input) {
+            return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
+        } else if (mode == OperandMode.Output) {
+            return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
+        }
+        throw Util.shouldNotReachHere();
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRDebugInfo.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRDebugInfo.java	Sat Jan 07 16:04:22 2012 -0800
@@ -22,6 +22,7 @@
  */
 package com.oracle.max.graal.compiler.lir;
 
+import static com.oracle.max.graal.compiler.lir.LIRInstruction.*;
 import static com.oracle.max.graal.alloc.util.ValueUtil.*;
 
 import java.util.*;
@@ -71,17 +72,22 @@
         }
     }
 
+    /**
+     * We filter out constant and illegal values ourself before calling the procedure, so {@link OperandFlag#Constant} and {@link OperandFlag#Illegal} need not be set.
+     */
+    private static final EnumSet<OperandFlag> STATE_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
+
     private void processValues(CiValue[] values, ValueProcedure proc) {
         for (int i = 0; i < values.length; i++) {
             CiValue value = values[i];
             if (value instanceof CiMonitorValue) {
                 CiMonitorValue monitor = (CiMonitorValue) value;
                 if (processed(monitor.owner)) {
-                    monitor.owner = proc.doValue(monitor.owner);
+                    monitor.owner = proc.doValue(monitor.owner, OperandMode.Alive, STATE_FLAGS);
                 }
 
             } else if (processed(value)) {
-                values[i] = proc.doValue(value);
+                values[i] = proc.doValue(value, OperandMode.Alive, STATE_FLAGS);
             }
         }
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java	Sat Jan 07 16:04:22 2012 -0800
@@ -22,6 +22,8 @@
  */
 package com.oracle.max.graal.compiler.lir;
 
+import java.util.*;
+
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
 import com.oracle.max.graal.compiler.util.*;
@@ -33,19 +35,34 @@
 
     public static final CiValue[] NO_OPERANDS = {};
 
-    public static final OperandMode[] OPERAND_MODES = OperandMode.values();
-
     /**
-     * Iterator interface for iterating over a list of values.
+     * Iterator for iterating over a list of values. Subclasses must overwrite one of the doValue methods.
+     * Clients of the class must only call the doValue method that takes additional parameters.
      */
-    public interface ValueProcedure {
+    public abstract static class ValueProcedure {
         /**
-         * The iterator method.
+         * Iterator method to be overwritten. This version of the iterator does not take additional parameters
+         * to keep the signature short.
          *
          * @param value The value that is iterated.
          * @return The new value to replace the value that was passed in.
          */
-        CiValue doValue(CiValue value);
+        protected CiValue doValue(CiValue value) {
+            throw Util.shouldNotReachHere("One of the doValue() methods must be overwritten");
+        }
+
+        /**
+         * Iterator method to be overwritten. This version of the iterator gets additional parameters about the
+         * processed value.
+         *
+         * @param value The value that is iterated.
+         * @param mode The operand mode for the value.
+         * @param flags A set of flags for the value.
+         * @return The new value to replace the value that was passed in.
+         */
+        public CiValue doValue(CiValue value, OperandMode mode, EnumSet<OperandFlag> flags) {
+            return doValue(value);
+        }
     }
 
 
@@ -82,6 +99,37 @@
     }
 
     /**
+     * Flags for an operand.
+     */
+    public enum OperandFlag {
+        /**
+         * The value can be a {@link CiRegisterValue}.
+         */
+        Register,
+
+        /**
+         * The value can be a {@link CiStackSlot}.
+         */
+        Stack,
+
+        /**
+         * The value can be a {@link CiConstant}.
+         */
+        Constant,
+
+        /**
+         * The value can be {@link CiValue#IllegalValue}.
+         */
+        Illegal,
+
+        /**
+         * The register allocator should try to assign a certain register to improve code quality.
+         * Use {@link LIRInstruction#forEachRegisterHint} to access the register hints.
+         */
+        RegisterHint,
+    }
+
+    /**
      * The opcode of this instruction.
      */
     public final LIROpcode code;
@@ -152,7 +200,7 @@
      * @param index the index of the operand requested.
      * @return the {@code index}'th input operand.
      */
-    public final CiValue input(int index) {
+    protected final CiValue input(int index) {
         return inputs[index];
     }
 
@@ -162,7 +210,7 @@
      * @param index the index of the operand requested.
      * @return the {@code index}'th alive operand.
      */
-    public final CiValue alive(int index) {
+    protected final CiValue alive(int index) {
         return alives[index];
     }
 
@@ -172,7 +220,7 @@
      * @param index the index of the operand requested.
      * @return the {@code index}'th temp operand.
      */
-    public final CiValue temp(int index) {
+    protected final CiValue temp(int index) {
         return temps[index];
     }
 
@@ -181,7 +229,7 @@
      *
      * @return return the result operand
      */
-    public final CiValue output(int index) {
+    protected final CiValue output(int index) {
         return outputs[index];
     }
 
@@ -196,62 +244,26 @@
         return inputs.length > 0 || alives.length > 0 || temps.length > 0 || outputs.length > 0 || info != null || hasCall();
     }
 
-    public final int operandCount(OperandMode mode) {
-        switch (mode) {
-            case Output: return outputs.length;
-            case Input:  return inputs.length;
-            case Alive:  return alives.length;
-            case Temp:   return temps.length;
-            default:     throw Util.shouldNotReachHere();
-        }
-    }
-
-    public final CiValue operandAt(OperandMode mode, int index) {
-        assert index < operandCount(mode);
-        switch (mode) {
-            case Output: return outputs[index];
-            case Input:  return inputs[index];
-            case Alive:  return alives[index];
-            case Temp:   return temps[index];
-            default:     throw Util.shouldNotReachHere();
-        }
-    }
-
-    public final void setOperandAt(OperandMode mode, int index, CiValue location) {
-        assert index < operandCount(mode);
-        assert location.kind != CiKind.Illegal;
-        assert operandAt(mode, index).kind == location.kind;
-        switch (mode) {
-            case Output: outputs[index] = location; break;
-            case Input:  inputs[index] = location; break;
-            case Alive:  alives[index] = location; break;
-            case Temp:   temps[index] = location; break;
-            default:     throw Util.shouldNotReachHere();
+    private void forEach(CiValue[] values, OperandMode mode, ValueProcedure proc) {
+        for (int i = 0; i < values.length; i++) {
+            values[i] = proc.doValue(values[i], mode, flagsFor(mode, i));
         }
     }
 
     public final void forEachInput(ValueProcedure proc) {
-        for (int i = 0; i < inputs.length; i++) {
-            inputs[i] = proc.doValue(inputs[i]);
-        }
+        forEach(inputs, OperandMode.Input, proc);
     }
 
     public final void forEachAlive(ValueProcedure proc) {
-        for (int i = 0; i < alives.length; i++) {
-            alives[i] = proc.doValue(alives[i]);
-        }
+        forEach(alives, OperandMode.Alive, proc);
     }
 
     public final void forEachTemp(ValueProcedure proc) {
-        for (int i = 0; i < temps.length; i++) {
-            temps[i] = proc.doValue(temps[i]);
-        }
+        forEach(temps, OperandMode.Temp, proc);
     }
 
     public final void forEachOutput(ValueProcedure proc) {
-        for (int i = 0; i < outputs.length; i++) {
-            outputs[i] = proc.doValue(outputs[i]);
-        }
+        forEach(outputs, OperandMode.Output, proc);
     }
 
     public final void forEachState(ValueProcedure proc) {
@@ -275,22 +287,46 @@
     }
 
     /**
-     * Used by the register allocator.  The result operand of this instruction should get
-     * the same register assigned as the returned operand.
-     * @return The register hint for the output operand, or null if no register hint should be defined.
+     * Iterates all register hints for the specified value, i.e., all preferred candidates for the register to be
+     * assigned to the value.
+     * <br>
+     * Subclasses can override this method. The default implementation processes all Input operands as the hints for
+     * an Output operand, and all Output operands as the hints for an Input operand.
+     *
+     * @param value The value the hints are needed for.
+     * @param mode The operand mode of the value.
+     * @param proc The procedure invoked for all the hints. If the procedure returns a non-null value, the iteration is stopped
+     *             and the value is returned by this method, i.e., clients can stop the iteration once a suitable hint has been found.
+     * @return The non-null value returned by the procedure, or null.
      */
-    public CiValue registerHint() {
+    public CiValue forEachRegisterHint(CiValue value, OperandMode mode, ValueProcedure proc) {
+        CiValue[] hints;
+        if (mode == OperandMode.Input) {
+            hints = outputs;
+        } else if (mode == OperandMode.Output) {
+            hints = inputs;
+        } else {
+            return null;
+        }
+
+        for (int i = 0; i < hints.length; i++) {
+            CiValue result = proc.doValue(hints[i], null, null);
+            if (result != null) {
+                return result;
+            }
+        }
         return null;
     }
 
     /**
-     * Used by the register allocator to decide whether an input operand can be assigned a stack slot.
-     * Subclasses should override this method when an input can be memory.
-     * @param index The index of the operand in {@link #inputs}.
-     * @return true if the input operand with the given index can be assigned a stack slot.
+     * Used by the register allocator to decide which kind of location can be assigned to the operand.
+     * @param mode The kind of operand.
+     * @param index The index of the operand.
+     * @return The flags for the operand.
      */
-    public boolean inputCanBeMemory(int index) {
-        return false;
+    // TODO this method will go away when we have named operands, the flags will be specified as annotations instead.
+    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+        return EnumSet.of(OperandFlag.Register);
     }
 
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRPhiMapping.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRPhiMapping.java	Sat Jan 07 16:04:22 2012 -0800
@@ -26,6 +26,8 @@
 
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.gen.*;
+import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandFlag;
+import com.oracle.max.graal.compiler.lir.LIRInstruction.OperandMode;
 import com.oracle.max.graal.compiler.lir.LIRInstruction.ValueProcedure;
 import com.oracle.max.graal.nodes.*;
 import com.oracle.max.graal.nodes.PhiNode.*;
@@ -91,30 +93,36 @@
         return inputs[block.getPredecessors().indexOf(pred)];
     }
 
-    public void forEachInput(LIRBlock pred, ValueProcedure proc) {
+    private static final EnumSet<OperandFlag> INPUT_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+    private static final EnumSet<OperandFlag> OUTPUT_FLAGS = EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
+
+    public void forEachInput(LIRBlock pred, PhiValueProcedure proc) {
         CiValue[] predInputs = inputs(pred);
         for (int i = 0; i < predInputs.length; i++) {
-            predInputs[i] = proc.doValue(predInputs[i]);
+            predInputs[i] = proc.doValue(predInputs[i], results[i]);
         }
     }
 
     public void forEachOutput(ValueProcedure proc) {
         for (int i = 0; i < results.length; i++) {
-            results[i] = proc.doValue(results[i]);
+            results[i] = proc.doValue(results[i], OperandMode.Output, OUTPUT_FLAGS);
         }
     }
 
-    public void forEachInput(LIRBlock pred, PhiValueProcedure proc) {
-        CiValue[] predInputs = inputs(pred);
-        for (int i = 0; i < predInputs.length; i++) {
-            proc.doValue(predInputs[i], results[i]);
+    public abstract static class PhiValueProcedure extends ValueProcedure {
+        /**
+         * Iterator method to be overwritten. This version of the iterator has both the input and output of the phi function as parameters.
+         * to keep the signature short.
+         *
+         * @param input The input value that is iterated.
+         * @param output The output value that is iterated.
+         * @return The new value to replace the input value that was passed in.
+         */
+        protected CiValue doValue(CiValue input, CiValue output) {
+            return doValue(input, OperandMode.Input, INPUT_FLAGS);
         }
     }
 
-    public interface PhiValueProcedure {
-        void doValue(CiValue input, CiValue output);
-    }
-
     @Override
     public String toString() {
         return "PhiMapping for " + block + ": " + Arrays.toString(results);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRXirInstruction.java	Sat Jan 07 16:04:22 2012 -0800
@@ -65,6 +65,13 @@
         assert isLegal(outputOperand) || outputOperandIndex == -1;
     }
 
+    @Override
+    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+        if (mode == OperandMode.Alive || mode == OperandMode.Temp) {
+            return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.Illegal);
+        }
+        return super.flagsFor(mode, index);
+    }
 
     public void setFalseSuccessor(LabelRef falseSuccessor) {
         this.falseSuccessor = falseSuccessor;
@@ -96,69 +103,8 @@
         return originalOperands;
     }
 
-     /**
-     * Prints this instruction.
-     */
     @Override
-    public String operationString() {
-        return toString();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("XIR: ");
-
-        if (operandCount(LIRInstruction.OperandMode.Output) > 0) {
-            sb.append(output(0) + " = ");
-        }
-
-        sb.append(snippet.template);
-        sb.append("(");
-        for (int i = 0; i < snippet.arguments.length; i++) {
-            XirArgument a = snippet.arguments[i];
-            if (i > 0) {
-                sb.append(", ");
-            }
-            if (a.constant != null) {
-                sb.append(a.constant);
-            } else {
-                sb.append(a.object);
-            }
-        }
-        sb.append(')');
-
-        if (method != null) {
-            sb.append(" method=");
-            sb.append(method.toString());
-        }
-
-
-        for (LIRInstruction.OperandMode mode : LIRInstruction.OPERAND_MODES) {
-            int n = operandCount(mode);
-            if (mode == OperandMode.Output && n <= 1) {
-                // Already printed single output (i.e. result())
-                continue;
-            }
-            if (n != 0) {
-                sb.append(' ').append(mode.name().toLowerCase()).append("=(");
-                HashSet<String> operands = new HashSet<>();
-                for (int i = 0; i < n; i++) {
-                    String operand = operandAt(mode, i).toString();
-                    if (!operands.contains(operand)) {
-                        if (!operands.isEmpty()) {
-                            sb.append(", ");
-                        }
-                        operands.add(operand);
-                        sb.append(operand);
-                    }
-                }
-                sb.append(')');
-            }
-        }
-
-        appendDebugInfo(sb);
-
-        return sb.toString();
+    public String name() {
+        return "XIR: " + snippet.template;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/MoveInstruction.java	Sat Jan 07 16:04:22 2012 -0800
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.max.graal.compiler.lir;
+
+import com.oracle.max.cri.ci.*;
+
+public abstract class MoveInstruction extends LIRInstruction {
+    public MoveInstruction(LIROpcode opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) {
+        super(opcode, outputs, info, inputs, alives, temps);
+    }
+
+    public abstract CiValue getSource();
+    public abstract CiValue getDest();
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/StandardOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/StandardOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -30,10 +30,11 @@
 import com.oracle.max.cri.xir.CiXirAssembler.XirMark;
 import com.oracle.max.cri.xir.*;
 import com.oracle.max.graal.compiler.asm.*;
+import com.oracle.max.graal.compiler.util.*;
 
 public class StandardOpcode {
     // Checkstyle: stop
-    public static MoveOpcode MOVE;
+    public static MoveOpcode SPILL_MOVE;
     public static NullCheckOpcode NULL_CHECK;
     public static CallOpcode DIRECT_CALL;
     public static CallOpcode INDIRECT_CALL;
@@ -45,7 +46,7 @@
     // Checkstyle: resume
 
     public interface MoveOpcode extends LIROpcode {
-        LIRInstruction create(CiValue result, CiValue input);
+        MoveInstruction create(CiValue result, CiValue input);
     }
 
     public interface NullCheckOpcode extends LIROpcode {
@@ -76,6 +77,14 @@
                 public void emitCode(TargetMethodAssembler tasm) {
                     // No code to emit. This is not the actual method prologue, but only a meta-instruction that defines the incoming method parameters.
                 }
+
+                @Override
+                protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                    if (mode == OperandMode.Output) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
+                    }
+                    throw Util.shouldNotReachHere();
+                }
             };
         }
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ArithmeticOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ArithmeticOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,6 +24,8 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -55,13 +57,15 @@
             }
 
             @Override
-            public boolean inputCanBeMemory(int index) {
-                return true;
-            }
-
-            @Override
-            public CiValue registerHint() {
-                return input(0);
+            public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                if (mode == OperandMode.Input && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                } else if (mode == OperandMode.Alive && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                } else if (mode == OperandMode.Output && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+                }
+                return super.flagsFor(mode, index);
             }
         };
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64CompareOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64CompareOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,6 +24,8 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -49,8 +51,11 @@
             }
 
             @Override
-            public boolean inputCanBeMemory(int index) {
-                return index == 1;
+            public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                if (mode == OperandMode.Input && index == 1) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                }
+                return super.flagsFor(mode, index);
             }
         };
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ControlFlowOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ControlFlowOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,12 +24,14 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.*;
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.asm.target.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ci.CiAddress.*;
-import com.oracle.max.cri.ci.CiTargetMethod.*;
+import com.oracle.max.cri.ci.CiAddress.Scale;
+import com.oracle.max.cri.ci.CiTargetMethod.JumpTable;
 import com.oracle.max.graal.compiler.asm.*;
 import com.oracle.max.graal.compiler.lir.*;
 import com.oracle.max.graal.compiler.util.*;
@@ -70,6 +72,14 @@
                 public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
                     masm.ret(0);
                 }
+
+                @Override
+                protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                    if (mode == OperandMode.Input && index == 0) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
+                    }
+                    throw Util.shouldNotReachHere();
+                }
             };
         }
     }
@@ -178,8 +188,13 @@
                 }
 
                 @Override
-                public CiValue registerHint() {
-                    return input(0);
+                protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                    if (mode == OperandMode.Input && index == 0) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                    } else if (mode == OperandMode.Output && index == 0) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+                    }
+                    return super.flagsFor(mode, index);
                 }
 
                 @Override
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ConvertOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ConvertOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,6 +24,8 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -48,8 +50,11 @@
             }
 
             @Override
-            public CiValue registerHint() {
-                return input(0);
+            protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                if (mode == OperandMode.Output && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+                }
+                return super.flagsFor(mode, index);
             }
         };
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LIRGenerator.java	Sat Jan 07 16:04:22 2012 -0800
@@ -63,7 +63,7 @@
     private static final CiRegisterValue RCX_I = AMD64.rcx.asValue(CiKind.Int);
 
     static {
-        StandardOpcode.MOVE = AMD64StandardOpcode.MOVE;
+        StandardOpcode.SPILL_MOVE = AMD64MoveOpcode.SpillMoveOpcode.SPILL_MOVE;
         StandardOpcode.NULL_CHECK = AMD64StandardOpcode.NULL_CHECK;
         StandardOpcode.DIRECT_CALL = AMD64CallOpcode.DIRECT_CALL;
         StandardOpcode.INDIRECT_CALL = AMD64CallOpcode.INDIRECT_CALL;
@@ -486,20 +486,28 @@
         CiValue expected = loadNonConst(operand(node.expected()));
         Variable newValue = load(operand(node.newValue()));
         Variable addrBase = load(operand(node.object()));
-        CiValue addrIndex = loadNonConst(operand(node.offset()));
+        CiValue addrIndex = operand(node.offset());
+        int addrDisplacement = 0;
+        if (isConstant(addrIndex) && NumUtil.isInt(asConstant(addrIndex).asLong())) {
+            addrDisplacement = (int) asConstant(addrIndex).asLong();
+            addrIndex = CiValue.IllegalValue;
+        } else {
+            addrIndex = load(addrIndex);
+        }
 
         if (kind == CiKind.Object) {
             Variable loadedAddress = newVariable(compilation.compiler.target.wordKind);
-            append(LEA_MEMORY.create(loadedAddress, addrBase, addrIndex, CiAddress.Scale.Times1, 0));
+            append(LEA_MEMORY.create(loadedAddress, addrBase, addrIndex, CiAddress.Scale.Times1, addrDisplacement));
+            preGCWriteBarrier(loadedAddress, false, null);
+
             addrBase = loadedAddress;
             addrIndex = Variable.IllegalValue;
-
-            preGCWriteBarrier(addrBase, false, null);
+            addrDisplacement = 0;
         }
 
         CiRegisterValue rax = AMD64.rax.asValue(kind);
         append(MOVE.create(rax, expected));
-        append(CAS.create(rax, addrBase, addrIndex, CiAddress.Scale.Times1, 0, rax, newValue));
+        append(CAS.create(rax, addrBase, addrIndex, CiAddress.Scale.Times1, addrDisplacement, rax, newValue));
 
         Variable result = newVariable(node.kind());
         if (node.directResult()) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LogicFloatOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64LogicFloatOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,6 +24,8 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -51,13 +53,15 @@
             }
 
             @Override
-            public boolean inputCanBeMemory(int index) {
-                return true;
-            }
-
-            @Override
-            public CiValue registerHint() {
-                return input(0);
+            public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                if (mode == OperandMode.Input && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                } else if (mode == OperandMode.Alive && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
+                } else if (mode == OperandMode.Output && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+                }
+                return super.flagsFor(mode, index);
             }
         };
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MoveOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MoveOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -22,10 +22,12 @@
  */
 package com.oracle.max.graal.compiler.target.amd64;
 
-import static com.oracle.max.cri.ci.CiValueUtil.*;
+import static com.oracle.max.graal.alloc.util.ValueUtil.*;
 import static java.lang.Double.*;
 import static java.lang.Float.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -34,29 +36,126 @@
 
 public class AMD64MoveOpcode {
 
-    public enum MoveOpcode implements StandardOpcode.MoveOpcode {
+    public enum MoveOpcode implements LIROpcode {
         MOVE;
 
-        @Override
         public LIRInstruction create(CiValue result, CiValue input) {
             assert result.kind == result.kind.stackKind() && result.kind != CiKind.Illegal;
             CiValue[] inputs = new CiValue[] {input};
             CiValue[] outputs = new CiValue[] {result};
 
-            return new AMD64LIRInstruction(this, outputs, null, inputs, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS) {
-                @Override
-                public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-                    move(tasm, masm, output(0), input(0));
-                }
+            if (isRegister(input) || isStackSlot(result)) {
+                return new AMD64MoveFromRegInstruction(this, outputs, null, inputs, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            } else {
+                return new AMD64MoveToRegInstruction(this, outputs, null, inputs, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
+            }
+        }
+    }
 
-                @Override
-                public CiValue registerHint() {
-                    return input(0);
-                }
-            };
+    public enum SpillMoveOpcode implements StandardOpcode.MoveOpcode {
+        SPILL_MOVE;
+
+        @Override
+        public MoveInstruction create(CiValue result, CiValue input) {
+            assert result.kind == result.kind.stackKind() && result.kind != CiKind.Illegal;
+            CiValue[] inputs = new CiValue[] {input};
+            CiValue[] outputs = new CiValue[] {result};
+
+            return new AMD64SpillMoveInstruction(this, outputs, null, inputs, LIRInstruction.NO_OPERANDS, LIRInstruction.NO_OPERANDS);
         }
     }
 
+    protected static class AMD64SpillMoveInstruction extends MoveInstruction {
+        public AMD64SpillMoveInstruction(LIROpcode opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) {
+            super(opcode, outputs, info, inputs, alives, temps);
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm) {
+            move(tasm, (AMD64MacroAssembler) tasm.asm, getDest(), getSource());
+        }
+
+        @Override
+        public CiValue getSource() {
+            return input(0);
+        }
+        @Override
+        public CiValue getDest() {
+            return output(0);
+        }
+
+        @Override
+        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+            if (mode == OperandMode.Input && index == 0) {
+                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+            } else if (mode == OperandMode.Output && index == 0) {
+                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
+            }
+            throw Util.shouldNotReachHere();
+        }
+
+    }
+
+    protected static class AMD64MoveToRegInstruction extends MoveInstruction {
+        public AMD64MoveToRegInstruction(LIROpcode opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) {
+            super(opcode, outputs, info, inputs, alives, temps);
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm) {
+            move(tasm, (AMD64MacroAssembler) tasm.asm, getDest(), getSource());
+        }
+
+        @Override
+        public CiValue getSource() {
+            return input(0);
+        }
+        @Override
+        public CiValue getDest() {
+            return output(0);
+        }
+
+        @Override
+        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+            if (mode == OperandMode.Input && index == 0) {
+                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+            } else if (mode == OperandMode.Output && index == 0) {
+                return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+            }
+            throw Util.shouldNotReachHere();
+        }
+    }
+
+    protected static class AMD64MoveFromRegInstruction extends MoveInstruction {
+        public AMD64MoveFromRegInstruction(LIROpcode opcode, CiValue[] outputs, LIRDebugInfo info, CiValue[] inputs, CiValue[] alives, CiValue[] temps) {
+            super(opcode, outputs, info, inputs, alives, temps);
+        }
+
+        @Override
+        public void emitCode(TargetMethodAssembler tasm) {
+            move(tasm, (AMD64MacroAssembler) tasm.asm, getDest(), getSource());
+        }
+
+        @Override
+        public CiValue getSource() {
+            return input(0);
+        }
+        @Override
+        public CiValue getDest() {
+            return output(0);
+        }
+
+
+        @Override
+        protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+            if (mode == OperandMode.Input && index == 0) {
+                return EnumSet.of(OperandFlag.Register, OperandFlag.Constant, OperandFlag.RegisterHint);
+            } else if (mode == OperandMode.Output && index == 0) {
+                return EnumSet.of(OperandFlag.Register, OperandFlag.Stack);
+            }
+            throw Util.shouldNotReachHere();
+        }
+    }
 
     public enum LoadOpcode implements LIROpcode {
         LOAD;
@@ -70,6 +169,14 @@
                 public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
                     load(tasm, masm, output(0), new CiAddress(CiKind.Illegal, input(0), input(1), addrScale, addrDisplacement), kind, info);
                 }
+
+                @Override
+                protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                    if (mode == OperandMode.Input && (index == 0 || index == 1)) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
+                    }
+                    return super.flagsFor(mode, index);
+                }
             };
         }
     }
@@ -86,6 +193,16 @@
                 public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
                     store(tasm, masm, new CiAddress(CiKind.Illegal, input(0), input(1), addrScale, addrDisplacement), input(2), kind, info);
                 }
+
+                @Override
+                protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                    if (mode == OperandMode.Input && (index == 0 || index == 1)) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
+                    } else if (mode == OperandMode.Input && index == 2) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
+                    }
+                    return super.flagsFor(mode, index);
+                }
             };
         }
     }
@@ -103,6 +220,14 @@
                 public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
                     masm.leaq(asLongReg(output(0)), new CiAddress(CiKind.Illegal, input(0), input(1), addrScale, addrDisplacement));
                 }
+
+                @Override
+                protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                    if (mode == OperandMode.Input && (index == 0 || index == 1)) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
+                    }
+                    return super.flagsFor(mode, index);
+                }
             };
         }
     }
@@ -172,11 +297,18 @@
                 public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
                     compareAndSwap(tasm, masm, output(0), new CiAddress(CiKind.Illegal, input(0), input(1), addrScale, addrDisplacement), input(2), input(3));
                 }
+
+                @Override
+                protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                    if (mode == OperandMode.Input && (index == 0 || index == 1)) {
+                        return EnumSet.of(OperandFlag.Register, OperandFlag.Illegal);
+                    }
+                    return super.flagsFor(mode, index);
+                }
             };
         }
     }
 
-
     protected static void move(TargetMethodAssembler tasm, AMD64MacroAssembler masm, CiValue result, CiValue input) {
         if (isRegister(input)) {
             if (isRegister(result)) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MulOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64MulOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,6 +24,8 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -47,13 +49,15 @@
             }
 
             @Override
-            public boolean inputCanBeMemory(int index) {
-                return index == 0;
-            }
-
-            @Override
-            public CiValue registerHint() {
-                return input(0);
+            public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                if (mode == OperandMode.Input && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                } else if (mode == OperandMode.Alive && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
+                } else if (mode == OperandMode.Output && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+                }
+                return super.flagsFor(mode, index);
             }
         };
     }
@@ -66,12 +70,14 @@
                 case LMUL: masm.imulq(dst, asRegister(right)); break;
                 default:   throw Util.shouldNotReachHere();
             }
-        } else {
+        } else if (isConstant(right)) {
             switch (this) {
                 case IMUL: masm.imull(dst, dst, tasm.asIntConst(right)); break;
                 case LMUL: masm.imulq(dst, dst, tasm.asIntConst(right)); break;
                 default:   throw Util.shouldNotReachHere();
             }
+        } else {
+            throw Util.shouldNotReachHere();
         }
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Op1Opcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64Op1Opcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,6 +24,8 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -45,13 +47,13 @@
             }
 
             @Override
-            public boolean inputCanBeMemory(int index) {
-                return true;
-            }
-
-            @Override
-            public CiValue registerHint() {
-                return input(0);
+            public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                if (mode == OperandMode.Input && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                } else if (mode == OperandMode.Output && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+                }
+                return super.flagsFor(mode, index);
             }
         };
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ShiftOpcode.java	Fri Jan 06 15:35:52 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/target/amd64/AMD64ShiftOpcode.java	Sat Jan 07 16:04:22 2012 -0800
@@ -24,6 +24,8 @@
 
 import static com.oracle.max.cri.ci.CiValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.max.asm.target.amd64.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.graal.compiler.asm.*;
@@ -48,13 +50,15 @@
             }
 
             @Override
-            public boolean inputCanBeMemory(int index) {
-                return true;
-            }
-
-            @Override
-            public CiValue registerHint() {
-                return input(0);
+            public EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+                if (mode == OperandMode.Input && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Stack, OperandFlag.Constant);
+                } else if (mode == OperandMode.Alive && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.Constant);
+                } else if (mode == OperandMode.Output && index == 0) {
+                    return EnumSet.of(OperandFlag.Register, OperandFlag.RegisterHint);
+                }
+                return super.flagsFor(mode, index);
             }
         };
     }
@@ -72,7 +76,7 @@
                 case ULSHR: masm.shrq(dst); break;
                 default:    throw Util.shouldNotReachHere();
             }
-        } else {
+        } else if (isConstant(right)) {
             switch (this) {
                 case ISHL:  masm.shll(dst, tasm.asIntConst(right) & 31); break;
                 case ISHR:  masm.sarl(dst, tasm.asIntConst(right) & 31); break;
@@ -82,6 +86,8 @@
                 case ULSHR: masm.shrq(dst, tasm.asIntConst(right) & 63); break;
                 default:   throw Util.shouldNotReachHere();
             }
+        } else {
+            throw Util.shouldNotReachHere();
         }
     }
 }