tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

IntermNode.cpp (146403B)


      1 //
      2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 //
      8 // Build the intermediate representation.
      9 //
     10 
     11 #include <float.h>
     12 #include <limits.h>
     13 #include <math.h>
     14 #include <stdlib.h>
     15 #include <algorithm>
     16 #include <vector>
     17 
     18 #include "common/mathutil.h"
     19 #include "common/matrix_utils.h"
     20 #include "common/utilities.h"
     21 #include "compiler/translator/Diagnostics.h"
     22 #include "compiler/translator/ImmutableString.h"
     23 #include "compiler/translator/IntermNode.h"
     24 #include "compiler/translator/SymbolTable.h"
     25 #include "compiler/translator/util.h"
     26 
     27 namespace sh
     28 {
     29 
     30 namespace
     31 {
     32 
     33 const float kPi                         = 3.14159265358979323846f;
     34 const float kDegreesToRadiansMultiplier = kPi / 180.0f;
     35 const float kRadiansToDegreesMultiplier = 180.0f / kPi;
     36 
     37 TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
     38 {
     39    return left > right ? left : right;
     40 }
     41 
     42 TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
     43 {
     44    TConstantUnion *constUnion = new TConstantUnion[size];
     45    for (size_t i = 0; i < size; ++i)
     46        constUnion[i] = constant;
     47 
     48    return constUnion;
     49 }
     50 
     51 void UndefinedConstantFoldingError(const TSourceLoc &loc,
     52                                   const TFunction *function,
     53                                   TBasicType basicType,
     54                                   TDiagnostics *diagnostics,
     55                                   TConstantUnion *result)
     56 {
     57    diagnostics->warning(loc, "operation result is undefined for the values passed in",
     58                         function->name().data());
     59 
     60    switch (basicType)
     61    {
     62        case EbtFloat:
     63            result->setFConst(0.0f);
     64            break;
     65        case EbtInt:
     66            result->setIConst(0);
     67            break;
     68        case EbtUInt:
     69            result->setUConst(0u);
     70            break;
     71        case EbtBool:
     72            result->setBConst(false);
     73            break;
     74        default:
     75            break;
     76    }
     77 }
     78 
     79 float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
     80 {
     81    float result = 0.0f;
     82    for (size_t i = 0; i < paramArraySize; i++)
     83    {
     84        float f = paramArray[i].getFConst();
     85        result += f * f;
     86    }
     87    return sqrtf(result);
     88 }
     89 
     90 float VectorDotProduct(const TConstantUnion *paramArray1,
     91                       const TConstantUnion *paramArray2,
     92                       size_t paramArraySize)
     93 {
     94    float result = 0.0f;
     95    for (size_t i = 0; i < paramArraySize; i++)
     96        result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
     97    return result;
     98 }
     99 
    100 TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray, const TIntermTyped *originalNode)
    101 {
    102    ASSERT(constArray != nullptr);
    103    // Note that we inherit whatever qualifier the folded node had. Nodes may be constant folded
    104    // without being qualified as constant.
    105    TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
    106    folded->setLine(originalNode->getLine());
    107    return folded;
    108 }
    109 
    110 angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
    111                               const unsigned int rows,
    112                               const unsigned int cols)
    113 {
    114    std::vector<float> elements;
    115    for (size_t i = 0; i < rows * cols; i++)
    116        elements.push_back(paramArray[i].getFConst());
    117    // Transpose is used since the Matrix constructor expects arguments in row-major order,
    118    // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
    119    // so that the created matrix will have the expected dimensions after the transpose.
    120    return angle::Matrix<float>(elements, cols, rows).transpose();
    121 }
    122 
    123 angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int size)
    124 {
    125    std::vector<float> elements;
    126    for (size_t i = 0; i < size * size; i++)
    127        elements.push_back(paramArray[i].getFConst());
    128    // Transpose is used since the Matrix constructor expects arguments in row-major order,
    129    // whereas the paramArray is in column-major order.
    130    return angle::Matrix<float>(elements, size).transpose();
    131 }
    132 
    133 void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
    134 {
    135    // Transpose is used since the input Matrix is in row-major order,
    136    // whereas the actual result should be in column-major order.
    137    angle::Matrix<float> result       = m.transpose();
    138    std::vector<float> resultElements = result.elements();
    139    for (size_t i = 0; i < resultElements.size(); i++)
    140        resultArray[i].setFConst(resultElements[i]);
    141 }
    142 
    143 bool CanFoldAggregateBuiltInOp(TOperator op)
    144 {
    145    switch (op)
    146    {
    147        case EOpAtan:
    148        case EOpPow:
    149        case EOpMod:
    150        case EOpMin:
    151        case EOpMax:
    152        case EOpClamp:
    153        case EOpMix:
    154        case EOpStep:
    155        case EOpSmoothstep:
    156        case EOpFma:
    157        case EOpLdexp:
    158        case EOpMatrixCompMult:
    159        case EOpOuterProduct:
    160        case EOpEqualComponentWise:
    161        case EOpNotEqualComponentWise:
    162        case EOpLessThanComponentWise:
    163        case EOpLessThanEqualComponentWise:
    164        case EOpGreaterThanComponentWise:
    165        case EOpGreaterThanEqualComponentWise:
    166        case EOpDistance:
    167        case EOpDot:
    168        case EOpCross:
    169        case EOpFaceforward:
    170        case EOpReflect:
    171        case EOpRefract:
    172        case EOpBitfieldExtract:
    173        case EOpBitfieldInsert:
    174        case EOpDFdx:
    175        case EOpDFdy:
    176        case EOpFwidth:
    177            return true;
    178        default:
    179            return false;
    180    }
    181 }
    182 
    183 void PropagatePrecisionIfApplicable(TIntermTyped *node, TPrecision precision)
    184 {
    185    if (precision == EbpUndefined || node->getPrecision() != EbpUndefined)
    186    {
    187        return;
    188    }
    189 
    190    if (IsPrecisionApplicableToType(node->getBasicType()))
    191    {
    192        node->propagatePrecision(precision);
    193    }
    194 }
    195 
    196 }  // namespace
    197 
    198 ////////////////////////////////////////////////////////////////
    199 //
    200 // Member functions of the nodes used for building the tree.
    201 //
    202 ////////////////////////////////////////////////////////////////
    203 
    204 TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t) {}
    205 
    206 #define REPLACE_IF_IS(node, type, original, replacement) \
    207    do                                                   \
    208    {                                                    \
    209        if (node == original)                            \
    210        {                                                \
    211            node = static_cast<type *>(replacement);     \
    212            return true;                                 \
    213        }                                                \
    214    } while (0)
    215 
    216 size_t TIntermSymbol::getChildCount() const
    217 {
    218    return 0;
    219 }
    220 
    221 TIntermNode *TIntermSymbol::getChildNode(size_t index) const
    222 {
    223    UNREACHABLE();
    224    return nullptr;
    225 }
    226 
    227 size_t TIntermConstantUnion::getChildCount() const
    228 {
    229    return 0;
    230 }
    231 
    232 TIntermNode *TIntermConstantUnion::getChildNode(size_t index) const
    233 {
    234    UNREACHABLE();
    235    return nullptr;
    236 }
    237 
    238 size_t TIntermLoop::getChildCount() const
    239 {
    240    return (mInit ? 1 : 0) + (mCond ? 1 : 0) + (mExpr ? 1 : 0) + (mBody ? 1 : 0);
    241 }
    242 
    243 TIntermNode *TIntermLoop::getChildNode(size_t index) const
    244 {
    245    TIntermNode *children[4];
    246    unsigned int childIndex = 0;
    247    if (mInit)
    248    {
    249        children[childIndex] = mInit;
    250        ++childIndex;
    251    }
    252    if (mCond)
    253    {
    254        children[childIndex] = mCond;
    255        ++childIndex;
    256    }
    257    if (mExpr)
    258    {
    259        children[childIndex] = mExpr;
    260        ++childIndex;
    261    }
    262    if (mBody)
    263    {
    264        children[childIndex] = mBody;
    265        ++childIndex;
    266    }
    267    ASSERT(index < childIndex);
    268    return children[index];
    269 }
    270 
    271 bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    272 {
    273    ASSERT(original != nullptr);  // This risks replacing multiple children.
    274    REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
    275    REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
    276    REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
    277    REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
    278    return false;
    279 }
    280 
    281 TIntermBranch::TIntermBranch(const TIntermBranch &node)
    282    : TIntermBranch(node.mFlowOp, node.mExpression ? node.mExpression->deepCopy() : nullptr)
    283 {}
    284 
    285 size_t TIntermBranch::getChildCount() const
    286 {
    287    return (mExpression ? 1 : 0);
    288 }
    289 
    290 TIntermNode *TIntermBranch::getChildNode(size_t index) const
    291 {
    292    ASSERT(mExpression);
    293    ASSERT(index == 0);
    294    return mExpression;
    295 }
    296 
    297 bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    298 {
    299    REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
    300    return false;
    301 }
    302 
    303 size_t TIntermSwizzle::getChildCount() const
    304 {
    305    return 1;
    306 }
    307 
    308 TIntermNode *TIntermSwizzle::getChildNode(size_t index) const
    309 {
    310    ASSERT(mOperand);
    311    ASSERT(index == 0);
    312    return mOperand;
    313 }
    314 
    315 bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    316 {
    317    ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
    318    REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
    319    return false;
    320 }
    321 
    322 size_t TIntermBinary::getChildCount() const
    323 {
    324    return 2;
    325 }
    326 
    327 TIntermNode *TIntermBinary::getChildNode(size_t index) const
    328 {
    329    ASSERT(index < 2);
    330    if (index == 0)
    331    {
    332        return mLeft;
    333    }
    334    return mRight;
    335 }
    336 
    337 bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    338 {
    339    REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
    340    REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
    341    return false;
    342 }
    343 
    344 size_t TIntermUnary::getChildCount() const
    345 {
    346    return 1;
    347 }
    348 
    349 TIntermNode *TIntermUnary::getChildNode(size_t index) const
    350 {
    351    ASSERT(mOperand);
    352    ASSERT(index == 0);
    353    return mOperand;
    354 }
    355 
    356 bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    357 {
    358    ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
    359    REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
    360    return false;
    361 }
    362 
    363 size_t TIntermGlobalQualifierDeclaration::getChildCount() const
    364 {
    365    return 1;
    366 }
    367 
    368 TIntermNode *TIntermGlobalQualifierDeclaration::getChildNode(size_t index) const
    369 {
    370    ASSERT(mSymbol);
    371    ASSERT(index == 0);
    372    return mSymbol;
    373 }
    374 
    375 bool TIntermGlobalQualifierDeclaration::replaceChildNode(TIntermNode *original,
    376                                                         TIntermNode *replacement)
    377 {
    378    REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
    379    return false;
    380 }
    381 
    382 size_t TIntermFunctionDefinition::getChildCount() const
    383 {
    384    return 2;
    385 }
    386 
    387 TIntermNode *TIntermFunctionDefinition::getChildNode(size_t index) const
    388 {
    389    ASSERT(index < 2);
    390    if (index == 0)
    391    {
    392        return mPrototype;
    393    }
    394    return mBody;
    395 }
    396 
    397 bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    398 {
    399    REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
    400    REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
    401    return false;
    402 }
    403 
    404 size_t TIntermAggregate::getChildCount() const
    405 {
    406    return mArguments.size();
    407 }
    408 
    409 TIntermNode *TIntermAggregate::getChildNode(size_t index) const
    410 {
    411    return mArguments[index];
    412 }
    413 
    414 bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    415 {
    416    return replaceChildNodeInternal(original, replacement);
    417 }
    418 
    419 TIntermBlock::TIntermBlock(const TIntermBlock &node)
    420 {
    421    for (TIntermNode *intermNode : node.mStatements)
    422    {
    423        mStatements.push_back(intermNode->deepCopy());
    424    }
    425 
    426    ASSERT(!node.mIsTreeRoot);
    427    mIsTreeRoot = false;
    428 }
    429 
    430 TIntermBlock::TIntermBlock(std::initializer_list<TIntermNode *> stmts)
    431 {
    432    for (TIntermNode *stmt : stmts)
    433    {
    434        appendStatement(stmt);
    435    }
    436 }
    437 
    438 size_t TIntermBlock::getChildCount() const
    439 {
    440    return mStatements.size();
    441 }
    442 
    443 TIntermNode *TIntermBlock::getChildNode(size_t index) const
    444 {
    445    return mStatements[index];
    446 }
    447 
    448 bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    449 {
    450    return replaceChildNodeInternal(original, replacement);
    451 }
    452 
    453 void TIntermBlock::replaceAllChildren(const TIntermSequence &newStatements)
    454 {
    455    mStatements.clear();
    456    mStatements.insert(mStatements.begin(), newStatements.begin(), newStatements.end());
    457 }
    458 
    459 size_t TIntermFunctionPrototype::getChildCount() const
    460 {
    461    return 0;
    462 }
    463 
    464 TIntermNode *TIntermFunctionPrototype::getChildNode(size_t index) const
    465 {
    466    UNREACHABLE();
    467    return nullptr;
    468 }
    469 
    470 bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    471 {
    472    return false;
    473 }
    474 
    475 TIntermDeclaration::TIntermDeclaration(const TVariable *var, TIntermTyped *initExpr)
    476 {
    477    if (initExpr)
    478    {
    479        appendDeclarator(
    480            new TIntermBinary(TOperator::EOpInitialize, new TIntermSymbol(var), initExpr));
    481    }
    482    else
    483    {
    484        appendDeclarator(new TIntermSymbol(var));
    485    }
    486 }
    487 
    488 TIntermDeclaration::TIntermDeclaration(std::initializer_list<const TVariable *> declarators)
    489    : TIntermDeclaration()
    490 {
    491    for (const TVariable *d : declarators)
    492    {
    493        appendDeclarator(new TIntermSymbol(d));
    494    }
    495 }
    496 
    497 TIntermDeclaration::TIntermDeclaration(std::initializer_list<TIntermTyped *> declarators)
    498    : TIntermDeclaration()
    499 {
    500    for (TIntermTyped *d : declarators)
    501    {
    502        appendDeclarator(d);
    503    }
    504 }
    505 
    506 size_t TIntermDeclaration::getChildCount() const
    507 {
    508    return mDeclarators.size();
    509 }
    510 
    511 TIntermNode *TIntermDeclaration::getChildNode(size_t index) const
    512 {
    513    return mDeclarators[index];
    514 }
    515 
    516 bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
    517 {
    518    return replaceChildNodeInternal(original, replacement);
    519 }
    520 
    521 TIntermDeclaration::TIntermDeclaration(const TIntermDeclaration &node)
    522 {
    523    for (TIntermNode *intermNode : node.mDeclarators)
    524    {
    525        mDeclarators.push_back(intermNode->deepCopy());
    526    }
    527 }
    528 
    529 bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
    530 {
    531    for (size_t ii = 0; ii < getSequence()->size(); ++ii)
    532    {
    533        REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
    534    }
    535    return false;
    536 }
    537 
    538 bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
    539                                                        const TIntermSequence &replacements)
    540 {
    541    for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
    542    {
    543        if (*it == original)
    544        {
    545            it = getSequence()->erase(it);
    546            getSequence()->insert(it, replacements.begin(), replacements.end());
    547            return true;
    548        }
    549    }
    550    return false;
    551 }
    552 
    553 bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
    554                                            const TIntermSequence &insertions)
    555 {
    556    if (position > getSequence()->size())
    557    {
    558        return false;
    559    }
    560    auto it = getSequence()->begin() + position;
    561    getSequence()->insert(it, insertions.begin(), insertions.end());
    562    return true;
    563 }
    564 
    565 TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable) {}
    566 
    567 bool TIntermSymbol::hasConstantValue() const
    568 {
    569    return variable().getConstPointer() != nullptr;
    570 }
    571 
    572 const TConstantUnion *TIntermSymbol::getConstantValue() const
    573 {
    574    return variable().getConstPointer();
    575 }
    576 
    577 const TSymbolUniqueId &TIntermSymbol::uniqueId() const
    578 {
    579    return mVariable->uniqueId();
    580 }
    581 
    582 ImmutableString TIntermSymbol::getName() const
    583 {
    584    return mVariable->name();
    585 }
    586 
    587 const TType &TIntermSymbol::getType() const
    588 {
    589    return mVariable->getType();
    590 }
    591 
    592 void TIntermSymbol::propagatePrecision(TPrecision precision)
    593 {
    594    // Every declared variable should already have a precision.  Some built-ins don't have a defined
    595    // precision.  This is not asserted however:
    596    //
    597    // - A shader with no precision specified either globally or on a variable will fail with a
    598    //   compilation error later on.
    599    // - Transformations declaring variables without precision will be caught by AST validation.
    600 }
    601 
    602 TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
    603                                                       TIntermSequence *arguments)
    604 {
    605    return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
    606 }
    607 
    608 TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
    609                                                          TIntermSequence *arguments)
    610 {
    611    return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
    612 }
    613 
    614 TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
    615                                                              TIntermSequence *arguments)
    616 {
    617    // Every built-in function should have an op.
    618    ASSERT(func.getBuiltInOp() != EOpNull);
    619    return new TIntermAggregate(&func, func.getReturnType(), func.getBuiltInOp(), arguments);
    620 }
    621 
    622 TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type, TIntermSequence *arguments)
    623 {
    624    return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
    625 }
    626 
    627 TIntermAggregate *TIntermAggregate::CreateConstructor(
    628    const TType &type,
    629    const std::initializer_list<TIntermNode *> &arguments)
    630 {
    631    TIntermSequence argSequence(arguments);
    632    return CreateConstructor(type, &argSequence);
    633 }
    634 
    635 TIntermAggregate::TIntermAggregate(const TFunction *func,
    636                                   const TType &type,
    637                                   TOperator op,
    638                                   TIntermSequence *arguments)
    639    : TIntermOperator(op, type), mUseEmulatedFunction(false), mFunction(func)
    640 {
    641    if (arguments != nullptr)
    642    {
    643        mArguments.swap(*arguments);
    644    }
    645    ASSERT(mFunction == nullptr || mFunction->symbolType() != SymbolType::Empty);
    646    setPrecisionAndQualifier();
    647 }
    648 
    649 void TIntermAggregate::setPrecisionAndQualifier()
    650 {
    651    mType.setQualifier(EvqTemporary);
    652    if ((!BuiltInGroup::IsBuiltIn(mOp) && !isFunctionCall()) || BuiltInGroup::IsMath(mOp))
    653    {
    654        if (areChildrenConstQualified())
    655        {
    656            mType.setQualifier(EvqConst);
    657        }
    658    }
    659 
    660    propagatePrecision(derivePrecision());
    661 }
    662 
    663 bool TIntermAggregate::areChildrenConstQualified()
    664 {
    665    for (TIntermNode *arg : mArguments)
    666    {
    667        TIntermTyped *typedArg = arg->getAsTyped();
    668        if (typedArg && typedArg->getQualifier() != EvqConst)
    669        {
    670            return false;
    671        }
    672    }
    673    return true;
    674 }
    675 
    676 // Derive precision from children nodes
    677 TPrecision TIntermAggregate::derivePrecision() const
    678 {
    679    if (getBasicType() == EbtBool || getBasicType() == EbtVoid || getBasicType() == EbtStruct)
    680    {
    681        return EbpUndefined;
    682    }
    683 
    684    // For AST function calls, take the qualifier from the declared one.
    685    if (isFunctionCall())
    686    {
    687        return mType.getPrecision();
    688    }
    689 
    690    // Some built-ins explicitly specify their precision.
    691    switch (mOp)
    692    {
    693        case EOpBitfieldExtract:
    694            return mArguments[0]->getAsTyped()->getPrecision();
    695        case EOpBitfieldInsert:
    696            return GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
    697                                      mArguments[1]->getAsTyped()->getPrecision());
    698        case EOpTextureSize:
    699        case EOpImageSize:
    700        case EOpUaddCarry:
    701        case EOpUsubBorrow:
    702        case EOpUmulExtended:
    703        case EOpImulExtended:
    704        case EOpFrexp:
    705        case EOpLdexp:
    706            return EbpHigh;
    707        default:
    708            break;
    709    }
    710 
    711    // The rest of the math operations and constructors get their precision from their arguments.
    712    if (BuiltInGroup::IsMath(mOp) || mOp == EOpConstruct)
    713    {
    714        TPrecision precision = EbpUndefined;
    715        for (TIntermNode *argument : mArguments)
    716        {
    717            precision = GetHigherPrecision(argument->getAsTyped()->getPrecision(), precision);
    718        }
    719        return precision;
    720    }
    721 
    722    // Atomic operations return highp.
    723    if (BuiltInGroup::IsImageAtomic(mOp) || BuiltInGroup::IsAtomicCounter(mOp) ||
    724        BuiltInGroup::IsAtomicMemory(mOp))
    725    {
    726        return EbpHigh;
    727    }
    728 
    729    // Texture functions return the same precision as that of the sampler (textureSize returns
    730    // highp, but that's handled above).  imageLoad similar takes the precision of the image.  The
    731    // same is true for dFd*, interpolateAt* and subpassLoad operations.
    732    if (BuiltInGroup::IsTexture(mOp) || BuiltInGroup::IsImageLoad(mOp) ||
    733        BuiltInGroup::IsDerivativesFS(mOp) || BuiltInGroup::IsInterpolationFS(mOp) ||
    734        mOp == EOpSubpassLoad)
    735    {
    736        return mArguments[0]->getAsTyped()->getPrecision();
    737    }
    738 
    739    // Every possibility must be explicitly handled, except for desktop-GLSL-specific built-ins
    740    // for which precision does't matter.
    741    return EbpUndefined;
    742 }
    743 
    744 // Propagate precision to children nodes that don't already have it defined.
    745 void TIntermAggregate::propagatePrecision(TPrecision precision)
    746 {
    747    mType.setPrecision(precision);
    748 
    749    // For constructors, propagate precision to arguments.
    750    if (isConstructor())
    751    {
    752        for (TIntermNode *arg : mArguments)
    753        {
    754            PropagatePrecisionIfApplicable(arg->getAsTyped(), precision);
    755        }
    756        return;
    757    }
    758 
    759    // For function calls, propagate precision of each parameter to its corresponding argument.
    760    if (isFunctionCall())
    761    {
    762        for (size_t paramIndex = 0; paramIndex < mFunction->getParamCount(); ++paramIndex)
    763        {
    764            const TVariable *paramVariable = mFunction->getParam(paramIndex);
    765            PropagatePrecisionIfApplicable(mArguments[paramIndex]->getAsTyped(),
    766                                           paramVariable->getType().getPrecision());
    767        }
    768        return;
    769    }
    770 
    771    // Some built-ins explicitly specify the precision of their parameters.
    772    switch (mOp)
    773    {
    774        case EOpUaddCarry:
    775        case EOpUsubBorrow:
    776        case EOpUmulExtended:
    777        case EOpImulExtended:
    778            PropagatePrecisionIfApplicable(mArguments[0]->getAsTyped(), EbpHigh);
    779            PropagatePrecisionIfApplicable(mArguments[1]->getAsTyped(), EbpHigh);
    780            break;
    781        case EOpFindMSB:
    782        case EOpFrexp:
    783        case EOpLdexp:
    784            PropagatePrecisionIfApplicable(mArguments[0]->getAsTyped(), EbpHigh);
    785            break;
    786        default:
    787            break;
    788    }
    789 }
    790 
    791 const char *TIntermAggregate::functionName() const
    792 {
    793    ASSERT(!isConstructor());
    794    switch (mOp)
    795    {
    796        case EOpCallInternalRawFunction:
    797        case EOpCallFunctionInAST:
    798            return mFunction->name().data();
    799        default:
    800            if (BuiltInGroup::IsBuiltIn(mOp))
    801            {
    802                return mFunction->name().data();
    803            }
    804            return GetOperatorString(mOp);
    805    }
    806 }
    807 
    808 bool TIntermAggregate::hasConstantValue() const
    809 {
    810    if (!isConstructor())
    811    {
    812        return false;
    813    }
    814    for (TIntermNode *constructorArg : mArguments)
    815    {
    816        if (!constructorArg->getAsTyped()->hasConstantValue())
    817        {
    818            return false;
    819        }
    820    }
    821    return true;
    822 }
    823 
    824 bool TIntermAggregate::isConstantNullValue() const
    825 {
    826    if (!isConstructor())
    827    {
    828        return false;
    829    }
    830    for (TIntermNode *constructorArg : mArguments)
    831    {
    832        if (!constructorArg->getAsTyped()->isConstantNullValue())
    833        {
    834            return false;
    835        }
    836    }
    837    return true;
    838 }
    839 
    840 const TConstantUnion *TIntermAggregate::getConstantValue() const
    841 {
    842    if (!hasConstantValue())
    843    {
    844        return nullptr;
    845    }
    846    ASSERT(isConstructor());
    847    ASSERT(mArguments.size() > 0u);
    848 
    849    TConstantUnion *constArray = nullptr;
    850    if (isArray())
    851    {
    852        size_t elementSize = mArguments.front()->getAsTyped()->getType().getObjectSize();
    853        constArray         = new TConstantUnion[elementSize * getOutermostArraySize()];
    854 
    855        size_t elementOffset = 0u;
    856        for (TIntermNode *constructorArg : mArguments)
    857        {
    858            const TConstantUnion *elementConstArray =
    859                constructorArg->getAsTyped()->getConstantValue();
    860            ASSERT(elementConstArray);
    861            size_t elementSizeBytes = sizeof(TConstantUnion) * elementSize;
    862            memcpy(static_cast<void *>(&constArray[elementOffset]),
    863                   static_cast<const void *>(elementConstArray), elementSizeBytes);
    864            elementOffset += elementSize;
    865        }
    866        return constArray;
    867    }
    868 
    869    size_t resultSize    = getType().getObjectSize();
    870    constArray           = new TConstantUnion[resultSize];
    871    TBasicType basicType = getBasicType();
    872 
    873    size_t resultIndex = 0u;
    874 
    875    if (mArguments.size() == 1u)
    876    {
    877        TIntermNode *argument                       = mArguments.front();
    878        TIntermTyped *argumentTyped                 = argument->getAsTyped();
    879        const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
    880        // Check the special case of constructing a matrix diagonal from a single scalar,
    881        // or a vector from a single scalar.
    882        if (argumentTyped->getType().getObjectSize() == 1u)
    883        {
    884            if (isMatrix())
    885            {
    886                const uint8_t resultCols = getType().getCols();
    887                const uint8_t resultRows = getType().getRows();
    888                for (uint8_t col = 0; col < resultCols; ++col)
    889                {
    890                    for (uint8_t row = 0; row < resultRows; ++row)
    891                    {
    892                        if (col == row)
    893                        {
    894                            constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
    895                        }
    896                        else
    897                        {
    898                            constArray[resultIndex].setFConst(0.0f);
    899                        }
    900                        ++resultIndex;
    901                    }
    902                }
    903            }
    904            else
    905            {
    906                while (resultIndex < resultSize)
    907                {
    908                    constArray[resultIndex].cast(basicType, argumentConstantValue[0]);
    909                    ++resultIndex;
    910                }
    911            }
    912            ASSERT(resultIndex == resultSize);
    913            return constArray;
    914        }
    915        else if (isMatrix() && argumentTyped->isMatrix())
    916        {
    917            // The special case of constructing a matrix from a matrix.
    918            const uint8_t argumentCols = argumentTyped->getType().getCols();
    919            const uint8_t argumentRows = argumentTyped->getType().getRows();
    920            const uint8_t resultCols   = getType().getCols();
    921            const uint8_t resultRows   = getType().getRows();
    922            for (uint8_t col = 0; col < resultCols; ++col)
    923            {
    924                for (uint8_t row = 0; row < resultRows; ++row)
    925                {
    926                    if (col < argumentCols && row < argumentRows)
    927                    {
    928                        constArray[resultIndex].cast(
    929                            basicType, argumentConstantValue[col * argumentRows + row]);
    930                    }
    931                    else if (col == row)
    932                    {
    933                        constArray[resultIndex].setFConst(1.0f);
    934                    }
    935                    else
    936                    {
    937                        constArray[resultIndex].setFConst(0.0f);
    938                    }
    939                    ++resultIndex;
    940                }
    941            }
    942            ASSERT(resultIndex == resultSize);
    943            return constArray;
    944        }
    945    }
    946 
    947    for (TIntermNode *argument : mArguments)
    948    {
    949        TIntermTyped *argumentTyped                 = argument->getAsTyped();
    950        size_t argumentSize                         = argumentTyped->getType().getObjectSize();
    951        const TConstantUnion *argumentConstantValue = argumentTyped->getConstantValue();
    952        for (size_t i = 0u; i < argumentSize; ++i)
    953        {
    954            if (resultIndex >= resultSize)
    955                break;
    956            constArray[resultIndex].cast(basicType, argumentConstantValue[i]);
    957            ++resultIndex;
    958        }
    959    }
    960    ASSERT(resultIndex == resultSize);
    961    return constArray;
    962 }
    963 
    964 bool TIntermAggregate::hasSideEffects() const
    965 {
    966    if (getQualifier() == EvqConst)
    967    {
    968        return false;
    969    }
    970 
    971    // If the function itself is known to have a side effect, the expression has a side effect.
    972    const bool calledFunctionHasSideEffects =
    973        mFunction != nullptr && !mFunction->isKnownToNotHaveSideEffects();
    974 
    975    if (calledFunctionHasSideEffects)
    976    {
    977        return true;
    978    }
    979 
    980    // Otherwise it only has a side effect if one of the arguments does.
    981    for (TIntermNode *arg : mArguments)
    982    {
    983        if (arg->getAsTyped()->hasSideEffects())
    984        {
    985            return true;
    986        }
    987    }
    988    return false;
    989 }
    990 
    991 void TIntermBlock::appendStatement(TIntermNode *statement)
    992 {
    993    // Declaration nodes with no children can appear if it was an empty declaration or if all the
    994    // declarators just added constants to the symbol table instead of generating code. We still
    995    // need to add the declaration to the AST in that case because it might be relevant to the
    996    // validity of switch/case.
    997    if (statement != nullptr)
    998    {
    999        mStatements.push_back(statement);
   1000    }
   1001 }
   1002 
   1003 void TIntermBlock::insertStatement(size_t insertPosition, TIntermNode *statement)
   1004 {
   1005    ASSERT(statement != nullptr);
   1006    mStatements.insert(mStatements.begin() + insertPosition, statement);
   1007 }
   1008 
   1009 void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
   1010 {
   1011    ASSERT(declarator != nullptr);
   1012    ASSERT(declarator->getAsSymbolNode() != nullptr ||
   1013           (declarator->getAsBinaryNode() != nullptr &&
   1014            declarator->getAsBinaryNode()->getOp() == EOpInitialize));
   1015    ASSERT(mDeclarators.empty() ||
   1016           declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
   1017    mDeclarators.push_back(declarator);
   1018 }
   1019 
   1020 size_t TIntermTernary::getChildCount() const
   1021 {
   1022    return 3;
   1023 }
   1024 
   1025 TIntermNode *TIntermTernary::getChildNode(size_t index) const
   1026 {
   1027    ASSERT(index < 3);
   1028    if (index == 0)
   1029    {
   1030        return mCondition;
   1031    }
   1032    if (index == 1)
   1033    {
   1034        return mTrueExpression;
   1035    }
   1036    return mFalseExpression;
   1037 }
   1038 
   1039 bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
   1040 {
   1041    REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
   1042    REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
   1043    REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
   1044    return false;
   1045 }
   1046 
   1047 size_t TIntermIfElse::getChildCount() const
   1048 {
   1049    return 1 + (mTrueBlock ? 1 : 0) + (mFalseBlock ? 1 : 0);
   1050 }
   1051 
   1052 TIntermNode *TIntermIfElse::getChildNode(size_t index) const
   1053 {
   1054    if (index == 0)
   1055    {
   1056        return mCondition;
   1057    }
   1058    if (mTrueBlock && index == 1)
   1059    {
   1060        return mTrueBlock;
   1061    }
   1062    return mFalseBlock;
   1063 }
   1064 
   1065 bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
   1066 {
   1067    REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
   1068    REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
   1069    REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
   1070    return false;
   1071 }
   1072 
   1073 size_t TIntermSwitch::getChildCount() const
   1074 {
   1075    return 2;
   1076 }
   1077 
   1078 TIntermNode *TIntermSwitch::getChildNode(size_t index) const
   1079 {
   1080    ASSERT(index < 2);
   1081    if (index == 0)
   1082    {
   1083        return mInit;
   1084    }
   1085    return mStatementList;
   1086 }
   1087 
   1088 bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
   1089 {
   1090    REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
   1091    REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
   1092    ASSERT(mStatementList);
   1093    return false;
   1094 }
   1095 
   1096 TIntermCase::TIntermCase(const TIntermCase &node) : TIntermCase(node.mCondition->deepCopy()) {}
   1097 
   1098 size_t TIntermCase::getChildCount() const
   1099 {
   1100    return (mCondition ? 1 : 0);
   1101 }
   1102 
   1103 TIntermNode *TIntermCase::getChildNode(size_t index) const
   1104 {
   1105    ASSERT(index == 0);
   1106    ASSERT(mCondition);
   1107    return mCondition;
   1108 }
   1109 
   1110 bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
   1111 {
   1112    REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
   1113    return false;
   1114 }
   1115 
   1116 TIntermTyped::TIntermTyped() : mIsPrecise(false) {}
   1117 TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermTyped()
   1118 {
   1119    // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
   1120    // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
   1121    // We need to manually copy any fields of TIntermNode.
   1122    mLine = node.mLine;
   1123 
   1124    // Once deteremined, the tree is not expected to transform.
   1125    ASSERT(!mIsPrecise);
   1126 }
   1127 
   1128 bool TIntermTyped::hasConstantValue() const
   1129 {
   1130    return false;
   1131 }
   1132 
   1133 bool TIntermTyped::isConstantNullValue() const
   1134 {
   1135    return false;
   1136 }
   1137 
   1138 const TConstantUnion *TIntermTyped::getConstantValue() const
   1139 {
   1140    return nullptr;
   1141 }
   1142 
   1143 TPrecision TIntermTyped::derivePrecision() const
   1144 {
   1145    UNREACHABLE();
   1146    return EbpUndefined;
   1147 }
   1148 
   1149 void TIntermTyped::propagatePrecision(TPrecision precision)
   1150 {
   1151    UNREACHABLE();
   1152 }
   1153 
   1154 TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
   1155    : TIntermExpression(node)
   1156 {
   1157    mUnionArrayPointer = node.mUnionArrayPointer;
   1158 }
   1159 
   1160 TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
   1161    : TIntermTyped(), mFunction(function)
   1162 {
   1163    ASSERT(mFunction->symbolType() != SymbolType::Empty);
   1164 }
   1165 
   1166 const TType &TIntermFunctionPrototype::getType() const
   1167 {
   1168    return mFunction->getReturnType();
   1169 }
   1170 
   1171 TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
   1172    : TIntermOperator(node),
   1173      mUseEmulatedFunction(node.mUseEmulatedFunction),
   1174      mFunction(node.mFunction)
   1175 {
   1176    for (TIntermNode *arg : node.mArguments)
   1177    {
   1178        TIntermTyped *typedArg = arg->getAsTyped();
   1179        ASSERT(typedArg != nullptr);
   1180        TIntermTyped *argCopy = typedArg->deepCopy();
   1181        mArguments.push_back(argCopy);
   1182    }
   1183 }
   1184 
   1185 TIntermAggregate *TIntermAggregate::shallowCopy() const
   1186 {
   1187    TIntermSequence copySeq;
   1188    copySeq.insert(copySeq.begin(), getSequence()->begin(), getSequence()->end());
   1189    TIntermAggregate *copyNode = new TIntermAggregate(mFunction, mType, mOp, &copySeq);
   1190    copyNode->setLine(mLine);
   1191    return copyNode;
   1192 }
   1193 
   1194 TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermExpression(node)
   1195 {
   1196    TIntermTyped *operandCopy = node.mOperand->deepCopy();
   1197    ASSERT(operandCopy != nullptr);
   1198    mOperand                   = operandCopy;
   1199    mSwizzleOffsets            = node.mSwizzleOffsets;
   1200    mHasFoldedDuplicateOffsets = node.mHasFoldedDuplicateOffsets;
   1201 }
   1202 
   1203 TIntermBinary::TIntermBinary(const TIntermBinary &node) : TIntermOperator(node)
   1204 {
   1205    TIntermTyped *leftCopy  = node.mLeft->deepCopy();
   1206    TIntermTyped *rightCopy = node.mRight->deepCopy();
   1207    ASSERT(leftCopy != nullptr && rightCopy != nullptr);
   1208    mLeft  = leftCopy;
   1209    mRight = rightCopy;
   1210 }
   1211 
   1212 TIntermUnary::TIntermUnary(const TIntermUnary &node)
   1213    : TIntermOperator(node),
   1214      mUseEmulatedFunction(node.mUseEmulatedFunction),
   1215      mFunction(node.mFunction)
   1216 {
   1217    TIntermTyped *operandCopy = node.mOperand->deepCopy();
   1218    ASSERT(operandCopy != nullptr);
   1219    mOperand = operandCopy;
   1220 }
   1221 
   1222 TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermExpression(node)
   1223 {
   1224    TIntermTyped *conditionCopy = node.mCondition->deepCopy();
   1225    TIntermTyped *trueCopy      = node.mTrueExpression->deepCopy();
   1226    TIntermTyped *falseCopy     = node.mFalseExpression->deepCopy();
   1227    ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
   1228    mCondition       = conditionCopy;
   1229    mTrueExpression  = trueCopy;
   1230    mFalseExpression = falseCopy;
   1231 }
   1232 
   1233 bool TIntermOperator::isAssignment() const
   1234 {
   1235    return IsAssignment(mOp);
   1236 }
   1237 
   1238 bool TIntermOperator::isMultiplication() const
   1239 {
   1240    switch (mOp)
   1241    {
   1242        case EOpMul:
   1243        case EOpMatrixTimesMatrix:
   1244        case EOpMatrixTimesVector:
   1245        case EOpMatrixTimesScalar:
   1246        case EOpVectorTimesMatrix:
   1247        case EOpVectorTimesScalar:
   1248            return true;
   1249        default:
   1250            return false;
   1251    }
   1252 }
   1253 
   1254 bool TIntermOperator::isConstructor() const
   1255 {
   1256    return (mOp == EOpConstruct);
   1257 }
   1258 
   1259 bool TIntermOperator::isFunctionCall() const
   1260 {
   1261    switch (mOp)
   1262    {
   1263        case EOpCallFunctionInAST:
   1264        case EOpCallInternalRawFunction:
   1265            return true;
   1266        default:
   1267            return false;
   1268    }
   1269 }
   1270 
   1271 TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
   1272 {
   1273    if (left.isMatrix())
   1274    {
   1275        if (right.isMatrix())
   1276        {
   1277            return EOpMatrixTimesMatrix;
   1278        }
   1279        else
   1280        {
   1281            if (right.isVector())
   1282            {
   1283                return EOpMatrixTimesVector;
   1284            }
   1285            else
   1286            {
   1287                return EOpMatrixTimesScalar;
   1288            }
   1289        }
   1290    }
   1291    else
   1292    {
   1293        if (right.isMatrix())
   1294        {
   1295            if (left.isVector())
   1296            {
   1297                return EOpVectorTimesMatrix;
   1298            }
   1299            else
   1300            {
   1301                return EOpMatrixTimesScalar;
   1302            }
   1303        }
   1304        else
   1305        {
   1306            // Neither operand is a matrix.
   1307            if (left.isVector() == right.isVector())
   1308            {
   1309                // Leave as component product.
   1310                return EOpMul;
   1311            }
   1312            else
   1313            {
   1314                return EOpVectorTimesScalar;
   1315            }
   1316        }
   1317    }
   1318 }
   1319 
   1320 TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
   1321 {
   1322    if (left.isMatrix())
   1323    {
   1324        if (right.isMatrix())
   1325        {
   1326            return EOpMatrixTimesMatrixAssign;
   1327        }
   1328        else
   1329        {
   1330            // right should be scalar, but this may not be validated yet.
   1331            return EOpMatrixTimesScalarAssign;
   1332        }
   1333    }
   1334    else
   1335    {
   1336        if (right.isMatrix())
   1337        {
   1338            // Left should be a vector, but this may not be validated yet.
   1339            return EOpVectorTimesMatrixAssign;
   1340        }
   1341        else
   1342        {
   1343            // Neither operand is a matrix.
   1344            if (left.isVector() == right.isVector())
   1345            {
   1346                // Leave as component product.
   1347                return EOpMulAssign;
   1348            }
   1349            else
   1350            {
   1351                // left should be vector and right should be scalar, but this may not be validated
   1352                // yet.
   1353                return EOpVectorTimesScalarAssign;
   1354            }
   1355        }
   1356    }
   1357 }
   1358 
   1359 //
   1360 // Make sure the type of a unary operator is appropriate for its
   1361 // combination of operation and operand type.
   1362 //
   1363 void TIntermUnary::promote()
   1364 {
   1365    if (mOp == EOpArrayLength)
   1366    {
   1367        // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
   1368        setType(TType(EbtInt, EbpHigh, EvqConst));
   1369        return;
   1370    }
   1371 
   1372    TQualifier resultQualifier = EvqTemporary;
   1373    if (mOperand->getQualifier() == EvqConst)
   1374        resultQualifier = EvqConst;
   1375 
   1376    TType resultType = mOperand->getType();
   1377    resultType.setQualifier(resultQualifier);
   1378 
   1379    // Result is an intermediate value, so make sure it's identified as such.
   1380    resultType.setInterfaceBlock(nullptr);
   1381 
   1382    // Override type properties for special built-ins.  Precision is determined later by
   1383    // |derivePrecision|.
   1384    switch (mOp)
   1385    {
   1386        case EOpFloatBitsToInt:
   1387            resultType.setBasicType(EbtInt);
   1388            break;
   1389        case EOpFloatBitsToUint:
   1390            resultType.setBasicType(EbtUInt);
   1391            break;
   1392        case EOpIntBitsToFloat:
   1393        case EOpUintBitsToFloat:
   1394            resultType.setBasicType(EbtFloat);
   1395            break;
   1396        case EOpPackSnorm2x16:
   1397        case EOpPackUnorm2x16:
   1398        case EOpPackHalf2x16:
   1399        case EOpPackUnorm4x8:
   1400        case EOpPackSnorm4x8:
   1401            resultType.setBasicType(EbtUInt);
   1402            resultType.setPrimarySize(1);
   1403            break;
   1404        case EOpUnpackSnorm2x16:
   1405        case EOpUnpackUnorm2x16:
   1406        case EOpUnpackHalf2x16:
   1407            resultType.setBasicType(EbtFloat);
   1408            resultType.setPrimarySize(2);
   1409            break;
   1410        case EOpUnpackUnorm4x8:
   1411        case EOpUnpackSnorm4x8:
   1412            resultType.setBasicType(EbtFloat);
   1413            resultType.setPrimarySize(4);
   1414            break;
   1415        case EOpAny:
   1416        case EOpAll:
   1417            resultType.setBasicType(EbtBool);
   1418            resultType.setPrimarySize(1);
   1419            break;
   1420        case EOpLength:
   1421        case EOpDeterminant:
   1422            resultType.setBasicType(EbtFloat);
   1423            resultType.setPrimarySize(1);
   1424            resultType.setSecondarySize(1);
   1425            break;
   1426        case EOpTranspose:
   1427            ASSERT(resultType.getBasicType() == EbtFloat);
   1428            resultType.setPrimarySize(mOperand->getType().getRows());
   1429            resultType.setSecondarySize(mOperand->getType().getCols());
   1430            break;
   1431        case EOpIsinf:
   1432        case EOpIsnan:
   1433            resultType.setBasicType(EbtBool);
   1434            break;
   1435        case EOpBitCount:
   1436        case EOpFindLSB:
   1437        case EOpFindMSB:
   1438            resultType.setBasicType(EbtInt);
   1439            break;
   1440        default:
   1441            break;
   1442    }
   1443 
   1444    setType(resultType);
   1445    propagatePrecision(derivePrecision());
   1446 }
   1447 
   1448 // Derive precision from children nodes
   1449 TPrecision TIntermUnary::derivePrecision() const
   1450 {
   1451    // Unary operators generally derive their precision from their operand, except for a few
   1452    // built-ins where this is overriden.
   1453    switch (mOp)
   1454    {
   1455        case EOpArrayLength:
   1456        case EOpFloatBitsToInt:
   1457        case EOpFloatBitsToUint:
   1458        case EOpIntBitsToFloat:
   1459        case EOpUintBitsToFloat:
   1460        case EOpPackSnorm2x16:
   1461        case EOpPackUnorm2x16:
   1462        case EOpPackHalf2x16:
   1463        case EOpPackUnorm4x8:
   1464        case EOpPackSnorm4x8:
   1465        case EOpUnpackSnorm2x16:
   1466        case EOpUnpackUnorm2x16:
   1467        case EOpBitfieldReverse:
   1468            return EbpHigh;
   1469        case EOpUnpackHalf2x16:
   1470        case EOpUnpackUnorm4x8:
   1471        case EOpUnpackSnorm4x8:
   1472            return EbpMedium;
   1473        case EOpBitCount:
   1474        case EOpFindLSB:
   1475        case EOpFindMSB:
   1476            return EbpLow;
   1477        case EOpAny:
   1478        case EOpAll:
   1479        case EOpIsinf:
   1480        case EOpIsnan:
   1481            return EbpUndefined;
   1482        default:
   1483            return mOperand->getPrecision();
   1484    }
   1485 }
   1486 
   1487 void TIntermUnary::propagatePrecision(TPrecision precision)
   1488 {
   1489    mType.setPrecision(precision);
   1490 
   1491    // Generally precision of the operand and the precision of the result match.  A few built-ins
   1492    // are exceptional.
   1493    switch (mOp)
   1494    {
   1495        case EOpArrayLength:
   1496        case EOpPackSnorm2x16:
   1497        case EOpPackUnorm2x16:
   1498        case EOpPackUnorm4x8:
   1499        case EOpPackSnorm4x8:
   1500        case EOpPackHalf2x16:
   1501        case EOpBitCount:
   1502        case EOpFindLSB:
   1503        case EOpFindMSB:
   1504        case EOpIsinf:
   1505        case EOpIsnan:
   1506            // Precision of result does not affect the operand in any way.
   1507            break;
   1508        case EOpFloatBitsToInt:
   1509        case EOpFloatBitsToUint:
   1510        case EOpIntBitsToFloat:
   1511        case EOpUintBitsToFloat:
   1512        case EOpUnpackSnorm2x16:
   1513        case EOpUnpackUnorm2x16:
   1514        case EOpUnpackUnorm4x8:
   1515        case EOpUnpackSnorm4x8:
   1516        case EOpUnpackHalf2x16:
   1517        case EOpBitfieldReverse:
   1518            PropagatePrecisionIfApplicable(mOperand, EbpHigh);
   1519            break;
   1520        default:
   1521            PropagatePrecisionIfApplicable(mOperand, precision);
   1522    }
   1523 }
   1524 
   1525 TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
   1526    : TIntermExpression(TType(EbtFloat, EbpUndefined)),
   1527      mOperand(operand),
   1528      mSwizzleOffsets(swizzleOffsets),
   1529      mHasFoldedDuplicateOffsets(false)
   1530 {
   1531    ASSERT(mOperand);
   1532    ASSERT(mOperand->getType().isVector());
   1533    ASSERT(mSwizzleOffsets.size() <= 4);
   1534    promote();
   1535 }
   1536 
   1537 TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function)
   1538    : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false), mFunction(function)
   1539 {
   1540    ASSERT(mOperand);
   1541    ASSERT(!BuiltInGroup::IsBuiltIn(op) || (function != nullptr && function->getBuiltInOp() == op));
   1542    promote();
   1543 }
   1544 
   1545 TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
   1546    : TIntermOperator(op), mLeft(left), mRight(right)
   1547 {
   1548    ASSERT(mLeft);
   1549    ASSERT(mRight);
   1550    promote();
   1551 }
   1552 
   1553 TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
   1554                                          TIntermTyped *right,
   1555                                          int shaderVersion)
   1556 {
   1557    TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
   1558    node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
   1559    return node;
   1560 }
   1561 
   1562 TIntermGlobalQualifierDeclaration::TIntermGlobalQualifierDeclaration(TIntermSymbol *symbol,
   1563                                                                     bool isPrecise,
   1564                                                                     const TSourceLoc &line)
   1565    : TIntermNode(), mSymbol(symbol), mIsPrecise(isPrecise)
   1566 {
   1567    ASSERT(symbol);
   1568    setLine(line);
   1569 }
   1570 
   1571 TIntermGlobalQualifierDeclaration::TIntermGlobalQualifierDeclaration(
   1572    const TIntermGlobalQualifierDeclaration &node)
   1573    : TIntermGlobalQualifierDeclaration(static_cast<TIntermSymbol *>(node.mSymbol->deepCopy()),
   1574                                        node.mIsPrecise,
   1575                                        node.mLine)
   1576 {}
   1577 
   1578 TIntermTernary::TIntermTernary(TIntermTyped *cond,
   1579                               TIntermTyped *trueExpression,
   1580                               TIntermTyped *falseExpression)
   1581    : TIntermExpression(trueExpression->getType()),
   1582      mCondition(cond),
   1583      mTrueExpression(trueExpression),
   1584      mFalseExpression(falseExpression)
   1585 {
   1586    ASSERT(mCondition);
   1587    ASSERT(mTrueExpression);
   1588    ASSERT(mFalseExpression);
   1589    getTypePointer()->setQualifier(
   1590        TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
   1591 
   1592    propagatePrecision(derivePrecision());
   1593 }
   1594 
   1595 TIntermLoop::TIntermLoop(TLoopType type,
   1596                         TIntermNode *init,
   1597                         TIntermTyped *cond,
   1598                         TIntermTyped *expr,
   1599                         TIntermBlock *body)
   1600    : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
   1601 {
   1602    // Declaration nodes with no children can appear if all the declarators just added constants to
   1603    // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
   1604    if (mInit && mInit->getAsDeclarationNode() &&
   1605        mInit->getAsDeclarationNode()->getSequence()->empty())
   1606    {
   1607        mInit = nullptr;
   1608    }
   1609 }
   1610 
   1611 TIntermLoop::TIntermLoop(const TIntermLoop &node)
   1612    : TIntermLoop(node.mType,
   1613                  node.mInit ? node.mInit->deepCopy() : nullptr,
   1614                  node.mCond ? node.mCond->deepCopy() : nullptr,
   1615                  node.mExpr ? node.mExpr->deepCopy() : nullptr,
   1616                  node.mBody ? node.mBody->deepCopy() : nullptr)
   1617 {}
   1618 
   1619 TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
   1620    : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
   1621 {
   1622    ASSERT(mCondition);
   1623    // Prune empty false blocks so that there won't be unnecessary operations done on it.
   1624    if (mFalseBlock && mFalseBlock->getSequence()->empty())
   1625    {
   1626        mFalseBlock = nullptr;
   1627    }
   1628 }
   1629 
   1630 TIntermIfElse::TIntermIfElse(const TIntermIfElse &node)
   1631    : TIntermIfElse(node.mCondition->deepCopy(),
   1632                    node.mTrueBlock->deepCopy(),
   1633                    node.mFalseBlock ? node.mFalseBlock->deepCopy() : nullptr)
   1634 {}
   1635 
   1636 TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
   1637    : TIntermNode(), mInit(init), mStatementList(statementList)
   1638 {
   1639    ASSERT(mInit);
   1640    ASSERT(mStatementList);
   1641 }
   1642 
   1643 TIntermSwitch::TIntermSwitch(const TIntermSwitch &node)
   1644    : TIntermSwitch(node.mInit->deepCopy(), node.mStatementList->deepCopy())
   1645 {}
   1646 
   1647 void TIntermSwitch::setStatementList(TIntermBlock *statementList)
   1648 {
   1649    ASSERT(statementList);
   1650    mStatementList = statementList;
   1651 }
   1652 
   1653 // static
   1654 TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
   1655                                              TIntermTyped *trueExpression,
   1656                                              TIntermTyped *falseExpression)
   1657 {
   1658    if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
   1659        falseExpression->getQualifier() == EvqConst)
   1660    {
   1661        return EvqConst;
   1662    }
   1663    return EvqTemporary;
   1664 }
   1665 
   1666 // Derive precision from children nodes
   1667 TPrecision TIntermTernary::derivePrecision() const
   1668 {
   1669    return GetHigherPrecision(mTrueExpression->getPrecision(), mFalseExpression->getPrecision());
   1670 }
   1671 
   1672 void TIntermTernary::propagatePrecision(TPrecision precision)
   1673 {
   1674    mType.setPrecision(precision);
   1675 
   1676    PropagatePrecisionIfApplicable(mTrueExpression, precision);
   1677    PropagatePrecisionIfApplicable(mFalseExpression, precision);
   1678 }
   1679 
   1680 TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
   1681 {
   1682    if (mCondition->getAsConstantUnion())
   1683    {
   1684        if (mCondition->getAsConstantUnion()->getBConst(0))
   1685        {
   1686            return mTrueExpression;
   1687        }
   1688        else
   1689        {
   1690            return mFalseExpression;
   1691        }
   1692    }
   1693    return this;
   1694 }
   1695 
   1696 void TIntermSwizzle::promote()
   1697 {
   1698    TQualifier resultQualifier = EvqTemporary;
   1699    if (mOperand->getQualifier() == EvqConst)
   1700        resultQualifier = EvqConst;
   1701 
   1702    size_t numFields = mSwizzleOffsets.size();
   1703    setType(TType(mOperand->getBasicType(), EbpUndefined, resultQualifier,
   1704                  static_cast<uint8_t>(numFields)));
   1705    propagatePrecision(derivePrecision());
   1706 }
   1707 
   1708 // Derive precision from children nodes
   1709 TPrecision TIntermSwizzle::derivePrecision() const
   1710 {
   1711    return mOperand->getPrecision();
   1712 }
   1713 
   1714 void TIntermSwizzle::propagatePrecision(TPrecision precision)
   1715 {
   1716    mType.setPrecision(precision);
   1717 
   1718    PropagatePrecisionIfApplicable(mOperand, precision);
   1719 }
   1720 
   1721 bool TIntermSwizzle::hasDuplicateOffsets() const
   1722 {
   1723    if (mHasFoldedDuplicateOffsets)
   1724    {
   1725        return true;
   1726    }
   1727    int offsetCount[4] = {0u, 0u, 0u, 0u};
   1728    for (const auto offset : mSwizzleOffsets)
   1729    {
   1730        offsetCount[offset]++;
   1731        if (offsetCount[offset] > 1)
   1732        {
   1733            return true;
   1734        }
   1735    }
   1736    return false;
   1737 }
   1738 
   1739 void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
   1740 {
   1741    mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
   1742 }
   1743 
   1744 bool TIntermSwizzle::offsetsMatch(int offset) const
   1745 {
   1746    return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
   1747 }
   1748 
   1749 void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
   1750 {
   1751    for (const int offset : mSwizzleOffsets)
   1752    {
   1753        switch (offset)
   1754        {
   1755            case 0:
   1756                *out << "x";
   1757                break;
   1758            case 1:
   1759                *out << "y";
   1760                break;
   1761            case 2:
   1762                *out << "z";
   1763                break;
   1764            case 3:
   1765                *out << "w";
   1766                break;
   1767            default:
   1768                UNREACHABLE();
   1769        }
   1770    }
   1771 }
   1772 
   1773 TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
   1774                                            const TIntermTyped *left,
   1775                                            const TIntermTyped *right)
   1776 {
   1777    // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
   1778    if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
   1779        right->getQualifier() != EvqConst)
   1780    {
   1781        return EvqTemporary;
   1782    }
   1783    return EvqConst;
   1784 }
   1785 
   1786 // Establishes the type of the result of the binary operation.
   1787 void TIntermBinary::promote()
   1788 {
   1789    ASSERT(!isMultiplication() ||
   1790           mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
   1791 
   1792    // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
   1793    // version and so is not being set here.
   1794    if (mOp == EOpComma)
   1795    {
   1796        setType(mRight->getType());
   1797        return;
   1798    }
   1799 
   1800    // Base assumption:  just make the type the same as the left
   1801    // operand.  Then only deviations from this need be coded.
   1802    setType(mLeft->getType());
   1803 
   1804    TQualifier resultQualifier = EvqConst;
   1805    // Binary operations results in temporary variables unless both
   1806    // operands are const.  If initializing a specialization constant, make the declarator also
   1807    // EvqSpecConst.
   1808    const bool isSpecConstInit = mOp == EOpInitialize && mLeft->getQualifier() == EvqSpecConst;
   1809    const bool isEitherNonConst =
   1810        mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst;
   1811    if (!isSpecConstInit && isEitherNonConst)
   1812    {
   1813        resultQualifier = EvqTemporary;
   1814        getTypePointer()->setQualifier(EvqTemporary);
   1815    }
   1816 
   1817    // Result is an intermediate value, so make sure it's identified as such.  That's not true for
   1818    // interface block arrays being indexed.
   1819    if (mOp != EOpIndexDirect && mOp != EOpIndexIndirect)
   1820    {
   1821        getTypePointer()->setInterfaceBlock(nullptr);
   1822    }
   1823 
   1824    // Handle indexing ops.
   1825    switch (mOp)
   1826    {
   1827        case EOpIndexDirect:
   1828        case EOpIndexIndirect:
   1829            if (mLeft->isArray())
   1830            {
   1831                mType.toArrayElementType();
   1832            }
   1833            else if (mLeft->isMatrix())
   1834            {
   1835                mType.toMatrixColumnType();
   1836            }
   1837            else if (mLeft->isVector())
   1838            {
   1839                mType.toComponentType();
   1840            }
   1841            else
   1842            {
   1843                UNREACHABLE();
   1844            }
   1845            return;
   1846        case EOpIndexDirectStruct:
   1847        {
   1848            const TFieldList &fields = mLeft->getType().getStruct()->fields();
   1849            const int fieldIndex     = mRight->getAsConstantUnion()->getIConst(0);
   1850            setType(*fields[fieldIndex]->type());
   1851            getTypePointer()->setQualifier(resultQualifier);
   1852            return;
   1853        }
   1854        case EOpIndexDirectInterfaceBlock:
   1855        {
   1856            const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
   1857            const int fieldIndex     = mRight->getAsConstantUnion()->getIConst(0);
   1858            setType(*fields[fieldIndex]->type());
   1859            getTypePointer()->setQualifier(resultQualifier);
   1860            return;
   1861        }
   1862        default:
   1863            break;
   1864    }
   1865 
   1866    ASSERT(mLeft->isArray() == mRight->isArray());
   1867 
   1868    const uint8_t nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
   1869 
   1870    switch (mOp)
   1871    {
   1872        case EOpMul:
   1873            break;
   1874        case EOpMatrixTimesScalar:
   1875            if (mRight->isMatrix())
   1876            {
   1877                getTypePointer()->setPrimarySize(mRight->getCols());
   1878                getTypePointer()->setSecondarySize(mRight->getRows());
   1879            }
   1880            break;
   1881        case EOpMatrixTimesVector:
   1882            getTypePointer()->setPrimarySize(mLeft->getRows());
   1883            getTypePointer()->setSecondarySize(1);
   1884            break;
   1885        case EOpMatrixTimesMatrix:
   1886            getTypePointer()->setPrimarySize(mRight->getCols());
   1887            getTypePointer()->setSecondarySize(mLeft->getRows());
   1888            break;
   1889        case EOpVectorTimesScalar:
   1890            getTypePointer()->setPrimarySize(nominalSize);
   1891            break;
   1892        case EOpVectorTimesMatrix:
   1893            getTypePointer()->setPrimarySize(mRight->getCols());
   1894            ASSERT(getType().getSecondarySize() == 1);
   1895            break;
   1896        case EOpMulAssign:
   1897        case EOpVectorTimesScalarAssign:
   1898        case EOpVectorTimesMatrixAssign:
   1899        case EOpMatrixTimesScalarAssign:
   1900        case EOpMatrixTimesMatrixAssign:
   1901            ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
   1902            break;
   1903        case EOpAssign:
   1904        case EOpInitialize:
   1905            ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
   1906                   (mLeft->getSecondarySize() == mRight->getSecondarySize()));
   1907            break;
   1908        case EOpAdd:
   1909        case EOpSub:
   1910        case EOpDiv:
   1911        case EOpIMod:
   1912        case EOpBitShiftLeft:
   1913        case EOpBitShiftRight:
   1914        case EOpBitwiseAnd:
   1915        case EOpBitwiseXor:
   1916        case EOpBitwiseOr:
   1917        case EOpAddAssign:
   1918        case EOpSubAssign:
   1919        case EOpDivAssign:
   1920        case EOpIModAssign:
   1921        case EOpBitShiftLeftAssign:
   1922        case EOpBitShiftRightAssign:
   1923        case EOpBitwiseAndAssign:
   1924        case EOpBitwiseXorAssign:
   1925        case EOpBitwiseOrAssign:
   1926        {
   1927            ASSERT(!mLeft->isArray() && !mRight->isArray());
   1928            const uint8_t secondarySize =
   1929                std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
   1930            getTypePointer()->setPrimarySize(nominalSize);
   1931            getTypePointer()->setSecondarySize(secondarySize);
   1932            break;
   1933        }
   1934        case EOpEqual:
   1935        case EOpNotEqual:
   1936        case EOpLessThan:
   1937        case EOpGreaterThan:
   1938        case EOpLessThanEqual:
   1939        case EOpGreaterThanEqual:
   1940            ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
   1941                   (mLeft->getSecondarySize() == mRight->getSecondarySize()));
   1942            setType(TType(EbtBool, EbpUndefined, resultQualifier));
   1943            break;
   1944 
   1945        //
   1946        // And and Or operate on conditionals
   1947        //
   1948        case EOpLogicalAnd:
   1949        case EOpLogicalXor:
   1950        case EOpLogicalOr:
   1951            ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
   1952            break;
   1953 
   1954        case EOpIndexDirect:
   1955        case EOpIndexIndirect:
   1956        case EOpIndexDirectInterfaceBlock:
   1957        case EOpIndexDirectStruct:
   1958            // These ops should be already fully handled.
   1959            UNREACHABLE();
   1960            break;
   1961        default:
   1962            UNREACHABLE();
   1963            break;
   1964    }
   1965 
   1966    propagatePrecision(derivePrecision());
   1967 }
   1968 
   1969 // Derive precision from children nodes
   1970 TPrecision TIntermBinary::derivePrecision() const
   1971 {
   1972    // Assignments use the type and precision of the lvalue-expression
   1973    // GLSL ES spec section 5.8: Assignments
   1974    // "The assignment operator stores the value of rvalue-expression into the l-value and returns
   1975    // an r-value with the type and precision of lvalue-expression."
   1976    if (IsAssignment(mOp))
   1977    {
   1978        return mLeft->getPrecision();
   1979    }
   1980 
   1981    const TPrecision higherPrecision =
   1982        GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
   1983 
   1984    switch (mOp)
   1985    {
   1986        case EOpComma:
   1987            // Comma takes the right node's value.
   1988            return mRight->getPrecision();
   1989 
   1990        case EOpIndexDirect:
   1991        case EOpIndexIndirect:
   1992        case EOpBitShiftLeft:
   1993        case EOpBitShiftRight:
   1994            // When indexing an array, the precision of the array is preserved (which is the left
   1995            // node).
   1996            // For shift operations, the precision is derived from the expression being shifted
   1997            // (which is also the left node).
   1998            return mLeft->getPrecision();
   1999 
   2000        case EOpIndexDirectStruct:
   2001        case EOpIndexDirectInterfaceBlock:
   2002        {
   2003            // When selecting the field of a block, the precision is taken from the field's
   2004            // declaration.
   2005            const TFieldList &fields = mOp == EOpIndexDirectStruct
   2006                                           ? mLeft->getType().getStruct()->fields()
   2007                                           : mLeft->getType().getInterfaceBlock()->fields();
   2008            const int fieldIndex     = mRight->getAsConstantUnion()->getIConst(0);
   2009            return fields[fieldIndex]->type()->getPrecision();
   2010        }
   2011 
   2012        case EOpEqual:
   2013        case EOpNotEqual:
   2014        case EOpLessThan:
   2015        case EOpGreaterThan:
   2016        case EOpLessThanEqual:
   2017        case EOpGreaterThanEqual:
   2018        case EOpLogicalAnd:
   2019        case EOpLogicalXor:
   2020        case EOpLogicalOr:
   2021            // No precision specified on bool results.
   2022            return EbpUndefined;
   2023 
   2024        default:
   2025            // All other operations are evaluated at the higher of the two operands' precisions.
   2026            return higherPrecision;
   2027    }
   2028 }
   2029 
   2030 void TIntermBinary::propagatePrecision(TPrecision precision)
   2031 {
   2032    getTypePointer()->setPrecision(precision);
   2033 
   2034    if (mOp != EOpComma)
   2035    {
   2036        PropagatePrecisionIfApplicable(mLeft, precision);
   2037    }
   2038 
   2039    if (mOp != EOpIndexDirect && mOp != EOpIndexIndirect && mOp != EOpIndexDirectStruct &&
   2040        mOp != EOpIndexDirectInterfaceBlock)
   2041    {
   2042        PropagatePrecisionIfApplicable(mRight, precision);
   2043    }
   2044 
   2045    // For indices, always apply highp.  This is purely for the purpose of making sure constant and
   2046    // constructor nodes are also given a precision, so if they are hoisted to a temp variable,
   2047    // there would be a precision to apply to that variable.
   2048    if (mOp == EOpIndexDirect || mOp == EOpIndexIndirect)
   2049    {
   2050        PropagatePrecisionIfApplicable(mRight, EbpHigh);
   2051    }
   2052 }
   2053 
   2054 bool TIntermConstantUnion::hasConstantValue() const
   2055 {
   2056    return true;
   2057 }
   2058 
   2059 bool TIntermConstantUnion::isConstantNullValue() const
   2060 {
   2061    const size_t size = mType.getObjectSize();
   2062    for (size_t index = 0; index < size; ++index)
   2063    {
   2064        if (!mUnionArrayPointer[index].isZero())
   2065        {
   2066            return false;
   2067        }
   2068    }
   2069    return true;
   2070 }
   2071 
   2072 const TConstantUnion *TIntermConstantUnion::getConstantValue() const
   2073 {
   2074    return mUnionArrayPointer;
   2075 }
   2076 
   2077 const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
   2078                                                         const TConstantUnion *constArray,
   2079                                                         int index)
   2080 {
   2081    if (type.isArray())
   2082    {
   2083        ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
   2084        TType arrayElementType(type);
   2085        arrayElementType.toArrayElementType();
   2086        size_t arrayElementSize = arrayElementType.getObjectSize();
   2087        return &constArray[arrayElementSize * index];
   2088    }
   2089    else if (type.isMatrix())
   2090    {
   2091        ASSERT(index < type.getCols());
   2092        const uint8_t size = type.getRows();
   2093        return &constArray[size * index];
   2094    }
   2095    else if (type.isVector())
   2096    {
   2097        ASSERT(index < type.getNominalSize());
   2098        return &constArray[index];
   2099    }
   2100    else
   2101    {
   2102        UNREACHABLE();
   2103        return nullptr;
   2104    }
   2105 }
   2106 
   2107 TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
   2108 {
   2109    TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
   2110    if (operandSwizzle)
   2111    {
   2112        // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
   2113        // overflow in ParseContext::checkCanBeLValue().
   2114        bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
   2115        TVector<int> foldedOffsets;
   2116        for (int offset : mSwizzleOffsets)
   2117        {
   2118            // Offset should already be validated.
   2119            ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
   2120            foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
   2121        }
   2122        operandSwizzle->mSwizzleOffsets = foldedOffsets;
   2123        operandSwizzle->setType(getType());
   2124        operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
   2125        return operandSwizzle;
   2126    }
   2127    TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
   2128    if (operandConstant == nullptr)
   2129    {
   2130        return this;
   2131    }
   2132 
   2133    TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
   2134    for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
   2135    {
   2136        constArray[i] = *TIntermConstantUnion::FoldIndexing(
   2137            operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
   2138    }
   2139    return CreateFoldedNode(constArray, this);
   2140 }
   2141 
   2142 TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
   2143 {
   2144    const TConstantUnion *rightConstant = mRight->getConstantValue();
   2145    switch (mOp)
   2146    {
   2147        case EOpComma:
   2148        {
   2149            if (mLeft->hasSideEffects())
   2150            {
   2151                return this;
   2152            }
   2153            return mRight;
   2154        }
   2155        case EOpIndexDirect:
   2156        case EOpIndexDirectStruct:
   2157        {
   2158            if (rightConstant == nullptr)
   2159            {
   2160                return this;
   2161            }
   2162            size_t index                    = static_cast<size_t>(rightConstant->getIConst());
   2163            TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
   2164            if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
   2165                !leftAggregate->hasSideEffects())
   2166            {
   2167                ASSERT(index < leftAggregate->getSequence()->size());
   2168                // This transformation can't add complexity as we're eliminating the constructor
   2169                // entirely.
   2170                return leftAggregate->getSequence()->at(index)->getAsTyped();
   2171            }
   2172 
   2173            // If the indexed value is already a constant union, we can't increase duplication of
   2174            // data by folding the indexing. Also fold the node in case it's generally beneficial to
   2175            // replace this type of node with a constant union even if that would mean duplicating
   2176            // data.
   2177            if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
   2178            {
   2179                const TConstantUnion *constantValue = getConstantValue();
   2180                if (constantValue == nullptr)
   2181                {
   2182                    return this;
   2183                }
   2184                return CreateFoldedNode(constantValue, this);
   2185            }
   2186            return this;
   2187        }
   2188        case EOpIndexIndirect:
   2189        case EOpIndexDirectInterfaceBlock:
   2190        case EOpInitialize:
   2191            // Can never be constant folded.
   2192            return this;
   2193        default:
   2194        {
   2195            if (rightConstant == nullptr)
   2196            {
   2197                return this;
   2198            }
   2199            const TConstantUnion *leftConstant = mLeft->getConstantValue();
   2200            if (leftConstant == nullptr)
   2201            {
   2202                return this;
   2203            }
   2204            const TConstantUnion *constArray =
   2205                TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
   2206                                                 mRight->getType(), diagnostics, mLeft->getLine());
   2207            if (!constArray)
   2208            {
   2209                return this;
   2210            }
   2211            return CreateFoldedNode(constArray, this);
   2212        }
   2213    }
   2214 }
   2215 
   2216 bool TIntermBinary::hasConstantValue() const
   2217 {
   2218    switch (mOp)
   2219    {
   2220        case EOpIndexDirect:
   2221        case EOpIndexDirectStruct:
   2222        {
   2223            if (mLeft->hasConstantValue() && mRight->hasConstantValue())
   2224            {
   2225                return true;
   2226            }
   2227            break;
   2228        }
   2229        default:
   2230            break;
   2231    }
   2232    return false;
   2233 }
   2234 
   2235 const TConstantUnion *TIntermBinary::getConstantValue() const
   2236 {
   2237    if (!hasConstantValue())
   2238    {
   2239        return nullptr;
   2240    }
   2241 
   2242    const TConstantUnion *leftConstantValue   = mLeft->getConstantValue();
   2243    int index                                 = mRight->getConstantValue()->getIConst();
   2244    const TConstantUnion *constIndexingResult = nullptr;
   2245    if (mOp == EOpIndexDirect)
   2246    {
   2247        constIndexingResult =
   2248            TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
   2249    }
   2250    else
   2251    {
   2252        ASSERT(mOp == EOpIndexDirectStruct);
   2253        const TFieldList &fields = mLeft->getType().getStruct()->fields();
   2254 
   2255        size_t previousFieldsSize = 0;
   2256        for (int i = 0; i < index; ++i)
   2257        {
   2258            previousFieldsSize += fields[i]->type()->getObjectSize();
   2259        }
   2260        constIndexingResult = leftConstantValue + previousFieldsSize;
   2261    }
   2262    return constIndexingResult;
   2263 }
   2264 
   2265 const ImmutableString &TIntermBinary::getIndexStructFieldName() const
   2266 {
   2267    ASSERT(mOp == EOpIndexDirectStruct);
   2268 
   2269    const TType &lhsType        = mLeft->getType();
   2270    const TStructure *structure = lhsType.getStruct();
   2271    const int index             = mRight->getAsConstantUnion()->getIConst(0);
   2272 
   2273    return structure->fields()[index]->name();
   2274 }
   2275 
   2276 TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
   2277 {
   2278    TConstantUnion *constArray = nullptr;
   2279 
   2280    if (mOp == EOpArrayLength)
   2281    {
   2282        // The size of runtime-sized arrays may only be determined at runtime.
   2283        if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
   2284        {
   2285            return this;
   2286        }
   2287        constArray = new TConstantUnion[1];
   2288        constArray->setIConst(mOperand->getOutermostArraySize());
   2289    }
   2290    else
   2291    {
   2292        TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
   2293        if (operandConstant == nullptr)
   2294        {
   2295            return this;
   2296        }
   2297 
   2298        switch (mOp)
   2299        {
   2300            case EOpAny:
   2301            case EOpAll:
   2302            case EOpLength:
   2303            case EOpTranspose:
   2304            case EOpDeterminant:
   2305            case EOpInverse:
   2306            case EOpPackSnorm2x16:
   2307            case EOpUnpackSnorm2x16:
   2308            case EOpPackUnorm2x16:
   2309            case EOpUnpackUnorm2x16:
   2310            case EOpPackHalf2x16:
   2311            case EOpUnpackHalf2x16:
   2312            case EOpPackUnorm4x8:
   2313            case EOpPackSnorm4x8:
   2314            case EOpUnpackUnorm4x8:
   2315            case EOpUnpackSnorm4x8:
   2316                constArray = operandConstant->foldUnaryNonComponentWise(mOp);
   2317                break;
   2318            default:
   2319                constArray = operandConstant->foldUnaryComponentWise(mOp, mFunction, diagnostics);
   2320                break;
   2321        }
   2322    }
   2323    if (constArray == nullptr)
   2324    {
   2325        return this;
   2326    }
   2327    return CreateFoldedNode(constArray, this);
   2328 }
   2329 
   2330 TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
   2331 {
   2332    // Make sure that all params are constant before actual constant folding.
   2333    for (auto *param : *getSequence())
   2334    {
   2335        if (param->getAsConstantUnion() == nullptr)
   2336        {
   2337            return this;
   2338        }
   2339    }
   2340    const TConstantUnion *constArray = nullptr;
   2341    if (isConstructor())
   2342    {
   2343        if (mType.canReplaceWithConstantUnion())
   2344        {
   2345            constArray = getConstantValue();
   2346            if (constArray && mType.getBasicType() == EbtUInt)
   2347            {
   2348                // Check if we converted a negative float to uint and issue a warning in that case.
   2349                size_t sizeRemaining = mType.getObjectSize();
   2350                for (TIntermNode *arg : mArguments)
   2351                {
   2352                    TIntermTyped *typedArg = arg->getAsTyped();
   2353                    if (typedArg->getBasicType() == EbtFloat)
   2354                    {
   2355                        const TConstantUnion *argValue = typedArg->getConstantValue();
   2356                        size_t castSize =
   2357                            std::min(typedArg->getType().getObjectSize(), sizeRemaining);
   2358                        for (size_t i = 0; i < castSize; ++i)
   2359                        {
   2360                            if (argValue[i].getFConst() < 0.0f)
   2361                            {
   2362                                // ESSL 3.00.6 section 5.4.1.
   2363                                diagnostics->warning(
   2364                                    mLine, "casting a negative float to uint is undefined",
   2365                                    mType.getBuiltInTypeNameString());
   2366                            }
   2367                        }
   2368                    }
   2369                    sizeRemaining -= typedArg->getType().getObjectSize();
   2370                }
   2371            }
   2372        }
   2373    }
   2374    else if (CanFoldAggregateBuiltInOp(mOp))
   2375    {
   2376        constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
   2377    }
   2378    if (constArray == nullptr)
   2379    {
   2380        return this;
   2381    }
   2382    return CreateFoldedNode(constArray, this);
   2383 }
   2384 
   2385 //
   2386 // The fold functions see if an operation on a constant can be done in place,
   2387 // without generating run-time code.
   2388 //
   2389 // Returns the constant value to keep using or nullptr.
   2390 //
   2391 const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
   2392                                                       const TConstantUnion *leftArray,
   2393                                                       const TType &leftType,
   2394                                                       const TConstantUnion *rightArray,
   2395                                                       const TType &rightType,
   2396                                                       TDiagnostics *diagnostics,
   2397                                                       const TSourceLoc &line)
   2398 {
   2399    ASSERT(leftArray && rightArray);
   2400 
   2401    size_t objectSize = leftType.getObjectSize();
   2402 
   2403    // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
   2404    if (rightType.getObjectSize() == 1 && objectSize > 1)
   2405    {
   2406        rightArray = Vectorize(*rightArray, objectSize);
   2407    }
   2408    else if (rightType.getObjectSize() > 1 && objectSize == 1)
   2409    {
   2410        // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
   2411        leftArray  = Vectorize(*leftArray, rightType.getObjectSize());
   2412        objectSize = rightType.getObjectSize();
   2413    }
   2414 
   2415    TConstantUnion *resultArray = nullptr;
   2416 
   2417    switch (op)
   2418    {
   2419        case EOpAdd:
   2420            resultArray = new TConstantUnion[objectSize];
   2421            for (size_t i = 0; i < objectSize; i++)
   2422                resultArray[i] =
   2423                    TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
   2424            break;
   2425        case EOpSub:
   2426            resultArray = new TConstantUnion[objectSize];
   2427            for (size_t i = 0; i < objectSize; i++)
   2428                resultArray[i] =
   2429                    TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
   2430            break;
   2431 
   2432        case EOpMul:
   2433        case EOpVectorTimesScalar:
   2434        case EOpMatrixTimesScalar:
   2435            resultArray = new TConstantUnion[objectSize];
   2436            for (size_t i = 0; i < objectSize; i++)
   2437                resultArray[i] =
   2438                    TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
   2439            break;
   2440 
   2441        case EOpMatrixTimesMatrix:
   2442        {
   2443            // TODO(jmadll): This code should check for overflows.
   2444            ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
   2445 
   2446            const uint8_t leftCols   = leftType.getCols();
   2447            const uint8_t leftRows   = leftType.getRows();
   2448            const uint8_t rightCols  = rightType.getCols();
   2449            const uint8_t rightRows  = rightType.getRows();
   2450            const uint8_t resultCols = rightCols;
   2451            const uint8_t resultRows = leftRows;
   2452 
   2453            resultArray = new TConstantUnion[resultCols * resultRows];
   2454            for (uint8_t row = 0; row < resultRows; row++)
   2455            {
   2456                for (uint8_t column = 0; column < resultCols; column++)
   2457                {
   2458                    resultArray[resultRows * column + row].setFConst(0.0f);
   2459                    for (uint8_t i = 0; i < leftCols; i++)
   2460                    {
   2461                        resultArray[resultRows * column + row].setFConst(
   2462                            resultArray[resultRows * column + row].getFConst() +
   2463                            leftArray[i * leftRows + row].getFConst() *
   2464                                rightArray[column * rightRows + i].getFConst());
   2465                    }
   2466                }
   2467            }
   2468        }
   2469        break;
   2470 
   2471        case EOpDiv:
   2472        case EOpIMod:
   2473        {
   2474            resultArray = new TConstantUnion[objectSize];
   2475            for (size_t i = 0; i < objectSize; i++)
   2476            {
   2477                if (IsFloatDivision(leftType.getBasicType(), rightType.getBasicType()))
   2478                {
   2479                    // Float division requested, possibly with implicit conversion
   2480                    ASSERT(op == EOpDiv);
   2481                    float dividend = leftArray[i].getFConst();
   2482                    float divisor  = rightArray[i].getFConst();
   2483 
   2484                    if (divisor == 0.0f)
   2485                    {
   2486                        if (dividend == 0.0f)
   2487                        {
   2488                            diagnostics->warning(line,
   2489                                                 "Zero divided by zero during constant "
   2490                                                 "folding generated NaN",
   2491                                                 "/");
   2492                            resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
   2493                        }
   2494                        else
   2495                        {
   2496                            diagnostics->warning(line, "Divide by zero during constant folding",
   2497                                                 "/");
   2498                            bool negativeResult = std::signbit(dividend) != std::signbit(divisor);
   2499                            resultArray[i].setFConst(negativeResult
   2500                                                         ? -std::numeric_limits<float>::infinity()
   2501                                                         : std::numeric_limits<float>::infinity());
   2502                        }
   2503                    }
   2504                    else if (gl::isInf(dividend) && gl::isInf(divisor))
   2505                    {
   2506                        diagnostics->warning(line,
   2507                                             "Infinity divided by infinity during constant "
   2508                                             "folding generated NaN",
   2509                                             "/");
   2510                        resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
   2511                    }
   2512                    else
   2513                    {
   2514                        float result = dividend / divisor;
   2515                        if (!gl::isInf(dividend) && gl::isInf(result))
   2516                        {
   2517                            diagnostics->warning(
   2518                                line, "Constant folded division overflowed to infinity", "/");
   2519                        }
   2520                        resultArray[i].setFConst(result);
   2521                    }
   2522                }
   2523                else
   2524                {
   2525                    // Types are either both int or both uint
   2526                    switch (leftType.getBasicType())
   2527                    {
   2528                        case EbtInt:
   2529                        {
   2530                            if (rightArray[i] == 0)
   2531                            {
   2532                                diagnostics->warning(
   2533                                    line, "Divide by zero error during constant folding", "/");
   2534                                resultArray[i].setIConst(INT_MAX);
   2535                            }
   2536                            else
   2537                            {
   2538                                int lhs     = leftArray[i].getIConst();
   2539                                int divisor = rightArray[i].getIConst();
   2540                                if (op == EOpDiv)
   2541                                {
   2542                                    // Check for the special case where the minimum
   2543                                    // representable number is divided by -1. If left alone this
   2544                                    // leads to integer overflow in C++. ESSL 3.00.6
   2545                                    // section 4.1.3 Integers: "However, for the case where the
   2546                                    // minimum representable value is divided by -1, it is
   2547                                    // allowed to return either the minimum representable value
   2548                                    // or the maximum representable value."
   2549                                    if (lhs == -0x7fffffff - 1 && divisor == -1)
   2550                                    {
   2551                                        resultArray[i].setIConst(0x7fffffff);
   2552                                    }
   2553                                    else
   2554                                    {
   2555                                        resultArray[i].setIConst(lhs / divisor);
   2556                                    }
   2557                                }
   2558                                else
   2559                                {
   2560                                    ASSERT(op == EOpIMod);
   2561                                    if (lhs < 0 || divisor < 0)
   2562                                    {
   2563                                        // ESSL 3.00.6 section 5.9: Results of modulus are
   2564                                        // undefined when either one of the operands is
   2565                                        // negative.
   2566                                        diagnostics->warning(line,
   2567                                                             "Negative modulus operator operand "
   2568                                                             "encountered during constant folding. "
   2569                                                             "Results are undefined.",
   2570                                                             "%");
   2571                                        resultArray[i].setIConst(0);
   2572                                    }
   2573                                    else
   2574                                    {
   2575                                        resultArray[i].setIConst(lhs % divisor);
   2576                                    }
   2577                                }
   2578                            }
   2579                            break;
   2580                        }
   2581                        case EbtUInt:
   2582                        {
   2583                            if (rightArray[i] == 0)
   2584                            {
   2585                                diagnostics->warning(
   2586                                    line, "Divide by zero error during constant folding", "/");
   2587                                resultArray[i].setUConst(UINT_MAX);
   2588                            }
   2589                            else
   2590                            {
   2591                                if (op == EOpDiv)
   2592                                {
   2593                                    resultArray[i].setUConst(leftArray[i].getUConst() /
   2594                                                             rightArray[i].getUConst());
   2595                                }
   2596                                else
   2597                                {
   2598                                    ASSERT(op == EOpIMod);
   2599                                    resultArray[i].setUConst(leftArray[i].getUConst() %
   2600                                                             rightArray[i].getUConst());
   2601                                }
   2602                            }
   2603                            break;
   2604                        }
   2605                        default:
   2606                            UNREACHABLE();
   2607                            return nullptr;
   2608                    }
   2609                }
   2610            }
   2611        }
   2612        break;
   2613 
   2614        case EOpMatrixTimesVector:
   2615        {
   2616            // TODO(jmadll): This code should check for overflows.
   2617            ASSERT(rightType.getBasicType() == EbtFloat);
   2618 
   2619            const uint8_t matrixCols = leftType.getCols();
   2620            const uint8_t matrixRows = leftType.getRows();
   2621 
   2622            resultArray = new TConstantUnion[matrixRows];
   2623 
   2624            for (uint8_t matrixRow = 0; matrixRow < matrixRows; matrixRow++)
   2625            {
   2626                resultArray[matrixRow].setFConst(0.0f);
   2627                for (uint8_t col = 0; col < matrixCols; col++)
   2628                {
   2629                    resultArray[matrixRow].setFConst(
   2630                        resultArray[matrixRow].getFConst() +
   2631                        leftArray[col * matrixRows + matrixRow].getFConst() *
   2632                            rightArray[col].getFConst());
   2633                }
   2634            }
   2635        }
   2636        break;
   2637 
   2638        case EOpVectorTimesMatrix:
   2639        {
   2640            // TODO(jmadll): This code should check for overflows.
   2641            ASSERT(leftType.getBasicType() == EbtFloat);
   2642 
   2643            const uint8_t matrixCols = rightType.getCols();
   2644            const uint8_t matrixRows = rightType.getRows();
   2645 
   2646            resultArray = new TConstantUnion[matrixCols];
   2647 
   2648            for (uint8_t matrixCol = 0; matrixCol < matrixCols; matrixCol++)
   2649            {
   2650                resultArray[matrixCol].setFConst(0.0f);
   2651                for (uint8_t matrixRow = 0; matrixRow < matrixRows; matrixRow++)
   2652                {
   2653                    resultArray[matrixCol].setFConst(
   2654                        resultArray[matrixCol].getFConst() +
   2655                        leftArray[matrixRow].getFConst() *
   2656                            rightArray[matrixCol * matrixRows + matrixRow].getFConst());
   2657                }
   2658            }
   2659        }
   2660        break;
   2661 
   2662        case EOpLogicalAnd:
   2663        {
   2664            resultArray = new TConstantUnion[objectSize];
   2665            for (size_t i = 0; i < objectSize; i++)
   2666            {
   2667                resultArray[i] = leftArray[i] && rightArray[i];
   2668            }
   2669        }
   2670        break;
   2671 
   2672        case EOpLogicalOr:
   2673        {
   2674            resultArray = new TConstantUnion[objectSize];
   2675            for (size_t i = 0; i < objectSize; i++)
   2676            {
   2677                resultArray[i] = leftArray[i] || rightArray[i];
   2678            }
   2679        }
   2680        break;
   2681 
   2682        case EOpLogicalXor:
   2683        {
   2684            ASSERT(leftType.getBasicType() == EbtBool);
   2685            resultArray = new TConstantUnion[objectSize];
   2686            for (size_t i = 0; i < objectSize; i++)
   2687            {
   2688                resultArray[i].setBConst(leftArray[i] != rightArray[i]);
   2689            }
   2690        }
   2691        break;
   2692 
   2693        case EOpBitwiseAnd:
   2694            resultArray = new TConstantUnion[objectSize];
   2695            for (size_t i = 0; i < objectSize; i++)
   2696                resultArray[i] = leftArray[i] & rightArray[i];
   2697            break;
   2698        case EOpBitwiseXor:
   2699            resultArray = new TConstantUnion[objectSize];
   2700            for (size_t i = 0; i < objectSize; i++)
   2701                resultArray[i] = leftArray[i] ^ rightArray[i];
   2702            break;
   2703        case EOpBitwiseOr:
   2704            resultArray = new TConstantUnion[objectSize];
   2705            for (size_t i = 0; i < objectSize; i++)
   2706                resultArray[i] = leftArray[i] | rightArray[i];
   2707            break;
   2708        case EOpBitShiftLeft:
   2709            resultArray = new TConstantUnion[objectSize];
   2710            for (size_t i = 0; i < objectSize; i++)
   2711                resultArray[i] =
   2712                    TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
   2713            break;
   2714        case EOpBitShiftRight:
   2715            resultArray = new TConstantUnion[objectSize];
   2716            for (size_t i = 0; i < objectSize; i++)
   2717                resultArray[i] =
   2718                    TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
   2719            break;
   2720 
   2721        case EOpLessThan:
   2722            ASSERT(objectSize == 1);
   2723            resultArray = new TConstantUnion[1];
   2724            resultArray->setBConst(*leftArray < *rightArray);
   2725            break;
   2726 
   2727        case EOpGreaterThan:
   2728            ASSERT(objectSize == 1);
   2729            resultArray = new TConstantUnion[1];
   2730            resultArray->setBConst(*leftArray > *rightArray);
   2731            break;
   2732 
   2733        case EOpLessThanEqual:
   2734            ASSERT(objectSize == 1);
   2735            resultArray = new TConstantUnion[1];
   2736            resultArray->setBConst(!(*leftArray > *rightArray));
   2737            break;
   2738 
   2739        case EOpGreaterThanEqual:
   2740            ASSERT(objectSize == 1);
   2741            resultArray = new TConstantUnion[1];
   2742            resultArray->setBConst(!(*leftArray < *rightArray));
   2743            break;
   2744 
   2745        case EOpEqual:
   2746        case EOpNotEqual:
   2747        {
   2748            resultArray = new TConstantUnion[1];
   2749            bool equal  = true;
   2750            for (size_t i = 0; i < objectSize; i++)
   2751            {
   2752                if (leftArray[i] != rightArray[i])
   2753                {
   2754                    equal = false;
   2755                    break;  // break out of for loop
   2756                }
   2757            }
   2758            if (op == EOpEqual)
   2759            {
   2760                resultArray->setBConst(equal);
   2761            }
   2762            else
   2763            {
   2764                resultArray->setBConst(!equal);
   2765            }
   2766        }
   2767        break;
   2768 
   2769        default:
   2770            UNREACHABLE();
   2771            return nullptr;
   2772    }
   2773    return resultArray;
   2774 }
   2775 
   2776 // The fold functions do operations on a constant at GLSL compile time, without generating run-time
   2777 // code. Returns the constant value to keep using. Nullptr should not be returned.
   2778 TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
   2779 {
   2780    // Do operations where the return type may have a different number of components compared to the
   2781    // operand type.
   2782 
   2783    const TConstantUnion *operandArray = getConstantValue();
   2784    ASSERT(operandArray);
   2785 
   2786    size_t objectSize           = getType().getObjectSize();
   2787    TConstantUnion *resultArray = nullptr;
   2788    switch (op)
   2789    {
   2790        case EOpAny:
   2791            ASSERT(getType().getBasicType() == EbtBool);
   2792            resultArray = new TConstantUnion();
   2793            resultArray->setBConst(false);
   2794            for (size_t i = 0; i < objectSize; i++)
   2795            {
   2796                if (operandArray[i].getBConst())
   2797                {
   2798                    resultArray->setBConst(true);
   2799                    break;
   2800                }
   2801            }
   2802            break;
   2803 
   2804        case EOpAll:
   2805            ASSERT(getType().getBasicType() == EbtBool);
   2806            resultArray = new TConstantUnion();
   2807            resultArray->setBConst(true);
   2808            for (size_t i = 0; i < objectSize; i++)
   2809            {
   2810                if (!operandArray[i].getBConst())
   2811                {
   2812                    resultArray->setBConst(false);
   2813                    break;
   2814                }
   2815            }
   2816            break;
   2817 
   2818        case EOpLength:
   2819            ASSERT(getType().getBasicType() == EbtFloat);
   2820            resultArray = new TConstantUnion();
   2821            resultArray->setFConst(VectorLength(operandArray, objectSize));
   2822            break;
   2823 
   2824        case EOpTranspose:
   2825        {
   2826            ASSERT(getType().getBasicType() == EbtFloat);
   2827            resultArray = new TConstantUnion[objectSize];
   2828            angle::Matrix<float> result =
   2829                GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
   2830            SetUnionArrayFromMatrix(result, resultArray);
   2831            break;
   2832        }
   2833 
   2834        case EOpDeterminant:
   2835        {
   2836            ASSERT(getType().getBasicType() == EbtFloat);
   2837            const uint8_t size = getType().getNominalSize();
   2838            ASSERT(size >= 2 && size <= 4);
   2839            resultArray = new TConstantUnion();
   2840            resultArray->setFConst(GetMatrix(operandArray, size).determinant());
   2841            break;
   2842        }
   2843 
   2844        case EOpInverse:
   2845        {
   2846            ASSERT(getType().getBasicType() == EbtFloat);
   2847            const uint8_t size = getType().getNominalSize();
   2848            ASSERT(size >= 2 && size <= 4);
   2849            resultArray                 = new TConstantUnion[objectSize];
   2850            angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
   2851            SetUnionArrayFromMatrix(result, resultArray);
   2852            break;
   2853        }
   2854 
   2855        case EOpPackSnorm2x16:
   2856            ASSERT(getType().getBasicType() == EbtFloat);
   2857            ASSERT(getType().getNominalSize() == 2);
   2858            resultArray = new TConstantUnion();
   2859            resultArray->setUConst(
   2860                gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
   2861            break;
   2862 
   2863        case EOpUnpackSnorm2x16:
   2864        {
   2865            ASSERT(getType().getBasicType() == EbtUInt);
   2866            resultArray = new TConstantUnion[2];
   2867            float f1, f2;
   2868            gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
   2869            resultArray[0].setFConst(f1);
   2870            resultArray[1].setFConst(f2);
   2871            break;
   2872        }
   2873 
   2874        case EOpPackUnorm2x16:
   2875            ASSERT(getType().getBasicType() == EbtFloat);
   2876            ASSERT(getType().getNominalSize() == 2);
   2877            resultArray = new TConstantUnion();
   2878            resultArray->setUConst(
   2879                gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
   2880            break;
   2881 
   2882        case EOpUnpackUnorm2x16:
   2883        {
   2884            ASSERT(getType().getBasicType() == EbtUInt);
   2885            resultArray = new TConstantUnion[2];
   2886            float f1, f2;
   2887            gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
   2888            resultArray[0].setFConst(f1);
   2889            resultArray[1].setFConst(f2);
   2890            break;
   2891        }
   2892 
   2893        case EOpPackHalf2x16:
   2894            ASSERT(getType().getBasicType() == EbtFloat);
   2895            ASSERT(getType().getNominalSize() == 2);
   2896            resultArray = new TConstantUnion();
   2897            resultArray->setUConst(
   2898                gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
   2899            break;
   2900 
   2901        case EOpUnpackHalf2x16:
   2902        {
   2903            ASSERT(getType().getBasicType() == EbtUInt);
   2904            resultArray = new TConstantUnion[2];
   2905            float f1, f2;
   2906            gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
   2907            resultArray[0].setFConst(f1);
   2908            resultArray[1].setFConst(f2);
   2909            break;
   2910        }
   2911 
   2912        case EOpPackUnorm4x8:
   2913        {
   2914            ASSERT(getType().getBasicType() == EbtFloat);
   2915            resultArray = new TConstantUnion();
   2916            resultArray->setUConst(
   2917                gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
   2918                                 operandArray[2].getFConst(), operandArray[3].getFConst()));
   2919            break;
   2920        }
   2921        case EOpPackSnorm4x8:
   2922        {
   2923            ASSERT(getType().getBasicType() == EbtFloat);
   2924            resultArray = new TConstantUnion();
   2925            resultArray->setUConst(
   2926                gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
   2927                                 operandArray[2].getFConst(), operandArray[3].getFConst()));
   2928            break;
   2929        }
   2930        case EOpUnpackUnorm4x8:
   2931        {
   2932            ASSERT(getType().getBasicType() == EbtUInt);
   2933            resultArray = new TConstantUnion[4];
   2934            float f[4];
   2935            gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
   2936            for (size_t i = 0; i < 4; ++i)
   2937            {
   2938                resultArray[i].setFConst(f[i]);
   2939            }
   2940            break;
   2941        }
   2942        case EOpUnpackSnorm4x8:
   2943        {
   2944            ASSERT(getType().getBasicType() == EbtUInt);
   2945            resultArray = new TConstantUnion[4];
   2946            float f[4];
   2947            gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
   2948            for (size_t i = 0; i < 4; ++i)
   2949            {
   2950                resultArray[i].setFConst(f[i]);
   2951            }
   2952            break;
   2953        }
   2954 
   2955        default:
   2956            UNREACHABLE();
   2957            break;
   2958    }
   2959 
   2960    return resultArray;
   2961 }
   2962 
   2963 TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
   2964                                                             const TFunction *function,
   2965                                                             TDiagnostics *diagnostics)
   2966 {
   2967    // Do unary operations where each component of the result is computed based on the corresponding
   2968    // component of the operand. Also folds normalize, though the divisor in that case takes all
   2969    // components into account.
   2970 
   2971    const TConstantUnion *operandArray = getConstantValue();
   2972    ASSERT(operandArray);
   2973 
   2974    size_t objectSize = getType().getObjectSize();
   2975 
   2976    TConstantUnion *resultArray = new TConstantUnion[objectSize];
   2977    for (size_t i = 0; i < objectSize; i++)
   2978    {
   2979        switch (op)
   2980        {
   2981            case EOpNegative:
   2982                switch (getType().getBasicType())
   2983                {
   2984                    case EbtFloat:
   2985                        resultArray[i].setFConst(-operandArray[i].getFConst());
   2986                        break;
   2987                    case EbtInt:
   2988                        if (operandArray[i] == std::numeric_limits<int>::min())
   2989                        {
   2990                            // The minimum representable integer doesn't have a positive
   2991                            // counterpart, rather the negation overflows and in ESSL is supposed to
   2992                            // wrap back to the minimum representable integer. Make sure that we
   2993                            // don't actually let the negation overflow, which has undefined
   2994                            // behavior in C++.
   2995                            resultArray[i].setIConst(std::numeric_limits<int>::min());
   2996                        }
   2997                        else
   2998                        {
   2999                            resultArray[i].setIConst(-operandArray[i].getIConst());
   3000                        }
   3001                        break;
   3002                    case EbtUInt:
   3003                        if (operandArray[i] == 0x80000000u)
   3004                        {
   3005                            resultArray[i].setUConst(0x80000000u);
   3006                        }
   3007                        else
   3008                        {
   3009                            resultArray[i].setUConst(static_cast<unsigned int>(
   3010                                -static_cast<int>(operandArray[i].getUConst())));
   3011                        }
   3012                        break;
   3013                    default:
   3014                        UNREACHABLE();
   3015                        return nullptr;
   3016                }
   3017                break;
   3018 
   3019            case EOpPositive:
   3020                switch (getType().getBasicType())
   3021                {
   3022                    case EbtFloat:
   3023                        resultArray[i].setFConst(operandArray[i].getFConst());
   3024                        break;
   3025                    case EbtInt:
   3026                        resultArray[i].setIConst(operandArray[i].getIConst());
   3027                        break;
   3028                    case EbtUInt:
   3029                        resultArray[i].setUConst(static_cast<unsigned int>(
   3030                            static_cast<int>(operandArray[i].getUConst())));
   3031                        break;
   3032                    default:
   3033                        UNREACHABLE();
   3034                        return nullptr;
   3035                }
   3036                break;
   3037 
   3038            case EOpLogicalNot:
   3039                switch (getType().getBasicType())
   3040                {
   3041                    case EbtBool:
   3042                        resultArray[i].setBConst(!operandArray[i].getBConst());
   3043                        break;
   3044                    default:
   3045                        UNREACHABLE();
   3046                        return nullptr;
   3047                }
   3048                break;
   3049 
   3050            case EOpBitwiseNot:
   3051                switch (getType().getBasicType())
   3052                {
   3053                    case EbtInt:
   3054                        resultArray[i].setIConst(~operandArray[i].getIConst());
   3055                        break;
   3056                    case EbtUInt:
   3057                        resultArray[i].setUConst(~operandArray[i].getUConst());
   3058                        break;
   3059                    default:
   3060                        UNREACHABLE();
   3061                        return nullptr;
   3062                }
   3063                break;
   3064 
   3065            case EOpRadians:
   3066                ASSERT(getType().getBasicType() == EbtFloat);
   3067                resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
   3068                break;
   3069 
   3070            case EOpDegrees:
   3071                ASSERT(getType().getBasicType() == EbtFloat);
   3072                resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
   3073                break;
   3074 
   3075            case EOpSin:
   3076                foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
   3077                break;
   3078 
   3079            case EOpCos:
   3080                foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
   3081                break;
   3082 
   3083            case EOpTan:
   3084                foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
   3085                break;
   3086 
   3087            case EOpAsin:
   3088                // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
   3089                // 0.
   3090                if (fabsf(operandArray[i].getFConst()) > 1.0f)
   3091                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3092                                                  diagnostics, &resultArray[i]);
   3093                else
   3094                    foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
   3095                break;
   3096 
   3097            case EOpAcos:
   3098                // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
   3099                // 0.
   3100                if (fabsf(operandArray[i].getFConst()) > 1.0f)
   3101                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3102                                                  diagnostics, &resultArray[i]);
   3103                else
   3104                    foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
   3105                break;
   3106 
   3107            case EOpAtan:
   3108                foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
   3109                break;
   3110 
   3111            case EOpSinh:
   3112                foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
   3113                break;
   3114 
   3115            case EOpCosh:
   3116                foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
   3117                break;
   3118 
   3119            case EOpTanh:
   3120                foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
   3121                break;
   3122 
   3123            case EOpAsinh:
   3124                foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
   3125                break;
   3126 
   3127            case EOpAcosh:
   3128                // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
   3129                if (operandArray[i].getFConst() < 1.0f)
   3130                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3131                                                  diagnostics, &resultArray[i]);
   3132                else
   3133                    foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
   3134                break;
   3135 
   3136            case EOpAtanh:
   3137                // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
   3138                // 0.
   3139                if (fabsf(operandArray[i].getFConst()) >= 1.0f)
   3140                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3141                                                  diagnostics, &resultArray[i]);
   3142                else
   3143                    foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
   3144                break;
   3145 
   3146            case EOpAbs:
   3147                switch (getType().getBasicType())
   3148                {
   3149                    case EbtFloat:
   3150                        resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
   3151                        break;
   3152                    case EbtInt:
   3153                        resultArray[i].setIConst(abs(operandArray[i].getIConst()));
   3154                        break;
   3155                    default:
   3156                        UNREACHABLE();
   3157                        return nullptr;
   3158                }
   3159                break;
   3160 
   3161            case EOpSign:
   3162                switch (getType().getBasicType())
   3163                {
   3164                    case EbtFloat:
   3165                    {
   3166                        float fConst  = operandArray[i].getFConst();
   3167                        float fResult = 0.0f;
   3168                        if (fConst > 0.0f)
   3169                            fResult = 1.0f;
   3170                        else if (fConst < 0.0f)
   3171                            fResult = -1.0f;
   3172                        resultArray[i].setFConst(fResult);
   3173                        break;
   3174                    }
   3175                    case EbtInt:
   3176                    {
   3177                        int iConst  = operandArray[i].getIConst();
   3178                        int iResult = 0;
   3179                        if (iConst > 0)
   3180                            iResult = 1;
   3181                        else if (iConst < 0)
   3182                            iResult = -1;
   3183                        resultArray[i].setIConst(iResult);
   3184                        break;
   3185                    }
   3186                    default:
   3187                        UNREACHABLE();
   3188                        return nullptr;
   3189                }
   3190                break;
   3191 
   3192            case EOpFloor:
   3193                foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
   3194                break;
   3195 
   3196            case EOpTrunc:
   3197                foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
   3198                break;
   3199 
   3200            case EOpRound:
   3201                foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
   3202                break;
   3203 
   3204            case EOpRoundEven:
   3205            {
   3206                ASSERT(getType().getBasicType() == EbtFloat);
   3207                float x = operandArray[i].getFConst();
   3208                float result;
   3209                float fractPart = modff(x, &result);
   3210                if (fabsf(fractPart) == 0.5f)
   3211                    result = 2.0f * roundf(x / 2.0f);
   3212                else
   3213                    result = roundf(x);
   3214                resultArray[i].setFConst(result);
   3215                break;
   3216            }
   3217 
   3218            case EOpCeil:
   3219                foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
   3220                break;
   3221 
   3222            case EOpFract:
   3223            {
   3224                ASSERT(getType().getBasicType() == EbtFloat);
   3225                float x = operandArray[i].getFConst();
   3226                resultArray[i].setFConst(x - floorf(x));
   3227                break;
   3228            }
   3229 
   3230            case EOpIsnan:
   3231                ASSERT(getType().getBasicType() == EbtFloat);
   3232                resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
   3233                break;
   3234 
   3235            case EOpIsinf:
   3236                ASSERT(getType().getBasicType() == EbtFloat);
   3237                resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
   3238                break;
   3239 
   3240            case EOpFloatBitsToInt:
   3241                ASSERT(getType().getBasicType() == EbtFloat);
   3242                resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
   3243                break;
   3244 
   3245            case EOpFloatBitsToUint:
   3246                ASSERT(getType().getBasicType() == EbtFloat);
   3247                resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
   3248                break;
   3249 
   3250            case EOpIntBitsToFloat:
   3251                ASSERT(getType().getBasicType() == EbtInt);
   3252                resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
   3253                break;
   3254 
   3255            case EOpUintBitsToFloat:
   3256                ASSERT(getType().getBasicType() == EbtUInt);
   3257                resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
   3258                break;
   3259 
   3260            case EOpExp:
   3261                foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
   3262                break;
   3263 
   3264            case EOpLog:
   3265                // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
   3266                if (operandArray[i].getFConst() <= 0.0f)
   3267                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3268                                                  diagnostics, &resultArray[i]);
   3269                else
   3270                    foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
   3271                break;
   3272 
   3273            case EOpExp2:
   3274                foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
   3275                break;
   3276 
   3277            case EOpLog2:
   3278                // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
   3279                // And log2f is not available on some plarforms like old android, so just using
   3280                // log(x)/log(2) here.
   3281                if (operandArray[i].getFConst() <= 0.0f)
   3282                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3283                                                  diagnostics, &resultArray[i]);
   3284                else
   3285                {
   3286                    foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
   3287                    resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
   3288                }
   3289                break;
   3290 
   3291            case EOpSqrt:
   3292                // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
   3293                if (operandArray[i].getFConst() < 0.0f)
   3294                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3295                                                  diagnostics, &resultArray[i]);
   3296                else
   3297                    foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
   3298                break;
   3299 
   3300            case EOpInversesqrt:
   3301                // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
   3302                // so getting the square root first using builtin function sqrt() and then taking
   3303                // its inverse.
   3304                // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
   3305                // result to 0.
   3306                if (operandArray[i].getFConst() <= 0.0f)
   3307                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3308                                                  diagnostics, &resultArray[i]);
   3309                else
   3310                {
   3311                    foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
   3312                    resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
   3313                }
   3314                break;
   3315 
   3316            case EOpNotComponentWise:
   3317                ASSERT(getType().getBasicType() == EbtBool);
   3318                resultArray[i].setBConst(!operandArray[i].getBConst());
   3319                break;
   3320 
   3321            case EOpNormalize:
   3322            {
   3323                ASSERT(getType().getBasicType() == EbtFloat);
   3324                float x      = operandArray[i].getFConst();
   3325                float length = VectorLength(operandArray, objectSize);
   3326                if (length != 0.0f)
   3327                    resultArray[i].setFConst(x / length);
   3328                else
   3329                    UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
   3330                                                  diagnostics, &resultArray[i]);
   3331                break;
   3332            }
   3333            case EOpBitfieldReverse:
   3334            {
   3335                uint32_t value;
   3336                if (getType().getBasicType() == EbtInt)
   3337                {
   3338                    value = static_cast<uint32_t>(operandArray[i].getIConst());
   3339                }
   3340                else
   3341                {
   3342                    ASSERT(getType().getBasicType() == EbtUInt);
   3343                    value = operandArray[i].getUConst();
   3344                }
   3345                uint32_t result = gl::BitfieldReverse(value);
   3346                if (getType().getBasicType() == EbtInt)
   3347                {
   3348                    resultArray[i].setIConst(static_cast<int32_t>(result));
   3349                }
   3350                else
   3351                {
   3352                    resultArray[i].setUConst(result);
   3353                }
   3354                break;
   3355            }
   3356            case EOpBitCount:
   3357            {
   3358                uint32_t value;
   3359                if (getType().getBasicType() == EbtInt)
   3360                {
   3361                    value = static_cast<uint32_t>(operandArray[i].getIConst());
   3362                }
   3363                else
   3364                {
   3365                    ASSERT(getType().getBasicType() == EbtUInt);
   3366                    value = operandArray[i].getUConst();
   3367                }
   3368                int result = gl::BitCount(value);
   3369                resultArray[i].setIConst(result);
   3370                break;
   3371            }
   3372            case EOpFindLSB:
   3373            {
   3374                uint32_t value;
   3375                if (getType().getBasicType() == EbtInt)
   3376                {
   3377                    value = static_cast<uint32_t>(operandArray[i].getIConst());
   3378                }
   3379                else
   3380                {
   3381                    ASSERT(getType().getBasicType() == EbtUInt);
   3382                    value = operandArray[i].getUConst();
   3383                }
   3384                resultArray[i].setIConst(gl::FindLSB(value));
   3385                break;
   3386            }
   3387            case EOpFindMSB:
   3388            {
   3389                uint32_t value;
   3390                if (getType().getBasicType() == EbtInt)
   3391                {
   3392                    int intValue = operandArray[i].getIConst();
   3393                    value        = static_cast<uint32_t>(intValue);
   3394                    if (intValue < 0)
   3395                    {
   3396                        // Look for zero instead of one in value. This also handles the intValue ==
   3397                        // -1 special case, where the return value needs to be -1.
   3398                        value = ~value;
   3399                    }
   3400                }
   3401                else
   3402                {
   3403                    ASSERT(getType().getBasicType() == EbtUInt);
   3404                    value = operandArray[i].getUConst();
   3405                }
   3406                resultArray[i].setIConst(gl::FindMSB(value));
   3407                break;
   3408            }
   3409 
   3410            default:
   3411                return nullptr;
   3412        }
   3413    }
   3414 
   3415    return resultArray;
   3416 }
   3417 
   3418 void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
   3419                                              FloatTypeUnaryFunc builtinFunc,
   3420                                              TConstantUnion *result) const
   3421 {
   3422    ASSERT(builtinFunc);
   3423 
   3424    ASSERT(getType().getBasicType() == EbtFloat);
   3425    result->setFConst(builtinFunc(parameter.getFConst()));
   3426 }
   3427 
   3428 void TIntermConstantUnion::propagatePrecision(TPrecision precision)
   3429 {
   3430    mType.setPrecision(precision);
   3431 }
   3432 
   3433 // static
   3434 TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
   3435                                                           TDiagnostics *diagnostics)
   3436 {
   3437    const TOperator op         = aggregate->getOp();
   3438    const TFunction *function  = aggregate->getFunction();
   3439    TIntermSequence *arguments = aggregate->getSequence();
   3440    unsigned int argsCount     = static_cast<unsigned int>(arguments->size());
   3441    std::vector<const TConstantUnion *> unionArrays(argsCount);
   3442    std::vector<size_t> objectSizes(argsCount);
   3443    size_t maxObjectSize = 0;
   3444    TBasicType basicType = EbtVoid;
   3445    TSourceLoc loc;
   3446    for (unsigned int i = 0; i < argsCount; i++)
   3447    {
   3448        TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
   3449        ASSERT(argConstant != nullptr);  // Should be checked already.
   3450 
   3451        if (i == 0)
   3452        {
   3453            basicType = argConstant->getType().getBasicType();
   3454            loc       = argConstant->getLine();
   3455        }
   3456        unionArrays[i] = argConstant->getConstantValue();
   3457        objectSizes[i] = argConstant->getType().getObjectSize();
   3458        if (objectSizes[i] > maxObjectSize)
   3459            maxObjectSize = objectSizes[i];
   3460    }
   3461 
   3462    if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
   3463    {
   3464        for (unsigned int i = 0; i < argsCount; i++)
   3465            if (objectSizes[i] != maxObjectSize)
   3466                unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
   3467    }
   3468 
   3469    TConstantUnion *resultArray = nullptr;
   3470 
   3471    switch (op)
   3472    {
   3473        case EOpAtan:
   3474        {
   3475            ASSERT(basicType == EbtFloat);
   3476            resultArray = new TConstantUnion[maxObjectSize];
   3477            for (size_t i = 0; i < maxObjectSize; i++)
   3478            {
   3479                float y = unionArrays[0][i].getFConst();
   3480                float x = unionArrays[1][i].getFConst();
   3481                // Results are undefined if x and y are both 0.
   3482                if (x == 0.0f && y == 0.0f)
   3483                    UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   3484                                                  &resultArray[i]);
   3485                else
   3486                    resultArray[i].setFConst(atan2f(y, x));
   3487            }
   3488            break;
   3489        }
   3490 
   3491        case EOpPow:
   3492        {
   3493            ASSERT(basicType == EbtFloat);
   3494            resultArray = new TConstantUnion[maxObjectSize];
   3495            for (size_t i = 0; i < maxObjectSize; i++)
   3496            {
   3497                float x = unionArrays[0][i].getFConst();
   3498                float y = unionArrays[1][i].getFConst();
   3499                // Results are undefined if x < 0.
   3500                // Results are undefined if x = 0 and y <= 0.
   3501                if (x < 0.0f)
   3502                    UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   3503                                                  &resultArray[i]);
   3504                else if (x == 0.0f && y <= 0.0f)
   3505                    UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   3506                                                  &resultArray[i]);
   3507                else
   3508                    resultArray[i].setFConst(powf(x, y));
   3509            }
   3510            break;
   3511        }
   3512 
   3513        case EOpMod:
   3514        {
   3515            ASSERT(basicType == EbtFloat);
   3516            resultArray = new TConstantUnion[maxObjectSize];
   3517            for (size_t i = 0; i < maxObjectSize; i++)
   3518            {
   3519                float x = unionArrays[0][i].getFConst();
   3520                float y = unionArrays[1][i].getFConst();
   3521                resultArray[i].setFConst(x - y * floorf(x / y));
   3522            }
   3523            break;
   3524        }
   3525 
   3526        case EOpMin:
   3527        {
   3528            resultArray = new TConstantUnion[maxObjectSize];
   3529            for (size_t i = 0; i < maxObjectSize; i++)
   3530            {
   3531                switch (basicType)
   3532                {
   3533                    case EbtFloat:
   3534                        resultArray[i].setFConst(
   3535                            std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
   3536                        break;
   3537                    case EbtInt:
   3538                        resultArray[i].setIConst(
   3539                            std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
   3540                        break;
   3541                    case EbtUInt:
   3542                        resultArray[i].setUConst(
   3543                            std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
   3544                        break;
   3545                    default:
   3546                        UNREACHABLE();
   3547                        break;
   3548                }
   3549            }
   3550            break;
   3551        }
   3552 
   3553        case EOpMax:
   3554        {
   3555            resultArray = new TConstantUnion[maxObjectSize];
   3556            for (size_t i = 0; i < maxObjectSize; i++)
   3557            {
   3558                switch (basicType)
   3559                {
   3560                    case EbtFloat:
   3561                        resultArray[i].setFConst(
   3562                            std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
   3563                        break;
   3564                    case EbtInt:
   3565                        resultArray[i].setIConst(
   3566                            std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
   3567                        break;
   3568                    case EbtUInt:
   3569                        resultArray[i].setUConst(
   3570                            std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
   3571                        break;
   3572                    default:
   3573                        UNREACHABLE();
   3574                        break;
   3575                }
   3576            }
   3577            break;
   3578        }
   3579 
   3580        case EOpStep:
   3581        {
   3582            ASSERT(basicType == EbtFloat);
   3583            resultArray = new TConstantUnion[maxObjectSize];
   3584            for (size_t i = 0; i < maxObjectSize; i++)
   3585                resultArray[i].setFConst(
   3586                    unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
   3587            break;
   3588        }
   3589 
   3590        case EOpLessThanComponentWise:
   3591        {
   3592            resultArray = new TConstantUnion[maxObjectSize];
   3593            for (size_t i = 0; i < maxObjectSize; i++)
   3594            {
   3595                switch (basicType)
   3596                {
   3597                    case EbtFloat:
   3598                        resultArray[i].setBConst(unionArrays[0][i].getFConst() <
   3599                                                 unionArrays[1][i].getFConst());
   3600                        break;
   3601                    case EbtInt:
   3602                        resultArray[i].setBConst(unionArrays[0][i].getIConst() <
   3603                                                 unionArrays[1][i].getIConst());
   3604                        break;
   3605                    case EbtUInt:
   3606                        resultArray[i].setBConst(unionArrays[0][i].getUConst() <
   3607                                                 unionArrays[1][i].getUConst());
   3608                        break;
   3609                    default:
   3610                        UNREACHABLE();
   3611                        break;
   3612                }
   3613            }
   3614            break;
   3615        }
   3616 
   3617        case EOpLessThanEqualComponentWise:
   3618        {
   3619            resultArray = new TConstantUnion[maxObjectSize];
   3620            for (size_t i = 0; i < maxObjectSize; i++)
   3621            {
   3622                switch (basicType)
   3623                {
   3624                    case EbtFloat:
   3625                        resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
   3626                                                 unionArrays[1][i].getFConst());
   3627                        break;
   3628                    case EbtInt:
   3629                        resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
   3630                                                 unionArrays[1][i].getIConst());
   3631                        break;
   3632                    case EbtUInt:
   3633                        resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
   3634                                                 unionArrays[1][i].getUConst());
   3635                        break;
   3636                    default:
   3637                        UNREACHABLE();
   3638                        break;
   3639                }
   3640            }
   3641            break;
   3642        }
   3643 
   3644        case EOpGreaterThanComponentWise:
   3645        {
   3646            resultArray = new TConstantUnion[maxObjectSize];
   3647            for (size_t i = 0; i < maxObjectSize; i++)
   3648            {
   3649                switch (basicType)
   3650                {
   3651                    case EbtFloat:
   3652                        resultArray[i].setBConst(unionArrays[0][i].getFConst() >
   3653                                                 unionArrays[1][i].getFConst());
   3654                        break;
   3655                    case EbtInt:
   3656                        resultArray[i].setBConst(unionArrays[0][i].getIConst() >
   3657                                                 unionArrays[1][i].getIConst());
   3658                        break;
   3659                    case EbtUInt:
   3660                        resultArray[i].setBConst(unionArrays[0][i].getUConst() >
   3661                                                 unionArrays[1][i].getUConst());
   3662                        break;
   3663                    default:
   3664                        UNREACHABLE();
   3665                        break;
   3666                }
   3667            }
   3668            break;
   3669        }
   3670        case EOpGreaterThanEqualComponentWise:
   3671        {
   3672            resultArray = new TConstantUnion[maxObjectSize];
   3673            for (size_t i = 0; i < maxObjectSize; i++)
   3674            {
   3675                switch (basicType)
   3676                {
   3677                    case EbtFloat:
   3678                        resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
   3679                                                 unionArrays[1][i].getFConst());
   3680                        break;
   3681                    case EbtInt:
   3682                        resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
   3683                                                 unionArrays[1][i].getIConst());
   3684                        break;
   3685                    case EbtUInt:
   3686                        resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
   3687                                                 unionArrays[1][i].getUConst());
   3688                        break;
   3689                    default:
   3690                        UNREACHABLE();
   3691                        break;
   3692                }
   3693            }
   3694        }
   3695        break;
   3696 
   3697        case EOpEqualComponentWise:
   3698        {
   3699            resultArray = new TConstantUnion[maxObjectSize];
   3700            for (size_t i = 0; i < maxObjectSize; i++)
   3701            {
   3702                switch (basicType)
   3703                {
   3704                    case EbtFloat:
   3705                        resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
   3706                                                 unionArrays[1][i].getFConst());
   3707                        break;
   3708                    case EbtInt:
   3709                        resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
   3710                                                 unionArrays[1][i].getIConst());
   3711                        break;
   3712                    case EbtUInt:
   3713                        resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
   3714                                                 unionArrays[1][i].getUConst());
   3715                        break;
   3716                    case EbtBool:
   3717                        resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
   3718                                                 unionArrays[1][i].getBConst());
   3719                        break;
   3720                    default:
   3721                        UNREACHABLE();
   3722                        break;
   3723                }
   3724            }
   3725            break;
   3726        }
   3727 
   3728        case EOpNotEqualComponentWise:
   3729        {
   3730            resultArray = new TConstantUnion[maxObjectSize];
   3731            for (size_t i = 0; i < maxObjectSize; i++)
   3732            {
   3733                switch (basicType)
   3734                {
   3735                    case EbtFloat:
   3736                        resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
   3737                                                 unionArrays[1][i].getFConst());
   3738                        break;
   3739                    case EbtInt:
   3740                        resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
   3741                                                 unionArrays[1][i].getIConst());
   3742                        break;
   3743                    case EbtUInt:
   3744                        resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
   3745                                                 unionArrays[1][i].getUConst());
   3746                        break;
   3747                    case EbtBool:
   3748                        resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
   3749                                                 unionArrays[1][i].getBConst());
   3750                        break;
   3751                    default:
   3752                        UNREACHABLE();
   3753                        break;
   3754                }
   3755            }
   3756            break;
   3757        }
   3758 
   3759        case EOpDistance:
   3760        {
   3761            ASSERT(basicType == EbtFloat);
   3762            TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
   3763            resultArray                   = new TConstantUnion();
   3764            for (size_t i = 0; i < maxObjectSize; i++)
   3765            {
   3766                float x = unionArrays[0][i].getFConst();
   3767                float y = unionArrays[1][i].getFConst();
   3768                distanceArray[i].setFConst(x - y);
   3769            }
   3770            resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
   3771            break;
   3772        }
   3773 
   3774        case EOpDot:
   3775            ASSERT(basicType == EbtFloat);
   3776            resultArray = new TConstantUnion();
   3777            resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
   3778            break;
   3779 
   3780        case EOpCross:
   3781        {
   3782            ASSERT(basicType == EbtFloat && maxObjectSize == 3);
   3783            resultArray = new TConstantUnion[maxObjectSize];
   3784            float x0    = unionArrays[0][0].getFConst();
   3785            float x1    = unionArrays[0][1].getFConst();
   3786            float x2    = unionArrays[0][2].getFConst();
   3787            float y0    = unionArrays[1][0].getFConst();
   3788            float y1    = unionArrays[1][1].getFConst();
   3789            float y2    = unionArrays[1][2].getFConst();
   3790            resultArray[0].setFConst(x1 * y2 - y1 * x2);
   3791            resultArray[1].setFConst(x2 * y0 - y2 * x0);
   3792            resultArray[2].setFConst(x0 * y1 - y0 * x1);
   3793            break;
   3794        }
   3795 
   3796        case EOpReflect:
   3797        {
   3798            ASSERT(basicType == EbtFloat);
   3799            // genType reflect (genType I, genType N) :
   3800            //     For the incident vector I and surface orientation N, returns the reflection
   3801            //     direction:
   3802            //     I - 2 * dot(N, I) * N.
   3803            resultArray      = new TConstantUnion[maxObjectSize];
   3804            float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
   3805            for (size_t i = 0; i < maxObjectSize; i++)
   3806            {
   3807                float result = unionArrays[0][i].getFConst() -
   3808                               2.0f * dotProduct * unionArrays[1][i].getFConst();
   3809                resultArray[i].setFConst(result);
   3810            }
   3811            break;
   3812        }
   3813 
   3814        case EOpMatrixCompMult:
   3815        {
   3816            ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
   3817                   (*arguments)[1]->getAsTyped()->isMatrix());
   3818            // Perform component-wise matrix multiplication.
   3819            resultArray                 = new TConstantUnion[maxObjectSize];
   3820            const uint8_t rows          = (*arguments)[0]->getAsTyped()->getRows();
   3821            const uint8_t cols          = (*arguments)[0]->getAsTyped()->getCols();
   3822            angle::Matrix<float> lhs    = GetMatrix(unionArrays[0], rows, cols);
   3823            angle::Matrix<float> rhs    = GetMatrix(unionArrays[1], rows, cols);
   3824            angle::Matrix<float> result = lhs.compMult(rhs);
   3825            SetUnionArrayFromMatrix(result, resultArray);
   3826            break;
   3827        }
   3828 
   3829        case EOpOuterProduct:
   3830        {
   3831            ASSERT(basicType == EbtFloat);
   3832            size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
   3833            size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
   3834            resultArray    = new TConstantUnion[numRows * numCols];
   3835            angle::Matrix<float> result =
   3836                GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
   3837                    .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
   3838            SetUnionArrayFromMatrix(result, resultArray);
   3839            break;
   3840        }
   3841 
   3842        case EOpClamp:
   3843        {
   3844            resultArray = new TConstantUnion[maxObjectSize];
   3845            for (size_t i = 0; i < maxObjectSize; i++)
   3846            {
   3847                switch (basicType)
   3848                {
   3849                    case EbtFloat:
   3850                    {
   3851                        float x   = unionArrays[0][i].getFConst();
   3852                        float min = unionArrays[1][i].getFConst();
   3853                        float max = unionArrays[2][i].getFConst();
   3854                        // Results are undefined if min > max.
   3855                        if (min > max)
   3856                            UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   3857                                                          &resultArray[i]);
   3858                        else
   3859                            resultArray[i].setFConst(gl::clamp(x, min, max));
   3860                        break;
   3861                    }
   3862 
   3863                    case EbtInt:
   3864                    {
   3865                        int x   = unionArrays[0][i].getIConst();
   3866                        int min = unionArrays[1][i].getIConst();
   3867                        int max = unionArrays[2][i].getIConst();
   3868                        // Results are undefined if min > max.
   3869                        if (min > max)
   3870                            UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   3871                                                          &resultArray[i]);
   3872                        else
   3873                            resultArray[i].setIConst(gl::clamp(x, min, max));
   3874                        break;
   3875                    }
   3876                    case EbtUInt:
   3877                    {
   3878                        unsigned int x   = unionArrays[0][i].getUConst();
   3879                        unsigned int min = unionArrays[1][i].getUConst();
   3880                        unsigned int max = unionArrays[2][i].getUConst();
   3881                        // Results are undefined if min > max.
   3882                        if (min > max)
   3883                            UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   3884                                                          &resultArray[i]);
   3885                        else
   3886                            resultArray[i].setUConst(gl::clamp(x, min, max));
   3887                        break;
   3888                    }
   3889                    default:
   3890                        UNREACHABLE();
   3891                        break;
   3892                }
   3893            }
   3894            break;
   3895        }
   3896 
   3897        case EOpMix:
   3898        {
   3899            resultArray = new TConstantUnion[maxObjectSize];
   3900            for (size_t i = 0; i < maxObjectSize; i++)
   3901            {
   3902                TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
   3903                if (type == EbtFloat)
   3904                {
   3905                    ASSERT(basicType == EbtFloat);
   3906                    float x = unionArrays[0][i].getFConst();
   3907                    float y = unionArrays[1][i].getFConst();
   3908 
   3909                    // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
   3910                    float a = unionArrays[2][i].getFConst();
   3911                    resultArray[i].setFConst(x * (1.0f - a) + y * a);
   3912                }
   3913                else  // 3rd parameter is EbtBool
   3914                {
   3915                    ASSERT(type == EbtBool);
   3916                    // Selects which vector each returned component comes from.
   3917                    // For a component of a that is false, the corresponding component of x is
   3918                    // returned.
   3919                    // For a component of a that is true, the corresponding component of y is
   3920                    // returned.
   3921                    bool a = unionArrays[2][i].getBConst();
   3922                    switch (basicType)
   3923                    {
   3924                        case EbtFloat:
   3925                        {
   3926                            float x = unionArrays[0][i].getFConst();
   3927                            float y = unionArrays[1][i].getFConst();
   3928                            resultArray[i].setFConst(a ? y : x);
   3929                        }
   3930                        break;
   3931                        case EbtInt:
   3932                        {
   3933                            int x = unionArrays[0][i].getIConst();
   3934                            int y = unionArrays[1][i].getIConst();
   3935                            resultArray[i].setIConst(a ? y : x);
   3936                        }
   3937                        break;
   3938                        case EbtUInt:
   3939                        {
   3940                            unsigned int x = unionArrays[0][i].getUConst();
   3941                            unsigned int y = unionArrays[1][i].getUConst();
   3942                            resultArray[i].setUConst(a ? y : x);
   3943                        }
   3944                        break;
   3945                        case EbtBool:
   3946                        {
   3947                            bool x = unionArrays[0][i].getBConst();
   3948                            bool y = unionArrays[1][i].getBConst();
   3949                            resultArray[i].setBConst(a ? y : x);
   3950                        }
   3951                        break;
   3952                        default:
   3953                            UNREACHABLE();
   3954                            break;
   3955                    }
   3956                }
   3957            }
   3958            break;
   3959        }
   3960 
   3961        case EOpSmoothstep:
   3962        {
   3963            ASSERT(basicType == EbtFloat);
   3964            resultArray = new TConstantUnion[maxObjectSize];
   3965            for (size_t i = 0; i < maxObjectSize; i++)
   3966            {
   3967                float edge0 = unionArrays[0][i].getFConst();
   3968                float edge1 = unionArrays[1][i].getFConst();
   3969                float x     = unionArrays[2][i].getFConst();
   3970                // Results are undefined if edge0 >= edge1.
   3971                if (edge0 >= edge1)
   3972                {
   3973                    UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   3974                                                  &resultArray[i]);
   3975                }
   3976                else
   3977                {
   3978                    // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
   3979                    // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
   3980                    float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
   3981                    resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
   3982                }
   3983            }
   3984            break;
   3985        }
   3986 
   3987        case EOpFma:
   3988        {
   3989            ASSERT(basicType == EbtFloat);
   3990            resultArray = new TConstantUnion[maxObjectSize];
   3991            for (size_t i = 0; i < maxObjectSize; i++)
   3992            {
   3993                float a = unionArrays[0][i].getFConst();
   3994                float b = unionArrays[1][i].getFConst();
   3995                float c = unionArrays[2][i].getFConst();
   3996 
   3997                // Returns a * b + c.
   3998                resultArray[i].setFConst(a * b + c);
   3999            }
   4000            break;
   4001        }
   4002 
   4003        case EOpLdexp:
   4004        {
   4005            resultArray = new TConstantUnion[maxObjectSize];
   4006            for (size_t i = 0; i < maxObjectSize; i++)
   4007            {
   4008                float x = unionArrays[0][i].getFConst();
   4009                int exp = unionArrays[1][i].getIConst();
   4010                if (exp > 128)
   4011                {
   4012                    UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
   4013                                                  &resultArray[i]);
   4014                }
   4015                else
   4016                {
   4017                    resultArray[i].setFConst(gl::Ldexp(x, exp));
   4018                }
   4019            }
   4020            break;
   4021        }
   4022 
   4023        case EOpFaceforward:
   4024        {
   4025            ASSERT(basicType == EbtFloat);
   4026            // genType faceforward(genType N, genType I, genType Nref) :
   4027            //     If dot(Nref, I) < 0 return N, otherwise return -N.
   4028            resultArray      = new TConstantUnion[maxObjectSize];
   4029            float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
   4030            for (size_t i = 0; i < maxObjectSize; i++)
   4031            {
   4032                if (dotProduct < 0)
   4033                    resultArray[i].setFConst(unionArrays[0][i].getFConst());
   4034                else
   4035                    resultArray[i].setFConst(-unionArrays[0][i].getFConst());
   4036            }
   4037            break;
   4038        }
   4039 
   4040        case EOpRefract:
   4041        {
   4042            ASSERT(basicType == EbtFloat);
   4043            // genType refract(genType I, genType N, float eta) :
   4044            //     For the incident vector I and surface normal N, and the ratio of indices of
   4045            //     refraction eta,
   4046            //     return the refraction vector. The result is computed by
   4047            //         k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
   4048            //         if (k < 0.0)
   4049            //             return genType(0.0)
   4050            //         else
   4051            //             return eta * I - (eta * dot(N, I) + sqrt(k)) * N
   4052            resultArray      = new TConstantUnion[maxObjectSize];
   4053            float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
   4054            for (size_t i = 0; i < maxObjectSize; i++)
   4055            {
   4056                float eta = unionArrays[2][i].getFConst();
   4057                float k   = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
   4058                if (k < 0.0f)
   4059                    resultArray[i].setFConst(0.0f);
   4060                else
   4061                    resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
   4062                                             (eta * dotProduct + sqrtf(k)) *
   4063                                                 unionArrays[1][i].getFConst());
   4064            }
   4065            break;
   4066        }
   4067        case EOpBitfieldExtract:
   4068        {
   4069            resultArray = new TConstantUnion[maxObjectSize];
   4070            for (size_t i = 0; i < maxObjectSize; ++i)
   4071            {
   4072                int offset = unionArrays[1][0].getIConst();
   4073                int bits   = unionArrays[2][0].getIConst();
   4074                if (bits == 0)
   4075                {
   4076                    if (aggregate->getBasicType() == EbtInt)
   4077                    {
   4078                        resultArray[i].setIConst(0);
   4079                    }
   4080                    else
   4081                    {
   4082                        ASSERT(aggregate->getBasicType() == EbtUInt);
   4083                        resultArray[i].setUConst(0);
   4084                    }
   4085                }
   4086                else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
   4087                {
   4088                    UndefinedConstantFoldingError(loc, function, aggregate->getBasicType(),
   4089                                                  diagnostics, &resultArray[i]);
   4090                }
   4091                else
   4092                {
   4093                    // bits can be 32 here, so we need to avoid bit shift overflow.
   4094                    uint32_t maskMsb = 1u << (bits - 1);
   4095                    uint32_t mask    = ((maskMsb - 1u) | maskMsb) << offset;
   4096                    if (aggregate->getBasicType() == EbtInt)
   4097                    {
   4098                        uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
   4099                        uint32_t resultUnsigned = (value & mask) >> offset;
   4100                        if ((resultUnsigned & maskMsb) != 0)
   4101                        {
   4102                            // The most significant bits (from bits+1 to the most significant bit)
   4103                            // should be set to 1.
   4104                            uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
   4105                            resultUnsigned |= higherBitsMask;
   4106                        }
   4107                        resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
   4108                    }
   4109                    else
   4110                    {
   4111                        ASSERT(aggregate->getBasicType() == EbtUInt);
   4112                        uint32_t value = unionArrays[0][i].getUConst();
   4113                        resultArray[i].setUConst((value & mask) >> offset);
   4114                    }
   4115                }
   4116            }
   4117            break;
   4118        }
   4119        case EOpBitfieldInsert:
   4120        {
   4121            resultArray = new TConstantUnion[maxObjectSize];
   4122            for (size_t i = 0; i < maxObjectSize; ++i)
   4123            {
   4124                int offset = unionArrays[2][0].getIConst();
   4125                int bits   = unionArrays[3][0].getIConst();
   4126                if (bits == 0)
   4127                {
   4128                    if (aggregate->getBasicType() == EbtInt)
   4129                    {
   4130                        int32_t base = unionArrays[0][i].getIConst();
   4131                        resultArray[i].setIConst(base);
   4132                    }
   4133                    else
   4134                    {
   4135                        ASSERT(aggregate->getBasicType() == EbtUInt);
   4136                        uint32_t base = unionArrays[0][i].getUConst();
   4137                        resultArray[i].setUConst(base);
   4138                    }
   4139                }
   4140                else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
   4141                {
   4142                    UndefinedConstantFoldingError(loc, function, aggregate->getBasicType(),
   4143                                                  diagnostics, &resultArray[i]);
   4144                }
   4145                else
   4146                {
   4147                    // bits can be 32 here, so we need to avoid bit shift overflow.
   4148                    uint32_t maskMsb    = 1u << (bits - 1);
   4149                    uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
   4150                    uint32_t baseMask   = ~insertMask;
   4151                    if (aggregate->getBasicType() == EbtInt)
   4152                    {
   4153                        uint32_t base   = static_cast<uint32_t>(unionArrays[0][i].getIConst());
   4154                        uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
   4155                        uint32_t resultUnsigned =
   4156                            (base & baseMask) | ((insert << offset) & insertMask);
   4157                        resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
   4158                    }
   4159                    else
   4160                    {
   4161                        ASSERT(aggregate->getBasicType() == EbtUInt);
   4162                        uint32_t base   = unionArrays[0][i].getUConst();
   4163                        uint32_t insert = unionArrays[1][i].getUConst();
   4164                        resultArray[i].setUConst((base & baseMask) |
   4165                                                 ((insert << offset) & insertMask));
   4166                    }
   4167                }
   4168            }
   4169            break;
   4170        }
   4171        case EOpDFdx:
   4172        case EOpDFdy:
   4173        case EOpFwidth:
   4174            ASSERT(basicType == EbtFloat);
   4175            resultArray = new TConstantUnion[maxObjectSize];
   4176            for (size_t i = 0; i < maxObjectSize; i++)
   4177            {
   4178                // Derivatives of constant arguments should be 0.
   4179                resultArray[i].setFConst(0.0f);
   4180            }
   4181            break;
   4182 
   4183        default:
   4184            UNREACHABLE();
   4185            return nullptr;
   4186    }
   4187    return resultArray;
   4188 }
   4189 
   4190 bool TIntermConstantUnion::IsFloatDivision(TBasicType t1, TBasicType t2)
   4191 {
   4192    ImplicitTypeConversion conversion = GetConversion(t1, t2);
   4193    ASSERT(conversion != ImplicitTypeConversion::Invalid);
   4194    if (conversion == ImplicitTypeConversion::Same)
   4195    {
   4196        if (t1 == EbtFloat)
   4197            return true;
   4198        return false;
   4199    }
   4200    ASSERT(t1 == EbtFloat || t2 == EbtFloat);
   4201    return true;
   4202 }
   4203 
   4204 // TIntermPreprocessorDirective implementation.
   4205 TIntermPreprocessorDirective::TIntermPreprocessorDirective(PreprocessorDirective directive,
   4206                                                           ImmutableString command)
   4207    : mDirective(directive), mCommand(std::move(command))
   4208 {}
   4209 
   4210 TIntermPreprocessorDirective::TIntermPreprocessorDirective(const TIntermPreprocessorDirective &node)
   4211    : TIntermPreprocessorDirective(node.mDirective, node.mCommand)
   4212 {}
   4213 
   4214 TIntermPreprocessorDirective::~TIntermPreprocessorDirective() = default;
   4215 
   4216 size_t TIntermPreprocessorDirective::getChildCount() const
   4217 {
   4218    return 0;
   4219 }
   4220 
   4221 TIntermNode *TIntermPreprocessorDirective::getChildNode(size_t index) const
   4222 {
   4223    UNREACHABLE();
   4224    return nullptr;
   4225 }
   4226 }  // namespace sh