changeset 17271:fa3637e235b1

Make ArithmeticOpTable fields final.
author Roland Schatz <roland.schatz@oracle.com>
date Tue, 30 Sep 2014 14:45:03 +0200
parents 5b7b1cb838e9
children 9eb112c9337d
files 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/FloatStamp.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java
diffstat 3 files changed, 517 insertions(+), 409 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Tue Sep 30 12:15:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Tue Sep 30 14:45:03 2014 +0200
@@ -23,24 +23,25 @@
 package com.oracle.graal.compiler.common.type;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 
 /**
  * Information about arithmetic operations.
  */
 public final class ArithmeticOpTable {
 
-    protected UnaryOp neg;
-    protected BinaryOp add;
-    protected BinaryOp sub;
+    private final UnaryOp neg;
+    private final BinaryOp add;
+    private final BinaryOp sub;
 
-    protected BinaryOp mul;
-    protected BinaryOp div;
-    protected BinaryOp rem;
+    private final BinaryOp mul;
+    private final BinaryOp div;
+    private final BinaryOp rem;
 
-    protected UnaryOp not;
-    protected BinaryOp and;
-    protected BinaryOp or;
-    protected BinaryOp xor;
+    private final UnaryOp not;
+    private final BinaryOp and;
+    private final BinaryOp or;
+    private final BinaryOp xor;
 
     public static ArithmeticOpTable forStamp(Stamp s) {
         if (s instanceof ArithmeticStamp) {
@@ -50,7 +51,97 @@
         }
     }
 
-    public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable();
+    public static final ArithmeticOpTable EMPTY = create();
+
+    public static ArithmeticOpTable create(Op... ops) {
+        UnaryOp neg = null;
+        BinaryOp add = null;
+        BinaryOp sub = null;
+
+        BinaryOp mul = null;
+        BinaryOp div = null;
+        BinaryOp rem = null;
+
+        UnaryOp not = null;
+        BinaryOp and = null;
+        BinaryOp or = null;
+        BinaryOp xor = null;
+
+        for (Op op : ops) {
+            if (op == null) {
+                continue;
+            }
+
+            if (op instanceof UnaryOp) {
+                UnaryOp unary = (UnaryOp) op;
+                switch (unary.getOperator()) {
+                    case '-':
+                        assert neg == null;
+                        neg = unary;
+                        break;
+                    case '~':
+                        assert not == null;
+                        not = unary;
+                        break;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere("unknown unary operator " + unary.getOperator());
+                }
+            } else {
+                BinaryOp binary = (BinaryOp) op;
+                switch (binary.getOperator()) {
+                    case '+':
+                        assert add == null;
+                        add = binary;
+                        break;
+                    case '-':
+                        assert sub == null;
+                        sub = binary;
+                        break;
+                    case '*':
+                        assert mul == null;
+                        mul = binary;
+                        break;
+                    case '/':
+                        assert div == null;
+                        div = binary;
+                        break;
+                    case '%':
+                        assert rem == null;
+                        rem = binary;
+                        break;
+                    case '&':
+                        assert and == null;
+                        and = binary;
+                        break;
+                    case '|':
+                        assert or == null;
+                        or = binary;
+                        break;
+                    case '^':
+                        assert xor == null;
+                        xor = binary;
+                        break;
+                    default:
+                        throw GraalInternalError.shouldNotReachHere("unknown binary operator " + binary.getOperator());
+                }
+            }
+        }
+
+        return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor);
+    }
+
+    private ArithmeticOpTable(UnaryOp neg, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, BinaryOp xor) {
+        this.neg = neg;
+        this.add = add;
+        this.sub = sub;
+        this.mul = mul;
+        this.div = div;
+        this.rem = rem;
+        this.not = not;
+        this.and = and;
+        this.or = or;
+        this.xor = xor;
+    }
 
     /**
      * Describes the unary negation operation.
@@ -122,10 +213,32 @@
         return xor;
     }
 
+    public abstract static class Op {
+
+        private final char operator;
+
+        protected Op(char operator) {
+            this.operator = operator;
+        }
+
+        public char getOperator() {
+            return operator;
+        }
+
+        @Override
+        public String toString() {
+            return Character.toString(operator);
+        }
+    }
+
     /**
      * Describes a unary arithmetic operation.
      */
