Edit

kc3-lang/angle/src/compiler/translator/ConstantUnion.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2016-12-16 09:32:03
    Hash : 4de340ac
    Message : Remove extraInfo parameter from compiler diagnostic functions This makes error messages more consistent. It was not clear what was supposed to go to the extraInfo parameter, and previously it was mostly being misused, resulting in poorly formatted error messages. Sometimes the order of parameters to the diagnostic functions like error() and warning() was wrong altogether. The diagnostics API is simpler when there's only the "reason" and "token" parameters that have clear meaning and that are separated by consistent punctuation in the output. Fixes error messages like "redifinition interface block member" to be grammatically reasonable like the rest of the error messages. For other error messages, punctuation is added to make them clearer. Example: "invalid layout qualifier location requires an argument" is changed to "invalid layout qualifier: location requires an argument". Extra spaces are also removed from the beginning of error messages. BUG=angleproject:1670 BUG=angleproject:911 TEST=angle_unittests Change-Id: Id5fb1a1f2892fad2b796aaef47ffb07e9d79759c Reviewed-on: https://chromium-review.googlesource.com/420789 Reviewed-by: Jamie Madill <jmadill@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>

  • src/compiler/translator/ConstantUnion.cpp
  • //
    // Copyright 2016 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // ConstantUnion: Constant folding helper class.
    
    #include "compiler/translator/ConstantUnion.h"
    
    #include "common/mathutil.h"
    #include "compiler/translator/Diagnostics.h"
    
    namespace sh
    {
    
    namespace
    {
    
    float CheckedSum(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
    {
        float result = lhs + rhs;
        if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
        {
            diag->warning(line, "Constant folded undefined addition generated NaN", "+");
        }
        else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
        {
            diag->warning(line, "Constant folded addition overflowed to infinity", "+");
        }
        return result;
    }
    
    float CheckedDiff(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
    {
        float result = lhs - rhs;
        if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
        {
            diag->warning(line, "Constant folded undefined subtraction generated NaN", "-");
        }
        else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
        {
            diag->warning(line, "Constant folded subtraction overflowed to infinity", "-");
        }
        return result;
    }
    
    float CheckedMul(float lhs, float rhs, TDiagnostics *diag, const TSourceLoc &line)
    {
        float result = lhs * rhs;
        if (gl::isNaN(result) && !gl::isNaN(lhs) && !gl::isNaN(rhs))
        {
            diag->warning(line, "Constant folded undefined multiplication generated NaN", "*");
        }
        else if (gl::isInf(result) && !gl::isInf(lhs) && !gl::isInf(rhs))
        {
            diag->warning(line, "Constant folded multiplication overflowed to infinity", "*");
        }
        return result;
    }
    
    }  // anonymous namespace
    
    TConstantUnion::TConstantUnion()
    {
        iConst = 0;
        type   = EbtVoid;
    }
    
    bool TConstantUnion::cast(TBasicType newType, const TConstantUnion &constant)
    {
        switch (newType)
        {
            case EbtFloat:
                switch (constant.type)
                {
                    case EbtInt:
                        setFConst(static_cast<float>(constant.getIConst()));
                        break;
                    case EbtUInt:
                        setFConst(static_cast<float>(constant.getUConst()));
                        break;
                    case EbtBool:
                        setFConst(static_cast<float>(constant.getBConst()));
                        break;
                    case EbtFloat:
                        setFConst(static_cast<float>(constant.getFConst()));
                        break;
                    default:
                        return false;
                }
                break;
            case EbtInt:
                switch (constant.type)
                {
                    case EbtInt:
                        setIConst(static_cast<int>(constant.getIConst()));
                        break;
                    case EbtUInt:
                        setIConst(static_cast<int>(constant.getUConst()));
                        break;
                    case EbtBool:
                        setIConst(static_cast<int>(constant.getBConst()));
                        break;
                    case EbtFloat:
                        setIConst(static_cast<int>(constant.getFConst()));
                        break;
                    default:
                        return false;
                }
                break;
            case EbtUInt:
                switch (constant.type)
                {
                    case EbtInt:
                        setUConst(static_cast<unsigned int>(constant.getIConst()));
                        break;
                    case EbtUInt:
                        setUConst(static_cast<unsigned int>(constant.getUConst()));
                        break;
                    case EbtBool:
                        setUConst(static_cast<unsigned int>(constant.getBConst()));
                        break;
                    case EbtFloat:
                        setUConst(static_cast<unsigned int>(constant.getFConst()));
                        break;
                    default:
                        return false;
                }
                break;
            case EbtBool:
                switch (constant.type)
                {
                    case EbtInt:
                        setBConst(constant.getIConst() != 0);
                        break;
                    case EbtUInt:
                        setBConst(constant.getUConst() != 0);
                        break;
                    case EbtBool:
                        setBConst(constant.getBConst());
                        break;
                    case EbtFloat:
                        setBConst(constant.getFConst() != 0.0f);
                        break;
                    default:
                        return false;
                }
                break;
            case EbtStruct:  // Struct fields don't get cast
                switch (constant.type)
                {
                    case EbtInt:
                        setIConst(constant.getIConst());
                        break;
                    case EbtUInt:
                        setUConst(constant.getUConst());
                        break;
                    case EbtBool:
                        setBConst(constant.getBConst());
                        break;
                    case EbtFloat:
                        setFConst(constant.getFConst());
                        break;
                    default:
                        return false;
                }
                break;
            default:
                return false;
        }
    
        return true;
    }
    
    bool TConstantUnion::operator==(const int i) const
    {
        return i == iConst;
    }
    
    bool TConstantUnion::operator==(const unsigned int u) const
    {
        return u == uConst;
    }
    
    bool TConstantUnion::operator==(const float f) const
    {
        return f == fConst;
    }
    
    bool TConstantUnion::operator==(const bool b) const
    {
        return b == bConst;
    }
    
    bool TConstantUnion::operator==(const TConstantUnion &constant) const
    {
        if (constant.type != type)
            return false;
    
        switch (type)
        {
            case EbtInt:
                return constant.iConst == iConst;
            case EbtUInt:
                return constant.uConst == uConst;
            case EbtFloat:
                return constant.fConst == fConst;
            case EbtBool:
                return constant.bConst == bConst;
            default:
                return false;
        }
    }
    
    bool TConstantUnion::operator!=(const int i) const
    {
        return !operator==(i);
    }
    
    bool TConstantUnion::operator!=(const unsigned int u) const
    {
        return !operator==(u);
    }
    
    bool TConstantUnion::operator!=(const float f) const
    {
        return !operator==(f);
    }
    
    bool TConstantUnion::operator!=(const bool b) const
    {
        return !operator==(b);
    }
    
    bool TConstantUnion::operator!=(const TConstantUnion &constant) const
    {
        return !operator==(constant);
    }
    
    bool TConstantUnion::operator>(const TConstantUnion &constant) const
    {
        ASSERT(type == constant.type);
        switch (type)
        {
            case EbtInt:
                return iConst > constant.iConst;
            case EbtUInt:
                return uConst > constant.uConst;
            case EbtFloat:
                return fConst > constant.fConst;
            default:
                return false;  // Invalid operation, handled at semantic analysis
        }
    }
    
    bool TConstantUnion::operator<(const TConstantUnion &constant) const
    {
        ASSERT(type == constant.type);
        switch (type)
        {
            case EbtInt:
                return iConst < constant.iConst;
            case EbtUInt:
                return uConst < constant.uConst;
            case EbtFloat:
                return fConst < constant.fConst;
            default:
                return false;  // Invalid operation, handled at semantic analysis
        }
    }
    
    // static
    TConstantUnion TConstantUnion::add(const TConstantUnion &lhs,
                                       const TConstantUnion &rhs,
                                       TDiagnostics *diag,
                                       const TSourceLoc &line)
    {
        TConstantUnion returnValue;
        ASSERT(lhs.type == rhs.type);
        switch (lhs.type)
        {
            case EbtInt:
                returnValue.setIConst(gl::WrappingSum<int>(lhs.iConst, rhs.iConst));
                break;
            case EbtUInt:
                returnValue.setUConst(gl::WrappingSum<unsigned int>(lhs.uConst, rhs.uConst));
                break;
            case EbtFloat:
                returnValue.setFConst(CheckedSum(lhs.fConst, rhs.fConst, diag, line));
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    // static
    TConstantUnion TConstantUnion::sub(const TConstantUnion &lhs,
                                       const TConstantUnion &rhs,
                                       TDiagnostics *diag,
                                       const TSourceLoc &line)
    {
        TConstantUnion returnValue;
        ASSERT(lhs.type == rhs.type);
        switch (lhs.type)
        {
            case EbtInt:
                returnValue.setIConst(gl::WrappingDiff<int>(lhs.iConst, rhs.iConst));
                break;
            case EbtUInt:
                returnValue.setUConst(gl::WrappingDiff<unsigned int>(lhs.uConst, rhs.uConst));
                break;
            case EbtFloat:
                returnValue.setFConst(CheckedDiff(lhs.fConst, rhs.fConst, diag, line));
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    // static
    TConstantUnion TConstantUnion::mul(const TConstantUnion &lhs,
                                       const TConstantUnion &rhs,
                                       TDiagnostics *diag,
                                       const TSourceLoc &line)
    {
        TConstantUnion returnValue;
        ASSERT(lhs.type == rhs.type);
        switch (lhs.type)
        {
            case EbtInt:
                returnValue.setIConst(gl::WrappingMul(lhs.iConst, rhs.iConst));
                break;
            case EbtUInt:
                // Unsigned integer math in C++ is defined to be done in modulo 2^n, so we rely on that
                // to implement wrapping multiplication.
                returnValue.setUConst(lhs.uConst * rhs.uConst);
                break;
            case EbtFloat:
                returnValue.setFConst(CheckedMul(lhs.fConst, rhs.fConst, diag, line));
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    TConstantUnion TConstantUnion::operator%(const TConstantUnion &constant) const
    {
        TConstantUnion returnValue;
        ASSERT(type == constant.type);
        switch (type)
        {
            case EbtInt:
                returnValue.setIConst(iConst % constant.iConst);
                break;
            case EbtUInt:
                returnValue.setUConst(uConst % constant.uConst);
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    // static
    TConstantUnion TConstantUnion::rshift(const TConstantUnion &lhs,
                                          const TConstantUnion &rhs,
                                          TDiagnostics *diag,
                                          const TSourceLoc &line)
    {
        TConstantUnion returnValue;
        ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
        ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
        if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
            (rhs.type == EbtUInt && rhs.uConst > 31u))
        {
            diag->error(line, "Undefined shift (operand out of range)", ">>");
            switch (lhs.type)
            {
                case EbtInt:
                    returnValue.setIConst(0);
                    break;
                case EbtUInt:
                    returnValue.setUConst(0u);
                    break;
                default:
                    UNREACHABLE();
            }
            return returnValue;
        }
    
        switch (lhs.type)
        {
            case EbtInt:
            {
                unsigned int shiftOffset = 0;
                switch (rhs.type)
                {
                    case EbtInt:
                        shiftOffset = static_cast<unsigned int>(rhs.iConst);
                        break;
                    case EbtUInt:
                        shiftOffset = rhs.uConst;
                        break;
                    default:
                        UNREACHABLE();
                }
                if (shiftOffset > 0)
                {
                    // ESSL 3.00.6 section 5.9: "If E1 is a signed integer, the right-shift will extend
                    // the sign bit." In C++ shifting negative integers is undefined, so we implement
                    // extending the sign bit manually.
                    int lhsSafe = lhs.iConst;
                    if (lhsSafe == std::numeric_limits<int>::min())
                    {
                        // The min integer needs special treatment because only bit it has set is the
                        // sign bit, which we clear later to implement safe right shift of negative
                        // numbers.
                        lhsSafe = -0x40000000;
                        --shiftOffset;
                    }
                    if (shiftOffset > 0)
                    {
                        bool extendSignBit = false;
                        if (lhsSafe < 0)
                        {
                            extendSignBit = true;
                            // Clear the sign bit so that bitshift right is defined in C++.
                            lhsSafe &= 0x7fffffff;
                            ASSERT(lhsSafe > 0);
                        }
                        returnValue.setIConst(lhsSafe >> shiftOffset);
    
                        // Manually fill in the extended sign bit if necessary.
                        if (extendSignBit)
                        {
                            int extendedSignBit = static_cast<int>(0xffffffffu << (31 - shiftOffset));
                            returnValue.setIConst(returnValue.getIConst() | extendedSignBit);
                        }
                    }
                    else
                    {
                        returnValue.setIConst(lhsSafe);
                    }
                }
                else
                {
                    returnValue.setIConst(lhs.iConst);
                }
                break;
            }
            case EbtUInt:
                switch (rhs.type)
                {
                    case EbtInt:
                        returnValue.setUConst(lhs.uConst >> rhs.iConst);
                        break;
                    case EbtUInt:
                        returnValue.setUConst(lhs.uConst >> rhs.uConst);
                        break;
                    default:
                        UNREACHABLE();
                }
                break;
    
            default:
                UNREACHABLE();
        }
        return returnValue;
    }
    
    // static
    TConstantUnion TConstantUnion::lshift(const TConstantUnion &lhs,
                                          const TConstantUnion &rhs,
                                          TDiagnostics *diag,
                                          const TSourceLoc &line)
    {
        TConstantUnion returnValue;
        ASSERT(lhs.type == EbtInt || lhs.type == EbtUInt);
        ASSERT(rhs.type == EbtInt || rhs.type == EbtUInt);
        if ((rhs.type == EbtInt && (rhs.iConst < 0 || rhs.iConst > 31)) ||
            (rhs.type == EbtUInt && rhs.uConst > 31u))
        {
            diag->error(line, "Undefined shift (operand out of range)", "<<");
            switch (lhs.type)
            {
                case EbtInt:
                    returnValue.setIConst(0);
                    break;
                case EbtUInt:
                    returnValue.setUConst(0u);
                    break;
                default:
                    UNREACHABLE();
            }
            return returnValue;
        }
    
        switch (lhs.type)
        {
            case EbtInt:
                switch (rhs.type)
                {
                    // Cast to unsigned integer before shifting, since ESSL 3.00.6 section 5.9 says that
                    // lhs is "interpreted as a bit pattern". This also avoids the possibility of signed
                    // integer overflow or undefined shift of a negative integer.
                    case EbtInt:
                        returnValue.setIConst(
                            static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.iConst));
                        break;
                    case EbtUInt:
                        returnValue.setIConst(
                            static_cast<int>(static_cast<uint32_t>(lhs.iConst) << rhs.uConst));
                        break;
                    default:
                        UNREACHABLE();
                }
                break;
    
            case EbtUInt:
                switch (rhs.type)
                {
                    case EbtInt:
                        returnValue.setUConst(lhs.uConst << rhs.iConst);
                        break;
                    case EbtUInt:
                        returnValue.setUConst(lhs.uConst << rhs.uConst);
                        break;
                    default:
                        UNREACHABLE();
                }
                break;
    
            default:
                UNREACHABLE();
        }
        return returnValue;
    }
    
    TConstantUnion TConstantUnion::operator&(const TConstantUnion &constant) const
    {
        TConstantUnion returnValue;
        ASSERT(constant.type == EbtInt || constant.type == EbtUInt);
        switch (type)
        {
            case EbtInt:
                returnValue.setIConst(iConst & constant.iConst);
                break;
            case EbtUInt:
                returnValue.setUConst(uConst & constant.uConst);
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    TConstantUnion TConstantUnion::operator|(const TConstantUnion &constant) const
    {
        TConstantUnion returnValue;
        ASSERT(type == constant.type);
        switch (type)
        {
            case EbtInt:
                returnValue.setIConst(iConst | constant.iConst);
                break;
            case EbtUInt:
                returnValue.setUConst(uConst | constant.uConst);
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    TConstantUnion TConstantUnion::operator^(const TConstantUnion &constant) const
    {
        TConstantUnion returnValue;
        ASSERT(type == constant.type);
        switch (type)
        {
            case EbtInt:
                returnValue.setIConst(iConst ^ constant.iConst);
                break;
            case EbtUInt:
                returnValue.setUConst(uConst ^ constant.uConst);
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    TConstantUnion TConstantUnion::operator&&(const TConstantUnion &constant) const
    {
        TConstantUnion returnValue;
        ASSERT(type == constant.type);
        switch (type)
        {
            case EbtBool:
                returnValue.setBConst(bConst && constant.bConst);
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    TConstantUnion TConstantUnion::operator||(const TConstantUnion &constant) const
    {
        TConstantUnion returnValue;
        ASSERT(type == constant.type);
        switch (type)
        {
            case EbtBool:
                returnValue.setBConst(bConst || constant.bConst);
                break;
            default:
                UNREACHABLE();
        }
    
        return returnValue;
    }
    
    }  // namespace sh