view graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/calc/Condition.java @ 21543:93c50cefb9e8

moved GraalInternalError to com.oracle.jvmci.common and renamed it to JVMCIError (JBS:GRAAL-53)
author Doug Simon <doug.simon@oracle.com>
date Mon, 25 May 2015 23:30:34 +0200
parents 8652481a1110
children 48c1ebd24120
line wrap: on
line source

/*
 * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.graal.compiler.common.calc;

import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.jvmci.common.*;

/**
 * Condition codes used in conditionals.
 */
public enum Condition {
    /**
     * Equal.
     */
    EQ("=="),

    /**
     * Not equal.
     */
    NE("!="),

    /**
     * Signed less than.
     */
    LT("<"),

    /**
     * Signed less than or equal.
     */
    LE("<="),

    /**
     * Signed greater than.
     */
    GT(">"),

    /**
     * Signed greater than or equal.
     */
    GE(">="),

    /**
     * Unsigned greater than or equal ("above than or equal").
     */
    AE("|>=|"),

    /**
     * Unsigned less than or equal ("below than or equal").
     */
    BE("|<=|"),

    /**
     * Unsigned greater than ("above than").
     */
    AT("|>|"),

    /**
     * Unsigned less than ("below than").
     */
    BT("|<|");

    public final String operator;

    private Condition(String operator) {
        this.operator = operator;
    }

    public boolean check(int left, int right) {
        switch (this) {
            case EQ:
                return left == right;
            case NE:
                return left != right;
            case LT:
                return left < right;
            case LE:
                return left <= right;
            case GT:
                return left > right;
            case GE:
                return left >= right;
            case AE:
                return UnsignedMath.aboveOrEqual(left, right);
            case BE:
                return UnsignedMath.belowOrEqual(left, right);
            case AT:
                return UnsignedMath.aboveThan(left, right);
            case BT:
                return UnsignedMath.belowThan(left, right);
        }
        throw new IllegalArgumentException(this.toString());
    }

    /**
     * Given a condition and its negation, this method returns true for one of the two and false for
     * the other one. This can be used to keep comparisons in a canonical form.
     *
     * @return true if this condition is considered to be the canonical form, false otherwise.
     */
    public boolean isCanonical() {
        switch (this) {
            case EQ:
                return true;
            case NE:
                return false;
            case LT:
                return true;
            case LE:
                return false;
            case GT:
                return false;
            case GE:
                return false;
            case BT:
                return true;
            case BE:
                return false;
            case AT:
                return false;
            case AE:
                return false;
        }
        throw new IllegalArgumentException(this.toString());
    }

    /**
     * Returns true if the condition needs to be mirrored to get to a canonical condition. The
     * result of the mirroring operation might still need to be negated to achieve a canonical form.
     */
    public boolean canonicalMirror() {
        switch (this) {
            case EQ:
                return false;
            case NE:
                return false;
            case LT:
                return false;
            case LE:
                return true;
            case GT:
                return true;
            case GE:
                return false;
            case BT:
                return false;
            case BE:
                return true;
            case AT:
                return true;
            case AE:
                return false;
        }
        throw new IllegalArgumentException(this.toString());
    }

    /**
     * Returns true if the condition needs to be negated to get to a canonical condition. The result
     * of the negation might still need to be mirrored to achieve a canonical form.
     */
    public boolean canonicalNegate() {
        switch (this) {
            case EQ:
                return false;
            case NE:
                return true;
            case LT:
                return false;
            case LE:
                return true;
            case GT:
                return false;
            case GE:
                return true;
            case BT:
                return false;
            case BE:
                return true;
            case AT:
                return false;
            case AE:
                return true;
        }
        throw new IllegalArgumentException(this.toString());
    }

    /**
     * Negate this conditional.
     *
     * @return the condition that represents the negation
     */
    public final Condition negate() {
        switch (this) {
            case EQ:
                return NE;
            case NE:
                return EQ;
            case LT:
                return GE;
            case LE:
                return GT;
            case GT:
                return LE;
            case GE:
                return LT;
            case BT:
                return AE;
            case BE:
                return AT;
            case AT:
                return BE;
            case AE:
                return BT;
        }
        throw new IllegalArgumentException(this.toString());
    }

    public boolean implies(Condition other) {
        if (other == this) {
            return true;
        }
        switch (this) {
            case EQ:
                return other == LE || other == GE || other == BE || other == AE;
            case NE:
                return false;
            case LT:
                return other == LE || other == NE;
            case LE:
                return false;
            case GT:
                return other == GE || other == NE;
            case GE:
                return false;
            case BT:
                return other == BE || other == NE;
            case BE:
                return false;
            case AT:
                return other == AE || other == NE;
            case AE:
                return false;
        }
        throw new IllegalArgumentException(this.toString());
    }

