changeset 14707:6ce6c4ccba8f

initial support for memory arithmetic on x86
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Thu, 20 Mar 2014 15:57:03 -0700
parents 579a2a124c95
children 0f73f8b75b81
files CHANGELOG.md graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryArithmeticTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java
diffstat 39 files changed, 3100 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Thu Mar 20 13:41:32 2014 -0700
+++ b/CHANGELOG.md	Thu Mar 20 15:57:03 2014 -0700
@@ -9,6 +9,7 @@
 * New (tested) invariant that equality comparisons for `JavaType`/`JavaMethod`/`JavaField` values use `.equals()` instead of `==`.
 * Made graph caching compilation-local.
 * Added AllocSpy tool for analyzing allocation in Graal using the [Java Allocation Instrumenter](https://code.google.com/p/java-allocation-instrumenter/).
+* Initial support for memory arithmetic operations on x86
 
 ### Truffle
 * New API `TruffleRuntime#createCallNode` to create call nodes and to give the runtime system control over its implementation.
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Thu Mar 20 15:57:03 2014 -0700
@@ -1669,6 +1669,13 @@
         emitInt(imm32);
     }
 
+    public final void testl(AMD64Address dst, int imm32) {
+        prefixq(dst);
+        emitByte(0xF7);
+        emitOperandHelper(0, dst);
+        emitInt(imm32);
+    }
+
     public final void testl(Register dst, Register src) {
         prefixAndEncode(dst.encoding, src.encoding);
         emitArith(0x85, 0xC0, dst, src);
@@ -2064,6 +2071,13 @@
         emitOperandHelper(dst, src);
     }
 
+    public final void cmpq(AMD64Address dst, int imm32) {
+        prefixq(dst);
+        emitByte(0x81);
+        emitOperandHelper(7, dst);
+        emitInt(imm32);
+    }
+
     public final void cmpq(Register dst, int imm32) {
         prefixqAndEncode(dst.encoding);
         emitArith(0x81, 0xF8, dst, imm32);
@@ -2410,6 +2424,13 @@
         emitOperandHelper(dst, src);
     }
 
+    public final void testq(AMD64Address dst, int imm32) {
+        prefixq(dst);
+        emitByte(0xF7);
+        emitOperandHelper(0, dst);
+        emitInt(imm32);
+    }
+
     public final void xorq(Register dst, int imm32) {
         prefixqAndEncode(dst.encoding);
         emitArith(0x81, 0xF0, dst, imm32);
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Thu Mar 20 15:57:03 2014 -0700
@@ -41,6 +41,7 @@
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryCommutative;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryMemory;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegConst;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegReg;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.BinaryRegStack;
@@ -48,7 +49,9 @@
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.DivRemOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.FPDivRemOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary1Op;
+import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2MemoryOp;
 import com.oracle.graal.lir.amd64.AMD64Arithmetic.Unary2Op;
+import com.oracle.graal.lir.amd64.AMD64Compare.CompareMemoryOp;
 import com.oracle.graal.lir.amd64.AMD64Compare.CompareOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
@@ -58,6 +61,7 @@
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.TableSwitchOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaOp;
+import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MembarOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
@@ -65,6 +69,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.util.*;
 
@@ -334,6 +339,42 @@
         }
     }
 
