changeset 18839:1b7dbb81df4f

Use ArithmeticOpTable for shift operations.
author Roland Schatz <roland.schatz@oracle.com>
date Mon, 12 Jan 2015 13:32:43 +0100
parents ae827362559d
children 4d1cf05c7545
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 graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java
diffstat 11 files changed, 334 insertions(+), 194 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/ArithmeticOpTable.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, 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
@@ -41,6 +41,9 @@
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shl;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shr;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.UShr;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Abs;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Neg;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Not;
@@ -64,6 +67,10 @@
     private final BinaryOp<Or> or;
     private final BinaryOp<Xor> xor;
 
+    private final ShiftOp<Shl> shl;
+    private final ShiftOp<Shr> shr;
+    private final ShiftOp<UShr> ushr;
+
     private final UnaryOp<Abs> abs;
     private final UnaryOp<Sqrt> sqrt;
 
@@ -81,12 +88,12 @@
         }
     }
 
-    public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
+    public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
 
     public ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
-                    BinaryOp<Xor> xor, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend, IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow,
-                    FloatConvertOp... floatConvert) {
-        this(neg, add, sub, mul, div, rem, not, and, or, xor, abs, sqrt, zeroExtend, signExtend, narrow, Stream.of(floatConvert));
+                    BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
+                    IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
+        this(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, Stream.of(floatConvert));
     }
 
     public interface ArithmeticOpWrapper {
@@ -95,6 +102,8 @@
 
         <OP> BinaryOp<OP> wrapBinaryOp(BinaryOp<OP> op);
 
+        <OP> ShiftOp<OP> wrapShiftOp(ShiftOp<OP> op);
+
         <OP> IntegerConvertOp<OP> wrapIntegerConvertOp(IntegerConvertOp<OP> op);
 
         FloatConvertOp wrapFloatConvertOp(FloatConvertOp op);
@@ -122,6 +131,10 @@
         BinaryOp<Or> or = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getOr());
         BinaryOp<Xor> xor = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getXor());
 
+        ShiftOp<Shl> shl = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShl());
+        ShiftOp<Shr> shr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShr());
+        ShiftOp<UShr> ushr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getUShr());
+
         UnaryOp<Abs> abs = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getAbs());
         UnaryOp<Sqrt> sqrt = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getSqrt());
 
@@ -131,12 +144,12 @@
 
         Stream<FloatConvertOp> floatConvert = Stream.of(inner.floatConvert).filter(Objects::nonNull).map(wrapper::wrapFloatConvertOp);
 
-        return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
+        return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
     }
 
     private ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
-                    BinaryOp<Xor> xor, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend, IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow,
-                    Stream<FloatConvertOp> floatConvert) {
+                    BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
+                    IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, Stream<FloatConvertOp> floatConvert) {
         this.neg = neg;
         this.add = add;
         this.sub = sub;
@@ -147,6 +160,9 @@
         this.and = and;
         this.or = or;
         this.xor = xor;
+        this.shl = shl;
+        this.shr = shr;
+        this.ushr = ushr;
         this.abs = abs;
         this.sqrt = sqrt;
         this.zeroExtend = zeroExtend;
@@ -227,6 +243,27 @@
     }
 
     /**
+     * Describes the shift left operation.
+     */
+    public ShiftOp<Shl> getShl() {
+        return shl;
+    }
+
+    /**
+     * Describes the signed shift right operation.
+     */
+    public ShiftOp<Shr> getShr() {
+        return shr;
+    }
+
+    /**
+     * Describes the unsigned shift right operation.
+     */
+    public ShiftOp<UShr> getUShr() {
+        return ushr;
+    }
+
+    /**
      * Describes the absolute value operation.
      */
     public UnaryOp<Abs> getAbs() {
@@ -274,8 +311,8 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" + toString(floatConvert) +
-                        "]]";
+        return getClass().getSimpleName() + "[" + toString(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow) + ",floatConvert[" +
+                        toString(floatConvert) + "]]";
     }
 
     public abstract static class Op {
@@ -502,6 +539,53 @@
         }
     }
 