-    public abstract static class UnaryOp {
+    public abstract static class UnaryOp extends Op {
+
+        protected UnaryOp(char operation) {
+            super(operation);
+        }
 
         /**
          * Apply the operation to a {@link Constant}.
@@ -141,12 +254,13 @@
     /**
      * Describes a binary arithmetic operation.
      */
-    public abstract static class BinaryOp {
+    public abstract static class BinaryOp extends Op {
 
         private final boolean associative;
         private final boolean commutative;
 
-        protected BinaryOp(boolean associative, boolean commutative) {
+        protected BinaryOp(char operation, boolean associative, boolean commutative) {
+            super(operation);
             this.associative = associative;
             this.commutative = commutative;
         }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Tue Sep 30 12:15:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Tue Sep 30 14:45:03 2014 +0200
@@ -252,188 +252,184 @@
         return null;
     }
 
-    private static final ArithmeticOpTable OPS = new ArithmeticOpTable();
+    private static final ArithmeticOpTable OPS = ArithmeticOpTable.create(
 
-    static {
-        OPS.neg = new UnaryOp() {
+    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());
+        @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();
             }
-        };
+        }
 
-        OPS.add = new BinaryOp(false, true) {
+        @Override
+        public Stamp foldStamp(Stamp s) {
+            FloatStamp stamp = (FloatStamp) s;
+            return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
+        }
+    },
+
+    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 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 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();
-                }
+        @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) {
+    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 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 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();
-                }
+        @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) {
+    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 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 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();
-                }
+        @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) {
+    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 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 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();
-                }
+        @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) {
+    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 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 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	Tue Sep 30 12:15:13 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Tue Sep 30 14:45:03 2014 +0200
@@ -350,290 +350,288 @@
         return (x + y) ^ x ^ y;
     }
 
-    public static final ArithmeticOpTable OPS = new ArithmeticOpTable();
+    public static final ArithmeticOpTable OPS = ArithmeticOpTable.create(
 
-    static {
-        OPS.neg = new UnaryOp() {
+    new UnaryOp('-') {
 
-            @Override
-            public Constant foldConstant(Constant value) {
-                return Constant.forIntegerKind(value.getKind(), -value.asLong());
-            }
+        @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();
-                }
+        @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) {
+    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 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;
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
 
-                int bits = a.getBits();
-                assert bits == b.getBits();
+            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;
+            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;
+            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;
+            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 Constant getZero(Stamp s) {
-                IntegerStamp stamp = (IntegerStamp) s;
-                return Constant.forPrimitiveInt(stamp.getBits(), 0);
-            }
-        };
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 0;
+        }
+    },
+
+    new BinaryOp('-', true, false) {
 
-        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 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.getAdd().foldStamp(a, OPS.getNeg().foldStamp(b));
+        }
+
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 0;
+        }
 
-            @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 Constant getZero(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            return Constant.forPrimitiveInt(stamp.getBits(), 0);
+        }
+    },
+
+    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 boolean isNeutral(Constant n) {
-                return n.asLong() == 1;
+        @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();
             }
-        };
+        }
 
-        OPS.div = new BinaryOp(true, false) {
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 1;
+        }
+    },
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() / b.asLong());
-            }
+    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 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;
-            }
-        };
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 1;
+        }
+    },
 
-        OPS.rem = new BinaryOp(false, false) {
+    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 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);
+        @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);
+            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);
-            }
-        };
+            return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
+        }
+    },
 
