--- /dev/null 2017-01-22 10:16:57.869617664 -0800 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java 2017-02-15 16:57:09.716839053 -0800 @@ -0,0 +1,759 @@ +/* + * 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 + * 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 org.graalvm.compiler.core.common.type; + +import static jdk.vm.ci.meta.MetaUtil.getSimpleName; + +import java.util.Arrays; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaKind; + +import org.graalvm.compiler.core.common.calc.FloatConvert; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Mul; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Or; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Rem; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Sub; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Xor; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shl; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shr; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.UShr; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not; +import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt; + +/** + * Information about arithmetic operations. + */ +public final class ArithmeticOpTable { + + private final UnaryOp neg; + private final BinaryOp add; + private final BinaryOp sub; + + private final BinaryOp mul; + private final BinaryOp
div; + private final BinaryOp rem; + + private final UnaryOp not; + private final BinaryOp and; + private final BinaryOp or; + private final BinaryOp xor; + + private final ShiftOp shl; + private final ShiftOp shr; + private final ShiftOp ushr; + + private final UnaryOp abs; + private final UnaryOp sqrt; + + private final IntegerConvertOp zeroExtend; + private final IntegerConvertOp signExtend; + private final IntegerConvertOp narrow; + + private final FloatConvertOp[] floatConvert; + private final int hash; + + public static ArithmeticOpTable forStamp(Stamp s) { + if (s instanceof ArithmeticStamp) { + return ((ArithmeticStamp) s).getOps(); + } else { + return EMPTY; + } + } + + 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, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp
div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, + BinaryOp xor, ShiftOp shl, ShiftOp shr, ShiftOp ushr, UnaryOp abs, UnaryOp sqrt, IntegerConvertOp zeroExtend, + IntegerConvertOp signExtend, IntegerConvertOp 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 { + + UnaryOp wrapUnaryOp(UnaryOp op); + + BinaryOp wrapBinaryOp(BinaryOp op); + + ShiftOp wrapShiftOp(ShiftOp op); + + IntegerConvertOp wrapIntegerConvertOp(IntegerConvertOp op); + + FloatConvertOp wrapFloatConvertOp(FloatConvertOp op); + } + + private static T wrapIfNonNull(Function wrapper, T obj) { + if (obj == null) { + return null; + } else { + return wrapper.apply(obj); + } + } + + public static ArithmeticOpTable wrap(ArithmeticOpWrapper wrapper, ArithmeticOpTable inner) { + UnaryOp neg = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNeg()); + BinaryOp add = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAdd()); + BinaryOp sub = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getSub()); + + BinaryOp mul = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getMul()); + BinaryOp
div = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getDiv()); + BinaryOp rem = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getRem()); + + UnaryOp not = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getNot()); + BinaryOp and = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getAnd()); + BinaryOp or = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getOr()); + BinaryOp xor = wrapIfNonNull(wrapper::wrapBinaryOp, inner.getXor()); + + ShiftOp shl = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShl()); + ShiftOp shr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getShr()); + ShiftOp ushr = wrapIfNonNull(wrapper::wrapShiftOp, inner.getUShr()); + + UnaryOp abs = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getAbs()); + UnaryOp sqrt = wrapIfNonNull(wrapper::wrapUnaryOp, inner.getSqrt()); + + IntegerConvertOp zeroExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getZeroExtend()); + IntegerConvertOp signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend()); + IntegerConvertOp narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow()); + + Stream floatConvert = Stream.of(inner.floatConvert).filter(Objects::nonNull).map(wrapper::wrapFloatConvertOp); + + 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, BinaryOp add, BinaryOp sub, BinaryOp mul, BinaryOp
div, BinaryOp rem, UnaryOp not, BinaryOp and, BinaryOp or, + BinaryOp xor, ShiftOp shl, ShiftOp shr, ShiftOp ushr, UnaryOp abs, UnaryOp sqrt, IntegerConvertOp zeroExtend, + IntegerConvertOp signExtend, IntegerConvertOp narrow, Stream floatConvert) { + 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; + this.shl = shl; + this.shr = shr; + this.ushr = ushr; + this.abs = abs; + this.sqrt = sqrt; + this.zeroExtend = zeroExtend; + this.signExtend = signExtend; + this.narrow = narrow; + this.floatConvert = new FloatConvertOp[FloatConvert.values().length]; + floatConvert.forEach(op -> this.floatConvert[op.getFloatConvert().ordinal()] = op); + + this.hash = Objects.hash(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow); + } + + @Override + public int hashCode() { + return hash; + } + + /** + * Describes the unary negation operation. + */ + public UnaryOp getNeg() { + return neg; + } + + /** + * Describes the addition operation. + */ + public BinaryOp getAdd() { + return add; + } + + /** + * Describes the subtraction operation. + */ + public BinaryOp getSub() { + return sub; + } + + /** + * Describes the multiplication operation. + */ + public BinaryOp getMul() { + return mul; + } + + /** + * Describes the division operation. + */ + public BinaryOp
getDiv() { + return div; + } + + /** + * Describes the remainder operation. + */ + public BinaryOp getRem() { + return rem; + } + + /** + * Describes the bitwise not operation. + */ + public UnaryOp getNot() { + return not; + } + + /** + * Describes the bitwise and operation. + */ + public BinaryOp getAnd() { + return and; + } + + /** + * Describes the bitwise or operation. + */ + public BinaryOp getOr() { + return or; + } + + /** + * Describes the bitwise xor operation. + */ + public BinaryOp getXor() { + return xor; + } + + /** + * Describes the shift left operation. + */ + public ShiftOp getShl() { + return shl; + } + + /** + * Describes the signed shift right operation. + */ + public ShiftOp getShr() { + return shr; + } + + /** + * Describes the unsigned shift right operation. + */ + public ShiftOp getUShr() { + return ushr; + } + + /** + * Describes the absolute value operation. + */ + public UnaryOp getAbs() { + return abs; + } + + /** + * Describes the square root operation. + */ + public UnaryOp getSqrt() { + return sqrt; + } + + /** + * Describes the zero extend conversion. + */ + public IntegerConvertOp getZeroExtend() { + return zeroExtend; + } + + /** + * Describes the sign extend conversion. + */ + public IntegerConvertOp getSignExtend() { + return signExtend; + } + + /** + * Describes the narrowing conversion. + */ + public IntegerConvertOp getNarrow() { + return narrow; + } + + /** + * Describes integer/float/double conversions. + */ + public FloatConvertOp getFloatConvert(FloatConvert op) { + return floatConvert[op.ordinal()]; + } + + public static String toString(Op... ops) { + return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(",")); + } + + private boolean opsEquals(ArithmeticOpTable that) { + // @formatter:off + return Objects.equals(neg, that.neg) && + Objects.equals(add, that.add) && + Objects.equals(sub, that.sub) && + Objects.equals(mul, that.mul) && + Objects.equals(div, that.div) && + Objects.equals(rem, that.rem) && + Objects.equals(not, that.not) && + Objects.equals(and, that.and) && + Objects.equals(or, that.or) && + Objects.equals(xor, that.xor) && + Objects.equals(shl, that.shl) && + Objects.equals(shr, that.shr) && + Objects.equals(ushr, that.ushr) && + Objects.equals(abs, that.abs) && + Objects.equals(sqrt, that.sqrt) && + Objects.equals(zeroExtend, that.zeroExtend) && + Objects.equals(signExtend, that.signExtend) && + Objects.equals(narrow, that.narrow); + // @formatter:on + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ArithmeticOpTable that = (ArithmeticOpTable) obj; + if (opsEquals(that)) { + if (Arrays.equals(this.floatConvert, that.floatConvert)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + 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 { + + private final String operator; + + protected Op(String operator) { + this.operator = operator; + } + + @Override + public String toString() { + return operator; + } + + @Override + public int hashCode() { + return operator.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Op that = (Op) obj; + if (operator.equals(that.operator)) { + return true; + } + return true; + } + } + + /** + * Describes a unary arithmetic operation. + */ + public abstract static class UnaryOp extends Op { + + public abstract static class Neg extends UnaryOp { + + protected Neg() { + super("-"); + } + } + + public abstract static class Not extends UnaryOp { + + protected Not() { + super("~"); + } + } + + public abstract static class Abs extends UnaryOp { + + protected Abs() { + super("ABS"); + } + } + + public abstract static class Sqrt extends UnaryOp { + + protected Sqrt() { + super("SQRT"); + } + } + + protected UnaryOp(String operation) { + super(operation); + } + + /** + * 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); + + public UnaryOp unwrap() { + return this; + } + } + + /** + * Describes a binary arithmetic operation. + */ + public abstract static class BinaryOp extends Op { + + public abstract static class Add extends BinaryOp { + + protected Add(boolean associative, boolean commutative) { + super("+", associative, commutative); + } + } + + public abstract static class Sub extends BinaryOp { + + protected Sub(boolean associative, boolean commutative) { + super("-", associative, commutative); + } + } + + public abstract static class Mul extends BinaryOp { + + protected Mul(boolean associative, boolean commutative) { + super("*", associative, commutative); + } + } + + public abstract static class Div extends BinaryOp
{ + + protected Div(boolean associative, boolean commutative) { + super("/", associative, commutative); + } + } + + public abstract static class Rem extends BinaryOp { + + protected Rem(boolean associative, boolean commutative) { + super("%", associative, commutative); + } + } + + public abstract static class And extends BinaryOp { + + protected And(boolean associative, boolean commutative) { + super("&", associative, commutative); + } + } + + public abstract static class Or extends BinaryOp { + + protected Or(boolean associative, boolean commutative) { + super("|", associative, commutative); + } + } + + public abstract static class Xor extends BinaryOp { + + protected Xor(boolean associative, boolean commutative) { + super("^", associative, commutative); + } + } + + private final boolean associative; + private final boolean commutative; + + protected BinaryOp(String operation, boolean associative, boolean commutative) { + super(operation); + 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; + } + + public BinaryOp unwrap() { + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = super.hashCode(); + result = prime * result + (associative ? 1231 : 1237); + result = prime * result + (commutative ? 1231 : 1237); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + BinaryOp that = (BinaryOp) obj; + if (associative != that.associative) { + return false; + } + if (commutative != that.commutative) { + return false; + } + return true; + } + + @Override + public String toString() { + if (associative) { + if (commutative) { + return super.toString() + "[AC]"; + } else { + return super.toString() + "[A]"; + } + } else if (commutative) { + return super.toString() + "[C]"; + } + return super.toString(); + } + } + + /** + * Describes a shift operation. The right argument of a shift operation always has kind + * {@link JavaKind#Int}. + */ + public abstract static class ShiftOp extends Op { + + public abstract static class Shl extends ShiftOp { + + public Shl() { + super("<<"); + } + } + + public abstract static class Shr extends ShiftOp { + + public Shr() { + super(">>"); + } + } + + public abstract static class UShr extends ShiftOp { + + 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 { + + private final FloatConvert op; + + protected FloatConvertOp(FloatConvert op) { + super(op.name()); + this.op = op; + } + + public FloatConvert getFloatConvert() { + return op; + } + + @Override + public FloatConvertOp unwrap() { + return this; + } + + @Override + public int hashCode() { + final int prime = 31; + return prime * super.hashCode() + op.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!super.equals(obj)) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + FloatConvertOp that = (FloatConvertOp) obj; + if (op != that.op) { + return false; + } + return true; + } + } + + public abstract static class IntegerConvertOp extends Op { + + public abstract static class ZeroExtend extends IntegerConvertOp { + + protected ZeroExtend() { + super("ZeroExtend"); + } + } + + public abstract static class SignExtend extends IntegerConvertOp { + + protected SignExtend() { + super("SignExtend"); + } + } + + public abstract static class Narrow extends IntegerConvertOp { + + protected Narrow() { + super("Narrow"); + } + } + + protected IntegerConvertOp(String op) { + super(op); + } + + public abstract Constant foldConstant(int inputBits, int resultBits, Constant value); + + public abstract Stamp foldStamp(int inputBits, int resultBits, Stamp stamp); + + public IntegerConvertOp unwrap() { + return this; + } + } +}