+    /**
+     * Describes a shift operation. The right argument of a shift operation always has kind
+     * {@link Kind#Int}.
+     */
+    public abstract static class ShiftOp<OP> extends Op {
+
+        public abstract static class Shl extends ShiftOp<Shl> {
+
+            public Shl() {
+                super("<<");
+            }
+        }
+
+        public abstract static class Shr extends ShiftOp<Shr> {
+
+            public Shr() {
+                super(">>");
+            }
+        }
+
+        public abstract static class UShr extends ShiftOp<UShr> {
+
+            public UShr() {
+                super(">>>");
+            }
+        }
+
+        protected ShiftOp(String operation) {
+            super(operation);
+        }
+
+        /**
+         * Apply the shift to a constant.
+         */
+        public abstract Constant foldConstant(Constant c, int amount);
+
+        /**
+         * Apply the shift to a stamp.
+         */
+        public abstract Stamp foldStamp(Stamp s, IntegerStamp amount);
+
+        /**
+         * Get the shift amount mask for a given result stamp.
+         */
+        public abstract int getShiftAmountMask(Stamp s);
+    }
+
     public abstract static class FloatConvertOp extends UnaryOp<FloatConvertOp> {
 
         private final FloatConvert op;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Mon Jan 12 13:32:43 2015 +0100
@@ -609,6 +609,8 @@
         }
     },
 