+    protected void emitCompareMemoryConOp(Kind kind, AMD64AddressValue left, Value right, LIRFrameState state) {
+        assert kind == right.getKind();
+        switch (kind) {
+            case Int:
+                append(new CompareMemoryOp(ICMP, left, right, state));
+                break;
+            case Long:
+                append(new CompareMemoryOp(LCMP, left, right, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    protected void emitCompareRegMemoryOp(Kind kind, Value left, AMD64AddressValue right, LIRFrameState state) {
+        switch (kind) {
+            case Int:
+                append(new CompareMemoryOp(ICMP, left, right, state));
+                break;
+            case Long:
+                append(new CompareMemoryOp(LCMP, left, right, state));
+                break;
+            case Object:
+                append(new CompareMemoryOp(ACMP, left, right, state));
+                break;
+            case Float:
+                append(new CompareMemoryOp(FCMP, left, right, state));
+                break;
+            case Double:
+                append(new CompareMemoryOp(DCMP, left, right, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     /**
      * This method emits the compare instruction, and may reorder the operands. It returns true if
      * it did so.
@@ -514,7 +555,7 @@
                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
                 if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
                     FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
-                    if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && operand(otherDivRem) == null) {
+                    if (otherDivRem.x() == divRem.x() && otherDivRem.y() == divRem.y() && !hasOperand(otherDivRem)) {
                         Value[] results = emitIntegerDivRem(operand(divRem.x()), operand(divRem.y()), (DeoptimizingNode) valueNode);
                         if (divRem instanceof IntegerDivNode) {
                             setResult(divRem, results[0]);
@@ -532,6 +573,38 @@
         return false;
     }
 
+    protected MemoryArithmeticLIRLowerer memoryPeephole;
+
+    @Override
+    protected MemoryArithmeticLIRLowerer getMemoryLowerer() {
+        if (memoryPeephole == null) {
+            // Use the generic one
+            memoryPeephole = new AMD64MemoryPeephole(this);
+        }
+        return memoryPeephole;
+    }
+
+    protected Value emitBinaryMemory(AMD64Arithmetic op, Kind kind, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
+        Variable result = newVariable(a.getKind());
+        append(new BinaryMemory(op, kind, result, a, location, state));
+        return result;
+    }
+
+    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, AMD64AddressValue address, LIRFrameState state) {
+        Variable result = newVariable(kind);
+        append(new Unary2MemoryOp(op, result, address, state));
+        return result;
+    }
+
+    protected Value emitZeroExtendMemory(Kind memoryKind, int resultBits, AMD64AddressValue address, LIRFrameState state) {
+        assert memoryKind.isUnsigned();
+        // Issue a zero extending load of the proper bit size and set the result to
+        // the proper kind.
+        Variable result = newVariable(resultBits == 32 ? Kind.Int : Kind.Long);
+        append(new LoadOp(memoryKind, result, address, state));
+        return result;
+    }
+
     private void emitDivRem(AMD64Arithmetic op, Value a, Value b, LIRFrameState state) {
         AllocatableValue rax = AMD64.rax.asValue(a.getPlatformKind());
         emitMove(rax, a);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64MemoryPeephole.java	Thu Mar 20 15:57:03 2014 -0700
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.compiler.amd64;
+
+import static com.oracle.graal.lir.amd64.AMD64Arithmetic.*;
+import static com.oracle.graal.nodes.ConstantNode.*;
+import static com.oracle.graal.phases.GraalOptions.*;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.FloatBranchOp;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public class AMD64MemoryPeephole implements MemoryArithmeticLIRLowerer {
+    protected final AMD64LIRGenerator gen;
+    protected List<ValueNode> deferredNodes;
+
+    protected AMD64MemoryPeephole(AMD64LIRGenerator gen) {
+        this.gen = gen;
+    }
+
+    public Value setResult(ValueNode x, Value operand) {
+        return gen.setResult(x, operand);
+    }
+
+    @Override
+    public boolean memoryPeephole(Access access, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred) {
+        this.deferredNodes = deferred;
+        boolean result = operation.generate(this, access);
+        if (result) {
+            Debug.log("merge %s %s with %1s %s %s", access, access.asNode().stamp(), operation, result, access.asNode().graph().method());
+        } else {
+            Debug.log("can't merge %s %s with %1s", access, access.asNode().stamp(), operation);
+        }
+        this.deferredNodes = null;
+        return result;
+    }
+
+    protected LIRFrameState getState(Access access) {
+        if (access instanceof DeoptimizingNode) {
+            return gen.state((DeoptimizingNode) access);
+        }
+        return null;
+    }
+
+    protected AMD64AddressValue makeAddress(Access access) {
+        return (AMD64AddressValue) access.nullCheckLocation().generateAddress(gen, gen.operand(access.object()));
+    }
+
+    protected Value emitBinaryMemory(AMD64Arithmetic op, boolean commutative, ValueNode x, ValueNode y, Access access) {
+        ValueNode other = x;
+        if (other == access) {
+            if (commutative) {
+                other = y;
+            } else {
+                return null;
+            }
+        }
+        ensureEvaluated(other);
+        return gen.emitBinaryMemory(op, access.nullCheckLocation().getValueKind(), gen.asAllocatable(gen.operand(other)), makeAddress(access), getState(access));
+    }
+
+    /**
+     * Constants with multiple users need to be evaluated in the right location so that later users
+     * can pick up the operand. Make sure that happens when it needs to.
+     */
+    protected void ensureEvaluated(ValueNode node) {
+        evaluateDeferred(node);
+        evaluateDeferred();
+    }
+
+    protected void evaluateDeferred(ValueNode node) {
+        // Ensure the other input value has a generated value.
+        if (ConstantNodeRecordsUsages) {
+            if (!gen.hasOperand(node)) {
+                assert node instanceof ConstantNode : node;
+                ((ConstantNode) node).generate(gen);
+            }
+        }
+    }
+
+    protected void evaluateDeferred() {
+        if (deferredNodes != null) {
+            for (ValueNode node : deferredNodes) {
+                evaluateDeferred(node);
+            }
+        }
+    }
+
+    protected Value emitConvert2MemoryOp(PlatformKind kind, AMD64Arithmetic op, Access access) {
+        AMD64AddressValue address = makeAddress(access);
+        LIRFrameState state = getState(access);
+        evaluateDeferred();
+        return gen.emitConvert2MemoryOp(kind, op, address, state);
+    }
+
+    @Override
+    public Value emitAddMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IADD, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LADD, true, x, y, access);
+            case Float:
+                return emitBinaryMemory(FADD, true, x, y, access);
+            case Double:
+                return emitBinaryMemory(DADD, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitSubMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(ISUB, false, x, y, access);
+            case Long:
+                return emitBinaryMemory(LSUB, false, x, y, access);
+            case Float:
+                return emitBinaryMemory(FSUB, false, x, y, access);
+            case Double:
+                return emitBinaryMemory(DSUB, false, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitMulMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IMUL, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LMUL, true, x, y, access);
+            case Float:
+                return emitBinaryMemory(FMUL, true, x, y, access);
+            case Double:
+                return emitBinaryMemory(DMUL, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitDivMemory(ValueNode x, ValueNode y, Access access) {
+        return null;
+    }
+
+    @Override
+    public Value emitRemMemory(ValueNode x, ValueNode y, Access access) {
+        return null;
+    }
+
+    @Override
+    public Value emitAndMemory(ValueNode x, ValueNode y, Access access) {
+        Kind kind = access.nullCheckLocation().getValueKind();
+        switch (kind) {
+            case Int:
+                return emitBinaryMemory(IAND, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LAND, true, x, y, access);
+            case Short: {
+                ValueNode other = x == access ? y : x;
+                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
+                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
+                    // Convert to unsigned load
+                    ensureEvaluated(other);
+                    return emitZeroExtendMemory(16, 32, access);
+                }
+                return null;
+            }
+            case Byte: {
+                if (OptFoldMemory.getValue()) {
+                    return null;
+                }
+                ValueNode other = x == access ? y : x;
+                Constant constant = other instanceof ConstantNode ? ((ConstantNode) other).asConstant() : null;
+                if (constant != null && constant.asInt() == IntegerStamp.defaultMask(kind.getBitCount())) {
+                    // Convert to unsigned load
+                    ensureEvaluated(other);
+                    return emitConvert2MemoryOp(Kind.Int, MOV_B2UI, access);
+                }
+                return null;
+            }
+
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitOrMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IOR, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LOR, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitXorMemory(ValueNode x, ValueNode y, Access access) {
+        switch (access.nullCheckLocation().getValueKind()) {
+            case Int:
+                return emitBinaryMemory(IXOR, true, x, y, access);
+            case Long:
+                return emitBinaryMemory(LXOR, true, x, y, access);
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public Value emitReinterpretMemory(Stamp stamp, Access access) {
+        PlatformKind to = gen.getPlatformKind(stamp);
+        Kind from = access.nullCheckLocation().getValueKind();
+        assert to != from : "should have been eliminated";
+
+        /*
+         * Conversions between integer to floating point types require moves between CPU and FPU
+         * registers.
+         */
+        switch ((Kind) to) {
+            case Int:
+                switch (from) {
+                    case Float:
+                        return emitConvert2MemoryOp(to, MOV_F2I, access);
+                }
+                break;
+            case Long:
+                switch (from) {
+                    case Double:
+                        return emitConvert2MemoryOp(to, MOV_D2L, access);
+                }
+                break;
+            case Float:
+                switch (from) {
+                    case Int:
+                        return emitConvert2MemoryOp(to, MOV_I2F, access);
+                }
+                break;
+            case Double:
+                switch (from) {
+                    case Long:
+                        return emitConvert2MemoryOp(to, MOV_L2D, access);
+                }
+                break;
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Value emitFloatConvertMemory(FloatConvert op, Access access) {
+        switch (op) {
+            case D2F:
+                return emitConvert2MemoryOp(Kind.Float, D2F, access);
+            case D2I:
+                return emitConvert2MemoryOp(Kind.Int, D2I, access);
+            case D2L:
+                return emitConvert2MemoryOp(Kind.Long, D2L, access);
+            case F2D:
+                return emitConvert2MemoryOp(Kind.Double, F2D, access);
+            case F2I:
+                return emitConvert2MemoryOp(Kind.Int, F2I, access);
+            case F2L:
+                return emitConvert2MemoryOp(Kind.Long, F2L, access);
+            case I2D:
+                return emitConvert2MemoryOp(Kind.Double, I2D, access);
+            case I2F:
+                return emitConvert2MemoryOp(Kind.Float, I2F, access);
+            case L2D:
+                return emitConvert2MemoryOp(Kind.Double, L2D, access);
+            case L2F:
+                return emitConvert2MemoryOp(Kind.Float, L2F, access);
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
+    @Override
+    public Value emitSignExtendMemory(Access access, int fromBits, int toBits) {
+        assert fromBits <= toBits && toBits <= 64;
+        if (fromBits == toBits) {
+            return null;
+        } else if (toBits > 32) {
+            // sign extend to 64 bits
+            switch (fromBits) {
+                case 8:
+                    return emitConvert2MemoryOp(Kind.Long, B2L, access);
+                case 16:
+                    return emitConvert2MemoryOp(Kind.Long, S2L, access);
+                case 32:
+                    return emitConvert2MemoryOp(Kind.Long, I2L, access);
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        } else {
+
+            // sign extend to 32 bits (smaller values are internally represented as 32 bit values)
+            switch (fromBits) {
+                case 8:
+                    return emitConvert2MemoryOp(Kind.Int, B2I, access);
+                case 16:
+                    return emitConvert2MemoryOp(Kind.Int, S2I, access);
+                case 32:
+                    return null;
+                default:
+                    throw GraalInternalError.unimplemented("unsupported sign extension (" + fromBits + " bit -> " + toBits + " bit)");
+            }
+        }
+    }
+
+    @Override
+    public Value emitNarrowMemory(int resultBits, Access access) {
+        // TODO
+        return null;
+    }
+
+    @Override
+    public Value emitZeroExtendMemory(int inputBits, int resultBits, Access access) {
+        assert resultBits == 32 || resultBits == 64;
+        Kind memoryKind = access.nullCheckLocation().getValueKind();
+        if (memoryKind.getBitCount() != inputBits && !memoryKind.isUnsigned()) {
+            // The memory being read from is signed and smaller than the result size so
+            // this is a sign extension to inputBits followed by a zero extension to resultBits
+            // which can't be expressed in a memory operation.
+            return null;
+        }
+        if (memoryKind == Kind.Short) {
+            memoryKind = Kind.Char;
+        }
+        evaluateDeferred();
+        return gen.emitZeroExtendMemory(memoryKind, resultBits, makeAddress(access), getState(access));
+    }
+
+    public boolean emitIfMemory(IfNode x, Access access) {
+        return emitBranchMemory(x.condition(), access, gen.getLIRBlock(x.trueSuccessor()), gen.getLIRBlock(x.falseSuccessor()), x.probability(x.trueSuccessor()));
+    }
+
+    private boolean emitBranchMemory(LogicNode node, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        if (node instanceof IsNullNode) {
+            // can't do anything interesting.
+            return false;
+        } else if (node instanceof CompareNode) {
+            CompareNode compare = (CompareNode) node;
+            return emitCompareBranchMemory(compare, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else if (node instanceof LogicConstantNode) {
+            return false;
+        } else if (node instanceof IntegerTestNode) {
+            return emitIntegerTestBranchMemory((IntegerTestNode) node, access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        } else {
+            throw GraalInternalError.unimplemented(node.toString());
+        }
+    }
+
+    public boolean emitCompareBranchMemory(CompareNode compare, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        return emitCompareBranchMemory(compare.x(), compare.y(), access, compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    public boolean emitIntegerTestBranchMemory(IntegerTestNode test, Access access, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
+        return emitIntegerTestBranchMemory(test.x(), test.y(), access, trueSuccessor, falseSuccessor, trueSuccessorProbability);
+    }
+
+    private boolean emitIntegerTestBranchMemory(ValueNode left, ValueNode right, Access access, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
+        assert left == access || right == access;
+        ValueNode other = left == access ? right : left;
+        Kind kind = access.nullCheckLocation().getValueKind();
+        if (other.isConstant()) {
+            Constant constant = other.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return false;
+            }
+            ensureEvaluated(other);
+            gen.append(new AMD64TestMemoryOp(makeAddress(access), constant, getState(access)));
+        } else {
+            evaluateDeferred();
+            gen.append(new AMD64TestMemoryOp(makeAddress(access), gen.operand(other), getState(access)));
+        }
+
+        gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
+        return true;
+    }
+
+    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        assert left == access || right == access;
+        ValueNode other = left == access ? right : left;
+        Kind kind = access.nullCheckLocation().getValueKind();
+        boolean mirrored = false;
+
+        if (other.isConstant()) {
+            Constant constant = other.asConstant();
+            if (kind == Kind.Long && !NumUtil.isInt(constant.asLong())) {
+                // Only imm32 as long
+                return false;
+            }
+            if (kind.isNumericFloat()) {
+                Debug.log("Skipping constant compares for float kinds");
+                return false;
+            }
+            if (kind == Kind.Object) {
+                if (!access.isCompressible() && !constant.isNull()) {
+                    Debug.log("Skipping constant compares for Object kinds");
+                    return false;
+                }
+            }
+            if (kind != kind.getStackKind()) {
+                Debug.log("Skipping constant compares for stack kinds");
+                return false;
+            }
+            ensureEvaluated(other);
+            gen.emitCompareMemoryConOp(kind, makeAddress(access), constant, getState(access));
+            mirrored = right == access;
+        } else {
+            if (kind != kind.getStackKind()) {
+                // Register compares only work for stack kinds
+                Debug.log("Register compares only work for stack kinds");
+                return false;
+            } else if (kind == Kind.Object) {
+                // Can't compare against objects since they require encode/decode
+                Debug.log("Skipping compares for Object kinds");
+                return false;
+            }
+
+            evaluateDeferred();
+            gen.emitCompareRegMemoryOp(kind, gen.operand(other), makeAddress(access), getState(access));
+            mirrored = left == access;
+        }
+
+        Condition finalCondition = mirrored ? cond.mirror() : cond;
+        switch (kind.getStackKind()) {
+            case Long:
+            case Int:
+            case Object:
+                gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+                return true;
+            case Float:
+            case Double:
+                gen.append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
+                return true;
+            default:
+                throw GraalInternalError.shouldNotReachHere("" + kind.getStackKind());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryArithmeticTest.java	Thu Mar 20 15:57:03 2014 -0700
@@ -0,0 +1,1525 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+
+public class MemoryArithmeticTest extends GraalCompilerTest {
+
+    @Override
+    protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph) {
+        return super.getCode(method, graph, true);
+    }
+
+    /**
+     * Called before a test is executed.
+     */
+    @Override
+    protected void before(Method method) {
+        // don't let any null exception tracking change the generated code.
+        getMetaAccess().lookupJavaMethod(method).reprofile();
+    }
+
+    /**
+     * A dummy field used by some tests to create side effects.
+     */
+    protected static int count;
+
+    static class FieldObject {
+        boolean booleanValue;
+        byte byteValue;
+        short shortValue;
+        char charValue;
+        int intValue;
+        float floatValue;
+        long longValue;
+        double doubleValue;
+        Object objectValue;
+    }
+
+    static final boolean booleanTestValue1 = false;
+    static final byte byteTestValue1 = 0;
+    static final short shortTestValue1 = 0;
+    static final char charTestValue1 = 0;
+    static final int intTestValue1 = 0;
+    static final float floatTestValue1 = 0;
+    static final long longTestValue1 = 0;
+    static final double doubleTestValue1 = 0;
+    static final Object objectTestValue1 = null;
+
+    static final boolean booleanTestValue2 = true;
+    static final byte byteTestValue2 = Byte.MAX_VALUE;
+    static final short shortTestValue2 = Short.MAX_VALUE;
+    static final char charTestValue2 = Character.MAX_VALUE;
+    static final int intTestValue2 = Integer.MAX_VALUE;
+    static final float floatTestValue2 = Float.MAX_VALUE;
+    static final long longTestValue2 = Long.MAX_VALUE;
+    static final double doubleTestValue2 = Double.MAX_VALUE;
+    static final Object objectTestValue2 = "String";
+
+    public static Object testBooleanCompare(FieldObject f, boolean booleanValue) {
+        if (f.booleanValue == booleanValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testBooleanCompareConstant1(FieldObject f) {
+        if (f.booleanValue == booleanTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testBooleanCompareConstant2(FieldObject f) {
+        if (f.booleanValue == booleanTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testBooleanCompares() {
+        FieldObject f = new FieldObject();
+        test("testBooleanCompare", f, booleanTestValue1);
+        test("testBooleanCompareConstant1", f);
+        test("testBooleanCompareConstant2", f);
+    }
+
+    @Test
+    public void testBooleanNullCompares() {
+        test("testBooleanCompare", null, booleanTestValue1);
+    }
+
+    public static Object testByteCompare(FieldObject f, byte byteValue) {
+        if (f.byteValue == byteValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareConstant1(FieldObject f) {
+        if (f.byteValue == byteTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testByteCompareConstant2(FieldObject f) {
+        if (f.byteValue == byteTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testByteCompares() {
+        FieldObject f = new FieldObject();
+        test("testByteCompare", f, byteTestValue1);
+        test("testByteCompareConstant1", f);
+        test("testByteCompareConstant2", f);
+    }
+
+    @Test
+    public void testByteNullCompares() {
+        test("testByteCompare", null, byteTestValue1);
+    }
+
+    public static Object testShortCompare(FieldObject f, short shortValue) {
+        if (f.shortValue == shortValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareConstant1(FieldObject f) {
+        if (f.shortValue == shortTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testShortCompareConstant2(FieldObject f) {
+        if (f.shortValue == shortTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testShortCompares() {
+        FieldObject f = new FieldObject();
+        test("testShortCompare", f, shortTestValue1);
+        test("testShortCompareConstant1", f);
+        test("testShortCompareConstant2", f);
+    }
+
+    @Test
+    public void testShortNullCompares() {
+        test("testShortCompare", null, shortTestValue1);
+    }
+
+    public static Object testCharCompare(FieldObject f, char charValue) {
+        if (f.charValue == charValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareConstant1(FieldObject f) {
+        if (f.charValue == charTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testCharCompareConstant2(FieldObject f) {
+        if (f.charValue == charTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testCharCompares() {
+        FieldObject f = new FieldObject();
+        test("testCharCompare", f, charTestValue1);
+        test("testCharCompareConstant1", f);
+        test("testCharCompareConstant2", f);
+    }
+
+    @Test
+    public void testCharNullCompares() {
+        test("testCharCompare", null, charTestValue1);
+    }
+
+    public static Object testIntCompare(FieldObject f, int intValue) {
+        if (f.intValue == intValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareConstant1(FieldObject f) {
+        if (f.intValue == intTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testIntCompareConstant2(FieldObject f) {
+        if (f.intValue == intTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testIntCompares() {
+        FieldObject f = new FieldObject();
+        test("testIntCompare", f, intTestValue1);
+        test("testIntCompareConstant1", f);
+        test("testIntCompareConstant2", f);
+    }
+
+    @Test
+    public void testIntNullCompares() {
+        test("testIntCompare", null, intTestValue1);
+    }
+
+    public static Object testFloatCompare(FieldObject f, float floatValue) {
+        if (f.floatValue == floatValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareConstant1(FieldObject f) {
+        if (f.floatValue == floatTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testFloatCompareConstant2(FieldObject f) {
+        if (f.floatValue == floatTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testFloatCompares() {
+        FieldObject f = new FieldObject();
+        test("testFloatCompare", f, floatTestValue1);
+        test("testFloatCompareConstant1", f);
+        test("testFloatCompareConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullCompares() {
+        test("testFloatCompare", null, floatTestValue1);
+    }
+
+    public static Object testLongCompare(FieldObject f, long longValue) {
+        if (f.longValue == longValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareConstant1(FieldObject f) {
+        if (f.longValue == longTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testLongCompareConstant2(FieldObject f) {
+        if (f.longValue == longTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testLongCompares() {
+        FieldObject f = new FieldObject();
+        test("testLongCompare", f, longTestValue1);
+        test("testLongCompareConstant1", f);
+        test("testLongCompareConstant2", f);
+    }
+
+    @Test
+    public void testLongNullCompares() {
+        test("testLongCompare", null, longTestValue1);
+    }
+
+    public static Object testDoubleCompare(FieldObject f, double doubleValue) {
+        if (f.doubleValue == doubleValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareConstant1(FieldObject f) {
+        if (f.doubleValue == doubleTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testDoubleCompareConstant2(FieldObject f) {
+        if (f.doubleValue == doubleTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testDoubleCompares() {
+        FieldObject f = new FieldObject();
+        test("testDoubleCompare", f, doubleTestValue1);
+        test("testDoubleCompareConstant1", f);
+        test("testDoubleCompareConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullCompares() {
+        test("testDoubleCompare", null, doubleTestValue1);
+    }
+
+    public static Object testObjectCompare(FieldObject f, Object objectValue) {
+        if (f.objectValue == objectValue) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testObjectCompareConstant1(FieldObject f) {
+        if (f.objectValue == objectTestValue1) {
+            return f;
+        }
+        return null;
+    }
+
+    public static Object testObjectCompareConstant2(FieldObject f) {
+        if (f.objectValue == objectTestValue2) {
+            return f;
+        }
+        return null;
+    }
+
+    @Test
+    public void testObjectCompares() {
+        FieldObject f = new FieldObject();
+        test("testObjectCompare", f, objectTestValue1);
+        test("testObjectCompareConstant1", f);
+        test("testObjectCompareConstant2", f);
+    }
+
+    @Test
+    public void testObjectNullCompares() {
+        test("testObjectCompare", null, objectTestValue1);
+    }
+
+    public static int testByteAdd(FieldObject f, byte byteValue) {
+        return f.byteValue + byteValue;
+    }
+
+    public static int testByteAddConstant1(FieldObject f) {
+        return f.byteValue + byteTestValue1;
+    }
+
+    public static int testByteAddConstant2(FieldObject f) {
+        return f.byteValue + byteTestValue2;
+    }
+
+    @Test
+    public void testByteAdds() {
+        FieldObject f = new FieldObject();
+        test("testByteAdd", f, byteTestValue1);
+        test("testByteAddConstant1", f);
+        test("testByteAddConstant2", f);
+    }
+
+    @Test
+    public void testByteNullAdd() {
+        test("testByteAdd", null, byteTestValue1);
+    }
+
+    public static int testShortAdd(FieldObject f, short shortValue) {
+        return f.shortValue + shortValue;
+    }
+
+    public static int testShortAddConstant1(FieldObject f) {
+        return f.shortValue + shortTestValue1;
+    }
+
+    public static int testShortAddConstant2(FieldObject f) {
+        return f.shortValue + shortTestValue2;
+    }
+
+    @Test
+    public void testShortAdds() {
+        FieldObject f = new FieldObject();
+        test("testShortAdd", f, shortTestValue1);
+        test("testShortAddConstant1", f);
+        test("testShortAddConstant2", f);
+    }
+
+    @Test
+    public void testShortNullAdd() {
+        test("testShortAdd", null, shortTestValue1);
+    }
+
+    public static int testCharAdd(FieldObject f, char charValue) {
+        return f.charValue + charValue;
+    }
+
+    public static int testCharAddConstant1(FieldObject f) {
+        return f.charValue + charTestValue1;
+    }
+
+    public static int testCharAddConstant2(FieldObject f) {
+        return f.charValue + charTestValue2;
+    }
+
+    @Test
+    public void testCharAdds() {
+        FieldObject f = new FieldObject();
+        test("testCharAdd", f, charTestValue1);
+        test("testCharAddConstant1", f);
+        test("testCharAddConstant2", f);
+    }
+
+    @Test
+    public void testCharNullAdd() {
+        test("testCharAdd", null, charTestValue1);
+    }
+
+    public static int testIntAdd(FieldObject f, int intValue) {
+        return f.intValue + intValue;
+    }
+
+    public static int testIntAddConstant1(FieldObject f) {
+        return f.intValue + intTestValue1;
+    }
+
+    public static int testIntAddConstant2(FieldObject f) {
+        return f.intValue + intTestValue2;
+    }
+
+    @Test
+    public void testIntAdds() {
+        FieldObject f = new FieldObject();
+        test("testIntAdd", f, intTestValue1);
+        test("testIntAddConstant1", f);
+        test("testIntAddConstant2", f);
+    }
+
+    @Test
+    public void testIntNullAdd() {
+        test("testIntAdd", null, intTestValue1);
+    }
+
+    public static long testLongAdd(FieldObject f, long longValue) {
+        return f.longValue + longValue;
+    }
+
+    public static long testLongAddConstant1(FieldObject f) {
+        return f.longValue + longTestValue1;
+    }
+
+    public static long testLongAddConstant2(FieldObject f) {
+        return f.longValue + longTestValue2;
+    }
+
+    @Test
+    public void testLongAdds() {
+        FieldObject f = new FieldObject();
+        test("testLongAdd", f, longTestValue1);
+        test("testLongAddConstant1", f);
+        test("testLongAddConstant2", f);
+    }
+
+    @Test
+    public void testLongNullAdd() {
+        test("testLongAdd", null, longTestValue1);
+    }
+
+    public static float testFloatAdd(FieldObject f, float floatValue) {
+        return f.floatValue + floatValue;
+    }
+
+    public static float testFloatAddConstant1(FieldObject f) {
+        return f.floatValue + floatTestValue1;
+    }
+
+    public static float testFloatAddConstant2(FieldObject f) {
+        return f.floatValue + floatTestValue2;
+    }
+
+    @Test
+    public void testFloatAdds() {
+        FieldObject f = new FieldObject();
+        test("testFloatAdd", f, floatTestValue1);
+        test("testFloatAddConstant1", f);
+        test("testFloatAddConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullAdd() {
+        test("testFloatAdd", null, floatTestValue1);
+    }
+
+    public static double testDoubleAdd(FieldObject f, double doubleValue) {
+        return f.doubleValue + doubleValue;
+    }
+
+    public static double testDoubleAddConstant1(FieldObject f) {
+        return f.doubleValue + doubleTestValue1;
+    }
+
+    public static double testDoubleAddConstant2(FieldObject f) {
+        return f.doubleValue + doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleAdds() {
+        FieldObject f = new FieldObject();
+        test("testDoubleAdd", f, doubleTestValue1);
+        test("testDoubleAddConstant1", f);
+        test("testDoubleAddConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullAdd() {
+        test("testDoubleAdd", null, doubleTestValue1);
+    }
+
+    public static int testByteSub(FieldObject f, byte byteValue) {
+        return f.byteValue - byteValue;
+    }
+
+    public static int testByteSubConstant1(FieldObject f) {
+        return f.byteValue - byteTestValue1;
+    }
+
+    public static int testByteSubConstant2(FieldObject f) {
+        return f.byteValue - byteTestValue2;
+    }
+
+    @Test
+    public void testByteSubs() {
+        FieldObject f = new FieldObject();
+        test("testByteSub", f, byteTestValue1);
+        test("testByteSubConstant1", f);
+        test("testByteSubConstant2", f);
+    }
+
+    @Test
+    public void testByteNullSub() {
+        test("testByteSub", null, byteTestValue1);
+    }
+
+    public static int testShortSub(FieldObject f, short shortValue) {
+        return f.shortValue - shortValue;
+    }
+
+    public static int testShortSubConstant1(FieldObject f) {
+        return f.shortValue - shortTestValue1;
+    }
+
+    public static int testShortSubConstant2(FieldObject f) {
+        return f.shortValue - shortTestValue2;
+    }
+
+    @Test
+    public void testShortSubs() {
+        FieldObject f = new FieldObject();
+        test("testShortSub", f, shortTestValue1);
+        test("testShortSubConstant1", f);
+        test("testShortSubConstant2", f);
+    }
+
+    @Test
+    public void testShortNullSub() {
+        test("testShortSub", null, shortTestValue1);
+    }
+
+    public static int testCharSub(FieldObject f, char charValue) {
+        return f.charValue - charValue;
+    }
+
+    public static int testCharSubConstant1(FieldObject f) {
+        return f.charValue - charTestValue1;
+    }
+
+    public static int testCharSubConstant2(FieldObject f) {
+        return f.charValue - charTestValue2;
+    }
+
+    @Test
+    public void testCharSubs() {
+        FieldObject f = new FieldObject();
+        test("testCharSub", f, charTestValue1);
+        test("testCharSubConstant1", f);
+        test("testCharSubConstant2", f);
+    }
+
+    @Test
+    public void testCharNullSub() {
+        test("testCharSub", null, charTestValue1);
+    }
+
+    public static int testIntSub(FieldObject f, int intValue) {
+        return f.intValue - intValue;
+    }
+
+    public static int testIntSubConstant1(FieldObject f) {
+        return f.intValue - intTestValue1;
+    }
+
+    public static int testIntSubConstant2(FieldObject f) {
+        return f.intValue - intTestValue2;
+    }
+
+    @Test
+    public void testIntSubs() {
+        FieldObject f = new FieldObject();
+        test("testIntSub", f, intTestValue1);
+        test("testIntSubConstant1", f);
+        test("testIntSubConstant2", f);
+    }
+
+    @Test
+    public void testIntNullSub() {
+        test("testIntSub", null, intTestValue1);
+    }
+
+    public static long testLongSub(FieldObject f, long longValue) {
+        return f.longValue - longValue;
+    }
+
+    public static long testLongSubConstant1(FieldObject f) {
+        return f.longValue - longTestValue1;
+    }
+
+    public static long testLongSubConstant2(FieldObject f) {
+        return f.longValue - longTestValue2;
+    }
+
+    @Test
+    public void testLongSubs() {
+        FieldObject f = new FieldObject();
+        test("testLongSub", f, longTestValue1);
+        test("testLongSubConstant1", f);
+        test("testLongSubConstant2", f);
+    }
+
+    @Test
+    public void testLongNullSub() {
+        test("testLongSub", null, longTestValue1);
+    }
+
+    public static float testFloatSub(FieldObject f, float floatValue) {
+        return f.floatValue - floatValue;
+    }
+
+    public static float testFloatSubConstant1(FieldObject f) {
+        return f.floatValue - floatTestValue1;
+    }
+
+    public static float testFloatSubConstant2(FieldObject f) {
+        return f.floatValue - floatTestValue2;
+    }
+
+    @Test
+    public void testFloatSubs() {
+        FieldObject f = new FieldObject();
+        test("testFloatSub", f, floatTestValue1);
+        test("testFloatSubConstant1", f);
+        test("testFloatSubConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullSub() {
+        test("testFloatSub", null, floatTestValue1);
+    }
+
+    public static double testDoubleSub(FieldObject f, double doubleValue) {
+        return f.doubleValue - doubleValue;
+    }
+
+    public static double testDoubleSubConstant1(FieldObject f) {
+        return f.doubleValue - doubleTestValue1;
+    }
+
+    public static double testDoubleSubConstant2(FieldObject f) {
+        return f.doubleValue - doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleSubs() {
+        FieldObject f = new FieldObject();
+        test("testDoubleSub", f, doubleTestValue1);
+        test("testDoubleSubConstant1", f);
+        test("testDoubleSubConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullSub() {
+        test("testDoubleSub", null, doubleTestValue1);
+    }
+
+    public static int testByteMul(FieldObject f, byte byteValue) {
+        return f.byteValue * byteValue;
+    }
+
+    public static int testByteMulConstant1(FieldObject f) {
+        return f.byteValue * byteTestValue1;
+    }
+
+    public static int testByteMulConstant2(FieldObject f) {
+        return f.byteValue * byteTestValue2;
+    }
+
+    @Test
+    public void testByteMuls() {
+        FieldObject f = new FieldObject();
+        test("testByteMul", f, byteTestValue1);
+        test("testByteMulConstant1", f);
+        test("testByteMulConstant2", f);
+    }
+
+    @Test
+    public void testByteNullMul() {
+        test("testByteMul", null, byteTestValue1);
+    }
+
+    public static int testShortMul(FieldObject f, short shortValue) {
+        return f.shortValue * shortValue;
+    }
+
+    public static int testShortMulConstant1(FieldObject f) {
+        return f.shortValue * shortTestValue1;
+    }
+
+    public static int testShortMulConstant2(FieldObject f) {
+        return f.shortValue * shortTestValue2;
+    }
+
+    @Test
+    public void testShortMuls() {
+        FieldObject f = new FieldObject();
+        test("testShortMul", f, shortTestValue1);
+        test("testShortMulConstant1", f);
+        test("testShortMulConstant2", f);
+    }
+
+    @Test
+    public void testShortNullMul() {
+        test("testShortMul", null, shortTestValue1);
+    }
+
+    public static int testCharMul(FieldObject f, char charValue) {
+        return f.charValue * charValue;
+    }
+
+    public static int testCharMulConstant1(FieldObject f) {
+        return f.charValue * charTestValue1;
+    }
+
+    public static int testCharMulConstant2(FieldObject f) {
+        return f.charValue * charTestValue2;
+    }
+
+    @Test
+    public void testCharMuls() {
+        FieldObject f = new FieldObject();
+        test("testCharMul", f, charTestValue1);
+        test("testCharMulConstant1", f);
+        test("testCharMulConstant2", f);
+    }
+
+    @Test
+    public void testCharNullMul() {
+        test("testCharMul", null, charTestValue1);
+    }
+
+    public static int testIntMul(FieldObject f, int intValue) {
+        return f.intValue * intValue;
+    }
+
+    public static int testIntMulConstant1(FieldObject f) {
+        return f.intValue * intTestValue1;
+    }
+
+    public static int testIntMulConstant2(FieldObject f) {
+        return f.intValue * intTestValue2;
+    }
+
+    @Test
+    public void testIntMuls() {
+        FieldObject f = new FieldObject();
+        test("testIntMul", f, intTestValue1);
+        test("testIntMulConstant1", f);
+        test("testIntMulConstant2", f);
+    }
+
+    @Test
+    public void testIntNullMul() {
+        test("testIntMul", null, intTestValue1);
+    }
+
+    public static long testLongMul(FieldObject f, long longValue) {
+        return f.longValue * longValue;
+    }
+
+    public static long testLongMulConstant1(FieldObject f) {
+        return f.longValue * longTestValue1;
+    }
+
+    public static long testLongMulConstant2(FieldObject f) {
+        return f.longValue * longTestValue2;
+    }
+
+    @Test
+    public void testLongMuls() {
+        FieldObject f = new FieldObject();
+        test("testLongMul", f, longTestValue1);
+        test("testLongMulConstant1", f);
+        test("testLongMulConstant2", f);
+    }
+
+    @Test
+    public void testLongNullMul() {
+        test("testLongMul", null, longTestValue1);
+    }
+
+    public static float testFloatMul(FieldObject f, float floatValue) {
+        return f.floatValue * floatValue;
+    }
+
+    public static float testFloatMulConstant1(FieldObject f) {
+        return f.floatValue * floatTestValue1;
+    }
+
+    public static float testFloatMulConstant2(FieldObject f) {
+        return f.floatValue * floatTestValue2;
+    }
+
+    @Test
+    public void testFloatMuls() {
+        FieldObject f = new FieldObject();
+        test("testFloatMul", f, floatTestValue1);
+        test("testFloatMulConstant1", f);
+        test("testFloatMulConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullMul() {
+        test("testFloatMul", null, floatTestValue1);
+    }
+
+    public static double testDoubleMul(FieldObject f, double doubleValue) {
+        return f.doubleValue * doubleValue;
+    }
+
+    public static double testDoubleMulConstant1(FieldObject f) {
+        return f.doubleValue * doubleTestValue1;
+    }
+
+    public static double testDoubleMulConstant2(FieldObject f) {
+        return f.doubleValue * doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleMuls() {
+        FieldObject f = new FieldObject();
+        test("testDoubleMul", f, doubleTestValue1);
+        test("testDoubleMulConstant1", f);
+        test("testDoubleMulConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullMul() {
+        test("testDoubleMul", null, doubleTestValue1);
+    }
+
+    public static int testByteDiv(FieldObject f, byte byteValue) {
+        return f.byteValue / byteValue;
+    }
+
+    public static int testByteDivConstant1(FieldObject f) {
+        return f.byteValue / byteTestValue1;
+    }
+
+    public static int testByteDivConstant2(FieldObject f) {
+        return f.byteValue / byteTestValue2;
+    }
+
+    @Test
+    public void testByteDivs() {
+        FieldObject f = new FieldObject();
+        test("testByteDiv", f, byteTestValue1);
+        test("testByteDivConstant1", f);
+        test("testByteDivConstant2", f);
+    }
+
+    @Test
+    public void testByteNullDiv() {
+        test("testByteDiv", null, byteTestValue1);
+    }
+
+    public static int testShortDiv(FieldObject f, short shortValue) {
+        return f.shortValue / shortValue;
+    }
+
+    public static int testShortDivConstant1(FieldObject f) {
+        return f.shortValue / shortTestValue1;
+    }
+
+    public static int testShortDivConstant2(FieldObject f) {
+        return f.shortValue / shortTestValue2;
+    }
+
+    @Test
+    public void testShortDivs() {
+        FieldObject f = new FieldObject();
+        test("testShortDiv", f, shortTestValue1);
+        test("testShortDivConstant1", f);
+        test("testShortDivConstant2", f);
+    }
+
+    @Test
+    public void testShortNullDiv() {
+        test("testShortDiv", null, shortTestValue1);
+    }
+
+    public static int testCharDiv(FieldObject f, char charValue) {
+        return f.charValue / charValue;
+    }
+
+    public static int testCharDivConstant1(FieldObject f) {
+        return f.charValue / charTestValue1;
+    }
+
+    public static int testCharDivConstant2(FieldObject f) {
+        return f.charValue / charTestValue2;
+    }
+
+    @Test
+    public void testCharDivs() {
+        FieldObject f = new FieldObject();
+        test("testCharDiv", f, charTestValue1);
+        test("testCharDivConstant1", f);
+        test("testCharDivConstant2", f);
+    }
+
+    @Test
+    public void testCharNullDiv() {
+        test("testCharDiv", null, charTestValue1);
+    }
+
+    public static int testIntDiv(FieldObject f, int intValue) {
+        return f.intValue / intValue;
+    }
+
+    public static int testIntDivConstant1(FieldObject f) {
+        return f.intValue / intTestValue1;
+    }
+
+    public static int testIntDivConstant2(FieldObject f) {
+        return f.intValue / intTestValue2;
+    }
+
+    @Test
+    public void testIntDivs() {
+        FieldObject f = new FieldObject();
+        test("testIntDiv", f, intTestValue1);
+        test("testIntDivConstant1", f);
+        test("testIntDivConstant2", f);
+    }
+
+    @Test
+    public void testIntNullDiv() {
+        test("testIntDiv", null, intTestValue1);
+    }
+
+    public static long testLongDiv(FieldObject f, long longValue) {
+        return f.longValue / longValue;
+    }
+
+    public static long testLongDivConstant1(FieldObject f) {
+        return f.longValue / longTestValue1;
+    }
+
+    public static long testLongDivConstant2(FieldObject f) {
+        return f.longValue / longTestValue2;
+    }
+
+    @Test
+    public void testLongDivs() {
+        FieldObject f = new FieldObject();
+        test("testLongDiv", f, longTestValue1);
+        test("testLongDivConstant1", f);
+        test("testLongDivConstant2", f);
+    }
+
+    @Test
+    public void testLongNullDiv() {
+        test("testLongDiv", null, longTestValue1);
+    }
+
+    public static float testFloatDiv(FieldObject f, float floatValue) {
+        return f.floatValue / floatValue;
+    }
+
+    public static float testFloatDivConstant1(FieldObject f) {
+        return f.floatValue / floatTestValue1;
+    }
+
+    public static float testFloatDivConstant2(FieldObject f) {
+        return f.floatValue / floatTestValue2;
+    }
+
+    @Test
+    public void testFloatDivs() {
+        FieldObject f = new FieldObject();
+        test("testFloatDiv", f, floatTestValue1);
+        test("testFloatDivConstant1", f);
+        test("testFloatDivConstant2", f);
+    }
+
+    @Test
+    public void testFloatNullDiv() {
+        test("testFloatDiv", null, floatTestValue1);
+    }
+
+    public static double testDoubleDiv(FieldObject f, double doubleValue) {
+        return f.doubleValue / doubleValue;
+    }
+
+    public static double testDoubleDivConstant1(FieldObject f) {
+        return f.doubleValue / doubleTestValue1;
+    }
+
+    public static double testDoubleDivConstant2(FieldObject f) {
+        return f.doubleValue / doubleTestValue2;
+    }
+
+    @Test
+    public void testDoubleDivs() {
+        FieldObject f = new FieldObject();
+        test("testDoubleDiv", f, doubleTestValue1);
+        test("testDoubleDivConstant1", f);
+        test("testDoubleDivConstant2", f);
+    }
+
+    @Test
+    public void testDoubleNullDiv() {
+        test("testDoubleDiv", null, doubleTestValue1);
+    }
+
+    public static int testByteOr(FieldObject f, byte byteValue) {
+        return f.byteValue | byteValue;
+    }
+
+    public static int testByteOrConstant1(FieldObject f) {
+        return f.byteValue | byteTestValue1;
+    }
+
+    public static int testByteOrConstant2(FieldObject f) {
+        return f.byteValue | byteTestValue2;
+    }
+
+    @Test
+    public void testByteOrs() {
+        FieldObject f = new FieldObject();
+        test("testByteOr", f, byteTestValue1);
+        test("testByteOrConstant1", f);
+        test("testByteOrConstant2", f);
+    }
+
+    @Test
+    public void testByteNullOr() {
+        test("testByteOr", null, byteTestValue1);
+    }
+
+    public static int testShortOr(FieldObject f, short shortValue) {
+        return f.shortValue | shortValue;
+    }
+
+    public static int testShortOrConstant1(FieldObject f) {
+        return f.shortValue | shortTestValue1;
+    }
+
+    public static int testShortOrConstant2(FieldObject f) {
+        return f.shortValue | shortTestValue2;
+    }
+
+    @Test
+    public void testShortOrs() {
+        FieldObject f = new FieldObject();
+        test("testShortOr", f, shortTestValue1);
+        test("testShortOrConstant1", f);
+        test("testShortOrConstant2", f);
+    }
+
+    @Test
+    public void testShortNullOr() {
+        test("testShortOr", null, shortTestValue1);
+    }
+
+    public static int testCharOr(FieldObject f, char charValue) {
+        return f.charValue | charValue;
+    }
+
+    public static int testCharOrConstant1(FieldObject f) {
+        return f.charValue | charTestValue1;
+    }
+
+    public static int testCharOrConstant2(FieldObject f) {
+        return f.charValue | charTestValue2;
+    }
+
+    @Test
+    public void testCharOrs() {
+        FieldObject f = new FieldObject();
+        test("testCharOr", f, charTestValue1);
+        test("testCharOrConstant1", f);
+        test("testCharOrConstant2", f);
+    }
+
+    @Test
+    public void testCharNullOr() {
+        test("testCharOr", null, charTestValue1);
+    }
+
+    public static int testIntOr(FieldObject f, int intValue) {
+        return f.intValue | intValue;
+    }
+
+    public static int testIntOrConstant1(FieldObject f) {
+        return f.intValue | intTestValue1;
+    }
+
+    public static int testIntOrConstant2(FieldObject f) {
+        return f.intValue | intTestValue2;
+    }
+
+    @Test
+    public void testIntOrs() {
+        FieldObject f = new FieldObject();
+        test("testIntOr", f, intTestValue1);
+        test("testIntOrConstant1", f);
+        test("testIntOrConstant2", f);
+    }
+
+    @Test
+    public void testIntNullOr() {
+        test("testIntOr", null, intTestValue1);
+    }
+
+    public static long testLongOr(FieldObject f, long longValue) {
+        return f.longValue | longValue;
+    }
+
+    public static long testLongOrConstant1(FieldObject f) {
+        return f.longValue | longTestValue1;
+    }
+
+    public static long testLongOrConstant2(FieldObject f) {
+        return f.longValue | longTestValue2;
+    }
+
+    @Test
+    public void testLongOrs() {
+        FieldObject f = new FieldObject();
+        test("testLongOr", f, longTestValue1);
+        test("testLongOrConstant1", f);
+        test("testLongOrConstant2", f);
+    }
+
+    @Test
+    public void testLongNullOr() {
+        test("testLongOr", null, longTestValue1);
+    }
+
+    public static int testByteXor(FieldObject f, byte byteValue) {
+        return f.byteValue ^ byteValue;
+    }
+
+    public static int testByteXorConstant1(FieldObject f) {
+        return f.byteValue ^ byteTestValue1;
+    }
+
+    public static int testByteXorConstant2(FieldObject f) {
+        return f.byteValue ^ byteTestValue2;
+    }
+
+    @Test
+    public void testByteXors() {
+        FieldObject f = new FieldObject();
+        test("testByteXor", f, byteTestValue1);
+        test("testByteXorConstant1", f);
+        test("testByteXorConstant2", f);
+    }
+
+    @Test
+    public void testByteNullXor() {
+        test("testByteXor", null, byteTestValue1);
+    }
+
+    public static int testShortXor(FieldObject f, short shortValue) {
+        return f.shortValue ^ shortValue;
+    }
+
+    public static int testShortXorConstant1(FieldObject f) {
+        return f.shortValue ^ shortTestValue1;
+    }
+
+    public static int testShortXorConstant2(FieldObject f) {
+        return f.shortValue ^ shortTestValue2;
+    }
+
+    @Test
+    public void testShortXors() {
+        FieldObject f = new FieldObject();
+        test("testShortXor", f, shortTestValue1);
+        test("testShortXorConstant1", f);
+        test("testShortXorConstant2", f);
+    }
+
+    @Test
+    public void testShortNullXor() {
+        test("testShortXor", null, shortTestValue1);
+    }
+
+    public static int testCharXor(FieldObject f, char charValue) {
+        return f.charValue ^ charValue;
+    }
+
+    public static int testCharXorConstant1(FieldObject f) {
+        return f.charValue ^ charTestValue1;
+    }
+
+    public static int testCharXorConstant2(FieldObject f) {
+        return f.charValue ^ charTestValue2;
+    }
+
+    @Test
+    public void testCharXors() {
+        FieldObject f = new FieldObject();
+        test("testCharXor", f, charTestValue1);
+        test("testCharXorConstant1", f);
+        test("testCharXorConstant2", f);
+    }
+
+    @Test
+    public void testCharNullXor() {
+        test("testCharXor", null, charTestValue1);
+    }
+
+    public static int testIntXor(FieldObject f, int intValue) {
+        return f.intValue ^ intValue;
+    }
+
+    public static int testIntXorConstant1(FieldObject f) {
+        return f.intValue ^ intTestValue1;
+    }
+
+    public static int testIntXorConstant2(FieldObject f) {
+        return f.intValue ^ intTestValue2;
+    }
+
+    @Test
+    public void testIntXors() {
+        FieldObject f = new FieldObject();
+        test("testIntXor", f, intTestValue1);
+        test("testIntXorConstant1", f);
+        test("testIntXorConstant2", f);
+    }
+
+    @Test
+    public void testIntNullXor() {
+        test("testIntXor", null, intTestValue1);
+    }
+
+    public static long testLongXor(FieldObject f, long longValue) {
+        return f.longValue ^ longValue;
+    }
+
+    public static long testLongXorConstant1(FieldObject f) {
+        return f.longValue ^ longTestValue1;
+    }
+
+    public static long testLongXorConstant2(FieldObject f) {
+        return f.longValue ^ longTestValue2;
+    }
+
+    @Test
+    public void testLongXors() {
+        FieldObject f = new FieldObject();
+        test("testLongXor", f, longTestValue1);
+        test("testLongXorConstant1", f);
+        test("testLongXorConstant2", f);
+    }
+
+    @Test
+    public void testLongNullXor() {
+        test("testLongXor", null, longTestValue1);
+    }
+
+    public static int testByteAnd(FieldObject f, byte byteValue) {
+        return f.byteValue & byteValue;
+    }
+
+    public static int testByteAndConstant1(FieldObject f) {
+        return f.byteValue & byteTestValue1;
+    }
+
+    public static int testByteAndConstant2(FieldObject f) {
+        return f.byteValue & byteTestValue2;
+    }
+
+    @Test
+    public void testByteAnds() {
+        FieldObject f = new FieldObject();
+        test("testByteAnd", f, byteTestValue1);
+        test("testByteAndConstant1", f);
+        test("testByteAndConstant2", f);
+    }
+
+    @Test
+    public void testByteNullAnd() {
+        test("testByteAnd", null, byteTestValue1);
+    }
+
+    public static int testShortAnd(FieldObject f, short shortValue) {
+        return f.shortValue & shortValue;
+    }
+
+    public static int testShortAndConstant1(FieldObject f) {
+        return f.shortValue & shortTestValue1;
+    }
+
+    public static int testShortAndConstant2(FieldObject f) {
+        return f.shortValue & shortTestValue2;
+    }
+
+    @Test
+    public void testShortAnds() {
+        FieldObject f = new FieldObject();
+        test("testShortAnd", f, shortTestValue1);
+        test("testShortAndConstant1", f);
+        test("testShortAndConstant2", f);
+    }
+
+    @Test
+    public void testShortNullAnd() {
+        test("testShortAnd", null, shortTestValue1);
+    }
+
+    public static int testCharAnd(FieldObject f, char charValue) {
+        return f.charValue & charValue;
+    }
+
+    public static int testCharAndConstant1(FieldObject f) {
+        return f.charValue & charTestValue1;
+    }
+
+    public static int testCharAndConstant2(FieldObject f) {
+        return f.charValue & charTestValue2;
+    }
+
+    @Test
+    public void testCharAnds() {
+        FieldObject f = new FieldObject();
+        test("testCharAnd", f, charTestValue1);
+        test("testCharAndConstant1", f);
+        test("testCharAndConstant2", f);
+    }
+
+    @Test
+    public void testCharNullAnd() {
+        test("testCharAnd", null, charTestValue1);
+    }
+
+    public static int testIntAnd(FieldObject f, int intValue) {
+        return f.intValue & intValue;
+    }
+
+    public static int testIntAndConstant1(FieldObject f) {
+        return f.intValue & intTestValue1;
+    }
+
+    public static int testIntAndConstant2(FieldObject f) {
+        return f.intValue & intTestValue2;
+    }
+
+    @Test
+    public void testIntAnds() {
+        FieldObject f = new FieldObject();
+        test("testIntAnd", f, intTestValue1);
+        test("testIntAndConstant1", f);
+        test("testIntAndConstant2", f);
+    }
+
+    @Test
+    public void testIntNullAnd() {
+        test("testIntAnd", null, intTestValue1);
+    }
+
+    public static long testLongAnd(FieldObject f, long longValue) {
+        return f.longValue & longValue;
+    }
+
+    public static long testLongAndConstant1(FieldObject f) {
+        return f.longValue & longTestValue1;
+    }
+
+    public static long testLongAndConstant2(FieldObject f) {
+        return f.longValue & longTestValue2;
+    }
+
+    @Test
+    public void testLongAnds() {
+        FieldObject f = new FieldObject();
+        test("testLongAnd", f, longTestValue1);
+        test("testLongAndConstant1", f);
+        test("testLongAndConstant2", f);
+    }
+
+    @Test
+    public void testLongNullAnd() {
+        test("testLongAnd", null, longTestValue1);
+    }
+
+    public static boolean testIntMask(FieldObject f, int intValue) {
+        if ((f.intValue & intValue) != 0) {
+            count++;
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean testIntMaskConstant1(FieldObject f) {
+        return (f.intValue & intTestValue1) != 0;
+    }
+
+    public static boolean testIntMaskConstant2(FieldObject f) {
+        return (f.intValue & intTestValue2) != 0;
+    }
+
+    @Test
+    public void testIntMasks() {
+        FieldObject f = new FieldObject();
+        test("testIntMask", f, intTestValue1);
+        test("testIntMaskConstant1", f);
+        test("testIntMaskConstant2", f);
+    }
+
+    @Test
+    public void testIntNullMask() {
+        test("testIntMask", null, intTestValue1);
+    }
+
+    public static boolean testLongMask(FieldObject f, long longValue) {
+        if ((f.longValue & longValue) != 0) {
+            count++;
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean testLongMaskConstant1(FieldObject f) {
+        return (f.longValue & longTestValue1) != 0;
+    }
+
+    public static boolean testLongMaskConstant2(FieldObject f) {
+        return (f.longValue & longTestValue2) != 0;
+    }
+
+    @Test
+    public void testLongMasks() {
+        FieldObject f = new FieldObject();
+        test("testLongMask", f, longTestValue1);
+        test("testLongMaskConstant1", f);
+        test("testLongMaskConstant2", f);
+    }
+
+    @Test
+    public void testLongNullMask() {
+        test("testLongMask", null, longTestValue1);
+    }
+
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu Mar 20 15:57:03 2014 -0700
@@ -37,6 +37,7 @@
 import com.oracle.graal.asm.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
@@ -227,18 +228,30 @@
 
     /**
      * Returns the operand that has been previously initialized by
-     * {@link #setResult(ValueNode, Value)} with the result of an instruction.
+     * {@link #setResult(ValueNode, Value)} with the result of an instruction. It's a code
+     * generation error to ask for the operand of ValueNode that doesn't have one yet.
      * 
      * @param node A node that produces a result value.
      */
     @Override
     public Value operand(ValueNode node) {
+        Value operand = getOperand(node);
+        assert operand != null : String.format("missing operand for %1s", node);
+        return operand;
+    }
+
+    @Override
+    public boolean hasOperand(ValueNode node) {
+        return getOperand(node) != null;
+    }
+
+    private Value getOperand(ValueNode node) {
         if (nodeOperands == null) {
             return null;
         }
         Value operand = nodeOperands.get(node);
         if (operand == null) {
-            return getConstantOperand(node);
+            operand = getConstantOperand(node);
         }
         return operand;
     }
@@ -434,23 +447,31 @@
         }
 
         List<ScheduledNode> nodes = blockMap.get(block);
+        int instructionsFolded = 0;
         for (int i = 0; i < nodes.size(); i++) {
             Node instr = nodes.get(i);
             if (traceLevel >= 3) {
                 TTY.println("LIRGen for " + instr);
             }
+            if (instructionsFolded > 0) {
+                instructionsFolded--;
+                continue;
+            }
             if (!ConstantNodeRecordsUsages && instr instanceof ConstantNode) {
                 // Loading of constants is done lazily by operand()
             } else if (instr instanceof ValueNode) {
                 ValueNode valueNode = (ValueNode) instr;
-                if (operand(valueNode) == null) {
+                if (!hasOperand(valueNode)) {
                     if (!peephole(valueNode)) {
-                        try {
-                            doRoot((ValueNode) instr);
-                        } catch (GraalInternalError e) {
-                            throw e.addContext(instr);
-                        } catch (Throwable e) {
-                            throw new GraalInternalError(e).addContext(instr);
+                        instructionsFolded = maybeFoldMemory(nodes, i, valueNode);
+                        if (instructionsFolded == 0) {
+                            try {
+                                doRoot((ValueNode) instr);
+                            } catch (GraalInternalError e) {
+                                throw e.addContext(instr);
+                            } catch (Throwable e) {
+                                throw new GraalInternalError(e).addContext(instr);
+                            }
                         }
                     }
                 } else {
@@ -486,6 +507,138 @@
         }
     }
 
+    private static final DebugMetric MemoryFoldSuccess = Debug.metric("MemoryFoldSuccess");
+    private static final DebugMetric MemoryFoldFailed = Debug.metric("MemoryFoldFailed");
+    private static final DebugMetric MemoryFoldFailedNonAdjacent = Debug.metric("MemoryFoldedFailedNonAdjacent");
+    private static final DebugMetric MemoryFoldFailedDifferentBlock = Debug.metric("MemoryFoldedFailedDifferentBlock");
+
+    /**
+     * Subclass can provide helper to fold memory operations into other operations.
+     */
+    protected MemoryArithmeticLIRLowerer getMemoryLowerer() {
+        return null;
+    }
+
+    /**
+     * Try to find a sequence of Nodes which can be passed to the backend to look for optimized
+     * instruction sequences using memory. Currently this basically is a read with a single
+     * arithmetic user followed by an possible if use. This should generalized to more generic
+     * pattern matching so that it can be more flexibly used.
+     */
+    private int maybeFoldMemory(List<ScheduledNode> nodes, int i, ValueNode access) {
+        MemoryArithmeticLIRLowerer lowerer = getMemoryLowerer();
+        if (lowerer != null && OptFoldMemory.getValue() && (access instanceof ReadNode || access instanceof FloatingReadNode) && access.usages().count() == 1 && i + 1 < nodes.size()) {
+            try (Scope s = Debug.scope("MaybeFoldMemory", access)) {
+                // This is all bit hacky since it's happening on the linearized schedule. This needs
+                // to be revisited at some point.
+
+                // Find a memory lowerable usage of this operation
+                if (access.usages().first() instanceof MemoryArithmeticLIRLowerable) {
+                    ValueNode operation = (ValueNode) access.usages().first();
+                    if (!nodes.contains(operation)) {
+                        Debug.log("node %1s in different block from %1s", access, operation);
+                        MemoryFoldFailedDifferentBlock.increment();
+                        return 0;
+                    }
+                    ValueNode firstOperation = operation;
+                    if (operation instanceof LogicNode) {
+                        if (operation.usages().count() == 1 && operation.usages().first() instanceof IfNode) {
+                            ValueNode ifNode = (ValueNode) operation.usages().first();
+                            if (!nodes.contains(ifNode)) {
+                                MemoryFoldFailedDifferentBlock.increment();
+                                Debug.log("if node %1s in different block from %1s", ifNode, operation);
+                                try (Indent indent = Debug.logAndIndent("checking operations")) {
+                                    int start = nodes.indexOf(access);
+                                    int end = nodes.indexOf(operation);
+                                    for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
+                                        indent.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
+                                    }
+                                }
+                                return 0;
+                            } else {
+                                operation = ifNode;
+                            }
+                        }
+                    }
+                    if (Debug.isLogEnabled()) {
+                        synchronized ("lock") {  // Hack to ensure the output is grouped.
+                            try (Indent indent = Debug.logAndIndent("checking operations")) {
+                                int start = nodes.indexOf(access);
+                                int end = nodes.indexOf(operation);
+                                for (int i1 = Math.min(start, end); i1 <= Math.max(start, end); i1++) {
+                                    indent.log("%d: (%d) %1s", i1, nodes.get(i1).usages().count(), nodes.get(i1));
+                                }
+                            }
+                        }
+                    }
+                    // Possible lowerable operation in the same block. Check out the dependencies.
+                    int opIndex = nodes.indexOf(operation);
+                    int current = i + 1;
+                    ArrayList<ValueNode> deferred = null;
+                    while (current < opIndex) {
+                        ScheduledNode node = nodes.get(current);
+                        if (node != firstOperation) {
+                            if (node instanceof LocationNode || node instanceof VirtualObjectNode) {
+                                // nothing to do
+                            } else if (node instanceof ConstantNode) {
+                                if (deferred == null) {
+                                    deferred = new ArrayList<>(2);
+                                }
+                                // These nodes are collected and the backend is expended to
+                                // evaluate them before generating the lowered form. This
+                                // basically works around unfriendly scheduling of values which
+                                // are defined in a block but not used there.
+                                deferred.add((ValueNode) node);
+                            } else {
+                                Debug.log("unexpected node %1s", node);
+                                // Unexpected inline node
+                                break;
+                            }
+                        }
+                        current++;
+                    }
+
+                    if (current == opIndex) {
+                        if (lowerer.memoryPeephole((Access) access, (MemoryArithmeticLIRLowerable) operation, deferred)) {
+                            MemoryFoldSuccess.increment();
+                            // if this operation had multiple access inputs, then previous attempts
+                            // would be marked as failures which is wrong. Try to adjust the
+                            // counters to account for this.
+                            for (Node input : operation.inputs()) {
+                                if (input == access) {
+                                    continue;
+                                }
+                                if (input instanceof Access && nodes.contains(input)) {
+                                    MemoryFoldFailedNonAdjacent.add(-1);
+                                }
+                            }
+                            if (deferred != null) {
+                                // Ensure deferred nodes were evaluated
+                                for (ValueNode node : deferred) {
+                                    assert hasOperand(node);
+                                }
+                            }
+                            return opIndex - i;
+                        } else {
+                            // This isn't true failure, it just means there wasn't match for the
+                            // pattern. Usually that means it's just not supported by the backend.
+                            MemoryFoldFailed.increment();
+                            return 0;
+                        }
+                    } else {
+                        MemoryFoldFailedNonAdjacent.increment();
+                    }
+                } else {
+                    // memory usage which isn't considered lowerable. Mostly these are
+                    // uninteresting but it might be worth looking at to ensure that interesting
+                    // nodes are being properly handled.
+                    // Debug.log("usage isn't lowerable %1s", access.usages().first());
+                }
+            }
+        }
+        return 0;
+    }
+
     protected abstract boolean peephole(ValueNode valueNode);
 
     private boolean hasBlockEnd(Block block) {
@@ -504,7 +657,7 @@
 
         Debug.log("Visiting %s", instr);
         emitNode(instr);
-        Debug.log("Operand for %s = %s", instr, operand(instr));
+        Debug.log("Operand for %s = %s", instr, getOperand(instr));
     }
 
     protected void emitNode(ValueNode node) {
@@ -599,7 +752,7 @@
 
     private Value operandForPhi(PhiNode phi) {
         assert phi.type() == PhiType.Value : "wrong phi type: " + phi;
-        Value result = operand(phi);
+        Value result = getOperand(phi);
         if (result == null) {
             // allocate a variable for this phi
             Variable newOperand = newVariable(getPhiKind(phi));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Thu Mar 20 15:57:03 2014 -0700
@@ -78,6 +78,7 @@
         assert config.basicLockSize == 8;
         this.config = config;
         this.stub = stub;
+        memoryPeephole = new AMD64HotSpotMemoryPeephole(this);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMemoryPeephole.java	Thu Mar 20 15:57:03 2014 -0700
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.graal.hotspot.amd64;
+
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.compiler.amd64.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.data.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.amd64.AMD64ControlFlow.BranchOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Specialized code gen for comparison with compressed memory.
+ */
+
+public class AMD64HotSpotMemoryPeephole extends AMD64MemoryPeephole {
+    public static class CompareMemoryCompressedOp extends AMD64LIRInstruction {
+        @Alive({COMPOSITE}) protected AMD64AddressValue x;
+        @Use({CONST}) protected Value y;
+        @State protected LIRFrameState state;
+
+        public CompareMemoryCompressedOp(AMD64AddressValue x, Constant y, LIRFrameState state) {
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            Constant constant = (Constant) y;
+            if (constant.isNull()) {
+                masm.cmpl(x.toAddress(), 0);
+            } else {
+                if (y.getKind() == Kind.Object) {
+                    crb.recordInlineDataInCode(new OopData(0, constant.asObject(), true));
+                } else if (y.getKind() == Kind.Long) {
+                    crb.recordInlineDataInCode(new MetaspaceData(0, constant.asLong(), constant.getPrimitiveAnnotation(), true));
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+                if (state != null) {
+                    crb.recordImplicitException(masm.position(), state);
+                }
+                masm.cmpl(x.toAddress(), 0xdeaddead);
+            }
+        }
+    }
+
+    AMD64HotSpotMemoryPeephole(AMD64LIRGenerator gen) {
+        super(gen);
+    }
+
+    @Override
+    protected boolean emitCompareBranchMemory(ValueNode left, ValueNode right, Access access, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel,
+                    double trueLabelProbability) {
+        assert left == access || right == access;
+        ValueNode other = left == access ? right : left;
+        Kind kind = access.nullCheckLocation().getValueKind();
+
+        if (other.isConstant() && kind == Kind.Object && access.isCompressible()) {
+            ensureEvaluated(other);
+            gen.append(new CompareMemoryCompressedOp(makeAddress(access), other.asConstant(), getState(access)));
+            Condition finalCondition = right == access ? cond.mirror() : cond;
+            gen.append(new BranchOp(finalCondition, trueLabel, falseLabel, trueLabelProbability));
+            return true;
+        }
+
+        return super.emitCompareBranchMemory(left, right, access, cond, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Thu Mar 20 15:57:03 2014 -0700
@@ -49,6 +49,7 @@
     I2F, I2D,
     L2F, L2D,
     MOV_I2F, MOV_L2D, MOV_F2I, MOV_D2L,
+    MOV_B2UI, MOV_B2UL, // Zero extending byte loads
 
     /*
      * Converts a float/double to an int/long. The result of the conversion does not comply with Java semantics
@@ -102,6 +103,32 @@
     }
 
     /**
+     * Unary operation with separate memory source and destination operand.
+     */
+    public static class Unary2MemoryOp extends AMD64LIRInstruction {
+
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG}) protected AllocatableValue result;
+        @Use({COMPOSITE}) protected AMD64AddressValue x;
+        @State protected LIRFrameState state;
+
+        public Unary2MemoryOp(AMD64Arithmetic opcode, AllocatableValue result, AMD64AddressValue x, LIRFrameState state) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emit(crb, masm, opcode, result, x, null);
+        }
+    }
+
+    /**
      * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand may be a stack slot.
      */
@@ -135,6 +162,45 @@
 
     /**
      * Binary operation with two operands. The first source operand is combined with the
+     * destination. The second source operand may be a stack slot.
+     */
+    public static class BinaryMemory extends AMD64LIRInstruction {
+
+        @Opcode private final AMD64Arithmetic opcode;
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue x;
+        protected final Kind kind;
+        @Alive({COMPOSITE}) protected AMD64AddressValue location;
+        @State protected LIRFrameState state;
+
+        public BinaryMemory(AMD64Arithmetic opcode, Kind kind, AllocatableValue result, AllocatableValue x, AMD64AddressValue location, LIRFrameState state) {
+            this.opcode = opcode;
+            this.result = result;
+            this.x = x;
+            this.location = location;
+            this.kind = kind;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emit(crb, masm, opcode, result, location, null);
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert differentRegisters(result, location) || sameRegister(x, location);
+            // verifyKind(opcode, result, x, location);
+        }
+    }
+
+    /**
+     * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand must be a register.
      */
     public static class BinaryRegReg extends AMD64LIRInstruction {
@@ -688,7 +754,8 @@
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
-        } else {
+        } else if (isStackSlot(src)) {
+
             switch (opcode) {
                 case IADD:
                     masm.addl(asIntReg(dst), (AMD64Address) crb.asIntAddr(src));
@@ -819,6 +886,143 @@
                 default:
                     throw GraalInternalError.shouldNotReachHere();
             }
+        } else {
+            switch (opcode) {
+                case IADD:
+                    masm.addl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case ISUB:
+                    masm.subl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IAND:
+                    masm.andl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IMUL:
+                    masm.imull(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IOR:
+                    masm.orl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case IXOR:
+                    masm.xorl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case LADD:
+                    masm.addq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LSUB:
+                    masm.subq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LMUL:
+                    masm.imulq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LAND:
+                    masm.andq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LOR:
+                    masm.orq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case LXOR:
+                    masm.xorq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case FADD:
+                    masm.addss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case FSUB:
+                    masm.subss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case FMUL:
+                    masm.mulss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case FDIV:
+                    masm.divss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case DADD:
+                    masm.addsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case DSUB:
+                    masm.subsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case DMUL:
+                    masm.mulsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case DDIV:
+                    masm.divsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case SQRT:
+                    masm.sqrtsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                case B2I:
+                    masm.movsbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case S2I:
+                    masm.movswl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case B2L:
+                    masm.movsbq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case S2L:
+                    masm.movswq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case I2L:
+                    masm.movslq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case F2D:
+                    masm.cvtss2sd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case D2F:
+                    masm.cvtsd2ss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case I2F:
+                    masm.cvtsi2ssl(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case I2D:
+                    masm.cvtsi2sdl(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case L2F:
+                    masm.cvtsi2ssq(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case L2D:
+                    masm.cvtsi2sdq(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case F2I:
+                    masm.cvttss2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case D2I:
+                    masm.cvttsd2sil(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case F2L:
+                    masm.cvttss2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case D2L:
+                    masm.cvttsd2siq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_I2F:
+                    masm.movss(asFloatReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_L2D:
+                    masm.movsd(asDoubleReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_F2I:
+                    masm.movl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_D2L:
+                    masm.movq(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_B2UI:
+                    masm.movzbl(asIntReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+                case MOV_B2UL:
+                    masm.movzbl(asLongReg(dst), ((AMD64AddressValue) src).toAddress());
+                    break;
+
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
 
         if (info != null) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Thu Mar 20 15:57:03 2014 -0700
@@ -31,7 +31,6 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
-// @formatter:off
 public enum AMD64Compare {
     ICMP, LCMP, ACMP, FCMP, DCMP;
 
@@ -54,57 +53,152 @@
         @Override
         protected void verify() {
             super.verify();
-            assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int)
-                || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long)
-                || (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object)
-                || (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float)
-                || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
+            assert (name().startsWith("I") && x.getKind() == Kind.Int && y.getKind().getStackKind() == Kind.Int) || (name().startsWith("L") && x.getKind() == Kind.Long && y.getKind() == Kind.Long) ||
+                            (name().startsWith("A") && x.getKind() == Kind.Object && y.getKind() == Kind.Object) ||
+                            (name().startsWith("F") && x.getKind() == Kind.Float && y.getKind() == Kind.Float) || (name().startsWith("D") && x.getKind() == Kind.Double && y.getKind() == Kind.Double);
+        }
+    }
+
+    public static class CompareMemoryOp extends AMD64LIRInstruction {
+        @Opcode private final AMD64Compare opcode;
+        @Use({REG, COMPOSITE}) protected Value x;
+        @Use({CONST, COMPOSITE}) protected Value y;
+        @State protected LIRFrameState state;
+
+        /**
+         * Compare memory, constant or register, memory.
+         */
+        public CompareMemoryOp(AMD64Compare opcode, Value x, Value y, LIRFrameState state) {
+            assert (x instanceof AMD64AddressValue && y instanceof Constant) || (x instanceof Variable && y instanceof AMD64AddressValue);
+            this.opcode = opcode;
+            this.x = x;
+            this.y = y;
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            emit(crb, masm, opcode, x, y);
+        }
+
+        @Override
+        protected void verify() {
+            super.verify();
+            assert (x instanceof AMD64AddressValue && y instanceof Constant) || (x instanceof Variable && y instanceof AMD64AddressValue);
         }
     }
 
     public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, AMD64Compare opcode, Value x, Value y) {
-        if (isRegister(y)) {
+        if (isRegister(x) && isRegister(y)) {
             switch (opcode) {
-                case ICMP: masm.cmpl(asIntReg(x), asIntReg(y)); break;
-                case LCMP: masm.cmpq(asLongReg(x), asLongReg(y)); break;
-                case ACMP: masm.cmpptr(asObjectReg(x), asObjectReg(y)); break;
-                case FCMP: masm.ucomiss(asFloatReg(x), asFloatReg(y)); break;
-                case DCMP: masm.ucomisd(asDoubleReg(x), asDoubleReg(y)); break;
-                default:   throw GraalInternalError.shouldNotReachHere();
+                case ICMP:
+                    masm.cmpl(asIntReg(x), asIntReg(y));
+                    break;
+                case LCMP:
+                    masm.cmpq(asLongReg(x), asLongReg(y));
+                    break;
+                case ACMP:
+                    masm.cmpptr(asObjectReg(x), asObjectReg(y));
+                    break;
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), asFloatReg(y));
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), asDoubleReg(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        } else if (isConstant(y)) {
+        } else if (isRegister(x) && isConstant(y)) {
             boolean isZero = ((Constant) y).isDefaultForKind();
             switch (opcode) {
-                case ICMP: if (isZero) {
-                    masm.testl(asIntReg(x), asIntReg(x));
-                } else {
-                    masm.cmpl(asIntReg(x), crb.asIntConst(y));
-                }
-                break;
-                case LCMP: if (isZero) {
-                    masm.testq(asLongReg(x), asLongReg(x));
-                } else {
-                    masm.cmpq(asLongReg(x), crb.asIntConst(y));
-                }
-                break;
+                case ICMP:
+                    if (isZero) {
+                        masm.testl(asIntReg(x), asIntReg(x));
+                    } else {
+                        masm.cmpl(asIntReg(x), crb.asIntConst(y));
+                    }
+                    break;
+                case LCMP:
+                    if (isZero) {
+                        masm.testq(asLongReg(x), asLongReg(x));
+                    } else {
+                        masm.cmpq(asLongReg(x), crb.asIntConst(y));
+                    }
+                    break;
                 case ACMP:
                     if (isZero) {
-                        masm.testq(asObjectReg(x), asObjectReg(x)); break;
+                        masm.testq(asObjectReg(x), asObjectReg(x));
+                        break;
                     } else {
                         throw GraalInternalError.shouldNotReachHere("Only null object constants are allowed in comparisons");
                     }
-                case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y)); break;
-                case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y)); break;
-                default:   throw GraalInternalError.shouldNotReachHere();
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatConstRef(y));
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleConstRef(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
-        } else {
+        } else if (isRegister(x) && isStackSlot(y)) {
             switch (opcode) {
-                case ICMP: masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y)); break;
-                case LCMP: masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y)); break;
-                case ACMP: masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y)); break;
-                case FCMP: masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y)); break;
-                case DCMP: masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y)); break;
-                default:  throw GraalInternalError.shouldNotReachHere();
+                case ICMP:
+                    masm.cmpl(asIntReg(x), (AMD64Address) crb.asIntAddr(y));
+                    break;
+                case LCMP:
+                    masm.cmpq(asLongReg(x), (AMD64Address) crb.asLongAddr(y));
+                    break;
+                case ACMP:
+                    masm.cmpptr(asObjectReg(x), (AMD64Address) crb.asObjectAddr(y));
+                    break;
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), (AMD64Address) crb.asFloatAddr(y));
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), (AMD64Address) crb.asDoubleAddr(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else if (isRegister(x) && y instanceof AMD64AddressValue) {
+            switch (opcode) {
+                case ICMP:
+                    masm.cmpl(asIntReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case LCMP:
+                    masm.cmpq(asLongReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case ACMP:
+                    masm.cmpptr(asObjectReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case FCMP:
+                    masm.ucomiss(asFloatReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                case DCMP:
+                    masm.ucomisd(asDoubleReg(x), ((AMD64AddressValue) y).toAddress());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else if (x instanceof AMD64AddressValue && isConstant(y)) {
+            switch (opcode) {
+                case ICMP:
+                    masm.cmpl(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y));
+                    break;
+                case LCMP:
+                    if (crb.asLongConst(y) == (int) crb.asLongConst(y)) {
+                        masm.cmpq(((AMD64AddressValue) x).toAddress(), (int) crb.asLongConst(y));
+                    } else {
+                        throw GraalInternalError.shouldNotReachHere();
+                    }
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Thu Mar 20 15:57:03 2014 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.lir.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64TestMemoryOp extends AMD64LIRInstruction {
+
+    @Use({COMPOSITE}) protected AMD64AddressValue x;
+    @Use({REG, CONST}) protected Value y;
+    @State protected LIRFrameState state;
+
+    public AMD64TestMemoryOp(AMD64AddressValue x, Value y, LIRFrameState state) {
+        this.x = x;
+        this.y = y;
+        this.state = state;
+    }
+
+    @Override
+    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+        if (state != null) {
+            crb.recordImplicitException(masm.position(), state);
+        }
+        emit(crb, masm, x, y);
+    }
+
+    @Override
+    protected void verify() {
+        super.verify();
+        // Can't check the kind of an address so just check the other input
+        assert (x.getKind() == Kind.Int || x.getKind() == Kind.Long) : x + " " + y;
+    }
+
+    public static void emit(CompilationResultBuilder crb, AMD64MacroAssembler masm, Value x, Value y) {
+        if (isRegister(y)) {
+            switch (y.getKind()) {
+                case Int:
+                    masm.testl(asIntReg(y), ((AMD64AddressValue) x).toAddress());
+                    break;
+                case Long:
+                    masm.testq(asLongReg(y), ((AMD64AddressValue) x).toAddress());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else if (isConstant(y)) {
+            switch (y.getKind()) {
+                case Int:
+                    masm.testl(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y));
+                    break;
+                case Long:
+                    masm.testq(((AMD64AddressValue) x).toAddress(), crb.asIntConst(y));
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -33,6 +33,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -42,7 +43,7 @@
  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
  * of a comparison.
  */
-public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Successor private AbstractBeginNode trueSuccessor;
     @Successor private AbstractBeginNode falseSuccessor;
@@ -131,6 +132,11 @@
     }
 
     @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        return gen.emitIfMemory(this, access);
+    }
+
+    @Override
     public boolean verify() {
         assertTrue(condition() != null, "missing condition");
         assertTrue(trueSuccessor() != null, "missing trueSuccessor");
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -83,4 +84,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitAnd(gen.operand(x()), gen.operand(y())));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitAndMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BitLogicNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -29,7 +29,7 @@
 /**
  * The {@code LogicNode} class definition.
  */
-public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public abstract class BitLogicNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable, NarrowableArithmeticNode {
 
     /**
      * Constructs a new logic operation node.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /* TODO (thomaswue/gdub) For high-level optimization purpose the compare node should be a boolean *value* (it is currently only a helper node)
@@ -34,7 +35,7 @@
  * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
  * into variants that do not materialize the value (CompareIf, CompareGuard...)
  */
-public abstract class CompareNode extends LogicNode implements Canonicalizable, LIRLowerable {
+public abstract class CompareNode extends LogicNode implements Canonicalizable, LIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
@@ -192,4 +193,8 @@
 
         return graph.unique(comparison);
     }
+
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatAddNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -77,10 +78,19 @@
 
     public static boolean livesLonger(ValueNode after, ValueNode value, ArithmeticLIRGenerator gen) {
         for (Node usage : value.usages()) {
-            if (usage != after && usage instanceof ValueNode && gen.operand(((ValueNode) usage)) != null) {
+            if (usage != after && usage instanceof ValueNode && gen.hasOperand(((ValueNode) usage))) {
                 return true;
             }
         }
         return false;
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitAddMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatArithmeticNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class FloatArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     private final boolean isStrictFP;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -33,7 +34,7 @@
  * A {@code FloatConvert} converts between integers and floating point numbers according to Java
  * semantics.
  */
-public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable {
+public class FloatConvertNode extends ConvertNode implements Canonicalizable, Lowerable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     public enum FloatConvert {
         F2I, D2I, F2L, D2L, I2F, L2F, D2F, I2D, L2D, F2D;
@@ -194,4 +195,12 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitFloatConvert(op, gen.operand(getInput())));
     }
+
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitFloatConvertMemory(getOp(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatDivNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -59,4 +60,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitDiv(gen.operand(x()), gen.operand(y()), null));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitDivMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatMulNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -69,4 +70,13 @@
         }
         gen.setResult(this, gen.emitMul(op1, op2));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitMulMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatRemNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -59,4 +60,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitRem(gen.operand(x()), gen.operand(y()), null));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitRemMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatSubNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -78,4 +79,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitSub(gen.operand(x()), gen.operand(y())));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitSubMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -78,9 +79,6 @@
             if (reassociated != this) {
                 return reassociated;
             }
-            if (c < 0) {
-                return IntegerArithmeticNode.sub(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph()));
-            }
         }
         if (x() instanceof NegateNode) {
             return IntegerArithmeticNode.sub(graph(), y(), ((NegateNode) x()).x());
@@ -102,4 +100,13 @@
         }
         gen.setResult(this, gen.emitAdd(op1, op2));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitAddMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
         super(stamp, x, y);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -31,7 +31,7 @@
 /**
  * An {@code IntegerConvert} converts an integer to an integer of different width.
  */
-public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable {
+public abstract class IntegerConvertNode extends ConvertNode implements ArithmeticLIRLowerable, Canonicalizable, MemoryArithmeticLIRLowerable {
 
     private final int resultBits;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -27,6 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -84,4 +85,13 @@
         }
         gen.setResult(this, gen.emitMul(op1, op2));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitMulMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -97,7 +98,9 @@
             if (reassociated != this) {
                 return reassociated;
             }
-            if (c < 0) {
+            if (c < 0 || ((IntegerStamp) StampFactory.forKind(y().getKind())).contains(-c)) {
+                // Adding a negative is more friendly to the backend since adds are
+                // commutative, so prefer add when it fits.
                 return IntegerArithmeticNode.add(graph(), x(), ConstantNode.forIntegerStamp(stamp(), -c, graph()));
             }
         } else if (x().isConstant()) {
@@ -117,4 +120,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitSub(gen.operand(x()), gen.operand(y())));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitSubMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -25,6 +25,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -33,7 +34,7 @@
  * expression "(x &amp; y) == 0", meaning that it will return true if (and only if) no bit is set in
  * both x and y.
  */
-public class IntegerTestNode extends LogicNode implements Canonicalizable, LIRLowerable {
+public class IntegerTestNode extends LogicNode implements Canonicalizable, LIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
@@ -76,4 +77,9 @@
         }
         return this;
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        return false;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -112,4 +113,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitNarrow(gen.operand(getInput()), getResultBits()));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitNarrowMemory(getResultBits(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -75,4 +76,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitOr(gen.operand(x()), gen.operand(y())));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitOrMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -34,7 +35,7 @@
  * of a primitive value to some other incompatible stamp. The new stamp must have the same width as
  * the old stamp.
  */
-public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable {
+public class ReinterpretNode extends FloatingNode implements Canonicalizable, ArithmeticLIRLowerable, MemoryArithmeticLIRLowerable {
 
     @Input private ValueNode value;
 
@@ -106,6 +107,15 @@
         gen.setResult(this, gen.emitReinterpret(kind, gen.operand(value())));
     }
 
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitReinterpretMemory(stamp(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
+
     public static ValueNode reinterpret(Kind toKind, ValueNode value) {
         return value.graph().unique(new ReinterpretNode(toKind, value));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -107,4 +108,14 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitSignExtend(gen.operand(getInput()), getInputBits(), getResultBits()));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        assert !access.nullCheckLocation().getValueKind().isUnsigned() : "can't sign extend unsigned value";
+        Value result = gen.emitSignExtendMemory(access, access.nullCheckLocation().getValueKind().getBitCount(), getResultBits());
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -74,4 +75,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitXor(gen.operand(x()), gen.operand(y())));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitXorMemory(x(), y(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Thu Mar 20 15:57:03 2014 -0700
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
@@ -87,4 +88,13 @@
     public void generate(ArithmeticLIRGenerator gen) {
         gen.setResult(this, gen.emitZeroExtend(gen.operand(getInput()), getInputBits(), getResultBits()));
     }
+
+    @Override
+    public boolean generate(MemoryArithmeticLIRLowerer gen, Access access) {
+        Value result = gen.emitZeroExtendMemory(getInputBits(), getResultBits(), access);
+        if (result != null) {
+            gen.setResult(this, result);
+        }
+        return result != null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/ArithmeticLIRGenerator.java	Thu Mar 20 15:57:03 2014 -0700
@@ -35,6 +35,8 @@
 
     Value operand(ValueNode object);
 
+    boolean hasOperand(ValueNode object);
+
     Value setResult(ValueNode x, Value operand);
 
     PlatformKind getPlatformKind(Stamp stamp);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerable.java	Thu Mar 20 15:57:03 2014 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+import com.oracle.graal.nodes.extended.*;
+
+/**
+ * Marks nodes which may be lowered in combination with a memory operation.
+ */
+public interface MemoryArithmeticLIRLowerable {
+
+    /**
+     * Attempt to generate a memory form of a node operation. On platforms that support it this will
+     * be called when the merging is safe.
+     * 
+     * @param gen
+     * @param access the memory input which can potentially merge into this operation.
+     * @return null if it's not possible to emit a memory form of this operation. A non-null value
+     *         will be set as the operand of this node.
+     */
+    boolean generate(MemoryArithmeticLIRLowerer gen, Access access);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MemoryArithmeticLIRLowerer.java	Thu Mar 20 15:57:03 2014 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.FloatConvertNode.FloatConvert;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * This interface can be used to generate LIR for arithmetic operations where one of the operations
+ * is load (@see ArithmeticLIRLowerable).
+ */
+public interface MemoryArithmeticLIRLowerer {
+
+    Value setResult(ValueNode x, Value operand);
+
+    Value emitAddMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitMulMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitSubMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitDivMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitRemMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitXorMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitOrMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitAndMemory(ValueNode x, ValueNode y, Access access);
+
+    Value emitReinterpretMemory(Stamp stamp, Access access);
+
+    Value emitSignExtendMemory(Access access, int fromBits, int toBits);
+
+    Value emitNarrowMemory(int resultBits, Access access);
+
+    Value emitZeroExtendMemory(int inputBits, int resultBits, Access access);
+
+    Value emitFloatConvertMemory(FloatConvert op, Access access);
+
+    boolean memoryPeephole(Access valueNode, MemoryArithmeticLIRLowerable operation, List<ValueNode> deferred);
+
+    boolean emitIfMemory(IfNode ifNode, Access access);
+
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Mar 20 15:57:03 2014 -0700
@@ -273,10 +273,10 @@
 // @formatter:on
         private boolean performReplacement(final Node node, Node canonical) {
             if (canonical == node) {
-                Debug.log("Canonicalizer: work on %s", node);
+                Debug.log("Canonicalizer: work on %1s", node);
                 return false;
             } else {
-                Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
+                Debug.log("Canonicalizer: replacing %1s with %1s", node, canonical);
                 METRIC_CANONICALIZED_NODES.increment();
                 StructuredGraph graph = (StructuredGraph) node.graph();
                 if (node instanceof FloatingNode) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Thu Mar 20 13:41:32 2014 -0700
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Thu Mar 20 15:57:03 2014 -0700
@@ -271,6 +271,8 @@
     public static final OptionValue<Boolean> OptDevirtualizeInvokesOptimistically = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true);
+    @Option(help = "Allow backend to emit arithmetic and compares directly against memory.")
+    public static final OptionValue<Boolean> OptFoldMemory = new OptionValue<>(true);
 
 
     /**