changeset 8173:6d23f64f2fdb

Merge.
author Roland Schatz <roland.schatz@oracle.com>
date Fri, 08 Mar 2013 13:19:28 +0100
parents 5c9fc4f75b4c (diff) da10229e5a33 (current diff)
children 67d654d9ee9a
files src/share/vm/utilities/machineCodePrinter.cpp src/share/vm/utilities/machineCodePrinter.hpp
diffstat 35 files changed, 1061 insertions(+), 722 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64.java	Fri Mar 08 13:19:28 2013 +0100
@@ -24,12 +24,11 @@
 
 import static com.oracle.graal.api.code.MemoryBarriers.*;
 import static com.oracle.graal.api.code.Register.RegisterFlag.*;
-import static com.oracle.graal.api.meta.Kind.*;
 
 import java.nio.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Register.*;
+import com.oracle.graal.api.code.Register.RegisterFlag;
 
 /**
  * Represents the AMD64 architecture.
@@ -106,8 +105,6 @@
         rip
     };
 
-    public static final RegisterValue RSP = rsp.asValue(Long);
-
     public AMD64() {
         super("AMD64",
               8,
--- a/graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64Address.java	Fri Mar 08 11:23:28 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-
-/**
- * Represents an address in target machine memory, specified via some combination of a base
- * register, an index register, a displacement and a scale. Note that the base and index registers
- * may be a variable that will get a register assigned later by the register allocator.
- */
-public final class AMD64Address extends Address {
-
-    private static final long serialVersionUID = -4101548147426595051L;
-
-    private final Value[] baseIndex;
-    private final Scale scale;
-    private final int displacement;
-
-    /**
-     * Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     */
-    public AMD64Address(Kind kind, Value base) {
-        this(kind, base, ILLEGAL, Scale.Times1, 0);
-    }
-
-    /**
-     * Creates an {@link AMD64Address} with given base register, no scaling and a given
-     * displacement.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     * @param displacement the displacement
-     */
-    public AMD64Address(Kind kind, Value base, int displacement) {
-        this(kind, base, ILLEGAL, Scale.Times1, displacement);
-    }
-
-    /**
-     * Creates an {@link AMD64Address} with given base and index registers, scaling and
-     * displacement. This is the most general constructor.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     * @param index the index register
-     * @param scale the scaling factor
-     * @param displacement the displacement
-     */
-    public AMD64Address(Kind kind, Value base, Value index, Scale scale, int displacement) {
-        super(kind);
-        this.baseIndex = new Value[2];
-        this.setBase(base);
-        this.setIndex(index);
-        this.scale = scale;
-        this.displacement = displacement;
-
-        assert !isConstant(base) && !isStackSlot(base);
-        assert !isConstant(index) && !isStackSlot(index);
-    }
-
-    /**
-     * A scaling factor used in the SIB addressing mode.
-     */
-    public enum Scale {
-        Times1(1, 0), Times2(2, 1), Times4(4, 2), Times8(8, 3);
-
-        private Scale(int value, int log2) {
-            this.value = value;
-            this.log2 = log2;
-        }
-
-        /**
-         * The value (or multiplier) of this scale.
-         */
-        public final int value;
-
-        /**
-         * The {@linkplain #value value} of this scale log 2.
-         */
-        public final int log2;
-
-        public static Scale fromInt(int scale) {
-            switch (scale) {
-                case 1:
-                    return Times1;
-                case 2:
-                    return Times2;
-                case 4:
-                    return Times4;
-                case 8:
-                    return Times8;
-                default:
-                    throw new IllegalArgumentException(String.valueOf(scale));
-            }
-        }
-    }
-
-    @Override
-    public Value[] components() {
-        return baseIndex;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder s = new StringBuilder();
-        s.append(getKind().getJavaName()).append("[");
-        String sep = "";
-        if (isLegal(getBase())) {
-            s.append(getBase());
-            sep = " + ";
-        }
-        if (isLegal(getIndex())) {
-            s.append(sep).append(getIndex()).append(" * ").append(getScale().value);
-            sep = " + ";
-        }
-        if (getDisplacement() < 0) {
-            s.append(" - ").append(-getDisplacement());
-        } else if (getDisplacement() > 0) {
-            s.append(sep).append(getDisplacement());
-        }
-        s.append("]");
-        return s.toString();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof AMD64Address) {
-            AMD64Address addr = (AMD64Address) obj;
-            return getKind() == addr.getKind() && getDisplacement() == addr.getDisplacement() && getBase().equals(addr.getBase()) && getScale() == addr.getScale() &&
-                            getIndex().equals(addr.getIndex());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return getBase().hashCode() ^ getIndex().hashCode() ^ (getDisplacement() << 4) ^ (getScale().value << 8) ^ (getKind().ordinal() << 12);
-    }
-
-    /**
-     * @return Base register that defines the start of the address computation. If not present, is
-     *         denoted by {@link Value#ILLEGAL}.
-     */
-    public Value getBase() {
-        return baseIndex[0];
-    }
-
-    public void setBase(Value base) {
-        this.baseIndex[0] = base;
-    }
-
-    /**
-     * @return Index register, the value of which (possibly scaled by {@link #scale}) is added to
-     *         {@link #getBase}. If not present, is denoted by {@link Value#ILLEGAL}.
-     */
-    public Value getIndex() {
-        return baseIndex[1];
-    }
-
-    public void setIndex(Value index) {
-        this.baseIndex[1] = index;
-    }
-
-    /**
-     * @return Scaling factor for indexing, dependent on target operand size.
-     */
-    public Scale getScale() {
-        return scale;
-    }
-
-    /**
-     * @return Optional additive displacement.
-     */
-    public int getDisplacement() {
-        return displacement;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/AbstractAddress.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.api.code;
+
+/**
+ * Abstract base class that represents a platform specific address.
+ */
+public abstract class AbstractAddress {
+}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java	Fri Mar 08 11:23:28 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.api.code;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * Base class to represent an address in target machine memory. The concrete representation of the
- * address is platform dependent.
- */
-public abstract class Address extends Value {
-
-    private static final long serialVersionUID = -1003772042519945089L;
-
-    public Address(Kind kind) {
-        super(kind);
-    }
-
-    /**
-     * The values that this address is composed of. Used by the register allocator to manipulate
-     * addresses in a platform independent way.
-     */
-    public abstract Value[] components();
-}
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ValueUtil.java	Fri Mar 08 13:19:28 2013 +0100
@@ -78,16 +78,6 @@
         return (StackSlot) value;
     }
 
-    public static boolean isAddress(Value value) {
-        assert value != null;
-        return value instanceof Address;
-    }
-
-    public static Address asAddress(Value value) {
-        assert value != null;
-        return (Address) value;
-    }
-
     public static boolean isRegister(Value value) {
         assert value != null;
         return value instanceof RegisterValue;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.asm.amd64;
+
+import com.oracle.graal.api.code.*;
+
+/**
+ * Represents an address in target machine memory, specified via some combination of a base
+ * register, an index register, a displacement and a scale. Note that the base and index registers
+ * may be a variable that will get a register assigned later by the register allocator.
+ */
+public final class AMD64Address extends AbstractAddress {
+
+    private final Register base;
+    private final Register index;
+    private final Scale scale;
+    private final int displacement;
+
+    /**
+     * Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
+     * 
+     * @param base the base register
+     */
+    public AMD64Address(Register base) {
+        this(base, Register.None, Scale.Times1, 0);
+    }
+
+    /**
+     * Creates an {@link AMD64Address} with given base register, no scaling and a given
+     * displacement.
+     * 
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public AMD64Address(Register base, int displacement) {
+        this(base, Register.None, Scale.Times1, displacement);
+    }
+
+    /**
+     * Creates an {@link AMD64Address} with given base and index registers, scaling and
+     * displacement. This is the most general constructor.
+     * 
+     * @param base the base register
+     * @param index the index register
+     * @param scale the scaling factor
+     * @param displacement the displacement
+     */
+    public AMD64Address(Register base, Register index, Scale scale, int displacement) {
+        this.base = base;
+        this.index = index;
+        this.scale = scale;
+        this.displacement = displacement;
+    }
+
+    /**
+     * A scaling factor used in the SIB addressing mode.
+     */
+    public enum Scale {
+        Times1(1, 0), Times2(2, 1), Times4(4, 2), Times8(8, 3);
+
+        private Scale(int value, int log2) {
+            this.value = value;
+            this.log2 = log2;
+        }
+
+        /**
+         * The value (or multiplier) of this scale.
+         */
+        public final int value;
+
+        /**
+         * The {@linkplain #value value} of this scale log 2.
+         */
+        public final int log2;
+
+        public static Scale fromInt(int scale) {
+            switch (scale) {
+                case 1:
+                    return Times1;
+                case 2:
+                    return Times2;
+                case 4:
+                    return Times4;
+                case 8:
+                    return Times8;
+                default:
+                    throw new IllegalArgumentException(String.valueOf(scale));
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append("[");
+        String sep = "";
+        if (getBase() != Register.None) {
+            s.append(getBase());
+            sep = " + ";
+        }
+        if (getIndex() != Register.None) {
+            s.append(sep).append(getIndex()).append(" * ").append(getScale().value);
+            sep = " + ";
+        }
+        if (getDisplacement() < 0) {
+            s.append(" - ").append(-getDisplacement());
+        } else if (getDisplacement() > 0) {
+            s.append(sep).append(getDisplacement());
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    /**
+     * @return Base register that defines the start of the address computation. If not present, is
+     *         denoted by {@link Register#None}.
+     */
+    public Register getBase() {
+        return base;
+    }
+
+    /**
+     * @return Index register, the value of which (possibly scaled by {@link #getScale}) is added to
+     *         {@link #getBase}. If not present, is denoted by {@link Register#None}.
+     */
+    public Register getIndex() {
+        return index;
+    }
+
+    /**
+     * @return Scaling factor for indexing, dependent on target operand size.
+     */
+    public Scale getScale() {
+        return scale;
+    }
+
+    /**
+     * @return Optional additive displacement.
+     */
+    public int getDisplacement() {
+        return displacement;
+    }
+}
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Fri Mar 08 13:19:28 2013 +0100
@@ -24,13 +24,11 @@
 
 import static com.oracle.graal.amd64.AMD64.*;
 import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.asm.NumUtil.*;
 import static com.oracle.graal.asm.amd64.AMD64AsmOptions.*;
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 
 /**
@@ -38,19 +36,13 @@
  */
 public class AMD64Assembler extends AbstractAssembler {
 
-    /**
-     * The kind for pointers and raw registers. Since we know we are 64 bit here, we can hardcode
-     * it.
-     */
-    private static final Kind Word = Kind.Long;
-
     private static final int MinEncodingNeedsRex = 8;
 
     /**
      * A sentinel value used as a place holder in an instruction stream for an address that will be
      * patched.
      */
-    private static final AMD64Address Placeholder = new AMD64Address(Kind.Illegal, rip.asValue());
+    private static final AMD64Address Placeholder = new AMD64Address(rip);
 
     /**
      * The x86 condition codes used for conditional jumps/moves.
@@ -232,8 +224,8 @@
         assert (reg & 0x07) == reg;
         int regenc = reg << 3;
 
-        Register base = isLegal(addr.getBase()) ? asRegister(addr.getBase()) : Register.None;
-        Register index = isLegal(addr.getIndex()) ? asRegister(addr.getIndex()) : Register.None;
+        Register base = addr.getBase();
+        Register index = addr.getIndex();
 
         AMD64Address.Scale scale = addr.getScale();
         int disp = addr.getDisplacement();
@@ -1781,8 +1773,8 @@
         }
     }
 
-    private static boolean needsRex(Value value) {
-        return isRegister(value) && asRegister(value).encoding >= MinEncodingNeedsRex;
+    private static boolean needsRex(Register reg) {
+        return reg.encoding >= MinEncodingNeedsRex;
     }
 
     private void prefix(AMD64Address adr) {
@@ -2249,7 +2241,7 @@
                 // the code where this idiom is used, in particular the
                 // orderAccess code.
                 lock();
-                addl(new AMD64Address(Word, RSP, 0), 0); // Assert the lock# signal here
+                addl(new AMD64Address(rsp, 0), 0); // Assert the lock# signal here
             }
         }
     }
@@ -2290,7 +2282,7 @@
     }
 
     public void nullCheck(Register r) {
-        testl(AMD64.rax, new AMD64Address(Word, r.asValue(Word), 0));
+        testl(AMD64.rax, new AMD64Address(r, 0));
     }
 
     @Override
@@ -2371,8 +2363,8 @@
     }
 
     @Override
-    public AMD64Address makeAddress(Kind kind, Value base, int displacement) {
-        return new AMD64Address(kind, base, displacement);
+    public AMD64Address makeAddress(Register base, int displacement) {
+        return new AMD64Address(base, displacement);
     }
 
     @Override
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64MacroAssembler.java	Fri Mar 08 13:19:28 2013 +0100
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 
 /**
  * This class implements commonly used X86 code patterns.
@@ -222,7 +221,7 @@
      * volatile field!
      */
     public final void movlong(AMD64Address dst, long src) {
-        AMD64Address high = new AMD64Address(dst.getKind(), dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
+        AMD64Address high = new AMD64Address(dst.getBase(), dst.getIndex(), dst.getScale(), dst.getDisplacement() + 4);
         movl(dst, (int) (src & 0xFFFFFFFF));
         movl(high, (int) (src >> 32));
     }
@@ -230,7 +229,7 @@
     public final void flog(Register dest, Register value, boolean base10) {
         assert dest.isFpu() && value.isFpu();
 
-        AMD64Address tmp = new AMD64Address(Kind.Double, AMD64.RSP);
+        AMD64Address tmp = new AMD64Address(AMD64.rsp);
         if (base10) {
             fldlg2();
         } else {
@@ -264,7 +263,7 @@
 
     private AMD64Address trigPrologue(Register value) {
         assert value.isFpu();
-        AMD64Address tmp = new AMD64Address(Kind.Double, AMD64.RSP);
+        AMD64Address tmp = new AMD64Address(AMD64.rsp);
         subq(AMD64.rsp, 8);
         movsd(tmp, value);
         fld(tmp);
@@ -286,18 +285,16 @@
      * @param frameToCSA offset from the frame pointer to the CSA
      */
     public final void save(CalleeSaveLayout csl, int frameToCSA) {
-        RegisterValue frame = frameRegister.asValue();
         for (Register r : csl.registers) {
             int offset = csl.offsetOf(r);
-            movq(new AMD64Address(target.wordKind, frame, frameToCSA + offset), r);
+            movq(new AMD64Address(frameRegister, frameToCSA + offset), r);
         }
     }
 
     public final void restore(CalleeSaveLayout csl, int frameToCSA) {
-        RegisterValue frame = frameRegister.asValue();
         for (Register r : csl.registers) {
             int offset = csl.offsetOf(r);
-            movq(r, new AMD64Address(target.wordKind, frame, frameToCSA + offset));
+            movq(r, new AMD64Address(frameRegister, frameToCSA + offset));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAddress.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.asm.ptx;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Represents an address in target machine memory, specified via some combination of a base register
+ * and a displacement.
+ */
+public final class PTXAddress extends AbstractAddress {
+
+    private final Register base;
+    private final long displacement;
+
+    /**
+     * Creates an {@link PTXAddress} with given base register and no displacement.
+     * 
+     * @param base the base register
+     */
+    public PTXAddress(Register base) {
+        this(base, 0);
+    }
+
+    /**
+     * Creates an {@link PTXAddress} with given base register and a displacement. This is the most
+     * general constructor.
+     * 
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public PTXAddress(Register base, long displacement) {
+        this.base = base;
+        this.displacement = displacement;
+    }
+
+    /**
+     * @return Base register that defines the start of the address computation. If not present, is
+     *         denoted by {@link Value#ILLEGAL}.
+     */
+    public Register getBase() {
+        return base;
+    }
+
+    /**
+     * @return Optional additive displacement.
+     */
+    public long getDisplacement() {
+        return displacement;
+    }
+}
--- a/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.asm.ptx/src/com/oracle/graal/asm/ptx/PTXAssembler.java	Fri Mar 08 13:19:28 2013 +0100
@@ -23,8 +23,6 @@
 package com.oracle.graal.asm.ptx;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.ptx.*;
 
 public class PTXAssembler extends AbstractPTXAssembler {
 
@@ -177,7 +175,7 @@
         emitString("exit;" + " " + "");
     }
 
-    public final void ld_global_b8(Register d, Register a, int immOff) {
+    public final void ld_global_b8(Register d, Register a, long immOff) {
         emitString("ld.global.b8" + " " + "%r" + d.encoding() + ", [%r" + a.encoding() + " + " + immOff + "]" + ";" + "");
     }
 
@@ -742,8 +740,8 @@
     }
 
     @Override
-    public PTXAddress makeAddress(Kind kind, Value base, int displacement) {
-        return new PTXAddress(kind, base, displacement);
+    public PTXAddress makeAddress(Register base, int displacement) {
+        return new PTXAddress(base, displacement);
     }
 
     @Override
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri Mar 08 13:19:28 2013 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.asm.sparc;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.sparc.*;
 
@@ -55,13 +54,13 @@
     }
 
     @Override
-    public Address makeAddress(Kind kind, Value base, int displacement) {
+    public AbstractAddress makeAddress(Register base, int displacement) {
         // SPARC: Implement address calculation.
         return null;
     }
 
     @Override
-    public Address getPlaceholder() {
+    public AbstractAddress getPlaceholder() {
         // SPARC: Implement address patching.
         return null;
     }
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/AbstractAssembler.java	Fri Mar 08 13:19:28 2013 +0100
@@ -25,7 +25,6 @@
 import java.nio.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
 
 /**
  * The platform-independent base class for the assembler.
@@ -87,12 +86,12 @@
 
     /**
      * This is used by the TargetMethodAssembler to convert a {@link StackSlot} to an
-     * {@link Address}.
+     * {@link AbstractAddress}.
      */
-    public abstract Address makeAddress(Kind kind, Value base, int displacement);
+    public abstract AbstractAddress makeAddress(Register base, int displacement);
 
     /**
      * Returns a target specific placeholder address that can be used for code patching.
      */
-    public abstract Address getPlaceholder();
+    public abstract AbstractAddress getPlaceholder();
 }
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Fri Mar 08 13:19:28 2013 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.compiler.target.*;
@@ -158,56 +159,64 @@
         append(createMove(dst, src));
     }
 
-    private AMD64Address prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
-        Value baseRegister = base;
+    private AMD64AddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+        AllocatableValue baseRegister;
         int finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
-                baseRegister = Value.ILLEGAL;
+                baseRegister = AllocatableValue.UNUSED;
             } else if (asConstant(base).getKind() != Kind.Object) {
                 long newDisplacement = displacement + asConstant(base).asLong();
                 if (NumUtil.isInt(newDisplacement)) {
                     assert !runtime.needsDataPatch(asConstant(base));
                     finalDisp = (int) newDisplacement;
-                    baseRegister = Value.ILLEGAL;
+                    baseRegister = AllocatableValue.UNUSED;
                 } else {
-                    Value newBase = newVariable(Kind.Long);
+                    Variable newBase = newVariable(Kind.Long);
                     emitMove(newBase, base);
                     baseRegister = newBase;
                 }
+            } else {
+                baseRegister = load(base);
             }
+        } else if (base == Value.ILLEGAL) {
+            baseRegister = AllocatableValue.UNUSED;
+        } else {
+            baseRegister = asAllocatable(base);
         }
 
-        Value indexRegister = index;
-        AMD64Address.Scale scaleEnum;
-        if (index != Value.ILLEGAL && scale > 0) {
-            scaleEnum = AMD64Address.Scale.fromInt(scale);
+        AllocatableValue indexRegister;
+        Scale scaleEnum;
+        if (index != Value.ILLEGAL && scale != 0) {
+            scaleEnum = Scale.fromInt(scale);
             if (isConstant(index)) {
                 long newDisplacement = finalDisp + asConstant(index).asLong() * scale;
                 // only use the constant index if the resulting displacement fits into a 32 bit
                 // offset
                 if (NumUtil.isInt(newDisplacement)) {
                     finalDisp = (int) newDisplacement;
-                    indexRegister = Value.ILLEGAL;
+                    indexRegister = AllocatableValue.UNUSED;
                 } else {
                     // create a temporary variable for the index, the pointer load cannot handle a
                     // constant index
-                    Value newIndex = newVariable(Kind.Long);
+                    Variable newIndex = newVariable(Kind.Long);
                     emitMove(newIndex, index);
                     indexRegister = newIndex;
                 }
+            } else {
+                indexRegister = asAllocatable(index);
             }
         } else {
-            indexRegister = Value.ILLEGAL;
-            scaleEnum = AMD64Address.Scale.Times1;
+            indexRegister = AllocatableValue.UNUSED;
+            scaleEnum = Scale.Times1;
         }
 
-        return new AMD64Address(kind, baseRegister, indexRegister, scaleEnum, finalDisp);
+        return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, finalDisp);
     }
 
     @Override
     public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) {
-        AMD64Address loadAddress = prepareAddress(kind, base, displacement, index, scale);
+        AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, canTrap ? state() : null));
         return result;
@@ -215,7 +224,7 @@
 
     @Override
     public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) {
-        AMD64Address storeAddress = prepareAddress(kind, base, displacement, index, scale);
+        AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         LIRFrameState state = canTrap ? state() : null;
 
         if (isConstant(inputVal)) {
@@ -233,7 +242,7 @@
     @Override
     public Variable emitLea(Value base, int displacement, Value index, int scale) {
         Variable result = newVariable(target().wordKind);
-        AMD64Address address = prepareAddress(result.getKind(), base, displacement, index, scale);
+        AMD64AddressValue address = prepareAddress(result.getKind(), base, displacement, index, scale);
         append(new LeaOp(result, address));
         return result;
     }
@@ -922,15 +931,15 @@
         Value expected = loadNonConst(operand(node.expected()));
         Variable newValue = load(operand(node.newValue()));
 
-        AMD64Address address;
+        AMD64AddressValue address;
         int displacement = node.displacement();
         Value index = operand(node.offset());
         if (isConstant(index) && NumUtil.isInt(asConstant(index).asLong() + displacement)) {
             assert !runtime.needsDataPatch(asConstant(index));
             displacement += (int) asConstant(index).asLong();
-            address = new AMD64Address(kind, load(operand(node.object())), displacement);
+            address = new AMD64AddressValue(kind, load(operand(node.object())), displacement);
         } else {
-            address = new AMD64Address(kind, load(operand(node.object())), load(index), AMD64Address.Scale.Times1, displacement);
+            address = new AMD64AddressValue(kind, load(operand(node.object())), load(index), Scale.Times1, displacement);
         }
 
         RegisterValue rax = AMD64.rax.asValue(kind);
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Fri Mar 08 13:19:28 2013 +0100
@@ -36,11 +36,11 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
+import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op1Stack;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Reg;
 import com.oracle.graal.lir.ptx.PTXArithmetic.Op2Stack;
 import com.oracle.graal.lir.ptx.PTXArithmetic.ShiftOp;
-import com.oracle.graal.lir.ptx.*;
 import com.oracle.graal.lir.ptx.PTXCompare.CompareOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.BranchOp;
 import com.oracle.graal.lir.ptx.PTXControlFlow.ReturnOp;
@@ -51,7 +51,6 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.ptx.*;
 
 /**
  * This class implements the PTX specific portion of the LIR generator.
@@ -114,40 +113,49 @@
         }
     }
 
-    private PTXAddress prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
-        Value baseRegister = base;
+    private PTXAddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+        AllocatableValue baseRegister;
         long finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
-                baseRegister = Value.ILLEGAL;
+                baseRegister = AllocatableValue.UNUSED;
             } else if (asConstant(base).getKind() != Kind.Object) {
                 finalDisp += asConstant(base).asLong();
-                baseRegister = Value.ILLEGAL;
+                baseRegister = AllocatableValue.UNUSED;
+            } else {
+                baseRegister = load(base);
             }
+        } else if (base == Value.ILLEGAL) {
+            baseRegister = AllocatableValue.UNUSED;
+        } else {
+            baseRegister = asAllocatable(base);
         }
 
         if (index != Value.ILLEGAL) {
             if (isConstant(index)) {
                 finalDisp += asConstant(index).asLong() * scale;
             } else {
-                Value indexRegister = index;
+                Value indexRegister;
                 if (scale != 1) {
                     indexRegister = emitMul(index, Constant.forInt(scale));
+                } else {
+                    indexRegister = index;
                 }
-                if (baseRegister == Value.ILLEGAL) {
-                    baseRegister = indexRegister;
+
+                if (baseRegister == AllocatableValue.UNUSED) {
+                    baseRegister = asAllocatable(indexRegister);
                 } else {
                     baseRegister = emitAdd(baseRegister, indexRegister);
                 }
             }
         }
 
-        return new PTXAddress(kind, baseRegister, finalDisp);
+        return new PTXAddressValue(kind, baseRegister, finalDisp);
     }
 
     @Override
     public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, boolean canTrap) {
-        PTXAddress loadAddress = prepareAddress(kind, base, displacement, index, scale);
+        PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, canTrap ? state() : null));
         return result;
@@ -155,7 +163,7 @@
 
     @Override
     public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, boolean canTrap) {
-        PTXAddress storeAddress = prepareAddress(kind, base, displacement, index, scale);
+        PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable input = load(inputVal);
         append(new StoreOp(storeAddress, input, canTrap ? state() : null));
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/Interval.java	Fri Mar 08 13:19:28 2013 +0100
@@ -417,8 +417,8 @@
     public final int operandNumber;
 
     /**
-     * The {@linkplain RegisterValue register}, {@linkplain StackSlot spill slot} or
-     * {@linkplain Address address} assigned to this interval.
+     * The {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to this
+     * interval.
      */
     private Value location;
 
@@ -515,8 +515,8 @@
     }
 
     /**
-     * Gets the {@linkplain RegisterValue register}, {@linkplain StackSlot spill slot} or
-     * {@linkplain Address address} assigned to this interval.
+     * Gets the {@linkplain RegisterValue register} or {@linkplain StackSlot spill slot} assigned to
+     * this interval.
      */
     public Value location() {
         return location;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/PhiResolver.java	Fri Mar 08 13:19:28 2013 +0100
@@ -192,10 +192,10 @@
 
     // Traverse assignment graph in depth first order and generate moves in post order
     // ie. two assignments: b := c, a := b start with node c:
-    // Call graph: move(NULL, c) -> move(c, b) -> move(b, a)
+    // Call graph: move(c, NULL) -> move(b, c) -> move(a, b)
     // Generates moves in this order: move b to a and move c to b
     // ie. cycle a := b, b := a start with node a
-    // Call graph: move(NULL, a) -> move(a, b) -> move(b, a)
+    // Call graph: move(a, NULL) -> move(b, a) -> move(a, b)
     // Generates moves in this order: move b to temp, move a to b, move temp to a
     private void move(PhiResolverNode dest, PhiResolverNode src) {
         if (!dest.visited) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Mar 08 13:19:28 2013 +0100
@@ -32,11 +32,12 @@
 
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.RuntimeCallTarget.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
-import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.hotspot.*;
@@ -128,14 +129,14 @@
             Variable newVal = load(operand(x.newValue()));
 
             int disp = 0;
-            AMD64Address address;
+            AMD64AddressValue address;
             Value index = operand(x.offset());
             if (ValueUtil.isConstant(index) && NumUtil.isInt(ValueUtil.asConstant(index).asLong() + disp)) {
                 assert !runtime.needsDataPatch(asConstant(index));
                 disp += (int) ValueUtil.asConstant(index).asLong();
-                address = new AMD64Address(kind, load(operand(x.object())), disp);
+                address = new AMD64AddressValue(kind, load(operand(x.object())), disp);
             } else {
-                address = new AMD64Address(kind, load(operand(x.object())), load(index), AMD64Address.Scale.Times1, disp);
+                address = new AMD64AddressValue(kind, load(operand(x.object())), load(index), Scale.Times1, disp);
             }
 
             RegisterValue rax = AMD64.rax.asValue(kind);
@@ -203,7 +204,7 @@
                         disp -= frameSize;
                     }
                     tasm.blockComment("[stack overflow check]");
-                    asm.movq(new AMD64Address(asm.target.wordKind, AMD64.RSP, -disp), AMD64.rax);
+                    asm.movq(new AMD64Address(rsp, -disp), AMD64.rax);
                 }
             }
         }
@@ -223,7 +224,7 @@
             if (GraalOptions.ZapStackOnMethodEntry) {
                 final int intSize = 4;
                 for (int i = 0; i < frameSize / intSize; ++i) {
-                    asm.movl(new AMD64Address(Kind.Int, rsp.asValue(), i * intSize), 0xC1C1C1C1);
+                    asm.movl(new AMD64Address(rsp, i * intSize), 0xC1C1C1C1);
                 }
             }
             CalleeSaveLayout csl = frameMap.registerConfig.getCalleeSaveLayout();
@@ -287,7 +288,7 @@
             Register inlineCacheKlass = rax; // see definition of IC_Klass in
                                              // c1_LIRAssembler_x86.cpp
             Register receiver = asRegister(cc.getArgument(0));
-            AMD64Address src = new AMD64Address(target.wordKind, receiver.asValue(), config.hubOffset);
+            AMD64Address src = new AMD64Address(receiver, config.hubOffset);
 
             asm.cmpq(inlineCacheKlass, src);
             asm.jcc(ConditionFlag.NotEqual, unverifiedStub);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64SafepointOp.java	Fri Mar 08 13:19:28 2013 +0100
@@ -26,7 +26,6 @@
 import static com.oracle.graal.phases.GraalOptions.*;
 import sun.misc.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.*;
@@ -65,13 +64,13 @@
             asm.movq(scratch.getRegister(), config.safepointPollingAddress + offset);
             tasm.recordMark(Marks.MARK_POLL_FAR);
             tasm.recordSafepoint(pos, state);
-            asm.movq(scratch.getRegister(), new AMD64Address(tasm.target.wordKind, scratch));
+            asm.movq(scratch.getRegister(), new AMD64Address(scratch.getRegister()));
         } else {
             tasm.recordMark(Marks.MARK_POLL_NEAR);
             tasm.recordSafepoint(pos, state);
             // The C++ code transforms the polling page offset into an RIP displacement
             // to the real address at that offset in the polling page.
-            asm.movq(scratch.getRegister(), new AMD64Address(tasm.target.wordKind, rip.asValue(), offset));
+            asm.movq(scratch.getRegister(), new AMD64Address(rip, offset));
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
+import com.oracle.graal.lir.*;
+
+public class AMD64AddressValue extends CompositeValue {
+
+    private static final long serialVersionUID = -4444600052487578694L;
+
+    @Component({REG, UNUSED}) protected AllocatableValue base;
+    @Component({REG, UNUSED}) protected AllocatableValue index;
+    protected final Scale scale;
+    protected final int displacement;
+
+    public AMD64AddressValue(Kind kind, AllocatableValue base, int displacement) {
+        this(kind, base, AllocatableValue.UNUSED, Scale.Times1, displacement);
+    }
+
+    public AMD64AddressValue(Kind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
+        super(kind);
+        this.base = base;
+        this.index = index;
+        this.scale = scale;
+        this.displacement = displacement;
+    }
+
+    private static Register toRegister(AllocatableValue value) {
+        if (value == AllocatableValue.UNUSED) {
+            return Register.None;
+        } else {
+            RegisterValue reg = (RegisterValue) value;
+            return reg.getRegister();
+        }
+    }
+
+    public AMD64Address toAddress() {
+        return new AMD64Address(toRegister(base), toRegister(index), scale, displacement);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append(getKind().getJavaName()).append("[");
+        String sep = "";
+        if (isLegal(base)) {
+            s.append(base);
+            sep = " + ";
+        }
+        if (isLegal(index)) {
+            s.append(sep).append(index).append(" * ").append(scale.value);
+            sep = " + ";
+        }
+        if (displacement < 0) {
+            s.append(" - ").append(-displacement);
+        } else if (displacement > 0) {
+            s.append(sep).append(displacement);
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof AMD64AddressValue) {
+            AMD64AddressValue addr = (AMD64AddressValue) obj;
+            return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base) && scale == addr.scale && index.equals(addr.index);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return base.hashCode() ^ index.hashCode() ^ (displacement << 4) ^ (scale.value << 8) ^ (getKind().ordinal() << 12);
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Fri Mar 08 13:19:28 2013 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.lir.amd64;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.lir.asm.*;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Fri Mar 08 13:19:28 2013 +0100
@@ -25,7 +25,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Fri Mar 08 13:19:28 2013 +0100
@@ -26,13 +26,13 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 import com.oracle.graal.amd64.*;
-import com.oracle.graal.amd64.AMD64Address.Scale;
+import com.oracle.graal.api.code.CompilationResult.JumpTable;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.CompilationResult.JumpTable;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Address.Scale;
 import com.oracle.graal.asm.amd64.AMD64Assembler.ConditionFlag;
-import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.Opcode;
@@ -338,11 +338,11 @@
 
         // Set scratch to address of jump table
         int leaPos = buf.position();
-        masm.leaq(scratch, new AMD64Address(tasm.target.wordKind, AMD64.rip.asValue(), 0));
+        masm.leaq(scratch, new AMD64Address(AMD64.rip, 0));
         int afterLea = buf.position();
 
         // Load jump table entry into scratch and jump to it
-        masm.movslq(value, new AMD64Address(Kind.Int, scratch.asValue(), value.asValue(), Scale.Times4, 0));
+        masm.movslq(value, new AMD64Address(scratch, value, Scale.Times4, 0));
         masm.addq(scratch, value);
         masm.jmp(scratch);
 
@@ -354,7 +354,7 @@
         // Patch LEA instruction above now that we know the position of the jump table
         int jumpTablePos = buf.position();
         buf.setPosition(leaPos);
-        masm.leaq(scratch, new AMD64Address(tasm.target.wordKind, AMD64.rip.asValue(), jumpTablePos - afterLea));
+        masm.leaq(scratch, new AMD64Address(AMD64.rip, jumpTablePos - afterLea));
         buf.setPosition(jumpTablePos);
 
         // Emit jump table entries
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Fri Mar 08 13:19:28 2013 +0100
@@ -97,10 +97,10 @@
 
     public abstract static class MemOp extends AMD64LIRInstruction {
 
-        @Use({ADDR}) protected AMD64Address address;
+        @Use({COMPOSITE}) protected AMD64AddressValue address;
         @State protected LIRFrameState state;
 
-        public MemOp(AMD64Address address, LIRFrameState state) {
+        public MemOp(AMD64AddressValue address, LIRFrameState state) {
             this.address = address;
             this.state = state;
         }
@@ -120,7 +120,7 @@
 
         @Def({REG}) protected AllocatableValue result;
 
-        public LoadOp(AllocatableValue result, AMD64Address address, LIRFrameState state) {
+        public LoadOp(AllocatableValue result, AMD64AddressValue address, LIRFrameState state) {
             super(address, state);
             this.result = result;
         }
@@ -130,28 +130,28 @@
             switch (address.getKind()) {
                 case Boolean:
                 case Byte:
-                    masm.movsxb(asRegister(result), address);
+                    masm.movsxb(asRegister(result), address.toAddress());
                     break;
                 case Char:
-                    masm.movzxl(asRegister(result), address);
+                    masm.movzxl(asRegister(result), address.toAddress());
                     break;
                 case Short:
-                    masm.movswl(asRegister(result), address);
+                    masm.movswl(asRegister(result), address.toAddress());
                     break;
                 case Int:
-                    masm.movslq(asRegister(result), address);
+                    masm.movslq(asRegister(result), address.toAddress());
                     break;
                 case Long:
-                    masm.movq(asRegister(result), address);
+                    masm.movq(asRegister(result), address.toAddress());
                     break;
                 case Float:
-                    masm.movflt(asFloatReg(result), address);
+                    masm.movflt(asFloatReg(result), address.toAddress());
                     break;
                 case Double:
-                    masm.movdbl(asDoubleReg(result), address);
+                    masm.movdbl(asDoubleReg(result), address.toAddress());
                     break;
                 case Object:
-                    masm.movq(asRegister(result), address);
+                    masm.movq(asRegister(result), address.toAddress());
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -163,7 +163,7 @@
 
         @Use({REG}) protected AllocatableValue input;
 
-        public StoreOp(AMD64Address address, AllocatableValue input, LIRFrameState state) {
+        public StoreOp(AMD64AddressValue address, AllocatableValue input, LIRFrameState state) {
             super(address, state);
             this.input = input;
         }
@@ -174,26 +174,26 @@
             switch (address.getKind()) {
                 case Boolean:
                 case Byte:
-                    masm.movb(address, asRegister(input));
+                    masm.movb(address.toAddress(), asRegister(input));
                     break;
                 case Char:
                 case Short:
-                    masm.movw(address, asRegister(input));
+                    masm.movw(address.toAddress(), asRegister(input));
                     break;
                 case Int:
-                    masm.movl(address, asRegister(input));
+                    masm.movl(address.toAddress(), asRegister(input));
                     break;
                 case Long:
-                    masm.movq(address, asRegister(input));
+                    masm.movq(address.toAddress(), asRegister(input));
                     break;
                 case Float:
-                    masm.movflt(address, asFloatReg(input));
+                    masm.movflt(address.toAddress(), asFloatReg(input));
                     break;
                 case Double:
-                    masm.movsd(address, asDoubleReg(input));
+                    masm.movsd(address.toAddress(), asDoubleReg(input));
                     break;
                 case Object:
-                    masm.movq(address, asRegister(input));
+                    masm.movq(address.toAddress(), asRegister(input));
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -205,7 +205,7 @@
 
         protected final Constant input;
 
-        public StoreConstantOp(AMD64Address address, Constant input, LIRFrameState state) {
+        public StoreConstantOp(AMD64AddressValue address, Constant input, LIRFrameState state) {
             super(address, state);
             this.input = input;
         }
@@ -215,30 +215,30 @@
             switch (address.getKind()) {
                 case Boolean:
                 case Byte:
-                    masm.movb(address, input.asInt() & 0xFF);
+                    masm.movb(address.toAddress(), input.asInt() & 0xFF);
                     break;
                 case Char:
                 case Short:
-                    masm.movw(address, input.asInt() & 0xFFFF);
+                    masm.movw(address.toAddress(), input.asInt() & 0xFFFF);
                     break;
                 case Int:
-                    masm.movl(address, input.asInt());
+                    masm.movl(address.toAddress(), input.asInt());
                     break;
                 case Long:
                     if (NumUtil.isInt(input.asLong())) {
-                        masm.movslq(address, (int) input.asLong());
+                        masm.movslq(address.toAddress(), (int) input.asLong());
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
                     }
                     break;
                 case Float:
-                    masm.movl(address, floatToRawIntBits(input.asFloat()));
+                    masm.movl(address.toAddress(), floatToRawIntBits(input.asFloat()));
                     break;
                 case Double:
                     throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
                 case Object:
                     if (input.isNull()) {
-                        masm.movptr(address, 0);
+                        masm.movptr(address.toAddress(), 0);
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
                     }
@@ -252,16 +252,16 @@
     public static class LeaOp extends AMD64LIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
-        @Use({ADDR, UNINITIALIZED}) protected AMD64Address address;
+        @Use({COMPOSITE, UNINITIALIZED}) protected AMD64AddressValue address;
 
-        public LeaOp(AllocatableValue result, AMD64Address address) {
+        public LeaOp(AllocatableValue result, AMD64AddressValue address) {
             this.result = result;
             this.address = address;
         }
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
-            masm.leaq(asLongReg(result), address);
+            masm.leaq(asLongReg(result), address.toAddress());
         }
     }
 
@@ -316,11 +316,11 @@
     public static class CompareAndSwapOp extends AMD64LIRInstruction {
 
         @Def protected AllocatableValue result;
-        @Use({ADDR}) protected AMD64Address address;
+        @Use({COMPOSITE}) protected AMD64AddressValue address;
         @Use protected AllocatableValue cmpValue;
         @Use protected AllocatableValue newValue;
 
-        public CompareAndSwapOp(AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) {
+        public CompareAndSwapOp(AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
             this.result = result;
             this.address = address;
             this.cmpValue = cmpValue;
@@ -523,7 +523,7 @@
         }
     }
 
-    protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64Address address, AllocatableValue cmpValue, AllocatableValue newValue) {
+    protected static void compareAndSwap(TargetMethodAssembler tasm, AMD64MacroAssembler masm, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
         assert asRegister(cmpValue) == AMD64.rax && asRegister(result) == AMD64.rax;
 
         if (tasm.target.isMP) {
@@ -531,11 +531,11 @@
         }
         switch (cmpValue.getKind()) {
             case Int:
-                masm.cmpxchgl(asRegister(newValue), address);
+                masm.cmpxchgl(asRegister(newValue), address.toAddress());
                 break;
             case Long:
             case Object:
-                masm.cmpxchgq(asRegister(newValue), address);
+                masm.cmpxchgq(asRegister(newValue), address.toAddress());
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Fri Mar 08 13:19:28 2013 +0100
@@ -25,7 +25,6 @@
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
-import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.graph.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXAddressValue.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.ptx;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.ptx.*;
+import com.oracle.graal.lir.*;
+
+/**
+ * Represents an address in target machine memory, specified via some combination of a base register
+ * and a displacement.
+ */
+public final class PTXAddressValue extends CompositeValue {
+
+    private static final long serialVersionUID = 1802222435353022623L;
+
+    @Component({REG, UNUSED}) private AllocatableValue base;
+    private final long displacement;
+
+    /**
+     * Creates an {@link PTXAddressValue} with given base register and no displacement.
+     * 
+     * @param kind the kind of the value being addressed
+     * @param base the base register
+     */
+    public PTXAddressValue(Kind kind, AllocatableValue base) {
+        this(kind, base, 0);
+    }
+
+    /**
+     * Creates an {@link PTXAddressValue} with given base register and a displacement. This is the
+     * most general constructor.
+     * 
+     * @param kind the kind of the value being addressed
+     * @param base the base register
+     * @param displacement the displacement
+     */
+    public PTXAddressValue(Kind kind, AllocatableValue base, long displacement) {
+        super(kind);
+        this.base = base;
+        this.displacement = displacement;
+
+        assert !isStackSlot(base);
+    }
+
+    public PTXAddress toAddress() {
+        Register baseReg = base == AllocatableValue.UNUSED ? Register.None : asRegister(base);
+        return new PTXAddress(baseReg, displacement);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder s = new StringBuilder();
+        s.append(getKind().getJavaName()).append("[");
+        String sep = "";
+        if (isLegal(base)) {
+            s.append(base);
+            sep = " + ";
+        }
+        if (displacement < 0) {
+            s.append(" - ").append(-displacement);
+        } else if (displacement > 0) {
+            s.append(sep).append(displacement);
+        }
+        s.append("]");
+        return s.toString();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof PTXAddressValue) {
+            PTXAddressValue addr = (PTXAddressValue) obj;
+            return getKind() == addr.getKind() && displacement == addr.displacement && base.equals(addr.base);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return base.hashCode() ^ ((int) displacement << 4) ^ (getKind().ordinal() << 12);
+    }
+}
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXBitManipulationOp.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXBitManipulationOp.java	Fri Mar 08 13:19:28 2013 +0100
@@ -36,7 +36,7 @@
 
     @Opcode private final IntrinsicOpcode opcode;
     @Def protected Value result;
-    @Use({OperandFlag.REG, OperandFlag.ADDR}) protected Value input;
+    @Use({OperandFlag.REG}) protected Value input;
 
     public PTXBitManipulationOp(IntrinsicOpcode opcode, Value result, Value input) {
         this.opcode = opcode;
--- a/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir.ptx/src/com/oracle/graal/lir/ptx/PTXMove.java	Fri Mar 08 13:19:28 2013 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.lir.LIRInstruction.Opcode;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.ptx.*;
 
 public class PTXMove {
 
@@ -121,10 +120,10 @@
     public static class LoadOp extends PTXLIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
-        @Use({ADDR}) protected PTXAddress address;
+        @Use({COMPOSITE}) protected PTXAddressValue address;
         @State protected LIRFrameState state;
 
-        public LoadOp(AllocatableValue result, PTXAddress address, LIRFrameState state) {
+        public LoadOp(AllocatableValue result, PTXAddressValue address, LIRFrameState state) {
             this.result = result;
             this.address = address;
             this.state = state;
@@ -132,14 +131,13 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            Register a = asRegister(address.getBase());
-            long immOff = address.getDisplacement();
+            PTXAddress addr = address.toAddress();
             switch (address.getKind()) {
                 case Int:
-                    masm.ld_global_s32(asRegister(result), a, immOff);
+                    masm.ld_global_s32(asRegister(result), addr.getBase(), addr.getDisplacement());
                     break;
                 case Object:
-                    masm.ld_global_u32(asRegister(result), a, immOff);
+                    masm.ld_global_u32(asRegister(result), addr.getBase(), addr.getDisplacement());
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -149,11 +147,11 @@
 
     public static class StoreOp extends PTXLIRInstruction {
 
-        @Use({ADDR}) protected PTXAddress address;
+        @Use({COMPOSITE}) protected PTXAddressValue address;
         @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
 
-        public StoreOp(PTXAddress address, AllocatableValue input, LIRFrameState state) {
+        public StoreOp(PTXAddressValue address, AllocatableValue input, LIRFrameState state) {
             this.address = address;
             this.input = input;
             this.state = state;
@@ -161,13 +159,11 @@
 
         @Override
         public void emitCode(TargetMethodAssembler tasm, PTXAssembler masm) {
-            Register a = asRegister(address.getBase());
-            long immOff = address.getDisplacement();
-
             assert isRegister(input);
+            PTXAddress addr = address.toAddress();
             switch (address.getKind()) {
                 case Int:
-                    masm.st_global_s32(a, immOff, asRegister(input));
+                    masm.st_global_s32(addr.getBase(), addr.getDisplacement(), asRegister(input));
                     break;
                 default:
                     throw GraalInternalError.shouldNotReachHere();
@@ -178,9 +174,9 @@
     public static class LeaOp extends PTXLIRInstruction {
 
         @Def({REG}) protected AllocatableValue result;
-        @Use({ADDR, UNINITIALIZED}) protected PTXAddress address;
+        @Use({COMPOSITE, UNINITIALIZED}) protected PTXAddressValue address;
 
-        public LeaOp(AllocatableValue result, PTXAddress address) {
+        public LeaOp(AllocatableValue result, PTXAddressValue address) {
             this.result = result;
             this.address = address;
         }
@@ -211,11 +207,11 @@
     public static class CompareAndSwapOp extends PTXLIRInstruction {
 
         @Def protected AllocatableValue result;
-        @Use({ADDR}) protected PTXAddress address;
+        @Use({COMPOSITE}) protected PTXAddressValue address;
         @Use protected AllocatableValue cmpValue;
         @Use protected AllocatableValue newValue;
 
-        public CompareAndSwapOp(AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) {
+        public CompareAndSwapOp(AllocatableValue result, PTXAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
             this.result = result;
             this.address = address;
             this.cmpValue = cmpValue;
@@ -276,7 +272,7 @@
     }
 
     @SuppressWarnings("unused")
-    protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, AllocatableValue result, PTXAddress address, AllocatableValue cmpValue, AllocatableValue newValue) {
+    protected static void compareAndSwap(TargetMethodAssembler tasm, PTXAssembler masm, AllocatableValue result, PTXAddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
         throw new InternalError("NYI");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import java.lang.annotation.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+/**
+ * Base class to represent values that need to be stored in more than one register.
+ */
+public abstract class CompositeValue extends Value {
+
+    private static final long serialVersionUID = -169180052684126180L;
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.FIELD)
+    public static @interface Component {
+
+        OperandFlag[] value() default OperandFlag.REG;
+    }
+
+    private final CompositeValueClass valueClass;
+
+    public CompositeValue(Kind kind) {
+        super(kind);
+        valueClass = CompositeValueClass.get(getClass());
+    }
+
+    public final void forEachComponent(OperandMode mode, ValueProcedure proc) {
+        valueClass.forEachComponent(this, mode, proc);
+    }
+
+    @Override
+    public String toString() {
+        return valueClass.toString(this);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+public class CompositeValueClass extends LIRIntrospection {
+
+    public static final CompositeValueClass get(Class<? extends CompositeValue> c) {
+        CompositeValueClass clazz = (CompositeValueClass) allClasses.get(c);
+        if (clazz != null) {
+            return clazz;
+        }
+
+        // We can have a race of multiple threads creating the LIRInstructionClass at the same time.
+        // However, only one will be put into the map, and this is the one returned by all threads.
+        clazz = new CompositeValueClass(c);
+        CompositeValueClass oldClazz = (CompositeValueClass) allClasses.putIfAbsent(c, clazz);
+        if (oldClazz != null) {
+            return oldClazz;
+        } else {
+            return clazz;
+        }
+    }
+
+    private final int directComponentCount;
+    private final long[] componentOffsets;
+    private final EnumSet<OperandFlag>[] componentFlags;
+
+    @SuppressWarnings("unchecked")
+    public CompositeValueClass(Class<? extends CompositeValue> clazz) {
+        super(clazz);
+
+        ValueFieldScanner scanner = new ValueFieldScanner(new DefaultCalcOffset());
+        scanner.scan(clazz);
+
+        OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
+        directComponentCount = mode.scalarOffsets.size();
+        componentOffsets = sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets);
+        componentFlags = arrayUsingSortedOffsets(mode.flags, componentOffsets, new EnumSet[componentOffsets.length]);
+
+        dataOffsets = sortedLongCopy(scanner.dataOffsets);
+
+        fieldNames = scanner.fieldNames;
+        fieldTypes = scanner.fieldTypes;
+    }
+
+    @Override
+    protected void rescanFieldOffsets(CalcOffset calc) {
+        ValueFieldScanner scanner = new ValueFieldScanner(calc);
+        scanner.scan(clazz);
+
+        OperandModeAnnotation mode = scanner.valueAnnotations.get(CompositeValue.Component.class);
+        copyInto(componentOffsets, sortedLongCopy(mode.scalarOffsets, mode.arrayOffsets));
+
+        copyInto(dataOffsets, sortedLongCopy(scanner.dataOffsets));
+
+        fieldNames.clear();
+        fieldNames.putAll(scanner.fieldNames);
+        fieldTypes.clear();
+        fieldTypes.putAll(scanner.fieldTypes);
+    }
+
+    private static class ValueFieldScanner extends FieldScanner {
+
+        public ValueFieldScanner(CalcOffset calc) {
+            super(calc);
+
+            valueAnnotations.put(CompositeValue.Component.class, new OperandModeAnnotation());
+        }
+
+        @Override
+        protected void scan(Class<?> clazz) {
+            super.scan(clazz);
+        }
+
+        @Override
+        protected EnumSet<OperandFlag> getFlags(Field field) {
+            EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
+            if (field.isAnnotationPresent(CompositeValue.Component.class)) {
+                result.addAll(Arrays.asList(field.getAnnotation(CompositeValue.Component.class).value()));
+            } else {
+                GraalInternalError.shouldNotReachHere();
+            }
+            return result;
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder str = new StringBuilder();
+        str.append(getClass().getSimpleName()).append(" ").append(clazz.getSimpleName()).append(" component[");
+        for (int i = 0; i < componentOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(componentOffsets[i]);
+        }
+        str.append("] data[");
+        for (int i = 0; i < dataOffsets.length; i++) {
+            str.append(i == 0 ? "" : ", ").append(dataOffsets[i]);
+        }
+        str.append("]");
+        return str.toString();
+    }
+
+    public final void forEachComponent(CompositeValue obj, OperandMode mode, ValueProcedure proc) {
+        forEach(obj, directComponentCount, componentOffsets, mode, componentFlags, proc);
+    }
+
+    public String toString(CompositeValue obj) {
+        StringBuilder result = new StringBuilder();
+
+        appendValues(result, obj, "", "", "{", "}", new String[]{""}, componentOffsets);
+
+        for (int i = 0; i < dataOffsets.length; i++) {
+            result.append(" ").append(fieldNames.get(dataOffsets[i])).append(": ").append(getFieldString(obj, dataOffsets[i]));
+        }
+
+        return result.toString();
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Fri Mar 08 13:19:28 2013 +0100
@@ -166,9 +166,9 @@
         STACK,
 
         /**
-         * The value can be a {@link Address}.
+         * The value can be a {@link CompositeValue}.
          */
-        ADDR,
+        COMPOSITE,
 
         /**
          * The value can be a {@link Constant}.
@@ -205,10 +205,10 @@
 
     static {
         ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
-        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED));
-        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, ADDR, CONST, ILLEGAL, HINT, UNINITIALIZED));
-        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, CONST, ILLEGAL, HINT));
-        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, ILLEGAL, HINT));
+        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED));
+        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNUSED, UNINITIALIZED));
+        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, UNUSED, HINT));
+        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, UNUSED, HINT));
     }
 
     /**
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Fri Mar 08 13:19:28 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, 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
@@ -22,12 +22,8 @@
  */
 package com.oracle.graal.lir;
 
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.*;
-import java.util.Map.Entry;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -37,7 +33,7 @@
 import com.oracle.graal.lir.LIRInstruction.StateProcedure;
 import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
 
-public class LIRInstructionClass extends FieldIntrospection {
+public class LIRInstructionClass extends LIRIntrospection {
 
     public static final LIRInstructionClass get(Class<? extends LIRInstruction> c) {
         LIRInstructionClass clazz = (LIRInstructionClass) allClasses.get(c);
@@ -56,11 +52,8 @@
         }
     }
 
-    private static final Class<?> INSTRUCTION_CLASS = LIRInstruction.class;
-    private static final Class<?> VALUE_CLASS = Value.class;
-    private static final Class<?> CONSTANT_CLASS = Constant.class;
-    private static final Class<?> VALUE_ARRAY_CLASS = Value[].class;
-    private static final Class<?> STATE_CLASS = LIRFrameState.class;
+    private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class;
+    private static final Class<LIRFrameState> STATE_CLASS = LIRFrameState.class;
 
     private final int directUseCount;
     private final long[] useOffsets;
@@ -81,11 +74,11 @@
     private long opcodeOffset;
 
     @SuppressWarnings("unchecked")
-    public LIRInstructionClass(Class<?> clazz) {
+    public LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
-        FieldScanner scanner = new FieldScanner(new DefaultCalcOffset());
+        InstructionFieldScanner scanner = new InstructionFieldScanner(new DefaultCalcOffset());
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
@@ -120,7 +113,7 @@
 
     @Override
     protected void rescanFieldOffsets(CalcOffset calc) {
-        FieldScanner scanner = new FieldScanner(calc);
+        InstructionFieldScanner scanner = new InstructionFieldScanner(calc);
         scanner.scan(clazz);
 
         OperandModeAnnotation mode = scanner.valueAnnotations.get(LIRInstruction.Use.class);
@@ -144,44 +137,22 @@
         opcodeOffset = scanner.opcodeOffset;
     }
 
-    private static class OperandModeAnnotation {
-
-        public final ArrayList<Long> scalarOffsets = new ArrayList<>();
-        public final ArrayList<Long> arrayOffsets = new ArrayList<>();
-        public final Map<Long, EnumSet<OperandFlag>> flags = new HashMap<>();
-    }
-
-    protected static class FieldScanner extends BaseFieldScanner {
-
-        public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
-        public final ArrayList<Long> stateOffsets = new ArrayList<>();
+    private static class InstructionFieldScanner extends FieldScanner {
 
         private String opcodeConstant;
         private long opcodeOffset;
 
-        public FieldScanner(CalcOffset calc) {
+        public InstructionFieldScanner(CalcOffset calc) {
             super(calc);
 
-            valueAnnotations = new HashMap<>();
-            valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation()); // LIRInstruction.Use.class));
-            valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation()); // LIRInstruction.Alive.class));
-            valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation()); // LIRInstruction.Temp.class));
-            valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation()); // LIRInstruction.Def.class));
+            valueAnnotations.put(LIRInstruction.Use.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Alive.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Temp.class, new OperandModeAnnotation());
+            valueAnnotations.put(LIRInstruction.Def.class, new OperandModeAnnotation());
         }
 
-        private OperandModeAnnotation getOperandModeAnnotation(Field field) {
-            OperandModeAnnotation result = null;
-            for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry : valueAnnotations.entrySet()) {
-                Annotation annotation = field.getAnnotation(entry.getKey());
-                if (annotation != null) {
-                    assert result == null : "Field has two operand mode annotations: " + field;
-                    result = entry.getValue();
-                }
-            }
-            return result;
-        }
-
-        private static EnumSet<OperandFlag> getFlags(Field field) {
+        @Override
+        protected EnumSet<OperandFlag> getFlags(Field field) {
             EnumSet<OperandFlag> result = EnumSet.noneOf(OperandFlag.class);
             // Unfortunately, annotations cannot have class hierarchies or implement interfaces, so
             // we have to duplicate the code for every operand mode.
@@ -220,25 +191,12 @@
 
         @Override
         protected void scanField(Field field, Class<?> type, long offset) {
-            if (VALUE_CLASS.isAssignableFrom(type) && type != CONSTANT_CLASS) {
-                assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field;
-                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
-                assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.scalarOffsets.add(offset);
-                annotation.flags.put(offset, getFlags(field));
-            } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
-                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
-                assert annotation != null : "Field must have operand mode annotation: " + field;
-                annotation.arrayOffsets.add(offset);
-                annotation.flags.put(offset, getFlags(field));
-            } else if (STATE_CLASS.isAssignableFrom(type)) {
+            if (STATE_CLASS.isAssignableFrom(type)) {
                 assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
                 assert field.getAnnotation(LIRInstruction.State.class) != null : "Field must have state annotation: " + field;
                 stateOffsets.add(offset);
             } else {
-                assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
-                assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
-                dataOffsets.add(offset);
+                super.scanField(field, type, offset);
             }
 
             if (field.getAnnotation(LIRInstruction.Opcode.class) != null) {
@@ -334,39 +292,6 @@
         }
     }
 
-    private static void forEach(LIRInstruction obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValueProcedure proc) {
-        for (int i = 0; i < offsets.length; i++) {
-            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
-
-            if (i < directCount) {
-                Value value = getValue(obj, offsets[i]);
-                if (isAddress(value)) {
-                    doAddress(asAddress(value), mode, flags[i], proc);
-                } else {
-                    setValue(obj, offsets[i], proc.doValue(value, mode, flags[i]));
-                }
-            } else {
-                Value[] values = getValueArray(obj, offsets[i]);
-                for (int j = 0; j < values.length; j++) {
-                    Value value = values[j];
-                    if (isAddress(value)) {
-                        doAddress(asAddress(value), mode, flags[i], proc);
-                    } else {
-                        values[j] = proc.doValue(value, mode, flags[i]);
-                    }
-                }
-            }
-        }
-    }
-
-    private static void doAddress(Address address, OperandMode mode, EnumSet<OperandFlag> flags, ValueProcedure proc) {
-        assert flags.contains(OperandFlag.ADDR);
-        Value[] components = address.components();
-        for (int i = 0; i < components.length; i++) {
-            components[i] = proc.doValue(components[i], mode, LIRInstruction.ADDRESS_FLAGS);
-        }
-    }
-
     public final Value forEachRegisterHint(LIRInstruction obj, OperandMode mode, ValueProcedure proc) {
         int hintDirectCount = 0;
         long[] hintOffsets = null;
@@ -401,18 +326,6 @@
         return null;
     }
 
-    private static Value getValue(LIRInstruction obj, long offset) {
-        return (Value) unsafe.getObject(obj, offset);
-    }
-
-    private static void setValue(LIRInstruction obj, long offset, Value value) {
-        unsafe.putObject(obj, offset, value);
-    }
-
-    private static Value[] getValueArray(LIRInstruction obj, long offset) {
-        return (Value[]) unsafe.getObject(obj, offset);
-    }
-
     private static LIRFrameState getState(LIRInstruction obj, long offset) {
         return (LIRFrameState) unsafe.getObject(obj, offset);
     }
@@ -447,65 +360,4 @@
 
         return result.toString();
     }
-
-    private void appendValues(StringBuilder result, LIRInstruction obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) {
-        int total = 0;
-        for (long[] offsets : moffsets) {
-            total += offsets.length;
-        }
-        if (total == 0) {
-            return;
-        }
-
-        result.append(start);
-        if (total > 1) {
-            result.append(startMultiple);
-        }
-        String sep = "";
-        for (int i = 0; i < moffsets.length; i++) {
-            long[] offsets = moffsets[i];
-
-            for (int j = 0; j < offsets.length; j++) {
-                result.append(sep).append(prefix[i]);
-                long offset = offsets[j];
-                if (total > 1) {
-                    result.append(fieldNames.get(offset)).append(": ");
-                }
-                result.append(getFieldString(obj, offset));
-                sep = ", ";
-            }
-        }
-        if (total > 1) {
-            result.append(endMultiple);
-        }
-        result.append(end);
-    }
-
-    private String getFieldString(Object obj, long offset) {
-        Class<?> type = fieldTypes.get(offset);
-        if (type == int.class) {
-            return String.valueOf(unsafe.getInt(obj, offset));
-        } else if (type == long.class) {
-            return String.valueOf(unsafe.getLong(obj, offset));
-        } else if (type == boolean.class) {
-            return String.valueOf(unsafe.getBoolean(obj, offset));
-        } else if (type == float.class) {
-            return String.valueOf(unsafe.getFloat(obj, offset));
-        } else if (type == double.class) {
-            return String.valueOf(unsafe.getDouble(obj, offset));
-        } else if (!type.isPrimitive()) {
-            Object value = unsafe.getObject(obj, offset);
-            if (!type.isArray()) {
-                return String.valueOf(value);
-            } else if (type == int[].class) {
-                return Arrays.toString((int[]) value);
-            } else if (type == double[].class) {
-                return Arrays.toString((double[]) value);
-            } else if (!type.getComponentType().isPrimitive()) {
-                return Arrays.toString((Object[]) value);
-            }
-        }
-        assert false : "unhandled field type: " + type;
-        return "";
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Fri Mar 08 13:19:28 2013 +0100
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir;
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.LIRInstruction.OperandFlag;
+import com.oracle.graal.lir.LIRInstruction.OperandMode;
+import com.oracle.graal.lir.LIRInstruction.ValueProcedure;
+
+abstract class LIRIntrospection extends FieldIntrospection {
+
+    private static final Class<Value> VALUE_CLASS = Value.class;
+    private static final Class<Constant> CONSTANT_CLASS = Constant.class;
+    private static final Class<Value[]> VALUE_ARRAY_CLASS = Value[].class;
+
+    public LIRIntrospection(Class<?> clazz) {
+        super(clazz);
+    }
+
+    protected static class OperandModeAnnotation {
+
+        public final ArrayList<Long> scalarOffsets = new ArrayList<>();
+        public final ArrayList<Long> arrayOffsets = new ArrayList<>();
+        public final Map<Long, EnumSet<OperandFlag>> flags = new HashMap<>();
+    }
+
+    protected abstract static class FieldScanner extends BaseFieldScanner {
+
+        public final Map<Class<? extends Annotation>, OperandModeAnnotation> valueAnnotations;
+        public final ArrayList<Long> stateOffsets = new ArrayList<>();
+
+        public FieldScanner(CalcOffset calc) {
+            super(calc);
+
+            valueAnnotations = new HashMap<>();
+        }
+
+        protected OperandModeAnnotation getOperandModeAnnotation(Field field) {
+            OperandModeAnnotation result = null;
+            for (Entry<Class<? extends Annotation>, OperandModeAnnotation> entry : valueAnnotations.entrySet()) {
+                Annotation annotation = field.getAnnotation(entry.getKey());
+                if (annotation != null) {
+                    assert result == null : "Field has two operand mode annotations: " + field;
+                    result = entry.getValue();
+                }
+            }
+            return result;
+        }
+
+        protected abstract EnumSet<OperandFlag> getFlags(Field field);
+
+        @Override
+        protected void scanField(Field field, Class<?> type, long offset) {
+            if (VALUE_CLASS.isAssignableFrom(type) && type != CONSTANT_CLASS) {
+                assert !Modifier.isFinal(field.getModifiers()) : "Value field must not be declared final because it is modified by register allocator: " + field;
+                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                assert annotation != null : "Field must have operand mode annotation: " + field;
+                annotation.scalarOffsets.add(offset);
+                annotation.flags.put(offset, getFlags(field));
+            } else if (VALUE_ARRAY_CLASS.isAssignableFrom(type)) {
+                OperandModeAnnotation annotation = getOperandModeAnnotation(field);
+                assert annotation != null : "Field must have operand mode annotation: " + field;
+                annotation.arrayOffsets.add(offset);
+                annotation.flags.put(offset, getFlags(field));
+            } else {
+                assert getOperandModeAnnotation(field) == null : "Field must not have operand mode annotation: " + field;
+                assert field.getAnnotation(LIRInstruction.State.class) == null : "Field must not have state annotation: " + field;
+                dataOffsets.add(offset);
+            }
+        }
+    }
+
+    protected static void forEach(Object obj, int directCount, long[] offsets, OperandMode mode, EnumSet<OperandFlag>[] flags, ValueProcedure proc) {
+        for (int i = 0; i < offsets.length; i++) {
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(flags[i]);
+
+            if (i < directCount) {
+                Value value = getValue(obj, offsets[i]);
+                if (value instanceof CompositeValue) {
+                    CompositeValue composite = (CompositeValue) value;
+                    composite.forEachComponent(mode, proc);
+                } else {
+                    setValue(obj, offsets[i], proc.doValue(value, mode, flags[i]));
+                }
+            } else {
+                Value[] values = getValueArray(obj, offsets[i]);
+                for (int j = 0; j < values.length; j++) {
+                    Value value = values[j];
+                    if (value instanceof CompositeValue) {
+                        CompositeValue composite = (CompositeValue) value;
+                        composite.forEachComponent(mode, proc);
+                    } else {
+                        values[j] = proc.doValue(value, mode, flags[i]);
+                    }
+                }
+            }
+        }
+    }
+
+    protected static Value getValue(Object obj, long offset) {
+        return (Value) unsafe.getObject(obj, offset);
+    }
+
+    protected static void setValue(Object obj, long offset, Value value) {
+        unsafe.putObject(obj, offset, value);
+    }
+
+    protected static Value[] getValueArray(Object obj, long offset) {
+        return (Value[]) unsafe.getObject(obj, offset);
+    }
+
+    protected void appendValues(StringBuilder result, Object obj, String start, String end, String startMultiple, String endMultiple, String[] prefix, long[]... moffsets) {
+        int total = 0;
+        for (long[] offsets : moffsets) {
+            total += offsets.length;
+        }
+        if (total == 0) {
+            return;
+        }
+
+        result.append(start);
+        if (total > 1) {
+            result.append(startMultiple);
+        }
+        String sep = "";
+        for (int i = 0; i < moffsets.length; i++) {
+            long[] offsets = moffsets[i];
+
+            for (int j = 0; j < offsets.length; j++) {
+                result.append(sep).append(prefix[i]);
+                long offset = offsets[j];
+                if (total > 1) {
+                    result.append(fieldNames.get(offset)).append(": ");
+                }
+                result.append(getFieldString(obj, offset));
+                sep = ", ";
+            }
+        }
+        if (total > 1) {
+            result.append(endMultiple);
+        }
+        result.append(end);
+    }
+
+    protected String getFieldString(Object obj, long offset) {
+        Class<?> type = fieldTypes.get(offset);
+        if (type == int.class) {
+            return String.valueOf(unsafe.getInt(obj, offset));
+        } else if (type == long.class) {
+            return String.valueOf(unsafe.getLong(obj, offset));
+        } else if (type == boolean.class) {
+            return String.valueOf(unsafe.getBoolean(obj, offset));
+        } else if (type == float.class) {
+            return String.valueOf(unsafe.getFloat(obj, offset));
+        } else if (type == double.class) {
+            return String.valueOf(unsafe.getDouble(obj, offset));
+        } else if (!type.isPrimitive()) {
+            Object value = unsafe.getObject(obj, offset);
+            if (!type.isArray()) {
+                return String.valueOf(value);
+            } else if (type == int[].class) {
+                return Arrays.toString((int[]) value);
+            } else if (type == double[].class) {
+                return Arrays.toString((double[]) value);
+            } else if (!type.getComponentType().isPrimitive()) {
+                return Arrays.toString((Object[]) value);
+            }
+        }
+        assert false : "unhandled field type: " + type;
+        return "";
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Fri Mar 08 11:23:28 2013 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java	Fri Mar 08 13:19:28 2013 +0100
@@ -150,7 +150,7 @@
         compilationResult.recordSafepoint(pos, debugInfo);
     }
 
-    public Address recordDataReferenceInCode(Constant data, int alignment, boolean inlined) {
+    public AbstractAddress recordDataReferenceInCode(Constant data, int alignment, boolean inlined) {
         assert data != null;
         int pos = asm.codeBuffer.position();
         Debug.log("Data reference in code: pos = %d, data = %s", pos, data.toString());
@@ -176,11 +176,11 @@
     /**
      * Returns the address of a float constant that is embedded as a data references into the code.
      */
-    public Address asFloatConstRef(Value value) {
+    public AbstractAddress asFloatConstRef(Value value) {
         return asFloatConstRef(value, 4);
     }
 
-    public Address asFloatConstRef(Value value, int alignment) {
+    public AbstractAddress asFloatConstRef(Value value, int alignment) {
         assert value.getKind() == Kind.Float && isConstant(value);
         return recordDataReferenceInCode((Constant) value, alignment, false);
     }
@@ -188,11 +188,11 @@
     /**
      * Returns the address of a double constant that is embedded as a data references into the code.
      */
-    public Address asDoubleConstRef(Value value) {
+    public AbstractAddress asDoubleConstRef(Value value) {
         return asDoubleConstRef(value, 8);
     }
 
-    public Address asDoubleConstRef(Value value, int alignment) {
+    public AbstractAddress asDoubleConstRef(Value value, int alignment) {
         assert value.getKind() == Kind.Double && isConstant(value);
         return recordDataReferenceInCode((Constant) value, alignment, false);
     }
@@ -200,41 +200,39 @@
     /**
      * Returns the address of a long constant that is embedded as a data references into the code.
      */
-    public Address asLongConstRef(Value value) {
+    public AbstractAddress asLongConstRef(Value value) {
         assert value.getKind() == Kind.Long && isConstant(value);
         return recordDataReferenceInCode((Constant) value, 8, false);
     }
 
-    public Address asIntAddr(Value value) {
+    public AbstractAddress asIntAddr(Value value) {
         assert value.getKind() == Kind.Int;
         return asAddress(value);
     }
 
-    public Address asLongAddr(Value value) {
+    public AbstractAddress asLongAddr(Value value) {
         assert value.getKind() == Kind.Long;
         return asAddress(value);
     }
 
-    public Address asObjectAddr(Value value) {
+    public AbstractAddress asObjectAddr(Value value) {
         assert value.getKind() == Kind.Object;
         return asAddress(value);
     }
 
-    public Address asFloatAddr(Value value) {
+    public AbstractAddress asFloatAddr(Value value) {
         assert value.getKind() == Kind.Float;
         return asAddress(value);
     }
 
-    public Address asDoubleAddr(Value value) {
+    public AbstractAddress asDoubleAddr(Value value) {
         assert value.getKind() == Kind.Double;
         return asAddress(value);
     }
 
-    public Address asAddress(Value value) {
-        if (isStackSlot(value)) {
-            StackSlot slot = (StackSlot) value;
-            return asm.makeAddress(slot.getKind(), frameMap.registerConfig.getFrameRegister().asValue(), frameMap.offsetForStackSlot(slot));
-        }
-        return (Address) value;
+    public AbstractAddress asAddress(Value value) {
+        assert isStackSlot(value);
+        StackSlot slot = asStackSlot(value);
+        return asm.makeAddress(frameMap.registerConfig.getFrameRegister(), frameMap.offsetForStackSlot(slot));
     }
 }
--- a/graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTXAddress.java	Fri Mar 08 11:23:28 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.ptx;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-
-/**
- * Represents an address in target machine memory, specified via some combination of a base register
- * and a displacement.
- */
-public final class PTXAddress extends Address {
-
-    private static final long serialVersionUID = 8343625682010474837L;
-
-    private final Value[] base;
-    private final long displacement;
-
-    /**
-     * Creates an {@link PTXAddress} with given base register and no displacement.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     */
-    public PTXAddress(Kind kind, Value base) {
-        this(kind, base, 0);
-    }
-
-    /**
-     * Creates an {@link PTXAddress} with given base register and a displacement. This is the most
-     * general constructor.
-     * 
-     * @param kind the kind of the value being addressed
-     * @param base the base register
-     * @param displacement the displacement
-     */
-    public PTXAddress(Kind kind, Value base, long displacement) {
-        super(kind);
-        this.base = new Value[1];
-        this.setBase(base);
-        this.displacement = displacement;
-
-        assert !isConstant(base) && !isStackSlot(base);
-    }
-
-    @Override
-    public Value[] components() {
-        return base;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder s = new StringBuilder();
-        s.append(getKind().getJavaName()).append("[");
-        String sep = "";
-        if (isLegal(getBase())) {
-            s.append(getBase());
-            sep = " + ";
-        }
-        if (getDisplacement() < 0) {
-            s.append(" - ").append(-getDisplacement());
-        } else if (getDisplacement() > 0) {
-            s.append(sep).append(getDisplacement());
-        }
-        s.append("]");
-        return s.toString();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof PTXAddress) {
-            PTXAddress addr = (PTXAddress) obj;
-            return getKind() == addr.getKind() && getDisplacement() == addr.getDisplacement() && getBase().equals(addr.getBase());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return getBase().hashCode() ^ ((int) getDisplacement() << 4) ^ (getKind().ordinal() << 12);
-    }
-
-    /**
-     * @return Base register that defines the start of the address computation. If not present, is
-     *         denoted by {@link Value#ILLEGAL}.
-     */
-    public Value getBase() {
-        return base[0];
-    }
-
-    public void setBase(Value base) {
-        this.base[0] = base;
-    }
-
-    /**
-     * @return Optional additive displacement.
-     */
-    public long getDisplacement() {
-        return displacement;
-    }
-}
--- a/mx/projects	Fri Mar 08 11:23:28 2013 +0100
+++ b/mx/projects	Fri Mar 08 13:19:28 2013 +0100
@@ -248,7 +248,7 @@
 # graal.compiler.ptx.test
 project@com.oracle.graal.compiler.ptx.test@subDir=graal
 project@com.oracle.graal.compiler.ptx.test@sourceDirs=src
-project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.compiler.ptx,com.oracle.graal.compiler.test
+project@com.oracle.graal.compiler.ptx.test@dependencies=com.oracle.graal.compiler.ptx,com.oracle.graal.compiler.test,com.oracle.graal.ptx
 project@com.oracle.graal.compiler.ptx.test@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.compiler.ptx.test@javaCompliance=1.7
 
@@ -331,7 +331,7 @@
 # graal.asm.ptx
 project@com.oracle.graal.asm.ptx@subDir=graal
 project@com.oracle.graal.asm.ptx@sourceDirs=src
-project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.asm,com.oracle.graal.ptx
+project@com.oracle.graal.asm.ptx@dependencies=com.oracle.graal.asm
 project@com.oracle.graal.asm.ptx@checkstyle=com.oracle.graal.graph
 project@com.oracle.graal.asm.ptx@javaCompliance=1.7