    /**
     * Mirror this conditional (i.e. commute "a op b" to "b op' a")
     *
     * @return the condition representing the equivalent commuted operation
     */
    public final Condition mirror() {
        switch (this) {
            case EQ:
                return EQ;
            case NE:
                return NE;
            case LT:
                return GT;
            case LE:
                return GE;
            case GT:
                return LT;
            case GE:
                return LE;
            case BT:
                return AT;
            case BE:
                return AE;
            case AT:
                return BT;
            case AE:
                return BE;
        }
        throw new IllegalArgumentException();
    }

    /**
     * Returns true if this condition represents an unsigned comparison. EQ and NE are not
     * considered to be unsigned.
     */
    public final boolean isUnsigned() {
        return this == Condition.BT || this == Condition.BE || this == Condition.AT || this == Condition.AE;
    }

    /**
     * Checks if this conditional operation is commutative.
     *
     * @return {@code true} if this operation is commutative
     */
    public final boolean isCommutative() {
        return this == EQ || this == NE;
    }

    /**
     * Attempts to fold a comparison between two constants and return the result.
     *
     * @param lt the constant on the left side of the comparison
     * @param rt the constant on the right side of the comparison
     * @param constantReflection needed to compare constants
     * @return {@link Boolean#TRUE} if the comparison is known to be true, {@link Boolean#FALSE} if
     *         the comparison is known to be false
     */
    public boolean foldCondition(JavaConstant lt, JavaConstant rt, ConstantReflectionProvider constantReflection) {
        assert !lt.getKind().isNumericFloat() && !rt.getKind().isNumericFloat();
        return foldCondition(lt, rt, constantReflection, false);
    }