-        OPS.not = new UnaryOp() {
+    new UnaryOp('~') {
 
-            @Override
-            public Constant foldConstant(Constant value) {
-                return Constant.forIntegerKind(value.getKind(), ~value.asLong());
-            }
+        @Override
+        public Constant foldConstant(Constant value) {
+            return Constant.forIntegerKind(value.getKind(), ~value.asLong());
+        }
 
-            @Override
-            public Stamp foldStamp(Stamp stamp) {
-                IntegerStamp integerStamp = (IntegerStamp) stamp;
-                int bits = integerStamp.getBits();
-                long defaultMask = CodeUtil.mask(bits);
-                return new IntegerStamp(bits, ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask);
-            }
-        };
+        @Override
+        public Stamp foldStamp(Stamp stamp) {
+            IntegerStamp integerStamp = (IntegerStamp) stamp;
+            int bits = integerStamp.getBits();
+            long defaultMask = CodeUtil.mask(bits);
+            return new IntegerStamp(bits, ~integerStamp.upperBound(), ~integerStamp.lowerBound(), (~integerStamp.upMask()) & defaultMask, (~integerStamp.downMask()) & defaultMask);
+        }
+    },
 
-        OPS.and = new BinaryOp(true, true) {
+    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 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();
-                return stampForMask(a.getBits(), a.downMask() & b.downMask(), a.upMask() & b.upMask());
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+            return stampForMask(a.getBits(), a.downMask() & b.downMask(), a.upMask() & b.upMask());
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                int bits = n.getKind().getBitCount();
-                long mask = CodeUtil.mask(bits);
-                return (n.asLong() & mask) == mask;
-            }
-        };
+        @Override
+        public boolean isNeutral(Constant n) {
+            int bits = n.getKind().getBitCount();
+            long mask = CodeUtil.mask(bits);
+            return (n.asLong() & mask) == mask;
+        }
+    },
 
-        OPS.or = new BinaryOp(true, true) {
+    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 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();
-                return stampForMask(a.getBits(), a.downMask() | b.downMask(), a.upMask() | b.upMask());
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+            return stampForMask(a.getBits(), a.downMask() | b.downMask(), a.upMask() | b.upMask());
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 0;
-            }
-        };
-
-        OPS.xor = new BinaryOp(true, true) {
+        @Override
+        public boolean isNeutral(Constant n) {
+            return n.asLong() == 0;
+        }
+    },
 
-            @Override
-            public Constant foldConstant(Constant a, Constant b) {
-                assert a.getKind() == b.getKind();
-                return Constant.forIntegerKind(a.getKind(), a.asLong() ^ b.asLong());
-            }
+    new BinaryOp('^', true, true) {
 
-            @Override
-            public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
-                IntegerStamp a = (IntegerStamp) stamp1;
-                IntegerStamp b = (IntegerStamp) stamp2;
-                assert a.getBits() == b.getBits();
+        @Override
+        public Constant foldConstant(Constant a, Constant b) {
+            assert a.getKind() == b.getKind();
+            return Constant.forIntegerKind(a.getKind(), a.asLong() ^ b.asLong());
+        }
 
-                long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
-                long newDownMask = (a.downMask() ^ b.downMask()) & ~variableBits;
-                long newUpMask = (a.downMask() ^ b.downMask()) | variableBits;
-                return stampForMask(a.getBits(), newDownMask, newUpMask);
-            }
+        @Override
+        public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+            IntegerStamp a = (IntegerStamp) stamp1;
+            IntegerStamp b = (IntegerStamp) stamp2;
+            assert a.getBits() == b.getBits();
+
+            long variableBits = (a.downMask() ^ a.upMask()) | (b.downMask() ^ b.upMask());
+            long newDownMask = (a.downMask() ^ b.downMask()) & ~variableBits;
+            long newUpMask = (a.downMask() ^ b.downMask()) | variableBits;
+            return stampForMask(a.getBits(), newDownMask, newUpMask);
+        }
 
-            @Override
-            public boolean isNeutral(Constant n) {
-                return n.asLong() == 0;
-            }
+        @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);
-            }
-        };
-    }
+        @Override
+        public Constant getZero(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            return Constant.forPrimitiveInt(stamp.getBits(), 0);
+        }
+    });
 }