+    null, null, null,
+
     new UnaryOp.Abs() {
 
         @Override
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Mon Jan 12 13:32:43 2015 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.FloatConvertOp;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
 
 /**
@@ -700,6 +701,155 @@
         }
     },
 
+    new ShiftOp.Shl() {
+
+        @Override
+        public Constant foldConstant(Constant value, int amount) {
+            PrimitiveConstant c = (PrimitiveConstant) value;
+            switch (c.getKind()) {
+                case Int:
+                    return JavaConstant.forInt(c.asInt() << amount);
+                case Long:
+                    return JavaConstant.forLong(c.asLong() << amount);
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        @Override
+        public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
+            IntegerStamp value = (IntegerStamp) stamp;
+            int bits = value.getBits();
+            long defaultMask = CodeUtil.mask(bits);
+            if (value.upMask() == 0) {
+                return value;
+            }
+            int shiftMask = getShiftAmountMask(stamp);
+            int shiftBits = Integer.bitCount(shiftMask);
+            if (shift.lowerBound() == shift.upperBound()) {
+                int shiftAmount = (int) (shift.lowerBound() & shiftMask);
+                if (shiftAmount == 0) {
+                    return value;
+                }
+                // the mask of bits that will be lost or shifted into the sign bit
+                long removedBits = -1L << (bits - shiftAmount - 1);
+                if ((value.lowerBound() & removedBits) == 0 && (value.upperBound() & removedBits) == 0) {
+                    // use a better stamp if neither lower nor upper bound can lose bits
+                    return new IntegerStamp(bits, value.lowerBound() << shiftAmount, value.upperBound() << shiftAmount, value.downMask() << shiftAmount, value.upMask() << shiftAmount);
+                }
+            }
+            if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) {
+                long downMask = defaultMask;
+                long upMask = 0;
+                for (long i = shift.lowerBound(); i <= shift.upperBound(); i++) {
+                    if (shift.contains(i)) {
+                        downMask &= value.downMask() << (i & shiftMask);
+                        upMask |= value.upMask() << (i & shiftMask);
+                    }
+                }
+                Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
+                return result;
+            }
+            return value.unrestricted();
+        }
+
+        @Override
+        public int getShiftAmountMask(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            assert CodeUtil.isPowerOf2(stamp.getBits());
+            return stamp.getBits() - 1;
+        }
+    },
+
+    new ShiftOp.Shr() {
+
+        @Override
+        public Constant foldConstant(Constant value, int amount) {
+            PrimitiveConstant c = (PrimitiveConstant) value;
+            switch (c.getKind()) {
+                case Int:
+                    return JavaConstant.forInt(c.asInt() >> amount);
+                case Long:
+                    return JavaConstant.forLong(c.asLong() >> amount);
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        @Override
+        public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
+            IntegerStamp value = (IntegerStamp) stamp;
+            int bits = value.getBits();
+            if (shift.lowerBound() == shift.upperBound()) {
+                long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
+                if (shiftCount == 0) {
+                    return stamp;
+                }
+
+                int extraBits = 64 - bits;
+                long defaultMask = CodeUtil.mask(bits);
+                // shifting back and forth performs sign extension
+                long downMask = (value.downMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
+                long upMask = (value.upMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
+                return new IntegerStamp(bits, value.lowerBound() >> shiftCount, value.upperBound() >> shiftCount, downMask, upMask);
+            }
+            long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
+            return IntegerStamp.stampForMask(bits, 0, mask);
+        }
+
+        @Override
+        public int getShiftAmountMask(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            assert CodeUtil.isPowerOf2(stamp.getBits());
+            return stamp.getBits() - 1;
+        }
+    },
+
+    new ShiftOp.UShr() {
+
+        @Override
+        public Constant foldConstant(Constant value, int amount) {
+            PrimitiveConstant c = (PrimitiveConstant) value;
+            switch (c.getKind()) {
+                case Int:
+                    return JavaConstant.forInt(c.asInt() >>> amount);
+                case Long:
+                    return JavaConstant.forLong(c.asLong() >>> amount);
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        @Override
+        public Stamp foldStamp(Stamp stamp, IntegerStamp shift) {
+            IntegerStamp value = (IntegerStamp) stamp;
+            int bits = value.getBits();
+            if (shift.lowerBound() == shift.upperBound()) {
+                long shiftCount = shift.lowerBound() & getShiftAmountMask(stamp);
+                if (shiftCount == 0) {
+                    return stamp;
+                }
+
+                long downMask = value.downMask() >>> shiftCount;
+                long upMask = value.upMask() >>> shiftCount;
+                if (value.lowerBound() < 0) {
+                    return new IntegerStamp(bits, downMask, upMask, downMask, upMask);
+                } else {
+                    return new IntegerStamp(bits, value.lowerBound() >>> shiftCount, value.upperBound() >>> shiftCount, downMask, upMask);
+                }
+            }
+            long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
+            return IntegerStamp.stampForMask(bits, 0, mask);
+        }
+
+        @Override
+        public int getShiftAmountMask(Stamp s) {
+            IntegerStamp stamp = (IntegerStamp) s;
+            assert CodeUtil.isPowerOf2(stamp.getBits());
+            return stamp.getBits() - 1;
+        }
+    },
+
     new UnaryOp.Abs() {
 
         @Override
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -28,9 +28,9 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This class tests that integer stamps are created correctly for constants.
@@ -311,13 +311,14 @@
 
     @Test
     public void testShiftLeft() {
-        assertEquals(new IntegerStamp(32, 0, 0x1ff, 0, 0x1ff), StampTool.leftShift(new IntegerStamp(32, 0, 0xff, 0, 0xff), new IntegerStamp(32, 0, 1, 0, 1)));
-        assertEquals(new IntegerStamp(32, 0, 0x1fe0, 0, 0x1fe0), StampTool.leftShift(new IntegerStamp(32, 0, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
-        assertEquals(new IntegerStamp(32, 0x1e0, 0x1fe0, 0, 0x1fe0), StampTool.leftShift(new IntegerStamp(32, 0xf, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+        ShiftOp<?> shl = IntegerStamp.OPS.getShl();
+        assertEquals(new IntegerStamp(32, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(new IntegerStamp(32, 0, 0xff, 0, 0xff), new IntegerStamp(32, 0, 1, 0, 1)));
+        assertEquals(new IntegerStamp(32, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(32, 0, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+        assertEquals(new IntegerStamp(32, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(32, 0xf, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
 
-        assertEquals(new IntegerStamp(64, 0, 0x1ff, 0, 0x1ff), StampTool.leftShift(new IntegerStamp(64, 0, 0xff, 0, 0xff), new IntegerStamp(32, 0, 1, 0, 1)));
-        assertEquals(new IntegerStamp(64, 0, 0x1fe0, 0, 0x1fe0), StampTool.leftShift(new IntegerStamp(64, 0, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
-        assertEquals(new IntegerStamp(64, 0x1e0, 0x1fe0, 0, 0x1fe0), StampTool.leftShift(new IntegerStamp(64, 0xf, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+        assertEquals(new IntegerStamp(64, 0, 0x1ff, 0, 0x1ff), shl.foldStamp(new IntegerStamp(64, 0, 0xff, 0, 0xff), new IntegerStamp(32, 0, 1, 0, 1)));
+        assertEquals(new IntegerStamp(64, 0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(64, 0, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
+        assertEquals(new IntegerStamp(64, 0x1e0, 0x1fe0, 0, 0x1fe0), shl.foldStamp(new IntegerStamp(64, 0xf, 0xff, 0, 0xff), new IntegerStamp(32, 5, 5, 5, 5)));
 
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -102,7 +102,7 @@
             if (nonConstant instanceof AndNode) {
                 AndNode andNode = (AndNode) nonConstant;
                 return IntegerTestNode.create(andNode.getX(), andNode.getY());
-            } else if (nonConstant instanceof ShiftNode) {
+            } else if (nonConstant instanceof ShiftNode && nonConstant.stamp() instanceof IntegerStamp) {
                 if (nonConstant instanceof LeftShiftNode) {
                     LeftShiftNode shift = (LeftShiftNode) nonConstant;
                     if (shift.getY().isConstant()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -23,43 +23,33 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shl;
 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 LeftShiftNode extends ShiftNode {
+public class LeftShiftNode extends ShiftNode<Shl> {
 
     public static LeftShiftNode create(ValueNode x, ValueNode y) {
         return new LeftShiftNode(x, y);
     }
 
     protected LeftShiftNode(ValueNode x, ValueNode y) {
-        super(x, y);
-    }
-
-    @Override
-    public boolean inferStamp() {
-        return updateStamp(StampTool.leftShift(getX().stamp(), getY().stamp()));
-    }
-
-    private static JavaConstant evalConst(JavaConstant a, JavaConstant b) {
-        if (a.getKind() == Kind.Int) {
-            return JavaConstant.forInt(a.asInt() << b.asInt());
-        } else {
-            assert a.getKind() == Kind.Long;
-            return JavaConstant.forLong(a.asLong() << b.asLong());
-        }
+        super(ArithmeticOpTable::getShl, x, y);
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && forY.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(forX.asJavaConstant(), forY.asJavaConstant()));
-        } else if (forY.isConstant()) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forY.isConstant()) {
             int amount = forY.asJavaConstant().asInt();
             int originalAmout = amount;
             int mask = getShiftAmountMask();
@@ -68,7 +58,7 @@
                 return forX;
             }
             if (forX instanceof ShiftNode) {
-                ShiftNode other = (ShiftNode) forX;
+                ShiftNode<?> other = (ShiftNode<?>) forX;
                 if (other.getY().isConstant()) {
                     int otherAmount = other.getY().asJavaConstant().asInt() & mask;
                     if (other instanceof LeftShiftNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,48 +22,37 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shr;
 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 RightShiftNode extends ShiftNode {
+public class RightShiftNode extends ShiftNode<Shr> {
 
     public static RightShiftNode create(ValueNode x, ValueNode y) {
         return new RightShiftNode(x, y);
     }
 
     protected RightShiftNode(ValueNode x, ValueNode y) {
-        super(x, y);
-    }
-
-    @Override
-    public boolean inferStamp() {
-        return updateStamp(StampTool.rightShift(getX().stamp(), getY().stamp()));
-    }
-
-    private static JavaConstant evalConst(JavaConstant a, JavaConstant b) {
-        if (a.getKind() == Kind.Int) {
-            return JavaConstant.forInt(a.asInt() >> b.asInt());
-        } else {
-            assert a.getKind() == Kind.Long;
-            return JavaConstant.forLong(a.asLong() >> b.asLong());
-        }
+        super(ArithmeticOpTable::getShr, 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.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) {
             return UnsignedRightShiftNode.create(forX, forY);
         }
-        if (forX.isConstant() && forY.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(forX.asJavaConstant(), forY.asJavaConstant()));
-        } else if (forY.isConstant()) {
+
+        if (forY.isConstant()) {
             int amount = forY.asJavaConstant().asInt();
             int originalAmout = amount;
             int mask = getShiftAmountMask();
@@ -72,7 +61,7 @@
                 return forX;
             }
             if (forX instanceof ShiftNode) {
-                ShiftNode other = (ShiftNode) forX;
+                ShiftNode<?> other = (ShiftNode<?>) forX;
                 if (other.getY().isConstant()) {
                     int otherAmount = other.getY().asJavaConstant().asInt() & mask;
                     if (other instanceof RightShiftNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,13 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import java.io.*;
+import java.util.function.*;
+
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp;
+import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -31,7 +37,12 @@
  * The {@code ShiftOp} class represents shift operations.
  */
 @NodeInfo
-public abstract class ShiftNode extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class ShiftNode<OP> extends BinaryNode implements ArithmeticLIRLowerable {
+
+    protected interface SerializableShiftFunction<T> extends Function<ArithmeticOpTable, ShiftOp<T>>, Serializable {
+    }
+
+    protected final SerializableShiftFunction<OP> getOp;
 
     /**
      * Creates a new shift operation.
@@ -39,19 +50,33 @@
      * @param x the first input value
      * @param s the second input value
      */
-    public ShiftNode(ValueNode x, ValueNode s) {
-        super(x.stamp().unrestricted(), x, s);
-        assert s.getKind() == Kind.Int;
+    public ShiftNode(SerializableShiftFunction<OP> getOp, ValueNode x, ValueNode s) {
+        super(getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), (IntegerStamp) s.stamp()), x, s);
+        assert ((IntegerStamp) s.stamp()).getBits() == 32;
+        this.getOp = getOp;
+    }
+
+    protected final ShiftOp<OP> getOp(ValueNode forValue) {
+        return getOp.apply(ArithmeticOpTable.forStamp(forValue.stamp()));
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(getOp(getX()).foldStamp(getX().stamp(), (IntegerStamp) getY().stamp()));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            JavaConstant amount = forY.asJavaConstant();
+            assert amount.getKind() == Kind.Int;
+            return ConstantNode.forPrimitive(stamp(), getOp(forX).foldConstant(forX.asConstant(), amount.asInt()));
+        }
+        return this;
     }
 
     public int getShiftAmountMask() {
-        int mask;
-        if (getKind() == Kind.Int) {
-            mask = 0x1f;
-        } else {
-            assert getKind() == Kind.Long;
-            mask = 0x3f;
-        }
-        return mask;
+        return getOp(getX()).getShiftAmountMask(stamp());
     }
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -23,43 +23,33 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.UShr;
 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 UnsignedRightShiftNode extends ShiftNode {
+public class UnsignedRightShiftNode extends ShiftNode<UShr> {
 
     public static UnsignedRightShiftNode create(ValueNode x, ValueNode y) {
         return new UnsignedRightShiftNode(x, y);
     }
 
     protected UnsignedRightShiftNode(ValueNode x, ValueNode y) {
-        super(x, y);
-    }
-
-    @Override
-    public boolean inferStamp() {
-        return updateStamp(StampTool.unsignedRightShift(getX().stamp(), getY().stamp()));
-    }
-
-    private static JavaConstant evalConst(JavaConstant a, JavaConstant b) {
-        if (a.getKind() == Kind.Int) {
-            return JavaConstant.forInt(a.asInt() >>> b.asInt());
-        } else {
-            assert a.getKind() == Kind.Long;
-            return JavaConstant.forLong(a.asLong() >>> b.asLong());
-        }
+        super(ArithmeticOpTable::getUShr, x, y);
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
-        if (forX.isConstant() && forY.isConstant()) {
-            return ConstantNode.forPrimitive(evalConst(forX.asJavaConstant(), forY.asJavaConstant()));
-        } else if (forY.isConstant()) {
+        ValueNode ret = super.canonical(tool, forX, forY);
+        if (ret != this) {
+            return ret;
+        }
+
+        if (forY.isConstant()) {
             int amount = forY.asJavaConstant().asInt();
             int originalAmout = amount;
             int mask = getShiftAmountMask();
@@ -68,7 +58,7 @@
                 return forX;
             }
             if (forX instanceof ShiftNode) {
-                ShiftNode other = (ShiftNode) forX;
+                ShiftNode<?> other = (ShiftNode<?>) forX;
                 if (other.getY().isConstant()) {
                     int otherAmount = other.getY().asJavaConstant().asInt() & mask;
                     if (other instanceof UnsignedRightShiftNode) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, 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
@@ -31,7 +31,6 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * Location node that has a displacement and a scaled index. Can represent locations in the form of
@@ -100,7 +99,7 @@
         assert indexScaling > 0 && CodeUtil.isPowerOf2(indexScaling);
         int scale = CodeUtil.log2(indexScaling);
         return (IntegerStamp) IntegerStamp.OPS.getAdd().foldStamp(StampFactory.forInteger(64, displacement, displacement),
-                        IntegerStamp.OPS.getSignExtend().foldStamp(32, 64, StampTool.leftShift(index.stamp(), StampFactory.forInteger(64, scale, scale))));
+                        IntegerStamp.OPS.getSignExtend().foldStamp(32, 64, IntegerStamp.OPS.getShl().foldStamp(index.stamp(), StampFactory.forInteger(64, scale, scale))));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Jan 12 12:04:22 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampTool.java	Mon Jan 12 13:32:43 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, 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
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
@@ -47,95 +46,6 @@
         }
     }
 
-    public static Stamp rightShift(Stamp value, Stamp shift) {
-        if (value instanceof IntegerStamp && shift instanceof IntegerStamp) {
-            return rightShift((IntegerStamp) value, (IntegerStamp) shift);
-        }
-        return value.illegal();
-    }
-
-    public static Stamp rightShift(IntegerStamp value, IntegerStamp shift) {
-        int bits = value.getBits();
-        if (shift.lowerBound() == shift.upperBound()) {
-            int extraBits = 64 - bits;
-            long shiftMask = bits > 32 ? 0x3FL : 0x1FL;
-            long shiftCount = shift.lowerBound() & shiftMask;
-            long defaultMask = CodeUtil.mask(bits);
-            // shifting back and forth performs sign extension
-            long downMask = (value.downMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
-            long upMask = (value.upMask() << extraBits) >> (shiftCount + extraBits) & defaultMask;
-            return new IntegerStamp(bits, value.lowerBound() >> shiftCount, value.upperBound() >> shiftCount, downMask, upMask);
-        }
-        long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
-        return IntegerStamp.stampForMask(bits, 0, mask);
-    }
-
-    public static Stamp unsignedRightShift(Stamp value, Stamp shift) {
-        if (value instanceof IntegerStamp && shift instanceof IntegerStamp) {
-            return unsignedRightShift((IntegerStamp) value, (IntegerStamp) shift);
-        }
-        return value.illegal();
-    }
-
-    public static Stamp unsignedRightShift(IntegerStamp value, IntegerStamp shift) {
-        int bits = value.getBits();
-        if (shift.lowerBound() == shift.upperBound()) {
-            long shiftMask = bits > 32 ? 0x3FL : 0x1FL;
-            long shiftCount = shift.lowerBound() & shiftMask;
-            long downMask = value.downMask() >>> shiftCount;
-            long upMask = value.upMask() >>> shiftCount;
-            if (value.lowerBound() < 0) {
-                return new IntegerStamp(bits, downMask, upMask, downMask, upMask);
-            } else {
-                return new IntegerStamp(bits, value.lowerBound() >>> shiftCount, value.upperBound() >>> shiftCount, downMask, upMask);
-            }
-        }
-        long mask = IntegerStamp.upMaskFor(bits, value.lowerBound(), value.upperBound());
-        return IntegerStamp.stampForMask(bits, 0, mask);
-    }
-
-    public static Stamp leftShift(Stamp value, Stamp shift) {
-        if (value instanceof IntegerStamp && shift instanceof IntegerStamp) {
-            return leftShift((IntegerStamp) value, (IntegerStamp) shift);
-        }
-        return value.illegal();
-    }
-
-    public static Stamp leftShift(IntegerStamp value, IntegerStamp shift) {
-        int bits = value.getBits();
-        long defaultMask = CodeUtil.mask(bits);
-        if (value.upMask() == 0) {
-            return value;
-        }
-        int shiftBits = bits > 32 ? 6 : 5;
-        long shiftMask = bits > 32 ? 0x3FL : 0x1FL;
-        if (shift.lowerBound() == shift.upperBound()) {
-            int shiftAmount = (int) (shift.lowerBound() & shiftMask);
-            if (shiftAmount == 0) {
-                return value;
-            }
-            // the mask of bits that will be lost or shifted into the sign bit
-            long removedBits = -1L << (bits - shiftAmount - 1);
-            if ((value.lowerBound() & removedBits) == 0 && (value.upperBound() & removedBits) == 0) {
-                // use a better stamp if neither lower nor upper bound can lose bits
-                return new IntegerStamp(bits, value.lowerBound() << shiftAmount, value.upperBound() << shiftAmount, value.downMask() << shiftAmount, value.upMask() << shiftAmount);
-            }
-        }
-        if ((shift.lowerBound() >>> shiftBits) == (shift.upperBound() >>> shiftBits)) {
-            long downMask = defaultMask;
-            long upMask = 0;
-            for (long i = shift.lowerBound(); i <= shift.upperBound(); i++) {
-                if (shift.contains(i)) {
-                    downMask &= value.downMask() << (i & shiftMask);
-                    upMask |= value.upMask() << (i & shiftMask);
-                }
-            }
-            Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
-            return result;
-        }
-        return value.unrestricted();
-    }
-
     /**
      * Compute the stamp resulting from the unsigned comparison being true.
      *