changeset 17197:ec35bb4eccb8

Add support for other data types to integer arithmetic nodes.
author Roland Schatz <roland.schatz@oracle.com>
date Wed, 24 Sep 2014 13:46:37 +0200
parents 189479d72dc8
children 75177b3cc5a8
files graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.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/BinaryArithmeticNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.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/IntegerDivNode.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/MulNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.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/SubNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java
diffstat 42 files changed, 1349 insertions(+), 675 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/Constant.java	Wed Sep 24 13:46:37 2014 +0200
@@ -255,6 +255,12 @@
      */
     public static Constant forIntegerKind(Kind kind, long i) {
         switch (kind) {
+            case Byte:
+                return new PrimitiveConstant(kind, (byte) i);
+            case Short:
+                return new PrimitiveConstant(kind, (short) i);
+            case Char:
+                return new PrimitiveConstant(kind, (char) i);
             case Int:
                 return new PrimitiveConstant(kind, (int) i);
             case Long:
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Wed Sep 24 13:46:37 2014 +0200
@@ -275,7 +275,7 @@
 
     protected AMD64Arithmetic getOp(ValueNode operation, Access access) {
         Kind memoryKind = getMemoryKind(access);
-        if (operation.getNodeClass().is(IntegerAddNode.class)) {
+        if (operation.getNodeClass().is(AddNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return IADD;
@@ -310,7 +310,7 @@
                 case Long:
                     return LXOR;
             }
-        } else if (operation.getNodeClass().is(IntegerSubNode.class)) {
+        } else if (operation.getNodeClass().is(SubNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return ISUB;
@@ -324,7 +324,7 @@
                 case Double:
                     return DSUB;
             }
-        } else if (operation.getNodeClass().is(IntegerMulNode.class)) {
+        } else if (operation.getNodeClass().is(MulNode.class)) {
             switch (memoryKind) {
                 case Int:
                     return IMUL;
@@ -370,7 +370,7 @@
         return null;
     }
 
-    @MatchRule("(Or (LeftShift value (IntegerSub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
+    @MatchRule("(Or (LeftShift value (Sub Constant=delta shiftAmount)) (UnsignedRightShift value shiftAmount))")
     public ComplexMatchResult rotateRightVariable(ValueNode value, ConstantNode delta, ValueNode shiftAmount) {
         if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
             return builder -> getLIRGeneratorTool().emitRor(operand(value), operand(shiftAmount));
@@ -378,7 +378,7 @@
         return null;
     }
 
-    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (IntegerSub Constant=delta shiftAmount)))")
+    @MatchRule("(Or (LeftShift value shiftAmount) (UnsignedRightShift value (Sub Constant=delta shiftAmount)))")
     public ComplexMatchResult rotateLeftVariable(ValueNode value, ValueNode shiftAmount, ConstantNode delta) {
         if (delta.asConstant().asLong() == 0 || delta.asConstant().asLong() == 32) {
             return builder -> getLIRGeneratorTool().emitRol(operand(value), operand(shiftAmount));
@@ -386,18 +386,18 @@
         return null;
     }
 
-    @MatchRule("(IntegerAdd value Read=access)")
-    @MatchRule("(IntegerSub value Read=access)")
-    @MatchRule("(IntegerMul value Read=access)")
+    @MatchRule("(Add value Read=access)")
+    @MatchRule("(Sub value Read=access)")
+    @MatchRule("(Mul value Read=access)")
     @MatchRule("(FloatAdd value Read=access)")
     @MatchRule("(FloatSub value Read=access)")
     @MatchRule("(FloatMul value Read=access)")
     @MatchRule("(Or value Read=access)")
     @MatchRule("(Xor value Read=access)")
     @MatchRule("(And value Read=access)")
-    @MatchRule("(IntegerAdd value FloatingRead=access)")
-    @MatchRule("(IntegerSub value FloatingRead=access)")
-    @MatchRule("(IntegerMul value FloatingRead=access)")
+    @MatchRule("(Add value FloatingRead=access)")
+    @MatchRule("(Sub value FloatingRead=access)")
+    @MatchRule("(Mul value FloatingRead=access)")
     @MatchRule("(FloatAdd value FloatingRead=access)")
     @MatchRule("(FloatSub value FloatingRead=access)")
     @MatchRule("(FloatMul value FloatingRead=access)")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Wed Sep 24 13:46:37 2014 +0200
@@ -0,0 +1,168 @@
+/*
+ * 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.common.type;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Information about arithmetic operations.
+ */
+public final class ArithmeticOpTable {
+
+    protected UnaryOp neg;
+    protected BinaryOp add;
+    protected BinaryOp sub;
+
+    protected BinaryOp mul;
+    protected BinaryOp div;
+    protected BinaryOp rem;
+
+    public static ArithmeticOpTable forStamp(Stamp s) {
+        return ((ArithmeticStamp) s).getOps();
+    }
+
+    /**
+     * Describes the unary negation operation.
+     */
+    public final UnaryOp getNeg() {
+        return neg;
+    }
+
+    /**
+     * Describes the addition operation.
+     */
+    public final BinaryOp getAdd() {
+        return add;
+    }
+
+    /**
+     * Describes the subtraction operation.
+     */
+    public final BinaryOp getSub() {
+        return sub;
+    }
+
+    /**
+     * Describes the multiplication operation.
+     */
+    public final BinaryOp getMul() {
+        return mul;
+    }
+
+    /**
+     * Describes the division operation.
+     */
+    public final BinaryOp getDiv() {
+        return div;
+    }
+
+    /**
+     * Describes the remainder operation.
+     */
+    public final BinaryOp getRem() {
+        return rem;
+    }
+
+    /**
+     * Describes a unary arithmetic operation.
+     */
+    public abstract static class UnaryOp {
+
+        /**
+         * Apply the operation to a {@link Constant}.
+         */
+        public abstract Constant foldConstant(Constant value);
+
+        /**
+         * Apply the operation to a {@link Stamp}.
+         */
+        public abstract Stamp foldStamp(Stamp stamp);
+    }
+
+    /**
+     * Describes a binary arithmetic operation.
+     */
+    public abstract static class BinaryOp {
+
+        private final boolean associative;
+        private final boolean commutative;
+
+        protected BinaryOp(boolean associative, boolean commutative) {
+            this.associative = associative;
+            this.commutative = commutative;
+        }
+
+        /**
+         * Apply the operation to two {@linkplain Constant Constants}.
+         */
+        public abstract Constant foldConstant(Constant a, Constant b);
+
+        /**
+         * Apply the operation to two {@linkplain Stamp Stamps}.
+         */
+        public abstract Stamp foldStamp(Stamp a, Stamp b);
+
+        /**
+         * Checks whether this operation is associative. An operation is associative when
+         * {@code (a . b) . c == a . (b . c)} for all a, b, c. Note that you still have to be
+         * careful with inverses. For example the integer subtraction operation will report
+         * {@code true} here, since you can still reassociate as long as the correct negations are
+         * inserted.
+         */
+        public final boolean isAssociative() {
+            return associative;
+        }
+
+        /**
+         * Checks whether this operation is commutative. An operation is commutative when
+         * {@code a . b == b . a} for all a, b.
+         */
+        public final boolean isCommutative() {
+            return commutative;
+        }
+
+        /**
+         * Check whether a {@link Constant} is a neutral element for this operation. A neutral
+         * element is any element {@code n} where {@code a . n == a} for all a.
+         *
+         * @param n the {@link Constant} that should be tested
+         * @return true iff for all {@code a}: {@code a . n == a}
+         */
+        public boolean isNeutral(Constant n) {
+            return false;
+        }
+
+        /**
+         * Check whether this operation has a zero {@code z == a . a} for each a. Examples of
+         * operations having such an element are subtraction and exclusive-or. Note that this may be
+         * different from the numbers tested by {@link #isNeutral}.
+         *
+         * @param stamp a {@link Stamp}
+         * @return a unique {@code z} such that {@code z == a . a} for each {@code a} in
+         *         {@code stamp} if it exists, otherwise {@code null}
+         */
+        public Constant getZero(Stamp stamp) {
+            return null;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticStamp.java	Wed Sep 24 13:46:37 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.common.type;
+
+/**
+ * Type describing values that support arithmetic operations.
+ */
+public abstract class ArithmeticStamp extends Stamp {
+
+    private final ArithmeticOpTable ops;
+
+    protected ArithmeticStamp(ArithmeticOpTable ops) {
+        this.ops = ops;
+    }
+
+    public ArithmeticOpTable getOps() {
+        return ops;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ops.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof ArithmeticStamp)) {
+            return false;
+        }
+        ArithmeticStamp other = (ArithmeticStamp) obj;
+        return this.ops == other.ops;
+    }
+}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Wed Sep 24 13:46:37 2014 +0200
@@ -27,6 +27,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
 
 public class FloatStamp extends PrimitiveStamp {
 
@@ -39,7 +41,7 @@
     }
 
     public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) {
-        super(bits);
+        super(bits, OPS);
         this.lowerBound = lowerBound;
         this.upperBound = upperBound;
         this.nonNaN = nonNaN;
@@ -234,7 +236,7 @@
         if (nonNaN != other.nonNaN) {
             return false;
         }
-        return true;
+        return super.equals(other);
     }
 
     @Override
@@ -249,4 +251,189 @@
         }
         return null;
     }
+
+    private static final ArithmeticOpTable OPS = new ArithmeticOpTable();
+
+    static {
+        OPS.neg = new UnaryOp() {
+
+            @Override
+            public Constant foldConstant(Constant value) {
+                switch (value.getKind()) {
+                    case Float:
+                        return Constant.forFloat(-value.asFloat());
+                    case Double:
+                        return Constant.forDouble(-value.asDouble());
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp s) {
+                FloatStamp stamp = (FloatStamp) s;
+                return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
+            }
+        };
+
+        OPS.add = new BinaryOp(false, true) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                switch (a.getKind()) {
+                    case Float:
+                        return Constant.forFloat(a.asFloat() + b.asFloat());
+                    case Double:
+                        return Constant.forDouble(a.asDouble() + b.asDouble());
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                // TODO
+                return stamp1.unrestricted();
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                switch (n.getKind()) {
+                    case Float:
+                        return Float.compare(n.asFloat(), -0.0f) == 0;
+                    case Double:
+                        return Double.compare(n.asDouble(), -0.0) == 0;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+        };
+
+        OPS.sub = new BinaryOp(false, false) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                switch (a.getKind()) {
+                    case Float:
+                        return Constant.forFloat(a.asFloat() - b.asFloat());
+                    case Double:
+                        return Constant.forDouble(a.asDouble() - b.asDouble());
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                // TODO
+                return stamp1.unrestricted();
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                switch (n.getKind()) {
+                    case Float:
+                        return Float.compare(n.asFloat(), 0.0f) == 0;
+                    case Double:
+                        return Double.compare(n.asDouble(), 0.0) == 0;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+        };
+
+        OPS.mul = new BinaryOp(false, true) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                switch (a.getKind()) {
+                    case Float:
+                        return Constant.forFloat(a.asFloat() * b.asFloat());
+                    case Double:
+                        return Constant.forDouble(a.asDouble() * b.asDouble());
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp a, Stamp b) {
+                // TODO
+                return a.unrestricted();
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                switch (n.getKind()) {
+                    case Float:
+                        return Float.compare(n.asFloat(), 1.0f) == 0;
+                    case Double:
+                        return Double.compare(n.asDouble(), 1.0) == 0;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            // there is no multiplicative zero, since both 0.0 and -0.0 can flip sign
+        };
+
+        OPS.div = new BinaryOp(false, false) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                switch (a.getKind()) {
+                    case Float:
+                        return Constant.forFloat(a.asFloat() / b.asFloat());
+                    case Double:
+                        return Constant.forDouble(a.asDouble() / b.asDouble());
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                // TODO
+                return stamp1.unrestricted();
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                switch (n.getKind()) {
+                    case Float:
+                        return Float.compare(n.asFloat(), 1.0f) == 0;
+                    case Double:
+                        return Double.compare(n.asDouble(), 1.0) == 0;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+        };
+
+        OPS.rem = new BinaryOp(false, false) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                switch (a.getKind()) {
+                    case Float:
+                        return Constant.forFloat(a.asFloat() % b.asFloat());
+                    case Double:
+                        return Constant.forDouble(a.asDouble() % b.asDouble());
+                    default:
+                        throw GraalInternalError.shouldNotReachHere();
+                }
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                // TODO
+                return stamp1.unrestricted();
+            }
+        };
+    }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Wed Sep 24 13:46:37 2014 +0200
@@ -28,6 +28,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.spi.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
 
 /**
  * Describes the possible values of a node that produces an int or long result.
@@ -43,7 +45,7 @@
     private final long upMask;
 
     public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
-        super(bits);
+        super(bits, OPS);
         this.lowerBound = lowerBound;
         this.upperBound = upperBound;
         this.downMask = downMask;
@@ -55,7 +57,7 @@
     }
 
     @Override
-    public Stamp unrestricted() {
+    public IntegerStamp unrestricted() {
         return new IntegerStamp(getBits(), CodeUtil.minValue(getBits()), CodeUtil.maxValue(getBits()), 0, CodeUtil.mask(getBits()));
     }
 
@@ -266,7 +268,7 @@
         if (lowerBound != other.lowerBound || upperBound != other.upperBound || downMask != other.downMask || upMask != other.upMask) {
             return false;
         }
-        return true;
+        return super.equals(other);
     }
 
     public static long upMaskFor(int bits, long lowerBound, long upperBound) {
@@ -307,4 +309,219 @@
         }
         return null;
     }
+
+    private static boolean addOverflowsPositively(long x, long y, int bits) {
+        long result = x + y;
+        if (bits == 64) {
+            return (~x & ~y & result) < 0;
+        } else {
+            return result > CodeUtil.maxValue(bits);
+        }
+    }
+
+    private static boolean addOverflowsNegatively(long x, long y, int bits) {
+        long result = x + y;
+        if (bits == 64) {
+            return (x & y & ~result) < 0;
+        } else {
+            return result < CodeUtil.minValue(bits);
+        }
+    }
+
+    private static long carryBits(long x, long y) {
+        return (x + y) ^ x ^ y;
+    }
+
+    public static final ArithmeticOpTable OPS = new ArithmeticOpTable();
+
+    static {
+        OPS.neg = new UnaryOp() {
+
+            @Override
+            public Constant foldConstant(Constant value) {
+                return Constant.forIntegerKind(value.getKind(), -value.asLong());
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp s) {
+                IntegerStamp stamp = (IntegerStamp) s;
+                int bits = stamp.getBits();
+                if (stamp.lowerBound() != CodeUtil.minValue(bits)) {
+                    // TODO(ls) check if the mask calculation is correct...
+                    return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound());
+                } else {
+                    return stamp.unrestricted();
+                }
+            }
+        };
+
+        OPS.add = new BinaryOp(true, true) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                return Constant.forIntegerKind(a.getKind(), a.asLong() + b.asLong());
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                IntegerStamp a = (IntegerStamp) stamp1;
+                IntegerStamp b = (IntegerStamp) stamp2;
+
+                int bits = a.getBits();
+                assert bits == b.getBits();
+
+                if (a.isUnrestricted()) {
+                    return a;
+                } else if (b.isUnrestricted()) {
+                    return b;
+                }
+                long defaultMask = CodeUtil.mask(bits);
+                long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
+                long variableBitsWithCarry = variableBits | (carryBits(a.downMask(), b.downMask()) ^ carryBits(a.upMask(), b.upMask()));
+                long newDownMask = (a.downMask() + b.downMask()) & ~variableBitsWithCarry;
+                long newUpMask = (a.downMask() + b.downMask()) | variableBitsWithCarry;
+
+                newDownMask &= defaultMask;
+                newUpMask &= defaultMask;
+
+                long newLowerBound;
+                long newUpperBound;
+                boolean lowerOverflowsPositively = addOverflowsPositively(a.lowerBound(), b.lowerBound(), bits);
+                boolean upperOverflowsPositively = addOverflowsPositively(a.upperBound(), b.upperBound(), bits);
+                boolean lowerOverflowsNegatively = addOverflowsNegatively(a.lowerBound(), b.lowerBound(), bits);
+                boolean upperOverflowsNegatively = addOverflowsNegatively(a.upperBound(), b.upperBound(), bits);
+                if ((lowerOverflowsNegatively && !upperOverflowsNegatively) || (!lowerOverflowsPositively && upperOverflowsPositively)) {
+                    newLowerBound = CodeUtil.minValue(bits);
+                    newUpperBound = CodeUtil.maxValue(bits);
+                } else {
+                    newLowerBound = CodeUtil.signExtend((a.lowerBound() + b.lowerBound()) & defaultMask, bits);
+                    newUpperBound = CodeUtil.signExtend((a.upperBound() + b.upperBound()) & defaultMask, bits);
+                }
+                IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
+                newUpMask &= limit.upMask();
+                newUpperBound = CodeUtil.signExtend(newUpperBound & newUpMask, bits);
+                newDownMask |= limit.downMask();
+                newLowerBound |= newDownMask;
+                return new IntegerStamp(bits, newLowerBound, newUpperBound, newDownMask, newUpMask);
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                return n.asLong() == 0;
+            }
+        };
+
+        OPS.sub = new BinaryOp(true, false) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                return Constant.forIntegerKind(a.getKind(), a.asLong() - b.asLong());
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp a, Stamp b) {
+                return OPS.add.foldStamp(a, OPS.neg.foldStamp(b));
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                return n.asLong() == 0;
+            }
+
+            @Override
+            public Constant getZero(Stamp s) {
+                IntegerStamp stamp = (IntegerStamp) s;
+                return Constant.forPrimitiveInt(stamp.getBits(), 0);
+            }
+        };
+
+        OPS.mul = new BinaryOp(true, true) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                return Constant.forIntegerKind(a.getKind(), a.asLong() * b.asLong());
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                IntegerStamp a = (IntegerStamp) stamp1;
+                IntegerStamp b = (IntegerStamp) stamp2;
+                if (a.upMask() == 0) {
+                    return a;
+                } else if (b.upMask() == 0) {
+                    return b;
+                } else {
+                    // TODO
+                    return a.unrestricted();
+                }
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                return n.asLong() == 1;
+            }
+        };
+
+        OPS.div = new BinaryOp(true, false) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                return Constant.forIntegerKind(a.getKind(), a.asLong() / b.asLong());
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                IntegerStamp a = (IntegerStamp) stamp1;
+                IntegerStamp b = (IntegerStamp) stamp2;
+                assert a.getBits() == b.getBits();
+                if (b.isStrictlyPositive()) {
+                    long newLowerBound = a.lowerBound() / b.lowerBound();
+                    long newUpperBound = a.upperBound() / b.lowerBound();
+                    return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
+                } else {
+                    return a.unrestricted();
+                }
+            }
+
+            @Override
+            public boolean isNeutral(Constant n) {
+                return n.asLong() == 1;
+            }
+        };
+
+        OPS.rem = new BinaryOp(false, false) {
+
+            @Override
+            public Constant foldConstant(Constant a, Constant b) {
+                assert a.getKind() == b.getKind();
+                return Constant.forIntegerKind(a.getKind(), a.asLong() % b.asLong());
+            }
+
+            @Override
+            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+                IntegerStamp a = (IntegerStamp) stamp1;
+                IntegerStamp b = (IntegerStamp) stamp2;
+                assert a.getBits() == b.getBits();
+                // zero is always possible
+                long newLowerBound = Math.min(a.lowerBound(), 0);
+                long newUpperBound = Math.max(a.upperBound(), 0);
+
+                long magnitude; // the maximum absolute value of the result, derived from b
+                if (b.lowerBound() == CodeUtil.minValue(b.getBits())) {
+                    // Math.abs(...) - 1 does not work in a case
+                    magnitude = CodeUtil.maxValue(b.getBits());
+                } else {
+                    magnitude = Math.max(Math.abs(b.lowerBound()), Math.abs(b.upperBound())) - 1;
+                }
+                newLowerBound = Math.max(newLowerBound, -magnitude);
+                newUpperBound = Math.min(newUpperBound, magnitude);
+
+                return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
+            }
+        };
+    }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/PrimitiveStamp.java	Wed Sep 24 13:46:37 2014 +0200
@@ -25,11 +25,12 @@
 /**
  * Type describing primitive values.
  */
-public abstract class PrimitiveStamp extends Stamp {
+public abstract class PrimitiveStamp extends ArithmeticStamp {
 
     private final int bits;
 
-    protected PrimitiveStamp(int bits) {
+    protected PrimitiveStamp(int bits, ArithmeticOpTable ops) {
+        super(ops);
         this.bits = bits;
     }
 
@@ -51,7 +52,7 @@
     @Override
     public int hashCode() {
         final int prime = 31;
-        int result = 1;
+        int result = super.hashCode();
         result = prime * result + bits;
         return result;
     }
@@ -61,10 +62,13 @@
         if (this == obj) {
             return true;
         }
-        if (obj instanceof PrimitiveStamp) {
-            PrimitiveStamp other = (PrimitiveStamp) obj;
-            return bits == other.bits;
+        if (!(obj instanceof PrimitiveStamp)) {
+            return false;
         }
-        return false;
+        PrimitiveStamp other = (PrimitiveStamp) obj;
+        if (bits != other.bits) {
+            return false;
+        }
+        return super.equals(obj);
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/Stamp.java	Wed Sep 24 13:46:37 2014 +0200
@@ -115,4 +115,8 @@
     public Constant asConstant() {
         return null;
     }
+
+    public final Stamp asStamp() {
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Wed Sep 24 13:46:37 2014 +0200
@@ -59,7 +59,7 @@
 @MatchableNode(nodeClass = FloatSubNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"object", "location"})
 @MatchableNode(nodeClass = IfNode.class, inputs = {"condition"})
-@MatchableNode(nodeClass = IntegerSubNode.class, inputs = {"x", "y"})
+@MatchableNode(nodeClass = SubNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = LeftShiftNode.class, inputs = {"x", "y"})
 @MatchableNode(nodeClass = NarrowNode.class, inputs = {"value"})
 @MatchableNode(nodeClass = ReadNode.class, inputs = {"object", "location"})
@@ -73,11 +73,11 @@
 @MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = FloatMulNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerAddNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = AddNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerBelowNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerEqualsNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerLessThanNode.class, inputs = {"x", "y"}, commutative = true)
-@MatchableNode(nodeClass = IntegerMulNode.class, inputs = {"x", "y"}, commutative = true)
+@MatchableNode(nodeClass = MulNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = IntegerTestNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = ObjectEqualsNode.class, inputs = {"x", "y"}, commutative = true)
 @MatchableNode(nodeClass = OrNode.class, inputs = {"x", "y"}, commutative = true)
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Wed Sep 24 13:46:37 2014 +0200
@@ -265,18 +265,18 @@
         return null;
     }
 
-    @MatchRule("(IntegerAdd value (Read=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(IntegerSub value (Read=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(IntegerMul value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Add value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Sub value (Read=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Mul value (Read=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(FloatAdd value (Read=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(FloatSub value (Read=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(FloatMul value (Read=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(Or value (Read=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(Xor value (Read=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(And value (Read=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(IntegerAdd value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(IntegerSub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
-    @MatchRule("(IntegerMul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Add value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Sub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
+    @MatchRule("(Mul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(FloatAdd value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(FloatSub value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
     @MatchRule("(FloatMul value (FloatingRead=access (Compression=compress object) ConstantLocation=location))")
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Wed Sep 24 13:46:37 2014 +0200
@@ -387,7 +387,7 @@
         ReadNode readArray = graph.add(ReadNode.create(thread, arrayLocation, StampFactory.forKind(wordKind), BarrierType.NONE));
         ConstantLocationNode location = ConstantLocationNode.create(LocationIdentity.ANY_LOCATION, Kind.Long, Unsafe.ARRAY_LONG_INDEX_SCALE * index, graph);
         ReadNode read = graph.add(ReadNode.create(readArray, location, StampFactory.forKind(Kind.Long), BarrierType.NONE));
-        IntegerAddNode add = graph.unique(IntegerAddNode.create(read, counter.getIncrement()));
+        AddNode add = graph.unique(AddNode.create(read, counter.getIncrement()));
         WriteNode write = graph.add(WriteNode.create(readArray, add, location, BarrierType.NONE));
 
         graph.addBeforeFixed(counter, thread);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed Sep 24 13:46:37 2014 +0200
@@ -472,17 +472,17 @@
 
             @Override
             protected ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y) {
-                return IntegerAddNode.create(x, y);
+                return AddNode.create(x, y);
             }
 
             @Override
             protected ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y) {
-                return IntegerSubNode.create(x, y);
+                return SubNode.create(x, y);
             }
 
             @Override
             protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) {
-                return IntegerMulNode.create(x, y);
+                return MulNode.create(x, y);
             }
 
             @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Wed Sep 24 13:46:37 2014 +0200
@@ -32,9 +32,9 @@
     private ValuePhiNode phi;
     private ValueNode init;
     private ValueNode rawStride;
-    private IntegerArithmeticNode op;
+    private BinaryArithmeticNode op;
 
-    public BasicInductionVariable(LoopEx loop, ValuePhiNode phi, ValueNode init, ValueNode rawStride, IntegerArithmeticNode op) {
+    public BasicInductionVariable(LoopEx loop, ValuePhiNode phi, ValueNode init, ValueNode rawStride, BinaryArithmeticNode op) {
         super(loop);
         this.phi = phi;
         this.init = init;
@@ -59,10 +59,10 @@
                 dir = Direction.Down;
             }
             if (dir != null) {
-                if (op instanceof IntegerAddNode) {
+                if (op instanceof AddNode) {
                     return dir;
                 } else {
-                    assert op instanceof IntegerSubNode;
+                    assert op instanceof SubNode;
                     return dir.opposite();
                 }
             }
@@ -82,10 +82,10 @@
 
     @Override
     public ValueNode strideNode() {
-        if (op instanceof IntegerAddNode) {
+        if (op instanceof AddNode) {
             return rawStride;
         }
-        if (op instanceof IntegerSubNode) {
+        if (op instanceof SubNode) {
             return graph().unique(NegateNode.create(rawStride));
         }
         throw GraalInternalError.shouldNotReachHere();
@@ -108,10 +108,10 @@
 
     @Override
     public long constantStride() {
-        if (op instanceof IntegerAddNode) {
+        if (op instanceof AddNode) {
             return rawStride.asConstant().asLong();
         }
-        if (op instanceof IntegerSubNode) {
+        if (op instanceof SubNode) {
             return -rawStride.asConstant().asLong();
         }
         throw GraalInternalError.shouldNotReachHere();
@@ -131,7 +131,7 @@
         if (!maxTripCount.stamp().isCompatible(stamp)) {
             maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
         }
-        return IntegerArithmeticNode.add(graph, IntegerArithmeticNode.mul(graph, stride, IntegerArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerStamp(stamp, 1, graph))), initNode);
+        return BinaryArithmeticNode.add(graph, BinaryArithmeticNode.mul(graph, stride, BinaryArithmeticNode.sub(graph, maxTripCount, ConstantNode.forIntegerStamp(stamp, 1, graph))), initNode);
     }
 
     @Override
@@ -141,7 +141,7 @@
         if (!maxTripCount.stamp().isCompatible(stamp)) {
             maxTripCount = IntegerConvertNode.convert(maxTripCount, stamp, graph());
         }
-        return IntegerArithmeticNode.add(graph(), IntegerArithmeticNode.mul(graph(), strideNode(), maxTripCount), initNode());
+        return BinaryArithmeticNode.add(graph(), BinaryArithmeticNode.mul(graph(), strideNode(), maxTripCount), initNode());
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Wed Sep 24 13:46:37 2014 +0200
@@ -22,7 +22,7 @@
  */
 package com.oracle.graal.loop;
 
-import static com.oracle.graal.nodes.calc.IntegerArithmeticNode.*;
+import static com.oracle.graal.nodes.calc.BinaryArithmeticNode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -55,12 +55,12 @@
     public ValueNode maxTripCountNode(boolean assumePositive) {
         StructuredGraph graph = iv.valueNode().graph();
         Stamp stamp = iv.valueNode().stamp();
-        IntegerArithmeticNode range = IntegerArithmeticNode.sub(graph, end, iv.initNode());
+        BinaryArithmeticNode range = BinaryArithmeticNode.sub(graph, end, iv.initNode());
         if (oneOff) {
             if (iv.direction() == Direction.Up) {
-                range = IntegerArithmeticNode.add(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
+                range = BinaryArithmeticNode.add(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
             } else {
-                range = IntegerArithmeticNode.sub(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
+                range = BinaryArithmeticNode.sub(graph, range, ConstantNode.forIntegerStamp(stamp, 1, graph));
             }
         }
         IntegerDivNode div = graph.add(IntegerDivNode.create(range, iv.strideNode()));
@@ -144,14 +144,14 @@
         CompareNode cond; // we use a negated guard with a < condition to achieve a >=
         ConstantNode one = ConstantNode.forIntegerStamp(stamp, 1, graph);
         if (iv.direction() == Direction.Up) {
-            IntegerArithmeticNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.maxValue(stamp.getBits()), graph), sub(graph, iv.strideNode(), one));
+            BinaryArithmeticNode v1 = sub(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.maxValue(stamp.getBits()), graph), sub(graph, iv.strideNode(), one));
             if (oneOff) {
                 v1 = sub(graph, v1, one);
             }
             cond = graph.unique(IntegerLessThanNode.create(v1, end));
         } else {
             assert iv.direction() == Direction.Down;
-            IntegerArithmeticNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.minValue(stamp.getBits()), graph), sub(graph, one, iv.strideNode()));
+            BinaryArithmeticNode v1 = add(graph, ConstantNode.forIntegerStamp(stamp, CodeUtil.minValue(stamp.getBits()), graph), sub(graph, one, iv.strideNode()));
             if (oneOff) {
                 v1 = add(graph, v1, one);
             }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Wed Sep 24 13:46:37 2014 +0200
@@ -31,9 +31,9 @@
 
     private InductionVariable base;
     private ValueNode offset;
-    private IntegerArithmeticNode value;
+    private BinaryArithmeticNode value;
 
-    public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, IntegerArithmeticNode value) {
+    public DerivedOffsetInductionVariable(LoopEx loop, InductionVariable base, ValueNode offset, BinaryArithmeticNode value) {
         super(loop);
         this.base = base;
         this.offset = offset;
@@ -72,7 +72,7 @@
 
     @Override
     public long constantStride() {
-        if (value instanceof IntegerSubNode && base.valueNode() == value.getY()) {
+        if (value instanceof SubNode && base.valueNode() == value.getY()) {
             return -base.constantStride();
         }
         return base.constantStride();
@@ -85,7 +85,7 @@
 
     @Override
     public ValueNode strideNode() {
-        if (value instanceof IntegerSubNode && base.valueNode() == value.getY()) {
+        if (value instanceof SubNode && base.valueNode() == value.getY()) {
             return graph().unique(NegateNode.create(base.strideNode()));
         }
         return base.strideNode();
@@ -112,10 +112,10 @@
     }
 
     private long op(long b, long o) {
-        if (value instanceof IntegerAddNode) {
+        if (value instanceof AddNode) {
             return b + o;
         }
-        if (value instanceof IntegerSubNode) {
+        if (value instanceof SubNode) {
             if (base.valueNode() == value.getX()) {
                 return b - o;
             } else {
@@ -127,15 +127,15 @@
     }
 
     private ValueNode op(ValueNode b, ValueNode o) {
-        if (value instanceof IntegerAddNode) {
-            return IntegerArithmeticNode.add(graph(), b, o);
+        if (value instanceof AddNode) {
+            return BinaryArithmeticNode.add(graph(), b, o);
         }
-        if (value instanceof IntegerSubNode) {
+        if (value instanceof SubNode) {
             if (base.valueNode() == value.getX()) {
-                return IntegerArithmeticNode.sub(graph(), b, o);
+                return BinaryArithmeticNode.sub(graph(), b, o);
             } else {
                 assert base.valueNode() == value.getY();
-                return IntegerArithmeticNode.sub(graph(), o, b);
+                return BinaryArithmeticNode.sub(graph(), o, b);
             }
         }
         throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Wed Sep 24 13:46:37 2014 +0200
@@ -73,12 +73,12 @@
 
     @Override
     public ValueNode initNode() {
-        return IntegerArithmeticNode.mul(graph(), base.initNode(), scale);
+        return BinaryArithmeticNode.mul(graph(), base.initNode(), scale);
     }
 
     @Override
     public ValueNode strideNode() {
-        return IntegerArithmeticNode.mul(graph(), base.strideNode(), scale);
+        return BinaryArithmeticNode.mul(graph(), base.strideNode(), scale);
     }
 
     @Override
@@ -103,12 +103,12 @@
 
     @Override
     public ValueNode extremumNode(boolean assumePositiveTripCount, Stamp stamp) {
-        return IntegerArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(scale, stamp, graph()));
+        return BinaryArithmeticNode.mul(graph(), base.extremumNode(assumePositiveTripCount, stamp), IntegerConvertNode.convert(scale, stamp, graph()));
     }
 
     @Override
     public ValueNode exitValueNode() {
-        return IntegerArithmeticNode.mul(graph(), base.exitValueNode(), scale);
+        return BinaryArithmeticNode.mul(graph(), base.exitValueNode(), scale);
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Wed Sep 24 13:46:37 2014 +0200
@@ -56,7 +56,7 @@
             }
             ValueNode stride = addSub(backValue, phi);
             if (stride != null) {
-                BasicInductionVariable biv = new BasicInductionVariable(loop, (ValuePhiNode) phi, phi.valueAt(forwardEnd), stride, (IntegerArithmeticNode) backValue);
+                BasicInductionVariable biv = new BasicInductionVariable(loop, (ValuePhiNode) phi, phi.valueAt(forwardEnd), stride, (BinaryArithmeticNode) backValue);
                 ivs.put(phi, biv);
                 bivs.add(biv);
             }
@@ -77,7 +77,7 @@
                 ValueNode offset = addSub(op, baseIvNode);
                 ValueNode scale;
                 if (offset != null) {
-                    iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (IntegerArithmeticNode) op);
+                    iv = new DerivedOffsetInductionVariable(loop, baseIv, offset, (BinaryArithmeticNode) op);
                 } else if (op instanceof NegateNode) {
                     iv = new DerivedScaledInductionVariable(loop, baseIv, (NegateNode) op);
                 } else if ((scale = mul(op, baseIvNode)) != null) {
@@ -93,8 +93,8 @@
     }
 
     private ValueNode addSub(ValueNode op, ValueNode base) {
-        if (op instanceof IntegerAddNode || op instanceof IntegerSubNode) {
-            IntegerArithmeticNode aritOp = (IntegerArithmeticNode) op;
+        if (op instanceof AddNode || op instanceof SubNode) {
+            BinaryArithmeticNode aritOp = (BinaryArithmeticNode) op;
             if (aritOp.getX() == base && loop.isOutsideLoop(aritOp.getY())) {
                 return aritOp.getY();
             } else if (aritOp.getY() == base && loop.isOutsideLoop(aritOp.getX())) {
@@ -105,8 +105,8 @@
     }
 
     private ValueNode mul(ValueNode op, ValueNode base) {
-        if (op instanceof IntegerMulNode) {
-            IntegerMulNode mul = (IntegerMulNode) op;
+        if (op instanceof MulNode) {
+            MulNode mul = (MulNode) op;
             if (mul.getX() == base && loop.isOutsideLoop(mul.getY())) {
                 return mul.getY();
             } else if (mul.getY() == base && loop.isOutsideLoop(mul.getX())) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Wed Sep 24 13:46:37 2014 +0200
@@ -138,10 +138,10 @@
         InvariantPredicate invariant = new InvariantPredicate();
         StructuredGraph graph = loopBegin().graph();
         for (BinaryNode binary : whole().nodes().filter(BinaryNode.class)) {
-            if (!BinaryNode.canTryReassociate(binary)) {
+            if (!BinaryArithmeticNode.canTryReassociate(binary)) {
                 continue;
             }
-            BinaryNode result = BinaryNode.reassociate(binary, invariant, binary.getX(), binary.getY());
+            BinaryNode result = BinaryArithmeticNode.reassociate(binary, invariant, binary.getX(), binary.getY());
             if (result != binary) {
                 if (Debug.isLogEnabled()) {
                     Debug.log("%s : Reassociated %s into %s", graph.method().format("%H::%n"), binary, result);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -247,8 +247,8 @@
         for (int i = 0; i < phi.valueCount(); i++) {
             ValueNode input = phi.valueAt(i);
             long increment = NO_INCREMENT;
-            if (input != null && input instanceof IntegerAddNode) {
-                IntegerAddNode add = (IntegerAddNode) input;
+            if (input != null && input instanceof AddNode) {
+                AddNode add = (AddNode) input;
                 if (add.getX() == phi && add.getY().isConstant()) {
                     increment = add.getY().asConstant().asLong();
                 } else if (add.getY() == phi && add.getX().isConstant()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo(shortName = "+")
+public class AddNode extends BinaryArithmeticNode implements NarrowableArithmeticNode {
+
+    public static AddNode create(ValueNode x, ValueNode y) {
+        return USE_GENERATED_NODES ? new AddNodeGen(x, y) : new AddNode(x, y);
+    }
+
+    protected AddNode(ValueNode x, ValueNode y) {
+        super(ArithmeticOpTable.forStamp(x.stamp()).getAdd(), x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX.isConstant() && !forY.isConstant()) {
+            return AddNode.create(forY, forX);
+        }
+        boolean associative = getOp().isAssociative();
+        if (associative) {
+            if (forX instanceof SubNode) {
+                SubNode sub = (SubNode) forX;
+                if (sub.getY() == forY) {
+                    // (a - b) + b
+                    return sub.getX();
+                }
+            }
+            if (forY instanceof SubNode) {
+                SubNode sub = (SubNode) forY;
+                if (sub.getY() == forX) {
+                    // b + (a - b)
+                    return sub.getX();
+                }
+            }
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (getOp().isNeutral(c)) {
+                return forX;
+            }
+            if (associative) {
+                // canonicalize expressions like "(a + 1) + 2"
+                BinaryNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+                if (reassociated != this) {
+                    return reassociated;
+                }
+            }
+        }
+        if (forX instanceof NegateNode) {
+            return BinaryArithmeticNode.sub(forY, ((NegateNode) forX).getValue());
+        } else if (forY instanceof NegateNode) {
+            return BinaryArithmeticNode.sub(forX, ((NegateNode) forY).getValue());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+        Value op1 = builder.operand(getX());
+        assert op1 != null : getX() + ", this=" + this;
+        Value op2 = builder.operand(getY());
+        if (!getY().isConstant() && !FloatAddNode.livesLonger(this, getY(), builder)) {
+            Value op = op1;
+            op1 = op2;
+            op2 = op;
+        }
+        builder.setResult(this, gen.emitAdd(op1, op2));
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -89,7 +89,7 @@
                 }
             }
 
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+            return BinaryArithmeticNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
         return this;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2009, 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.calc;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo
+public abstract class BinaryArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
+
+    private final BinaryOp op;
+
+    public BinaryArithmeticNode(BinaryOp op, ValueNode x, ValueNode y) {
+        super(op.foldStamp(x.stamp(), y.stamp()), x, y);
+        this.op = op;
+    }
+
+    public BinaryOp getOp() {
+        return op;
+    }
+
+    @Override
+    public Constant evalConst(Constant... inputs) {
+        assert inputs.length == 2;
+        return op.foldConstant(inputs[0], inputs[1]);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            Constant ret = op.foldConstant(forX.asConstant(), forY.asConstant());
+            return ConstantNode.forPrimitive(stamp(), ret);
+        }
+        return this;
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(op.foldStamp(getX().stamp(), getY().stamp()));
+    }
+
+    public static AddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        return graph.unique(AddNode.create(v1, v2));
+    }
+
+    public static AddNode add(ValueNode v1, ValueNode v2) {
+        return AddNode.create(v1, v2);
+    }
+
+    public static MulNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        return graph.unique(MulNode.create(v1, v2));
+    }
+
+    public static MulNode mul(ValueNode v1, ValueNode v2) {
+        return MulNode.create(v1, v2);
+    }
+
+    public static SubNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) {
+        return graph.unique(SubNode.create(v1, v2));
+    }
+
+    public static SubNode sub(ValueNode v1, ValueNode v2) {
+        return SubNode.create(v1, v2);
+    }
+
+    private enum ReassociateMatch {
+        x,
+        y;
+
+        public ValueNode getValue(BinaryNode binary) {
+            switch (this) {
+                case x:
+                    return binary.getX();
+                case y:
+                    return binary.getY();
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        public ValueNode getOtherValue(BinaryNode binary) {
+            switch (this) {
+                case x:
+                    return binary.getY();
+                case y:
+                    return binary.getX();
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+    }
+
+    public static boolean canTryReassociate(BinaryNode node) {
+        return (node instanceof BinaryArithmeticNode && ((BinaryArithmeticNode) node).getOp().isAssociative()) || node instanceof AndNode || node instanceof OrNode || node instanceof XorNode;
+    }
+
+    public static ReassociateMatch findReassociate(BinaryNode binary, NodePredicate criterion) {
+        boolean resultX = criterion.apply(binary.getX());
+        boolean resultY = criterion.apply(binary.getY());
+        if (resultX && !resultY) {
+            return ReassociateMatch.x;
+        }
+        if (!resultX && resultY) {
+            return ReassociateMatch.y;
+        }
+        return null;
+    }
+
+    //@formatter:off
+    /*
+     * In reassociate, complexity comes from the handling of IntegerSub (non commutative) which can
+     * be mixed with IntegerAdd. It first tries to find m1, m2 which match the criterion :
+     * (a o m2) o m1
+     * (m2 o a) o m1
+     * m1 o (a o m2)
+     * m1 o (m2 o a)
+     * It then produces 4 boolean for the -/+ cases:
+     * invertA : should the final expression be like *-a (rather than a+*)
+     * aSub : should the final expression be like a-* (rather than a+*)
+     * invertM1 : should the final expression contain -m1
+     * invertM2 : should the final expression contain -m2
+     *
+     */
+    //@formatter:on
+    /**
+     * Tries to re-associate values which satisfy the criterion. For example with a constantness
+     * criterion: {@code (a + 2) + 1 => a + (1 + 2)}
+     * <p>
+     * This method accepts only {@linkplain #canTryReassociate(BinaryNode) reassociable} operations
+     * such as +, -, *, &amp;, | and ^
+     *
+     * @param forY
+     * @param forX
+     */
+    public static BinaryNode reassociate(BinaryNode node, NodePredicate criterion, ValueNode forX, ValueNode forY) {
+        assert canTryReassociate(node);
+        ReassociateMatch match1 = findReassociate(node, criterion);
+        if (match1 == null) {
+            return node;
+        }
+        ValueNode otherValue = match1.getOtherValue(node);
+        boolean addSub = false;
+        boolean subAdd = false;
+        if (otherValue.getClass() != node.getClass()) {
+            if (node instanceof AddNode && otherValue instanceof SubNode) {
+                addSub = true;
+            } else if (node instanceof SubNode && otherValue instanceof AddNode) {
+                subAdd = true;
+            } else {
+                return node;
+            }
+        }
+        BinaryNode other = (BinaryNode) otherValue;
+        ReassociateMatch match2 = findReassociate(other, criterion);
+        if (match2 == null) {
+            return node;
+        }
+        boolean invertA = false;
+        boolean aSub = false;
+        boolean invertM1 = false;
+        boolean invertM2 = false;
+        if (addSub) {
+            invertM2 = match2 == ReassociateMatch.y;
+            invertA = !invertM2;
+        } else if (subAdd) {
+            invertA = invertM2 = match1 == ReassociateMatch.x;
+            invertM1 = !invertM2;
+        } else if (node instanceof SubNode && other instanceof SubNode) {
+            invertA = match1 == ReassociateMatch.x ^ match2 == ReassociateMatch.x;
+            aSub = match1 == ReassociateMatch.y && match2 == ReassociateMatch.y;
+            invertM1 = match1 == ReassociateMatch.y && match2 == ReassociateMatch.x;
+            invertM2 = match1 == ReassociateMatch.x && match2 == ReassociateMatch.x;
+        }
+        assert !(invertM1 && invertM2) && !(invertA && aSub);
+        ValueNode m1 = match1.getValue(node);
+        ValueNode m2 = match2.getValue(other);
+        ValueNode a = match2.getOtherValue(other);
+        if (node instanceof AddNode || node instanceof SubNode) {
+            BinaryNode associated;
+            if (invertM1) {
+                associated = BinaryArithmeticNode.sub(m2, m1);
+            } else if (invertM2) {
+                associated = BinaryArithmeticNode.sub(m1, m2);
+            } else {
+                associated = BinaryArithmeticNode.add(m1, m2);
+            }
+            if (invertA) {
+                return BinaryArithmeticNode.sub(associated, a);
+            }
+            if (aSub) {
+                return BinaryArithmeticNode.sub(a, associated);
+            }
+            return BinaryArithmeticNode.add(a, associated);
+        } else if (node instanceof MulNode) {
+            return BinaryArithmeticNode.mul(a, AddNode.mul(m1, m2));
+        } else if (node instanceof AndNode) {
+            return BitLogicNode.and(a, BitLogicNode.and(m1, m2));
+        } else if (node instanceof OrNode) {
+            return BitLogicNode.or(a, BitLogicNode.or(m1, m2));
+        } else if (node instanceof XorNode) {
+            return BitLogicNode.xor(a, BitLogicNode.xor(m1, m2));
+        } else {
+            throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -24,7 +24,6 @@
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -59,38 +58,11 @@
         this.y = y;
     }
 
-    public enum ReassociateMatch {
-        x,
-        y;
-
-        public ValueNode getValue(BinaryNode binary) {
-            switch (this) {
-                case x:
-                    return binary.getX();
-                case y:
-                    return binary.getY();
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-
-        public ValueNode getOtherValue(BinaryNode binary) {
-            switch (this) {
-                case x:
-                    return binary.getY();
-                case y:
-                    return binary.getX();
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
     public static BinaryNode add(StructuredGraph graph, ValueNode x, ValueNode y) {
         assert x.stamp().isCompatible(y.stamp());
         Stamp stamp = x.stamp();
         if (stamp instanceof IntegerStamp) {
-            return IntegerArithmeticNode.add(graph, x, y);
+            return BinaryArithmeticNode.add(graph, x, y);
         } else if (stamp instanceof FloatStamp) {
             return graph.unique(FloatAddNode.create(x, y, false));
         } else {
@@ -102,7 +74,7 @@
         assert x.stamp().isCompatible(y.stamp());
         Stamp stamp = x.stamp();
         if (stamp instanceof IntegerStamp) {
-            return IntegerArithmeticNode.sub(graph, x, y);
+            return BinaryArithmeticNode.sub(graph, x, y);
         } else if (stamp instanceof FloatStamp) {
             return graph.unique(FloatSubNode.create(x, y, false));
         } else {
@@ -114,125 +86,11 @@
         assert x.stamp().isCompatible(y.stamp());
         Stamp stamp = x.stamp();
         if (stamp instanceof IntegerStamp) {
-            return IntegerArithmeticNode.mul(graph, x, y);
+            return BinaryArithmeticNode.mul(graph, x, y);
         } else if (stamp instanceof FloatStamp) {
             return graph.unique(FloatMulNode.create(x, y, false));
         } else {
             throw GraalInternalError.shouldNotReachHere();
         }
     }
-
-    public static boolean canTryReassociate(BinaryNode node) {
-        return node instanceof IntegerAddNode || node instanceof IntegerSubNode || node instanceof IntegerMulNode || node instanceof AndNode || node instanceof OrNode || node instanceof XorNode;
-    }
-
-    public static ReassociateMatch findReassociate(BinaryNode binary, NodePredicate criterion) {
-        boolean resultX = criterion.apply(binary.getX());
-        boolean resultY = criterion.apply(binary.getY());
-        if (resultX && !resultY) {
-            return ReassociateMatch.x;
-        }
-        if (!resultX && resultY) {
-            return ReassociateMatch.y;
-        }
-        return null;
-    }
-
-    //@formatter:off
-    /*
-     * In reassociate, complexity comes from the handling of IntegerSub (non commutative) which can
-     * be mixed with IntegerAdd. It first tries to find m1, m2 which match the criterion :
-     * (a o m2) o m1
-     * (m2 o a) o m1
-     * m1 o (a o m2)
-     * m1 o (m2 o a)
-     * It then produces 4 boolean for the -/+ cases:
-     * invertA : should the final expression be like *-a (rather than a+*)
-     * aSub : should the final expression be like a-* (rather than a+*)
-     * invertM1 : should the final expression contain -m1
-     * invertM2 : should the final expression contain -m2
-     *
-     */
-    //@formatter:on
-    /**
-     * Tries to re-associate values which satisfy the criterion. For example with a constantness
-     * criterion: {@code (a + 2) + 1 => a + (1 + 2)}
-     * <p>
-     * This method accepts only {@linkplain #canTryReassociate(BinaryNode) reassociable} operations
-     * such as +, -, *, &amp;, | and ^
-     *
-     * @param forY
-     * @param forX
-     */
-    public static BinaryNode reassociate(BinaryNode node, NodePredicate criterion, ValueNode forX, ValueNode forY) {
-        assert canTryReassociate(node);
-        ReassociateMatch match1 = findReassociate(node, criterion);
-        if (match1 == null) {
-            return node;
-        }
-        ValueNode otherValue = match1.getOtherValue(node);
-        boolean addSub = false;
-        boolean subAdd = false;
-        if (otherValue.getClass() != node.getClass()) {
-            if (node instanceof IntegerAddNode && otherValue instanceof IntegerSubNode) {
-                addSub = true;
-            } else if (node instanceof IntegerSubNode && otherValue instanceof IntegerAddNode) {
-                subAdd = true;
-            } else {
-                return node;
-            }
-        }
-        BinaryNode other = (BinaryNode) otherValue;
-        ReassociateMatch match2 = findReassociate(other, criterion);
-        if (match2 == null) {
-            return node;
-        }
-        boolean invertA = false;
-        boolean aSub = false;
-        boolean invertM1 = false;
-        boolean invertM2 = false;
-        if (addSub) {
-            invertM2 = match2 == ReassociateMatch.y;
-            invertA = !invertM2;
-        } else if (subAdd) {
-            invertA = invertM2 = match1 == ReassociateMatch.x;
-            invertM1 = !invertM2;
-        } else if (node instanceof IntegerSubNode && other instanceof IntegerSubNode) {
-            invertA = match1 == ReassociateMatch.x ^ match2 == ReassociateMatch.x;
-            aSub = match1 == ReassociateMatch.y && match2 == ReassociateMatch.y;
-            invertM1 = match1 == ReassociateMatch.y && match2 == ReassociateMatch.x;
-            invertM2 = match1 == ReassociateMatch.x && match2 == ReassociateMatch.x;
-        }
-        assert !(invertM1 && invertM2) && !(invertA && aSub);
-        ValueNode m1 = match1.getValue(node);
-        ValueNode m2 = match2.getValue(other);
-        ValueNode a = match2.getOtherValue(other);
-        if (node instanceof IntegerAddNode || node instanceof IntegerSubNode) {
-            BinaryNode associated;
-            if (invertM1) {
-                associated = IntegerArithmeticNode.sub(m2, m1);
-            } else if (invertM2) {
-                associated = IntegerArithmeticNode.sub(m1, m2);
-            } else {
-                associated = IntegerArithmeticNode.add(m1, m2);
-            }
-            if (invertA) {
-                return IntegerArithmeticNode.sub(associated, a);
-            }
-            if (aSub) {
-                return IntegerArithmeticNode.sub(a, associated);
-            }
-            return IntegerArithmeticNode.add(a, associated);
-        } else if (node instanceof IntegerMulNode) {
-            return IntegerArithmeticNode.mul(a, IntegerAddNode.mul(m1, m2));
-        } else if (node instanceof AndNode) {
-            return BitLogicNode.and(a, BitLogicNode.and(m1, m2));
-        } else if (node instanceof OrNode) {
-            return BitLogicNode.or(a, BitLogicNode.or(m1, m2));
-        } else if (node instanceof XorNode) {
-            return BitLogicNode.xor(a, BitLogicNode.xor(m1, m2));
-        } else {
-            throw GraalInternalError.shouldNotReachHere();
-        }
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2011, 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.calc;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-@NodeInfo(shortName = "+")
-public class IntegerAddNode extends IntegerArithmeticNode implements NarrowableArithmeticNode {
-
-    public static IntegerAddNode create(ValueNode x, ValueNode y) {
-        return USE_GENERATED_NODES ? new IntegerAddNodeGen(x, y) : new IntegerAddNode(x, y);
-    }
-
-    protected IntegerAddNode(ValueNode x, ValueNode y) {
-        super(StampTool.add(x.stamp(), y.stamp()), x, y);
-    }
-
-    @Override
-    public boolean inferStamp() {
-        return updateStamp(StampTool.add(getX().stamp(), getY().stamp()));
-    }
-
-    @Override
-    public Constant evalConst(Constant... inputs) {
-        assert inputs.length == 2;
-        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() + inputs[1].asLong());
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && !forY.isConstant()) {
-            return IntegerAddNode.create(forY, forX);
-        }
-        if (forX instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) forX;
-            if (sub.getY() == forY) {
-                // (a - b) + b
-                return sub.getX();
-            }
-        }
-        if (forY instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) forY;
-            if (sub.getY() == forX) {
-                // b + (a - b)
-                return sub.getX();
-            }
-        }
-        if (forX.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
-        } else if (forY.isConstant()) {
-            long c = forY.asConstant().asLong();
-            if (c == 0) {
-                return forX;
-            }
-            // canonicalize expressions like "(a + 1) + 2"
-            BinaryNode reassociated = BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
-            if (reassociated != this) {
-                return reassociated;
-            }
-        }
-        if (forX instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(forY, ((NegateNode) forX).getValue());
-        } else if (forY instanceof NegateNode) {
-            return IntegerArithmeticNode.sub(forX, ((NegateNode) forY).getValue());
-        }
-        return this;
-    }
-
-    @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(getX());
-        assert op1 != null : getX() + ", this=" + this;
-        Value op2 = builder.operand(getY());
-        if (!getY().isConstant() && !FloatAddNode.livesLonger(this, getY(), builder)) {
-            Value op = op1;
-            op1 = op2;
-            op2 = op;
-        }
-        builder.setResult(this, gen.emitAdd(op1, op2));
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerArithmeticNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2011, 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.calc;
-
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-@NodeInfo
-public abstract class IntegerArithmeticNode extends BinaryNode implements ArithmeticLIRLowerable {
-
-    public IntegerArithmeticNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
-        assert stamp instanceof IntegerStamp;
-    }
-
-    public static IntegerAddNode add(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        return graph.unique(IntegerAddNode.create(v1, v2));
-    }
-
-    public static IntegerAddNode add(ValueNode v1, ValueNode v2) {
-        return IntegerAddNode.create(v1, v2);
-    }
-
-    public static IntegerMulNode mul(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        return graph.unique(IntegerMulNode.create(v1, v2));
-    }
-
-    public static IntegerMulNode mul(ValueNode v1, ValueNode v2) {
-        return IntegerMulNode.create(v1, v2);
-    }
-
-    public static IntegerSubNode sub(StructuredGraph graph, ValueNode v1, ValueNode v2) {
-        return graph.unique(IntegerSubNode.create(v1, v2));
-    }
-
-    public static IntegerSubNode sub(ValueNode v1, ValueNode v2) {
-        return IntegerSubNode.create(v1, v2);
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -74,7 +74,7 @@
                     int bits = PrimitiveStamp.getBits(stamp());
                     RightShiftNode sign = RightShiftNode.create(forX, ConstantNode.forInt(bits - 1));
                     UnsignedRightShiftNode round = UnsignedRightShiftNode.create(sign, ConstantNode.forInt(bits - log2));
-                    dividend = IntegerArithmeticNode.add(dividend, round);
+                    dividend = BinaryArithmeticNode.add(dividend, round);
                 }
                 RightShiftNode shift = RightShiftNode.create(dividend, ConstantNode.forInt(log2));
                 if (c < 0) {
@@ -85,8 +85,8 @@
         }
 
         // Convert the expression ((a - a % b) / b) into (a / b).
-        if (forX instanceof IntegerSubNode) {
-            IntegerSubNode integerSubNode = (IntegerSubNode) forX;
+        if (forX instanceof SubNode) {
+            SubNode integerSubNode = (SubNode) forX;
             if (integerSubNode.getY() instanceof IntegerRemNode) {
                 IntegerRemNode integerRemNode = (IntegerRemNode) integerSubNode.getY();
                 if (integerSubNode.stamp().isCompatible(this.stamp()) && integerRemNode.stamp().isCompatible(this.stamp()) && integerSubNode.getX() == integerRemNode.getX() &&
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2011, 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.calc;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-
-@NodeInfo(shortName = "*")
-public class IntegerMulNode extends IntegerArithmeticNode implements NarrowableArithmeticNode {
-
-    public static IntegerMulNode create(ValueNode x, ValueNode y) {
-        return USE_GENERATED_NODES ? new IntegerMulNodeGen(x, y) : new IntegerMulNode(x, y);
-    }
-
-    protected IntegerMulNode(ValueNode x, ValueNode y) {
-        super(x.stamp().unrestricted(), x, y);
-        assert x.stamp().isCompatible(y.stamp());
-    }
-
-    @Override
-    public Constant evalConst(Constant... inputs) {
-        assert inputs.length == 2;
-        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() * inputs[1].asLong());
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && !forY.isConstant()) {
-            return IntegerMulNode.create(forY, forX);
-        }
-        if (forX.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
-        } else if (forY.isConstant()) {
-            long c = forY.asConstant().asLong();
-            if (c == 1) {
-                return forX;
-            }
-            if (c == 0) {
-                return ConstantNode.forIntegerStamp(stamp(), 0);
-            }
-            long abs = Math.abs(c);
-            if (abs > 0 && CodeUtil.isPowerOf2(abs)) {
-                LeftShiftNode shift = LeftShiftNode.create(forX, ConstantNode.forInt(CodeUtil.log2(abs)));
-                if (c < 0) {
-                    return NegateNode.create(shift);
-                } else {
-                    return shift;
-                }
-            }
-            // canonicalize expressions like "(a * 1) * 2"
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
-        }
-        return this;
-    }
-
-    @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        Value op1 = builder.operand(getX());
-        Value op2 = builder.operand(getY());
-        if (!getY().isConstant() && !FloatAddNode.livesLonger(this, getY(), builder)) {
-            Value op = op1;
-            op1 = op2;
-            op2 = op;
-        }
-        builder.setResult(this, gen.emitMul(op1, op2));
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerSubNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2011, 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.calc;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-
-@NodeInfo(shortName = "-")
-public class IntegerSubNode extends IntegerArithmeticNode implements NarrowableArithmeticNode {
-
-    public static IntegerSubNode create(ValueNode x, ValueNode y) {
-        return USE_GENERATED_NODES ? new IntegerSubNodeGen(x, y) : new IntegerSubNode(x, y);
-    }
-
-    protected IntegerSubNode(ValueNode x, ValueNode y) {
-        super(StampTool.sub(x.stamp(), y.stamp()), x, y);
-    }
-
-    @Override
-    public boolean inferStamp() {
-        return updateStamp(StampTool.sub(getX().stamp(), getY().stamp()));
-    }
-
-    @Override
-    public Constant evalConst(Constant... inputs) {
-        assert inputs.length == 2;
-        return Constant.forPrimitiveInt(PrimitiveStamp.getBits(stamp()), inputs[0].asLong() - inputs[1].asLong());
-    }
-
-    @SuppressWarnings("hiding")
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
-            return ConstantNode.forIntegerStamp(stamp(), 0);
-        }
-        if (forX instanceof IntegerAddNode) {
-            IntegerAddNode x = (IntegerAddNode) forX;
-            if (x.getY() == forY) {
-                // (a + b) - b
-                return x.getX();
-            }
-            if (x.getX() == forY) {
-                // (a + b) - a
-                return x.getY();
-            }
-        } else if (forX instanceof IntegerSubNode) {
-            IntegerSubNode x = (IntegerSubNode) forX;
-            if (x.getX() == forY) {
-                // (a - b) - a
-                return NegateNode.create(x.getY());
-            }
-        }
-        if (forY instanceof IntegerAddNode) {
-            IntegerAddNode y = (IntegerAddNode) forY;
-            if (y.getX() == forX) {
-                // a - (a + b)
-                return NegateNode.create(y.getY());
-            }
-            if (y.getY() == forX) {
-                // b - (a + b)
-                return NegateNode.create(y.getX());
-            }
-        } else if (forY instanceof IntegerSubNode) {
-            IntegerSubNode y = (IntegerSubNode) forY;
-            if (y.getX() == forX) {
-                // a - (a - b)
-                return y.getY();
-            }
-        }
-        if (forX.isConstant() && forY.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(forX.asConstant(), forY.asConstant()));
-        } else if (forY.isConstant()) {
-            long c = forY.asConstant().asLong();
-            if (c == 0) {
-                return forX;
-            }
-            BinaryNode reassociated = BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
-            if (reassociated != this) {
-                return reassociated;
-            }
-            if (c < 0 || ((IntegerStamp) StampFactory.forKind(forY.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(forX, ConstantNode.forIntegerStamp(stamp(), -c));
-            }
-        } else if (forX.isConstant()) {
-            long c = forX.asConstant().asLong();
-            if (c == 0) {
-                return NegateNode.create(forY);
-            }
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
-        }
-        if (forY instanceof NegateNode) {
-            return IntegerArithmeticNode.add(forX, ((NegateNode) forY).getValue());
-        }
-        return this;
-    }
-
-    @Override
-    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
-        builder.setResult(this, gen.emitSub(builder.operand(getX()), builder.operand(getY())));
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo(shortName = "*")
+public class MulNode extends BinaryArithmeticNode implements NarrowableArithmeticNode {
+
+    public static MulNode create(ValueNode x, ValueNode y) {
+        return USE_GENERATED_NODES ? new MulNodeGen(x, y) : new MulNode(x, y);
+    }
+
+    protected MulNode(ValueNode x, ValueNode y) {
+        super(ArithmeticOpTable.forStamp(x.stamp()).getMul(), x, y);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forX.isConstant() && !forY.isConstant()) {
+            return MulNode.create(forY, forX);
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (getOp().isNeutral(c)) {
+                return forX;
+            }
+
+            if (c.getKind().isNumericInteger()) {
+                long i = c.asLong();
+                long abs = Math.abs(i);
+                if (abs > 0 && CodeUtil.isPowerOf2(abs)) {
+                    LeftShiftNode shift = LeftShiftNode.create(forX, ConstantNode.forInt(CodeUtil.log2(abs)));
+                    if (i < 0) {
+                        return NegateNode.create(shift);
+                    } else {
+                        return shift;
+                    }
+                }
+            }
+
+            if (getOp().isAssociative()) {
+                // canonicalize expressions like "(a * 1) * 2"
+                return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+        Value op1 = builder.operand(getX());
+        Value op2 = builder.operand(getY());
+        if (!getY().isConstant() && !FloatAddNode.livesLonger(this, getY(), builder)) {
+            Value op = op1;
+            op1 = op2;
+            op2 = op;
+        }
+        builder.setResult(this, gen.emitMul(op1, op2));
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -23,13 +23,13 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code NegateNode} node negates its operand.
@@ -37,9 +37,11 @@
 @NodeInfo
 public class NegateNode extends UnaryNode implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
 
+    private final UnaryOp op;
+
     @Override
     public boolean inferStamp() {
-        return updateStamp(StampTool.negate(getValue().stamp()));
+        return updateStamp(op.foldStamp(getValue().stamp()));
     }
 
     /**
@@ -48,41 +50,34 @@
      * @param value the instruction producing the value that is input to this instruction
      */
     public static NegateNode create(ValueNode value) {
-        return USE_GENERATED_NODES ? new NegateNodeGen(value) : new NegateNode(value);
+        return create(ArithmeticOpTable.forStamp(value.stamp()).getNeg(), value);
     }
 
-    protected NegateNode(ValueNode value) {
-        super(StampTool.negate(value.stamp()), value);
+    public static NegateNode create(UnaryOp op, ValueNode value) {
+        return USE_GENERATED_NODES ? new NegateNodeGen(op, value) : new NegateNode(op, value);
+    }
+
+    protected NegateNode(UnaryOp op, ValueNode value) {
+        super(op.foldStamp(value.stamp()), value);
+        this.op = op;
     }
 
     public Constant evalConst(Constant... inputs) {
         assert inputs.length == 1;
-        Constant constant = inputs[0];
-        switch (constant.getKind()) {
-            case Int:
-                return Constant.forInt(-(constant.asInt()));
-            case Long:
-                return Constant.forLong(-(constant.asLong()));
-            case Float:
-                return Constant.forFloat(-(constant.asFloat()));
-            case Double:
-                return Constant.forDouble(-(constant.asDouble()));
-            default:
-                throw GraalInternalError.shouldNotReachHere("unknown kind " + constant.getKind());
-        }
+        return op.foldConstant(inputs[0]);
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
         if (forValue.isConstant()) {
-            return ConstantNode.forConstant(evalConst(forValue.asConstant()), null);
+            return ConstantNode.forPrimitive(stamp(), op.foldConstant(forValue.asConstant()));
         }
         if (forValue instanceof NegateNode) {
             return ((NegateNode) forValue).getValue();
         }
-        if (forValue instanceof IntegerSubNode) {
-            IntegerSubNode sub = (IntegerSubNode) forValue;
-            return IntegerSubNode.create(sub.getY(), sub.getX());
+        if (forValue instanceof SubNode) {
+            SubNode sub = (SubNode) forValue;
+            return SubNode.create(sub.getY(), sub.getX());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -75,7 +75,7 @@
             if ((rawY & mask) == 0) {
                 return forX;
             }
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+            return BinaryArithmeticNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
         return this;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.nodeinfo.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
+
+@NodeInfo(shortName = "-")
+public class SubNode extends BinaryArithmeticNode implements NarrowableArithmeticNode {
+
+    public static SubNode create(ValueNode x, ValueNode y) {
+        return USE_GENERATED_NODES ? new SubNodeGen(x, y) : new SubNode(x, y);
+    }
+
+    protected SubNode(ValueNode x, ValueNode y) {
+        super(ArithmeticOpTable.forStamp(x.stamp()).getSub(), x, y);
+    }
+
+    @SuppressWarnings("hiding")
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
+            Constant zero = getOp().getZero(forX.stamp());
+            if (zero != null) {
+                return ConstantNode.forPrimitive(stamp(), zero);
+            }
+        }
+        boolean associative = getOp().isAssociative();
+        if (associative) {
+            if (forX instanceof AddNode) {
+                AddNode x = (AddNode) forX;
+                if (x.getY() == forY) {
+                    // (a + b) - b
+                    return x.getX();
+                }
+                if (x.getX() == forY) {
+                    // (a + b) - a
+                    return x.getY();
+                }
+            } else if (forX instanceof SubNode) {
+                SubNode x = (SubNode) forX;
+                if (x.getX() == forY) {
+                    // (a - b) - a
+                    return NegateNode.create(x.getY());
+                }
+            }
+            if (forY instanceof AddNode) {
+                AddNode y = (AddNode) forY;
+                if (y.getX() == forX) {
+                    // a - (a + b)
+                    return NegateNode.create(y.getY());
+                }
+                if (y.getY() == forX) {
+                    // b - (a + b)
+                    return NegateNode.create(y.getX());
+                }
+            } else if (forY instanceof SubNode) {
+                SubNode y = (SubNode) forY;
+                if (y.getX() == forX) {
+                    // a - (a - b)
+                    return y.getY();
+                }
+            }
+        }
+        if (forY.isConstant()) {
+            Constant c = forY.asConstant();
+            if (getOp().isNeutral(c)) {
+                return forX;
+            }
+            if (associative) {
+                BinaryNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+                if (reassociated != this) {
+                    return reassociated;
+                }
+            }
+            if (c.getKind().isNumericInteger()) {
+                long i = c.asLong();
+                if (i < 0 || ((IntegerStamp) StampFactory.forKind(forY.getKind())).contains(-i)) {
+                    // Adding a negative is more friendly to the backend since adds are
+                    // commutative, so prefer add when it fits.
+                    return BinaryArithmeticNode.add(forX, ConstantNode.forIntegerStamp(stamp(), -i));
+                }
+            }
+        } else if (forX.isConstant()) {
+            Constant c = forX.asConstant();
+            if (ArithmeticOpTable.forStamp(stamp()).getAdd().isNeutral(c)) {
+                /*
+                 * Note that for floating point numbers, + and - have different neutral elements. We
+                 * have to test for the neutral element of +, because we are doing this
+                 * transformation: 0 - x == (-x) + 0 == -x.
+                 */
+                return NegateNode.create(forY);
+            }
+            if (associative) {
+                return reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+            }
+        }
+        if (forY instanceof NegateNode) {
+            return BinaryArithmeticNode.add(forX, ((NegateNode) forY).getValue());
+        }
+        return this;
+    }
+
+    @Override
+    public void generate(NodeMappableLIRBuilder builder, ArithmeticLIRGenerator gen) {
+        builder.setResult(this, gen.emitSub(builder.operand(getX()), builder.operand(getY())));
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -74,7 +74,7 @@
             } else if ((rawY & mask) == mask) {
                 return NotNode.create(forX);
             }
-            return BinaryNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
+            return BinaryArithmeticNode.reassociate(this, ValueNode.isConstantPredicate(), forX, forY);
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -88,7 +88,7 @@
             IndexedLocationNode yIdx = (IndexedLocationNode) forY;
             if (xIdx.getIndexScaling() == yIdx.getIndexScaling()) {
                 long displacement = xIdx.getDisplacement() + yIdx.getDisplacement();
-                ValueNode index = IntegerArithmeticNode.add(xIdx.getIndex(), yIdx.getIndex());
+                ValueNode index = BinaryArithmeticNode.add(xIdx.getIndex(), yIdx.getIndex());
                 return IndexedLocationNode.create(getLocationIdentity(), getValueKind(), displacement, index, xIdx.getIndexScaling());
             }
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java	Wed Sep 24 13:46:37 2014 +0200
@@ -138,7 +138,7 @@
             return 1;
         } else if (node instanceof IntegerDivNode || node instanceof FloatDivNode || node instanceof IntegerRemNode || node instanceof FloatRemNode) {
             return 10;
-        } else if (node instanceof IntegerMulNode || node instanceof FloatMulNode) {
+        } else if (node instanceof MulNode || node instanceof FloatMulNode) {
             return 3;
         } else if (node instanceof Invoke) {
             return 5;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultJavaLoweringProvider.java	Wed Sep 24 13:46:37 2014 +0200
@@ -625,19 +625,19 @@
                 offset = extend.getValue();
             }
         }
-        if (offset instanceof IntegerAddNode) {
-            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
+        if (offset instanceof AddNode) {
+            AddNode integerAddNode = (AddNode) offset;
             if (integerAddNode.getY() instanceof ConstantNode) {
                 displacement = integerAddNode.getY().asConstant().asLong();
                 offset = integerAddNode.getX();
             }
         }
-        if (base != null && signExtend == false && offset instanceof IntegerAddNode) {
+        if (base != null && signExtend == false && offset instanceof AddNode) {
             /*
              * Try to decompose the operation into base plus offset so the base can go into a new
              * node. Prefer the unshifted side of an add as the base.
              */
-            IntegerAddNode integerAddNode = (IntegerAddNode) offset;
+            AddNode integerAddNode = (AddNode) offset;
             if (integerAddNode.getY() instanceof LeftShiftNode) {
                 base[0] = integerAddNode.getX();
                 offset = integerAddNode.getY();
@@ -645,8 +645,8 @@
                 base[0] = integerAddNode.getY();
                 offset = integerAddNode.getX();
             }
-            if (offset instanceof IntegerAddNode) {
-                integerAddNode = (IntegerAddNode) offset;
+            if (offset instanceof AddNode) {
+                integerAddNode = (AddNode) offset;
                 if (integerAddNode.getY() instanceof ConstantNode) {
                     displacement = integerAddNode.getY().asConstant().asLong();
                     offset = integerAddNode.getX();
@@ -748,7 +748,7 @@
             if (base == 0) {
                 return index;
             } else {
-                return IntegerArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
+                return BinaryArithmeticNode.add(graph, ConstantNode.forInt((int) base, graph), index);
             }
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -37,7 +37,7 @@
  * case the addition would overflow the 32 bit range.
  */
 @NodeInfo
-public class IntegerAddExactNode extends IntegerAddNode implements IntegerExactArithmeticNode {
+public class IntegerAddExactNode extends AddNode implements IntegerExactArithmeticNode {
 
     public static IntegerAddExactNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new IntegerAddExactNodeGen(x, y) : new IntegerAddExactNode(x, y);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -36,7 +36,7 @@
  * in case the addition would overflow the 32 bit range.
  */
 @NodeInfo
-public class IntegerMulExactNode extends IntegerMulNode implements IntegerExactArithmeticNode {
+public class IntegerMulExactNode extends MulNode implements IntegerExactArithmeticNode {
 
     public static IntegerMulExactNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new IntegerMulExactNodeGen(x, y) : new IntegerMulExactNode(x, y);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -36,21 +36,21 @@
 import com.oracle.truffle.api.*;
 
 @NodeInfo(shortName = "*H")
-public class IntegerMulHighNode extends IntegerArithmeticNode {
+public class IntegerMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     public static IntegerMulHighNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new IntegerMulHighNodeGen(x, y) : new IntegerMulHighNode(x, y);
     }
 
     protected IntegerMulHighNode(ValueNode x, ValueNode y) {
-        this(x.stamp().unrestricted(), x, y);
+        this((IntegerStamp) x.stamp().unrestricted(), x, y);
     }
 
-    public static IntegerMulHighNode create(Stamp stamp, ValueNode x, ValueNode y) {
+    public static IntegerMulHighNode create(IntegerStamp stamp, ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new IntegerMulHighNodeGen(stamp, x, y) : new IntegerMulHighNode(stamp, x, y);
     }
 
-    protected IntegerMulHighNode(Stamp stamp, ValueNode x, ValueNode y) {
+    protected IntegerMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
         super(stamp, x, y);
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -38,7 +38,7 @@
  * case the addition would overflow the 32 bit range.
  */
 @NodeInfo
-public class IntegerSubExactNode extends IntegerSubNode implements IntegerExactArithmeticNode {
+public class IntegerSubExactNode extends SubNode implements IntegerExactArithmeticNode {
 
     public static IntegerSubExactNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new IntegerSubExactNodeGen(x, y) : new IntegerSubExactNode(x, y);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Wed Sep 24 13:46:37 2014 +0200
@@ -36,21 +36,21 @@
 import com.oracle.truffle.api.*;
 
 @NodeInfo(shortName = "|*H|")
-public class UnsignedMulHighNode extends IntegerArithmeticNode {
+public class UnsignedMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
 
     public static UnsignedMulHighNode create(ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new UnsignedMulHighNodeGen(x, y) : new UnsignedMulHighNode(x, y);
     }
 
     protected UnsignedMulHighNode(ValueNode x, ValueNode y) {
-        this(x.stamp().unrestricted(), x, y);
+        this((IntegerStamp) x.stamp().unrestricted(), x, y);
     }
 
-    public static UnsignedMulHighNode create(Stamp stamp, ValueNode x, ValueNode y) {
+    public static UnsignedMulHighNode create(IntegerStamp stamp, ValueNode x, ValueNode y) {
         return USE_GENERATED_NODES ? new UnsignedMulHighNodeGen(stamp, x, y) : new UnsignedMulHighNode(stamp, x, y);
     }
 
-    protected UnsignedMulHighNode(Stamp stamp, ValueNode x, ValueNode y) {
+    protected UnsignedMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
         super(stamp, x, y);
     }
 
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Fri Sep 19 11:00:46 2014 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Word.java	Wed Sep 24 13:46:37 2014 +0200
@@ -181,70 +181,70 @@
     public native Object toObject();
 
     @Override
-    @Operation(node = IntegerAddNode.class)
+    @Operation(node = AddNode.class)
     public Word add(Signed val) {
         return add((Word) val);
     }
 
     @Override
-    @Operation(node = IntegerAddNode.class)
+    @Operation(node = AddNode.class)
     public Word add(Unsigned val) {
         return add((Word) val);
     }
 
     @Override
-    @Operation(node = IntegerAddNode.class)
+    @Operation(node = AddNode.class)
     public Word add(int val) {
         return add(intParam(val));
     }
 
-    @Operation(node = IntegerAddNode.class)
+    @Operation(node = AddNode.class)
     public Word add(Word val) {
         return box(unbox() + val.unbox());
     }
 
     @Override
-    @Operation(node = IntegerSubNode.class)
+    @Operation(node = SubNode.class)
     public Word subtract(Signed val) {
         return subtract((Word) val);
     }
 
     @Override
-    @Operation(node = IntegerSubNode.class)
+    @Operation(node = SubNode.class)
     public Word subtract(Unsigned val) {
         return subtract((Word) val);
     }
 
     @Override
-    @Operation(node = IntegerSubNode.class)
+    @Operation(node = SubNode.class)
     public Word subtract(int val) {
         return subtract(intParam(val));
     }
 
-    @Operation(node = IntegerSubNode.class)
+    @Operation(node = SubNode.class)
     public Word subtract(Word val) {
         return box(unbox() - val.unbox());
     }
 
     @Override
-    @Operation(node = IntegerMulNode.class)
+    @Operation(node = MulNode.class)
     public Word multiply(Signed val) {
         return multiply((Word) val);
     }
 
     @Override
-    @Operation(node = IntegerMulNode.class)
+    @Operation(node = MulNode.class)
     public Word multiply(Unsigned val) {
         return multiply((Word) val);
     }
 
     @Override
-    @Operation(node = IntegerMulNode.class)
+    @Operation(node = MulNode.class)
     public Word multiply(int val) {
         return multiply(intParam(val));
     }
 
-    @Operation(node = IntegerMulNode.class)
+    @Operation(node = MulNode.class)
     public Word multiply(Word val) {
         return box(unbox() * val.unbox());
     }