    /**
     * Attempts to fold a comparison between two constants and return the result.
     *
     * @param lt the constant on the left side of the comparison
     * @param rt the constant on the right side of the comparison
     * @param constantReflection needed to compare constants
     * @param unorderedIsTrue true if an undecided float comparison should result in "true"
     * @return true if the comparison is known to be true, false if the comparison is known to be
     *         false
     */
    public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
        if (lt instanceof PrimitiveConstant) {
            PrimitiveConstant lp = (PrimitiveConstant) lt;
            PrimitiveConstant rp = (PrimitiveConstant) rt;
            switch (lp.getKind()) {
                case Boolean:
                case Byte:
                case Char:
                case Short:
                case Int: {
                    int x = lp.asInt();
                    int y = rp.asInt();
                    switch (this) {
                        case EQ:
                            return x == y;
                        case NE:
                            return x != y;
                        case LT:
                            return x < y;
                        case LE:
                            return x <= y;
                        case GT:
                            return x > y;
                        case GE:
                            return x >= y;
                        case AE:
                            return UnsignedMath.aboveOrEqual(x, y);
                        case BE:
                            return UnsignedMath.belowOrEqual(x, y);
                        case AT:
                            return UnsignedMath.aboveThan(x, y);
                        case BT:
                            return UnsignedMath.belowThan(x, y);
                        default:
                            throw new JVMCIError("expected condition: %s", this);
                    }
                }
                case Long: {
                    long x = lp.asLong();
                    long y = rp.asLong();
                    switch (this) {
                        case EQ:
                            return x == y;
                        case NE:
                            return x != y;
                        case LT:
                            return x < y;
                        case LE:
                            return x <= y;
                        case GT:
                            return x > y;
                        case GE:
                            return x >= y;
                        case AE:
                            return UnsignedMath.aboveOrEqual(x, y);
                        case BE:
                            return UnsignedMath.belowOrEqual(x, y);
                        case AT:
                            return UnsignedMath.aboveThan(x, y);
                        case BT:
                            return UnsignedMath.belowThan(x, y);
                        default:
                            throw new JVMCIError("expected condition: %s", this);
                    }
                }
                case Float: {
                    float x = lp.asFloat();
                    float y = rp.asFloat();
                    if (Float.isNaN(x) || Float.isNaN(y)) {
                        return unorderedIsTrue;
                    }
                    switch (this) {
                        case EQ:
                            return x == y;
                        case NE:
                            return x != y;
                        case LT:
                            return x < y;
                        case LE:
                            return x <= y;
                        case GT:
                            return x > y;
                        case GE:
                            return x >= y;
                        default:
                            throw new JVMCIError("expected condition: %s", this);
                    }
                }
                case Double: {
                    double x = lp.asDouble();
                    double y = rp.asDouble();
                    if (Double.isNaN(x) || Double.isNaN(y)) {
                        return unorderedIsTrue;
                    }
                    switch (this) {
                        case EQ:
                            return x == y;
                        case NE:
                            return x != y;
                        case LT:
                            return x < y;
                        case LE:
                            return x <= y;
                        case GT:
                            return x > y;
                        case GE:
                            return x >= y;
                        default:
                            throw new JVMCIError("expected condition: %s", this);
                    }
                }
                default:
                    throw new JVMCIError("expected value kind %s while folding condition: %s", lp.getKind(), this);
            }
        } else {
            Boolean equal = constantReflection.constantEquals(lt, rt);
            if (equal == null) {
                throw new JVMCIError("could not fold %s %s %s", lt, this, rt);
            }
            switch (this) {
                case EQ:
                    return equal.booleanValue();
                case NE:
                    return !equal.booleanValue();
                default:
                    throw new JVMCIError("expected condition: %s", this);
            }
        }
    }

    public Condition join(Condition other) {
        if (other == this) {
            return this;
        }
        switch (this) {
            case EQ:
                if (other == LE || other == GE || other == BE || other == AE) {
                    return EQ;
                } else {
                    return null;
                }
            case NE:
                if (other == LT || other == GT || other == BT || other == AT) {
                    return other;
                } else if (other == LE) {
                    return LT;
                } else if (other == GE) {
                    return GT;
                } else if (other == BE) {
                    return BT;
                } else if (other == AE) {
                    return AT;
                } else {
                    return null;
                }
            case LE:
                if (other == GE || other == EQ) {
                    return EQ;
                } else if (other == NE || other == LT) {
                    return LT;
                } else {
                    return null;
                }
            case LT:
                if (other == NE || other == LE) {
                    return LT;
                } else {
                    return null;
                }
            case GE:
                if (other == LE || other == EQ) {
                    return EQ;
                } else if (other == NE || other == GT) {
                    return GT;
                } else {
                    return null;
                }
            case GT:
                if (other == NE || other == GE) {
                    return GT;
                } else {
                    return null;
                }
            case BE:
                if (other == AE || other == EQ) {
                    return EQ;
                } else if (other == NE || other == BT) {
                    return BT;
                } else {
                    return null;
                }
            case BT:
                if (other == NE || other == BE) {
                    return BT;
                } else {
                    return null;
                }
            case AE:
                if (other == BE || other == EQ) {
                    return EQ;
                } else if (other == NE || other == AT) {
                    return AT;
                } else {
                    return null;
                }
            case AT:
                if (other == NE || other == AE) {
                    return AT;
                } else {
                    return null;
                }
        }
        throw new IllegalArgumentException(this.toString());
    }

    public Condition meet(Condition other) {
        if (other == this) {
            return this;
        }
        switch (this) {
            case EQ:
                if (other == LE || other == GE || other == BE || other == AE) {
                    return other;
                } else if (other == LT) {
                    return LE;
                } else if (other == GT) {
                    return GE;
                } else if (other == BT) {
                    return BE;
                } else if (other == AT) {
                    return AE;
                } else {
                    return null;
                }
            case NE:
                if (other == LT || other == GT || other == BT || other == AT) {
                    return NE;
                } else {
                    return null;
                }
            case LE:
                if (other == EQ || other == LT) {
                    return LE;
                } else {
                    return null;
                }
            case LT:
                if (other == EQ || other == LE) {
                    return LE;
                } else if (other == NE || other == GT) {
                    return NE;
                } else {
                    return null;
                }
            case GE:
                if (other == EQ || other == GT) {
                    return GE;
                } else {
                    return null;
                }
            case GT:
                if (other == EQ || other == GE) {
                    return GE;
                } else if (other == NE || other == LT) {
                    return NE;
                } else {
                    return null;
                }
            case BE:
                if (other == EQ || other == BT) {
                    return BE;
                } else {
                    return null;
                }
            case BT:
                if (other == EQ || other == BE) {
                    return BE;
                } else if (other == NE || other == AT) {
                    return NE;
                } else {
                    return null;
                }
            case AE:
                if (other == EQ || other == AT) {
                    return AE;
                } else {
                    return null;
                }
            case AT:
                if (other == EQ || other == AE) {
                    return AE;
                } else if (other == NE || other == BT) {
                    return NE;
                } else {
                    return null;
                }
        }
        throw new IllegalArgumentException(this.toString());
    }
}