LCOV - code coverage report
Current view: top level - gfx/angle/src/compiler/translator - IntermNode.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1403 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 74 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //
       2             : // Copyright (c) 2002-2014 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 "compiler/translator/Diagnostics.h"
      21             : #include "compiler/translator/HashNames.h"
      22             : #include "compiler/translator/IntermNode.h"
      23             : #include "compiler/translator/SymbolTable.h"
      24             : #include "compiler/translator/util.h"
      25             : 
      26             : namespace sh
      27             : {
      28             : 
      29             : namespace
      30             : {
      31             : 
      32             : const float kPi = 3.14159265358979323846f;
      33             : const float kDegreesToRadiansMultiplier = kPi / 180.0f;
      34             : const float kRadiansToDegreesMultiplier = 180.0f / kPi;
      35             : 
      36           0 : TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
      37             : {
      38           0 :     return left > right ? left : right;
      39             : }
      40             : 
      41           0 : TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
      42             : {
      43           0 :     TConstantUnion *constUnion = new TConstantUnion[size];
      44           0 :     for (unsigned int i = 0; i < size; ++i)
      45           0 :         constUnion[i] = constant;
      46             : 
      47           0 :     return constUnion;
      48             : }
      49             : 
      50           0 : void UndefinedConstantFoldingError(const TSourceLoc &loc,
      51             :                                    TOperator op,
      52             :                                    TBasicType basicType,
      53             :                                    TDiagnostics *diagnostics,
      54             :                                    TConstantUnion *result)
      55             : {
      56           0 :     diagnostics->warning(loc, "operation result is undefined for the values passed in",
      57           0 :                          GetOperatorString(op), "");
      58             : 
      59           0 :     switch (basicType)
      60             :     {
      61             :       case EbtFloat :
      62           0 :         result->setFConst(0.0f);
      63           0 :         break;
      64             :       case EbtInt:
      65           0 :         result->setIConst(0);
      66           0 :         break;
      67             :       case EbtUInt:
      68           0 :         result->setUConst(0u);
      69           0 :         break;
      70             :       case EbtBool:
      71           0 :         result->setBConst(false);
      72           0 :         break;
      73             :       default:
      74           0 :         break;
      75             :     }
      76           0 : }
      77             : 
      78           0 : float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
      79             : {
      80           0 :     float result = 0.0f;
      81           0 :     for (size_t i = 0; i < paramArraySize; i++)
      82             :     {
      83           0 :         float f = paramArray[i].getFConst();
      84           0 :         result += f * f;
      85             :     }
      86           0 :     return sqrtf(result);
      87             : }
      88             : 
      89           0 : float VectorDotProduct(const TConstantUnion *paramArray1,
      90             :                        const TConstantUnion *paramArray2,
      91             :                        size_t paramArraySize)
      92             : {
      93           0 :     float result = 0.0f;
      94           0 :     for (size_t i = 0; i < paramArraySize; i++)
      95           0 :         result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
      96           0 :     return result;
      97             : }
      98             : 
      99           0 : TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
     100             :                                const TIntermTyped *originalNode,
     101             :                                TQualifier qualifier)
     102             : {
     103           0 :     if (constArray == nullptr)
     104             :     {
     105           0 :         return nullptr;
     106             :     }
     107           0 :     TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
     108           0 :     folded->getTypePointer()->setQualifier(qualifier);
     109           0 :     folded->setLine(originalNode->getLine());
     110           0 :     return folded;
     111             : }
     112             : 
     113           0 : angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
     114             :                                const unsigned int &rows,
     115             :                                const unsigned int &cols)
     116             : {
     117           0 :     std::vector<float> elements;
     118           0 :     for (size_t i = 0; i < rows * cols; i++)
     119           0 :         elements.push_back(paramArray[i].getFConst());
     120             :     // Transpose is used since the Matrix constructor expects arguments in row-major order,
     121             :     // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
     122             :     // so that the created matrix will have the expected dimensions after the transpose.
     123           0 :     return angle::Matrix<float>(elements, cols, rows).transpose();
     124             : }
     125             : 
     126           0 : angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
     127             : {
     128           0 :     std::vector<float> elements;
     129           0 :     for (size_t i = 0; i < size * size; i++)
     130           0 :         elements.push_back(paramArray[i].getFConst());
     131             :     // Transpose is used since the Matrix constructor expects arguments in row-major order,
     132             :     // whereas the paramArray is in column-major order.
     133           0 :     return angle::Matrix<float>(elements, size).transpose();
     134             : }
     135             : 
     136           0 : void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
     137             : {
     138             :     // Transpose is used since the input Matrix is in row-major order,
     139             :     // whereas the actual result should be in column-major order.
     140           0 :     angle::Matrix<float> result = m.transpose();
     141           0 :     std::vector<float> resultElements = result.elements();
     142           0 :     for (size_t i = 0; i < resultElements.size(); i++)
     143           0 :         resultArray[i].setFConst(resultElements[i]);
     144           0 : }
     145             : 
     146             : }  // namespace anonymous
     147             : 
     148             : 
     149             : ////////////////////////////////////////////////////////////////
     150             : //
     151             : // Member functions of the nodes used for building the tree.
     152             : //
     153             : ////////////////////////////////////////////////////////////////
     154             : 
     155           0 : void TIntermTyped::setTypePreservePrecision(const TType &t)
     156             : {
     157           0 :     TPrecision precision = getPrecision();
     158           0 :     mType = t;
     159           0 :     ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
     160           0 :     mType.setPrecision(precision);
     161           0 : }
     162             : 
     163             : #define REPLACE_IF_IS(node, type, original, replacement) \
     164             :     if (node == original) { \
     165             :         node = static_cast<type *>(replacement); \
     166             :         return true; \
     167             :     }
     168             : 
     169           0 : bool TIntermLoop::replaceChildNode(
     170             :     TIntermNode *original, TIntermNode *replacement)
     171             : {
     172           0 :     ASSERT(original != nullptr);  // This risks replacing multiple children.
     173           0 :     REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
     174           0 :     REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
     175           0 :     REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
     176           0 :     REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
     177           0 :     return false;
     178             : }
     179             : 
     180           0 : bool TIntermBranch::replaceChildNode(
     181             :     TIntermNode *original, TIntermNode *replacement)
     182             : {
     183           0 :     REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
     184           0 :     return false;
     185             : }
     186             : 
     187           0 : bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
     188             : {
     189           0 :     ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
     190           0 :     REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
     191           0 :     return false;
     192             : }
     193             : 
     194           0 : bool TIntermBinary::replaceChildNode(
     195             :     TIntermNode *original, TIntermNode *replacement)
     196             : {
     197           0 :     REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
     198           0 :     REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
     199           0 :     return false;
     200             : }
     201             : 
     202           0 : bool TIntermUnary::replaceChildNode(
     203             :     TIntermNode *original, TIntermNode *replacement)
     204             : {
     205           0 :     ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
     206           0 :     REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
     207           0 :     return false;
     208             : }
     209             : 
     210           0 : bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
     211             : {
     212           0 :     REPLACE_IF_IS(mParameters, TIntermAggregate, original, replacement);
     213           0 :     REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
     214           0 :     return false;
     215             : }
     216             : 
     217           0 : bool TIntermAggregate::replaceChildNode(
     218             :     TIntermNode *original, TIntermNode *replacement)
     219             : {
     220           0 :     return replaceChildNodeInternal(original, replacement);
     221             : }
     222             : 
     223           0 : bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
     224             : {
     225           0 :     return replaceChildNodeInternal(original, replacement);
     226             : }
     227             : 
     228           0 : bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
     229             : {
     230           0 :     return replaceChildNodeInternal(original, replacement);
     231             : }
     232             : 
     233           0 : bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
     234             : {
     235           0 :     for (size_t ii = 0; ii < getSequence()->size(); ++ii)
     236             :     {
     237           0 :         REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
     238             :     }
     239           0 :     return false;
     240             : }
     241             : 
     242           0 : bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
     243             :                                                         const TIntermSequence &replacements)
     244             : {
     245           0 :     for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
     246             :     {
     247           0 :         if (*it == original)
     248             :         {
     249           0 :             it = getSequence()->erase(it);
     250           0 :             getSequence()->insert(it, replacements.begin(), replacements.end());
     251           0 :             return true;
     252             :         }
     253             :     }
     254           0 :     return false;
     255             : }
     256             : 
     257           0 : bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
     258             :                                             const TIntermSequence &insertions)
     259             : {
     260           0 :     if (position > getSequence()->size())
     261             :     {
     262           0 :         return false;
     263             :     }
     264           0 :     auto it = getSequence()->begin() + position;
     265           0 :     getSequence()->insert(it, insertions.begin(), insertions.end());
     266           0 :     return true;
     267             : }
     268             : 
     269           0 : bool TIntermAggregate::areChildrenConstQualified()
     270             : {
     271           0 :     for (TIntermNode *&child : mSequence)
     272             :     {
     273           0 :         TIntermTyped *typed = child->getAsTyped();
     274           0 :         if (typed && typed->getQualifier() != EvqConst)
     275             :         {
     276           0 :             return false;
     277             :         }
     278             :     }
     279           0 :     return true;
     280             : }
     281             : 
     282           0 : void TIntermAggregate::setPrecisionFromChildren()
     283             : {
     284           0 :     mGotPrecisionFromChildren = true;
     285           0 :     if (getBasicType() == EbtBool)
     286             :     {
     287           0 :         mType.setPrecision(EbpUndefined);
     288           0 :         return;
     289             :     }
     290             : 
     291           0 :     TPrecision precision = EbpUndefined;
     292           0 :     TIntermSequence::iterator childIter = mSequence.begin();
     293           0 :     while (childIter != mSequence.end())
     294             :     {
     295           0 :         TIntermTyped *typed = (*childIter)->getAsTyped();
     296           0 :         if (typed)
     297           0 :             precision = GetHigherPrecision(typed->getPrecision(), precision);
     298           0 :         ++childIter;
     299             :     }
     300           0 :     mType.setPrecision(precision);
     301             : }
     302             : 
     303           0 : void TIntermAggregate::setBuiltInFunctionPrecision()
     304             : {
     305             :     // All built-ins returning bool should be handled as ops, not functions.
     306           0 :     ASSERT(getBasicType() != EbtBool);
     307             : 
     308           0 :     TPrecision precision = EbpUndefined;
     309           0 :     TIntermSequence::iterator childIter = mSequence.begin();
     310           0 :     while (childIter != mSequence.end())
     311             :     {
     312           0 :         TIntermTyped *typed = (*childIter)->getAsTyped();
     313             :         // ESSL spec section 8: texture functions get their precision from the sampler.
     314           0 :         if (typed && IsSampler(typed->getBasicType()))
     315             :         {
     316           0 :             precision = typed->getPrecision();
     317           0 :             break;
     318             :         }
     319           0 :         ++childIter;
     320             :     }
     321             :     // ESSL 3.0 spec section 8: textureSize always gets highp precision.
     322             :     // All other functions that take a sampler are assumed to be texture functions.
     323           0 :     if (mFunctionInfo.getName().find("textureSize") == 0)
     324           0 :         mType.setPrecision(EbpHigh);
     325             :     else
     326           0 :         mType.setPrecision(precision);
     327           0 : }
     328             : 
     329           0 : void TIntermBlock::appendStatement(TIntermNode *statement)
     330             : {
     331             :     // Declaration nodes with no children can appear if all the declarators just added constants to
     332             :     // the symbol table instead of generating code. They're no-ops so they aren't added to blocks.
     333           0 :     if (statement != nullptr && (statement->getAsDeclarationNode() == nullptr ||
     334           0 :                                  !statement->getAsDeclarationNode()->getSequence()->empty()))
     335             :     {
     336           0 :         mStatements.push_back(statement);
     337             :     }
     338           0 : }
     339             : 
     340           0 : void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
     341             : {
     342           0 :     ASSERT(declarator != nullptr);
     343           0 :     ASSERT(declarator->getAsSymbolNode() != nullptr ||
     344             :            (declarator->getAsBinaryNode() != nullptr &&
     345             :             declarator->getAsBinaryNode()->getOp() == EOpInitialize));
     346           0 :     ASSERT(mDeclarators.empty() ||
     347             :            declarator->getType().sameElementType(mDeclarators.back()->getAsTyped()->getType()));
     348           0 :     mDeclarators.push_back(declarator);
     349           0 : }
     350             : 
     351           0 : bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
     352             : {
     353           0 :     REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
     354           0 :     REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
     355           0 :     REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
     356           0 :     return false;
     357             : }
     358             : 
     359           0 : bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
     360             : {
     361           0 :     REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
     362           0 :     REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
     363           0 :     REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
     364           0 :     return false;
     365             : }
     366             : 
     367           0 : bool TIntermSwitch::replaceChildNode(
     368             :     TIntermNode *original, TIntermNode *replacement)
     369             : {
     370           0 :     REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
     371           0 :     REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
     372           0 :     return false;
     373             : }
     374             : 
     375           0 : bool TIntermCase::replaceChildNode(
     376             :     TIntermNode *original, TIntermNode *replacement)
     377             : {
     378           0 :     REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
     379           0 :     return false;
     380             : }
     381             : 
     382           0 : TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
     383             : {
     384             :     // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
     385             :     // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
     386             :     // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
     387           0 :     mLine = node.mLine;
     388           0 : }
     389             : 
     390           0 : bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
     391             : {
     392           0 :     TIntermAggregate *constructor = getAsAggregate();
     393           0 :     if (!constructor || !constructor->isConstructor())
     394             :     {
     395           0 :         return false;
     396             :     }
     397           0 :     for (TIntermNode *&node : *constructor->getSequence())
     398             :     {
     399           0 :         if (!node->getAsConstantUnion())
     400           0 :             return false;
     401             :     }
     402           0 :     return true;
     403             : }
     404             : 
     405             : // static
     406           0 : TIntermTyped *TIntermTyped::CreateIndexNode(int index)
     407             : {
     408           0 :     TConstantUnion *u = new TConstantUnion[1];
     409           0 :     u[0].setIConst(index);
     410             : 
     411           0 :     TType type(EbtInt, EbpUndefined, EvqConst, 1);
     412           0 :     TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
     413           0 :     return node;
     414             : }
     415             : 
     416             : // static
     417           0 : TIntermTyped *TIntermTyped::CreateZero(const TType &type)
     418             : {
     419           0 :     TType constType(type);
     420           0 :     constType.setQualifier(EvqConst);
     421             : 
     422           0 :     if (!type.isArray() && type.getBasicType() != EbtStruct)
     423             :     {
     424           0 :         ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
     425             : 
     426           0 :         size_t size       = constType.getObjectSize();
     427           0 :         TConstantUnion *u = new TConstantUnion[size];
     428           0 :         for (size_t i = 0; i < size; ++i)
     429             :         {
     430           0 :             switch (type.getBasicType())
     431             :             {
     432             :                 case EbtFloat:
     433           0 :                     u[i].setFConst(0.0f);
     434           0 :                     break;
     435             :                 case EbtInt:
     436           0 :                     u[i].setIConst(0);
     437           0 :                     break;
     438             :                 case EbtUInt:
     439           0 :                     u[i].setUConst(0u);
     440           0 :                     break;
     441             :                 case EbtBool:
     442           0 :                     u[i].setBConst(false);
     443           0 :                     break;
     444             :                 default:
     445           0 :                     UNREACHABLE();
     446             :                     return nullptr;
     447             :             }
     448             :         }
     449             : 
     450           0 :         TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
     451           0 :         return node;
     452             :     }
     453             : 
     454           0 :     TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
     455           0 :     constructor->setType(constType);
     456             : 
     457           0 :     if (type.isArray())
     458             :     {
     459           0 :         TType elementType(type);
     460           0 :         elementType.clearArrayness();
     461             : 
     462           0 :         size_t arraySize = type.getArraySize();
     463           0 :         for (size_t i = 0; i < arraySize; ++i)
     464             :         {
     465           0 :             constructor->getSequence()->push_back(CreateZero(elementType));
     466             :         }
     467             :     }
     468             :     else
     469             :     {
     470           0 :         ASSERT(type.getBasicType() == EbtStruct);
     471             : 
     472           0 :         TStructure *structure = type.getStruct();
     473           0 :         for (const auto &field : structure->fields())
     474             :         {
     475           0 :             constructor->getSequence()->push_back(CreateZero(*field->type()));
     476             :         }
     477             :     }
     478             : 
     479           0 :     return constructor;
     480             : }
     481             : 
     482           0 : TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
     483             : {
     484           0 :     mUnionArrayPointer = node.mUnionArrayPointer;
     485           0 : }
     486             : 
     487           0 : void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
     488             : {
     489           0 :     setName(function.getMangledName());
     490           0 :     setId(function.getUniqueId());
     491           0 : }
     492             : 
     493           0 : TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
     494             :     : TIntermOperator(node),
     495           0 :       mUserDefined(node.mUserDefined),
     496           0 :       mUseEmulatedFunction(node.mUseEmulatedFunction),
     497           0 :       mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
     498           0 :       mFunctionInfo(node.mFunctionInfo)
     499             : {
     500           0 :     for (TIntermNode *child : node.mSequence)
     501             :     {
     502           0 :         TIntermTyped *typedChild = child->getAsTyped();
     503           0 :         ASSERT(typedChild != nullptr);
     504           0 :         TIntermTyped *childCopy = typedChild->deepCopy();
     505           0 :         mSequence.push_back(childCopy);
     506             :     }
     507           0 : }
     508             : 
     509           0 : TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
     510             : {
     511           0 :     TIntermTyped *operandCopy = node.mOperand->deepCopy();
     512           0 :     ASSERT(operandCopy != nullptr);
     513           0 :     mOperand = operandCopy;
     514           0 : }
     515             : 
     516           0 : TIntermBinary::TIntermBinary(const TIntermBinary &node)
     517           0 :     : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
     518             : {
     519           0 :     TIntermTyped *leftCopy  = node.mLeft->deepCopy();
     520           0 :     TIntermTyped *rightCopy = node.mRight->deepCopy();
     521           0 :     ASSERT(leftCopy != nullptr && rightCopy != nullptr);
     522           0 :     mLeft  = leftCopy;
     523           0 :     mRight = rightCopy;
     524           0 : }
     525             : 
     526           0 : TIntermUnary::TIntermUnary(const TIntermUnary &node)
     527           0 :     : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
     528             : {
     529           0 :     TIntermTyped *operandCopy = node.mOperand->deepCopy();
     530           0 :     ASSERT(operandCopy != nullptr);
     531           0 :     mOperand = operandCopy;
     532           0 : }
     533             : 
     534           0 : TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
     535             : {
     536           0 :     TIntermTyped *conditionCopy = node.mCondition->deepCopy();
     537           0 :     TIntermTyped *trueCopy      = node.mTrueExpression->deepCopy();
     538           0 :     TIntermTyped *falseCopy     = node.mFalseExpression->deepCopy();
     539           0 :     ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
     540           0 :     mCondition       = conditionCopy;
     541           0 :     mTrueExpression  = trueCopy;
     542           0 :     mFalseExpression = falseCopy;
     543           0 : }
     544             : 
     545           0 : bool TIntermOperator::isAssignment() const
     546             : {
     547           0 :     return IsAssignment(mOp);
     548             : }
     549             : 
     550           0 : bool TIntermOperator::isMultiplication() const
     551             : {
     552           0 :     switch (mOp)
     553             :     {
     554             :       case EOpMul:
     555             :       case EOpMatrixTimesMatrix:
     556             :       case EOpMatrixTimesVector:
     557             :       case EOpMatrixTimesScalar:
     558             :       case EOpVectorTimesMatrix:
     559             :       case EOpVectorTimesScalar:
     560           0 :         return true;
     561             :       default:
     562           0 :         return false;
     563             :     }
     564             : }
     565             : 
     566             : //
     567             : // returns true if the operator is for one of the constructors
     568             : //
     569           0 : bool TIntermOperator::isConstructor() const
     570             : {
     571           0 :     switch (mOp)
     572             :     {
     573             :       case EOpConstructVec2:
     574             :       case EOpConstructVec3:
     575             :       case EOpConstructVec4:
     576             :       case EOpConstructMat2:
     577             :       case EOpConstructMat2x3:
     578             :       case EOpConstructMat2x4:
     579             :       case EOpConstructMat3x2:
     580             :       case EOpConstructMat3:
     581             :       case EOpConstructMat3x4:
     582             :       case EOpConstructMat4x2:
     583             :       case EOpConstructMat4x3:
     584             :       case EOpConstructMat4:
     585             :       case EOpConstructFloat:
     586             :       case EOpConstructIVec2:
     587             :       case EOpConstructIVec3:
     588             :       case EOpConstructIVec4:
     589             :       case EOpConstructInt:
     590             :       case EOpConstructUVec2:
     591             :       case EOpConstructUVec3:
     592             :       case EOpConstructUVec4:
     593             :       case EOpConstructUInt:
     594             :       case EOpConstructBVec2:
     595             :       case EOpConstructBVec3:
     596             :       case EOpConstructBVec4:
     597             :       case EOpConstructBool:
     598             :       case EOpConstructStruct:
     599           0 :         return true;
     600             :       default:
     601           0 :         return false;
     602             :     }
     603             : }
     604             : 
     605           0 : TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
     606             : {
     607           0 :     if (left.isMatrix())
     608             :     {
     609           0 :         if (right.isMatrix())
     610             :         {
     611           0 :             return EOpMatrixTimesMatrix;
     612             :         }
     613             :         else
     614             :         {
     615           0 :             if (right.isVector())
     616             :             {
     617           0 :                 return EOpMatrixTimesVector;
     618             :             }
     619             :             else
     620             :             {
     621           0 :                 return EOpMatrixTimesScalar;
     622             :             }
     623             :         }
     624             :     }
     625             :     else
     626             :     {
     627           0 :         if (right.isMatrix())
     628             :         {
     629           0 :             if (left.isVector())
     630             :             {
     631           0 :                 return EOpVectorTimesMatrix;
     632             :             }
     633             :             else
     634             :             {
     635           0 :                 return EOpMatrixTimesScalar;
     636             :             }
     637             :         }
     638             :         else
     639             :         {
     640             :             // Neither operand is a matrix.
     641           0 :             if (left.isVector() == right.isVector())
     642             :             {
     643             :                 // Leave as component product.
     644           0 :                 return EOpMul;
     645             :             }
     646             :             else
     647             :             {
     648           0 :                 return EOpVectorTimesScalar;
     649             :             }
     650             :         }
     651             :     }
     652             : }
     653             : 
     654           0 : TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
     655             : {
     656           0 :     if (left.isMatrix())
     657             :     {
     658           0 :         if (right.isMatrix())
     659             :         {
     660           0 :             return EOpMatrixTimesMatrixAssign;
     661             :         }
     662             :         else
     663             :         {
     664             :             // right should be scalar, but this may not be validated yet.
     665           0 :             return EOpMatrixTimesScalarAssign;
     666             :         }
     667             :     }
     668             :     else
     669             :     {
     670           0 :         if (right.isMatrix())
     671             :         {
     672             :             // Left should be a vector, but this may not be validated yet.
     673           0 :             return EOpVectorTimesMatrixAssign;
     674             :         }
     675             :         else
     676             :         {
     677             :             // Neither operand is a matrix.
     678           0 :             if (left.isVector() == right.isVector())
     679             :             {
     680             :                 // Leave as component product.
     681           0 :                 return EOpMulAssign;
     682             :             }
     683             :             else
     684             :             {
     685             :                 // left should be vector and right should be scalar, but this may not be validated
     686             :                 // yet.
     687           0 :                 return EOpVectorTimesScalarAssign;
     688             :             }
     689             :         }
     690             :     }
     691             : }
     692             : 
     693             : //
     694             : // Make sure the type of a unary operator is appropriate for its
     695             : // combination of operation and operand type.
     696             : //
     697           0 : void TIntermUnary::promote()
     698             : {
     699           0 :     TQualifier resultQualifier = EvqTemporary;
     700           0 :     if (mOperand->getQualifier() == EvqConst)
     701           0 :         resultQualifier = EvqConst;
     702             : 
     703             :     unsigned char operandPrimarySize =
     704           0 :         static_cast<unsigned char>(mOperand->getType().getNominalSize());
     705           0 :     switch (mOp)
     706             :     {
     707             :         case EOpFloatBitsToInt:
     708           0 :             setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
     709           0 :             break;
     710             :         case EOpFloatBitsToUint:
     711           0 :             setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
     712           0 :             break;
     713             :         case EOpIntBitsToFloat:
     714             :         case EOpUintBitsToFloat:
     715           0 :             setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
     716           0 :             break;
     717             :         case EOpPackSnorm2x16:
     718             :         case EOpPackUnorm2x16:
     719             :         case EOpPackHalf2x16:
     720           0 :             setType(TType(EbtUInt, EbpHigh, resultQualifier));
     721           0 :             break;
     722             :         case EOpUnpackSnorm2x16:
     723             :         case EOpUnpackUnorm2x16:
     724           0 :             setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
     725           0 :             break;
     726             :         case EOpUnpackHalf2x16:
     727           0 :             setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
     728           0 :             break;
     729             :         case EOpAny:
     730             :         case EOpAll:
     731           0 :             setType(TType(EbtBool, EbpUndefined, resultQualifier));
     732           0 :             break;
     733             :         case EOpLength:
     734             :         case EOpDeterminant:
     735           0 :             setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
     736           0 :             break;
     737             :         case EOpTranspose:
     738           0 :             setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
     739           0 :                           static_cast<unsigned char>(mOperand->getType().getRows()),
     740           0 :                           static_cast<unsigned char>(mOperand->getType().getCols())));
     741           0 :             break;
     742             :         case EOpIsInf:
     743             :         case EOpIsNan:
     744           0 :             setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
     745           0 :             break;
     746             :         default:
     747           0 :             setType(mOperand->getType());
     748           0 :             mType.setQualifier(resultQualifier);
     749           0 :             break;
     750             :     }
     751           0 : }
     752             : 
     753           0 : TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
     754           0 :     : TIntermTyped(TType(EbtFloat, EbpUndefined)),
     755             :       mOperand(operand),
     756           0 :       mSwizzleOffsets(swizzleOffsets)
     757             : {
     758           0 :     ASSERT(mSwizzleOffsets.size() <= 4);
     759           0 :     promote();
     760           0 : }
     761             : 
     762           0 : TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
     763           0 :     : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
     764             : {
     765           0 :     promote();
     766           0 : }
     767             : 
     768           0 : TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
     769           0 :     : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
     770             : {
     771           0 :     promote();
     772           0 : }
     773             : 
     774           0 : TIntermTernary::TIntermTernary(TIntermTyped *cond,
     775             :                                TIntermTyped *trueExpression,
     776           0 :                                TIntermTyped *falseExpression)
     777             :     : TIntermTyped(trueExpression->getType()),
     778             :       mCondition(cond),
     779             :       mTrueExpression(trueExpression),
     780           0 :       mFalseExpression(falseExpression)
     781             : {
     782           0 :     getTypePointer()->setQualifier(
     783           0 :         TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
     784           0 : }
     785             : 
     786             : // static
     787           0 : TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
     788             :                                               TIntermTyped *trueExpression,
     789             :                                               TIntermTyped *falseExpression)
     790             : {
     791           0 :     if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
     792           0 :         falseExpression->getQualifier() == EvqConst)
     793             :     {
     794           0 :         return EvqConst;
     795             :     }
     796           0 :     return EvqTemporary;
     797             : }
     798             : 
     799           0 : void TIntermSwizzle::promote()
     800             : {
     801           0 :     TQualifier resultQualifier = EvqTemporary;
     802           0 :     if (mOperand->getQualifier() == EvqConst)
     803           0 :         resultQualifier = EvqConst;
     804             : 
     805           0 :     auto numFields = mSwizzleOffsets.size();
     806           0 :     setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
     807           0 :                   static_cast<unsigned char>(numFields)));
     808           0 : }
     809             : 
     810           0 : bool TIntermSwizzle::hasDuplicateOffsets() const
     811             : {
     812           0 :     int offsetCount[4] = {0u, 0u, 0u, 0u};
     813           0 :     for (const auto offset : mSwizzleOffsets)
     814             :     {
     815           0 :         offsetCount[offset]++;
     816           0 :         if (offsetCount[offset] > 1)
     817             :         {
     818           0 :             return true;
     819             :         }
     820             :     }
     821           0 :     return false;
     822             : }
     823             : 
     824           0 : void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
     825             : {
     826           0 :     for (const int offset : mSwizzleOffsets)
     827             :     {
     828           0 :         switch (offset)
     829             :         {
     830             :         case 0:
     831           0 :             *out << "x";
     832           0 :             break;
     833             :         case 1:
     834           0 :             *out << "y";
     835           0 :             break;
     836             :         case 2:
     837           0 :             *out << "z";
     838           0 :             break;
     839             :         case 3:
     840           0 :             *out << "w";
     841           0 :             break;
     842             :         default:
     843           0 :             UNREACHABLE();
     844             :         }
     845             :     }
     846           0 : }
     847             : 
     848           0 : TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
     849             :                                             const TIntermTyped *left,
     850             :                                             const TIntermTyped *right)
     851             : {
     852             :     // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
     853           0 :     if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
     854           0 :         right->getQualifier() != EvqConst)
     855             :     {
     856           0 :         return EvqTemporary;
     857             :     }
     858           0 :     return EvqConst;
     859             : }
     860             : 
     861             : // Establishes the type of the result of the binary operation.
     862           0 : void TIntermBinary::promote()
     863             : {
     864           0 :     ASSERT(!isMultiplication() ||
     865             :            mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
     866             : 
     867             :     // Comma is handled as a special case.
     868           0 :     if (mOp == EOpComma)
     869             :     {
     870           0 :         setType(mRight->getType());
     871           0 :         return;
     872             :     }
     873             : 
     874             :     // Base assumption:  just make the type the same as the left
     875             :     // operand.  Then only deviations from this need be coded.
     876           0 :     setType(mLeft->getType());
     877             : 
     878           0 :     TQualifier resultQualifier = EvqConst;
     879             :     // Binary operations results in temporary variables unless both
     880             :     // operands are const.
     881           0 :     if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
     882             :     {
     883           0 :         resultQualifier = EvqTemporary;
     884           0 :         getTypePointer()->setQualifier(EvqTemporary);
     885             :     }
     886             : 
     887             :     // Handle indexing ops.
     888           0 :     switch (mOp)
     889             :     {
     890             :         case EOpIndexDirect:
     891             :         case EOpIndexIndirect:
     892           0 :             if (mLeft->isArray())
     893             :             {
     894           0 :                 mType.clearArrayness();
     895             :             }
     896           0 :             else if (mLeft->isMatrix())
     897             :             {
     898           0 :                 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
     899           0 :                               static_cast<unsigned char>(mLeft->getRows())));
     900             :             }
     901           0 :             else if (mLeft->isVector())
     902             :             {
     903           0 :                 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
     904             :             }
     905             :             else
     906             :             {
     907           0 :                 UNREACHABLE();
     908             :             }
     909           0 :             return;
     910             :         case EOpIndexDirectStruct:
     911             :         {
     912           0 :             const TFieldList &fields = mLeft->getType().getStruct()->fields();
     913           0 :             const int i              = mRight->getAsConstantUnion()->getIConst(0);
     914           0 :             setType(*fields[i]->type());
     915           0 :             getTypePointer()->setQualifier(resultQualifier);
     916           0 :             return;
     917             :         }
     918             :         case EOpIndexDirectInterfaceBlock:
     919             :         {
     920           0 :             const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
     921           0 :             const int i              = mRight->getAsConstantUnion()->getIConst(0);
     922           0 :             setType(*fields[i]->type());
     923           0 :             getTypePointer()->setQualifier(resultQualifier);
     924           0 :             return;
     925             :         }
     926             :         default:
     927           0 :             break;
     928             :     }
     929             : 
     930           0 :     ASSERT(mLeft->isArray() == mRight->isArray());
     931             : 
     932             :     // The result gets promoted to the highest precision.
     933           0 :     TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
     934           0 :     getTypePointer()->setPrecision(higherPrecision);
     935             : 
     936             :     const int nominalSize =
     937           0 :         std::max(mLeft->getNominalSize(), mRight->getNominalSize());
     938             : 
     939             :     //
     940             :     // All scalars or structs. Code after this test assumes this case is removed!
     941             :     //
     942           0 :     if (nominalSize == 1)
     943             :     {
     944           0 :         switch (mOp)
     945             :         {
     946             :           //
     947             :           // Promote to conditional
     948             :           //
     949             :           case EOpEqual:
     950             :           case EOpNotEqual:
     951             :           case EOpLessThan:
     952             :           case EOpGreaterThan:
     953             :           case EOpLessThanEqual:
     954             :           case EOpGreaterThanEqual:
     955           0 :               setType(TType(EbtBool, EbpUndefined, resultQualifier));
     956           0 :               break;
     957             : 
     958             :           //
     959             :           // And and Or operate on conditionals
     960             :           //
     961             :           case EOpLogicalAnd:
     962             :           case EOpLogicalXor:
     963             :           case EOpLogicalOr:
     964           0 :             ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
     965           0 :             setType(TType(EbtBool, EbpUndefined, resultQualifier));
     966           0 :             break;
     967             : 
     968             :           default:
     969           0 :             break;
     970             :         }
     971           0 :         return;
     972             :     }
     973             : 
     974             :     // If we reach here, at least one of the operands is vector or matrix.
     975             :     // The other operand could be a scalar, vector, or matrix.
     976           0 :     TBasicType basicType = mLeft->getBasicType();
     977             : 
     978           0 :     switch (mOp)
     979             :     {
     980             :         case EOpMul:
     981           0 :             break;
     982             :         case EOpMatrixTimesScalar:
     983           0 :             if (mRight->isMatrix())
     984             :             {
     985           0 :                 setType(TType(basicType, higherPrecision, resultQualifier,
     986           0 :                               static_cast<unsigned char>(mRight->getCols()),
     987           0 :                               static_cast<unsigned char>(mRight->getRows())));
     988             :             }
     989           0 :             break;
     990             :         case EOpMatrixTimesVector:
     991           0 :             setType(TType(basicType, higherPrecision, resultQualifier,
     992           0 :                           static_cast<unsigned char>(mLeft->getRows()), 1));
     993           0 :             break;
     994             :         case EOpMatrixTimesMatrix:
     995           0 :             setType(TType(basicType, higherPrecision, resultQualifier,
     996           0 :                           static_cast<unsigned char>(mRight->getCols()),
     997           0 :                           static_cast<unsigned char>(mLeft->getRows())));
     998           0 :             break;
     999             :         case EOpVectorTimesScalar:
    1000           0 :             setType(TType(basicType, higherPrecision, resultQualifier,
    1001           0 :                           static_cast<unsigned char>(nominalSize), 1));
    1002           0 :             break;
    1003             :         case EOpVectorTimesMatrix:
    1004           0 :             setType(TType(basicType, higherPrecision, resultQualifier,
    1005           0 :                           static_cast<unsigned char>(mRight->getCols()), 1));
    1006           0 :             break;
    1007             :         case EOpMulAssign:
    1008             :         case EOpVectorTimesScalarAssign:
    1009             :         case EOpVectorTimesMatrixAssign:
    1010             :         case EOpMatrixTimesScalarAssign:
    1011             :         case EOpMatrixTimesMatrixAssign:
    1012           0 :             ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
    1013           0 :             break;
    1014             :         case EOpAssign:
    1015             :         case EOpInitialize:
    1016           0 :             ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
    1017             :                    (mLeft->getSecondarySize() == mRight->getSecondarySize()));
    1018           0 :             break;
    1019             :         case EOpAdd:
    1020             :         case EOpSub:
    1021             :         case EOpDiv:
    1022             :         case EOpIMod:
    1023             :         case EOpBitShiftLeft:
    1024             :         case EOpBitShiftRight:
    1025             :         case EOpBitwiseAnd:
    1026             :         case EOpBitwiseXor:
    1027             :         case EOpBitwiseOr:
    1028             :         case EOpAddAssign:
    1029             :         case EOpSubAssign:
    1030             :         case EOpDivAssign:
    1031             :         case EOpIModAssign:
    1032             :         case EOpBitShiftLeftAssign:
    1033             :         case EOpBitShiftRightAssign:
    1034             :         case EOpBitwiseAndAssign:
    1035             :         case EOpBitwiseXorAssign:
    1036             :         case EOpBitwiseOrAssign:
    1037             :         {
    1038             :             const int secondarySize =
    1039           0 :                 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
    1040           0 :             setType(TType(basicType, higherPrecision, resultQualifier,
    1041             :                           static_cast<unsigned char>(nominalSize),
    1042           0 :                           static_cast<unsigned char>(secondarySize)));
    1043           0 :             ASSERT(!mLeft->isArray() && !mRight->isArray());
    1044           0 :             break;
    1045             :         }
    1046             :         case EOpEqual:
    1047             :         case EOpNotEqual:
    1048             :         case EOpLessThan:
    1049             :         case EOpGreaterThan:
    1050             :         case EOpLessThanEqual:
    1051             :         case EOpGreaterThanEqual:
    1052           0 :             ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
    1053             :                    (mLeft->getSecondarySize() == mRight->getSecondarySize()));
    1054           0 :             setType(TType(EbtBool, EbpUndefined, resultQualifier));
    1055           0 :             break;
    1056             : 
    1057             :         case EOpIndexDirect:
    1058             :         case EOpIndexIndirect:
    1059             :         case EOpIndexDirectInterfaceBlock:
    1060             :         case EOpIndexDirectStruct:
    1061             :             // These ops should be already fully handled.
    1062           0 :             UNREACHABLE();
    1063             :             break;
    1064             :         default:
    1065           0 :             UNREACHABLE();
    1066             :             break;
    1067             :     }
    1068             : }
    1069             : 
    1070           0 : const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
    1071             : {
    1072           0 :     if (isArray())
    1073             :     {
    1074           0 :         ASSERT(index < static_cast<int>(getType().getArraySize()));
    1075           0 :         TType arrayElementType = getType();
    1076           0 :         arrayElementType.clearArrayness();
    1077           0 :         size_t arrayElementSize = arrayElementType.getObjectSize();
    1078           0 :         return &mUnionArrayPointer[arrayElementSize * index];
    1079             :     }
    1080           0 :     else if (isMatrix())
    1081             :     {
    1082           0 :         ASSERT(index < getType().getCols());
    1083           0 :         int size = getType().getRows();
    1084           0 :         return &mUnionArrayPointer[size * index];
    1085             :     }
    1086           0 :     else if (isVector())
    1087             :     {
    1088           0 :         ASSERT(index < getType().getNominalSize());
    1089           0 :         return &mUnionArrayPointer[index];
    1090             :     }
    1091             :     else
    1092             :     {
    1093           0 :         UNREACHABLE();
    1094             :         return nullptr;
    1095             :     }
    1096             : }
    1097             : 
    1098           0 : TIntermTyped *TIntermSwizzle::fold()
    1099             : {
    1100           0 :     TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
    1101           0 :     if (operandConstant == nullptr)
    1102             :     {
    1103           0 :         return nullptr;
    1104             :     }
    1105             : 
    1106           0 :     TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
    1107           0 :     for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
    1108             :     {
    1109           0 :         constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
    1110             :     }
    1111           0 :     return CreateFoldedNode(constArray, this, mType.getQualifier());
    1112             : }
    1113             : 
    1114           0 : TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
    1115             : {
    1116           0 :     TIntermConstantUnion *leftConstant  = mLeft->getAsConstantUnion();
    1117           0 :     TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
    1118           0 :     switch (mOp)
    1119             :     {
    1120             :         case EOpIndexDirect:
    1121             :         {
    1122           0 :             if (leftConstant == nullptr || rightConstant == nullptr)
    1123             :             {
    1124           0 :                 return nullptr;
    1125             :             }
    1126           0 :             int index = rightConstant->getIConst(0);
    1127             : 
    1128           0 :             const TConstantUnion *constArray = leftConstant->foldIndexing(index);
    1129           0 :             return CreateFoldedNode(constArray, this, mType.getQualifier());
    1130             :         }
    1131             :         case EOpIndexDirectStruct:
    1132             :         {
    1133           0 :             if (leftConstant == nullptr || rightConstant == nullptr)
    1134             :             {
    1135           0 :                 return nullptr;
    1136             :             }
    1137           0 :             const TFieldList &fields = mLeft->getType().getStruct()->fields();
    1138           0 :             size_t index             = static_cast<size_t>(rightConstant->getIConst(0));
    1139             : 
    1140           0 :             size_t previousFieldsSize = 0;
    1141           0 :             for (size_t i = 0; i < index; ++i)
    1142             :             {
    1143           0 :                 previousFieldsSize += fields[i]->type()->getObjectSize();
    1144             :             }
    1145             : 
    1146           0 :             const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
    1147           0 :             return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
    1148             :         }
    1149             :         case EOpIndexIndirect:
    1150             :         case EOpIndexDirectInterfaceBlock:
    1151             :             // Can never be constant folded.
    1152           0 :             return nullptr;
    1153             :         default:
    1154             :         {
    1155           0 :             if (leftConstant == nullptr || rightConstant == nullptr)
    1156             :             {
    1157           0 :                 return nullptr;
    1158             :             }
    1159             :             TConstantUnion *constArray =
    1160           0 :                 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
    1161             : 
    1162             :             // Nodes may be constant folded without being qualified as constant.
    1163           0 :             return CreateFoldedNode(constArray, this, mType.getQualifier());
    1164             :         }
    1165             :     }
    1166             : }
    1167             : 
    1168           0 : TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
    1169             : {
    1170           0 :     TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
    1171           0 :     if (operandConstant == nullptr)
    1172             :     {
    1173           0 :         return nullptr;
    1174             :     }
    1175             : 
    1176           0 :     TConstantUnion *constArray = nullptr;
    1177           0 :     switch (mOp)
    1178             :     {
    1179             :       case EOpAny:
    1180             :       case EOpAll:
    1181             :       case EOpLength:
    1182             :       case EOpTranspose:
    1183             :       case EOpDeterminant:
    1184             :       case EOpInverse:
    1185             :       case EOpPackSnorm2x16:
    1186             :       case EOpUnpackSnorm2x16:
    1187             :       case EOpPackUnorm2x16:
    1188             :       case EOpUnpackUnorm2x16:
    1189             :       case EOpPackHalf2x16:
    1190             :       case EOpUnpackHalf2x16:
    1191           0 :           constArray = operandConstant->foldUnaryNonComponentWise(mOp);
    1192           0 :           break;
    1193             :       default:
    1194           0 :           constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
    1195           0 :           break;
    1196             :     }
    1197             : 
    1198             :     // Nodes may be constant folded without being qualified as constant.
    1199           0 :     return CreateFoldedNode(constArray, this, mType.getQualifier());
    1200             : }
    1201             : 
    1202           0 : TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
    1203             : {
    1204             :     // Make sure that all params are constant before actual constant folding.
    1205           0 :     for (auto *param : *getSequence())
    1206             :     {
    1207           0 :         if (param->getAsConstantUnion() == nullptr)
    1208             :         {
    1209           0 :             return nullptr;
    1210             :         }
    1211             :     }
    1212           0 :     TConstantUnion *constArray = nullptr;
    1213           0 :     if (isConstructor())
    1214           0 :         constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
    1215             :     else
    1216           0 :         constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
    1217             : 
    1218             :     // Nodes may be constant folded without being qualified as constant.
    1219           0 :     TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
    1220           0 :     return CreateFoldedNode(constArray, this, resultQualifier);
    1221             : }
    1222             : 
    1223             : //
    1224             : // The fold functions see if an operation on a constant can be done in place,
    1225             : // without generating run-time code.
    1226             : //
    1227             : // Returns the constant value to keep using or nullptr.
    1228             : //
    1229           0 : TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
    1230             :                                                  TIntermConstantUnion *rightNode,
    1231             :                                                  TDiagnostics *diagnostics,
    1232             :                                                  const TSourceLoc &line)
    1233             : {
    1234           0 :     const TConstantUnion *leftArray  = getUnionArrayPointer();
    1235           0 :     const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
    1236             : 
    1237           0 :     ASSERT(leftArray && rightArray);
    1238             : 
    1239           0 :     size_t objectSize = getType().getObjectSize();
    1240             : 
    1241             :     // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
    1242           0 :     if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
    1243             :     {
    1244           0 :         rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
    1245             :     }
    1246           0 :     else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
    1247             :     {
    1248             :         // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
    1249           0 :         leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
    1250           0 :         objectSize = rightNode->getType().getObjectSize();
    1251             :     }
    1252             : 
    1253           0 :     TConstantUnion *resultArray = nullptr;
    1254             : 
    1255           0 :     switch(op)
    1256             :     {
    1257             :       case EOpAdd:
    1258           0 :         resultArray = new TConstantUnion[objectSize];
    1259           0 :         for (size_t i = 0; i < objectSize; i++)
    1260           0 :             resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
    1261           0 :         break;
    1262             :       case EOpSub:
    1263           0 :         resultArray = new TConstantUnion[objectSize];
    1264           0 :         for (size_t i = 0; i < objectSize; i++)
    1265           0 :             resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
    1266           0 :         break;
    1267             : 
    1268             :       case EOpMul:
    1269             :       case EOpVectorTimesScalar:
    1270             :       case EOpMatrixTimesScalar:
    1271           0 :         resultArray = new TConstantUnion[objectSize];
    1272           0 :         for (size_t i = 0; i < objectSize; i++)
    1273           0 :             resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
    1274           0 :         break;
    1275             : 
    1276             :       case EOpMatrixTimesMatrix:
    1277             :         {
    1278             :             // TODO(jmadll): This code should check for overflows.
    1279           0 :             ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
    1280             : 
    1281           0 :             const int leftCols = getCols();
    1282           0 :             const int leftRows = getRows();
    1283           0 :             const int rightCols = rightNode->getType().getCols();
    1284           0 :             const int rightRows = rightNode->getType().getRows();
    1285           0 :             const int resultCols = rightCols;
    1286           0 :             const int resultRows = leftRows;
    1287             : 
    1288           0 :             resultArray = new TConstantUnion[resultCols * resultRows];
    1289           0 :             for (int row = 0; row < resultRows; row++)
    1290             :             {
    1291           0 :                 for (int column = 0; column < resultCols; column++)
    1292             :                 {
    1293           0 :                     resultArray[resultRows * column + row].setFConst(0.0f);
    1294           0 :                     for (int i = 0; i < leftCols; i++)
    1295             :                     {
    1296           0 :                         resultArray[resultRows * column + row].setFConst(
    1297           0 :                             resultArray[resultRows * column + row].getFConst() +
    1298           0 :                             leftArray[i * leftRows + row].getFConst() *
    1299           0 :                             rightArray[column * rightRows + i].getFConst());
    1300             :                     }
    1301             :                 }
    1302             :             }
    1303             :         }
    1304           0 :         break;
    1305             : 
    1306             :       case EOpDiv:
    1307             :       case EOpIMod:
    1308             :         {
    1309           0 :             resultArray = new TConstantUnion[objectSize];
    1310           0 :             for (size_t i = 0; i < objectSize; i++)
    1311             :             {
    1312           0 :                 switch (getType().getBasicType())
    1313             :                 {
    1314             :                   case EbtFloat:
    1315             :                   {
    1316           0 :                       ASSERT(op == EOpDiv);
    1317           0 :                       float dividend = leftArray[i].getFConst();
    1318           0 :                       float divisor  = rightArray[i].getFConst();
    1319           0 :                       if (divisor == 0.0f)
    1320             :                       {
    1321           0 :                           if (dividend == 0.0f)
    1322             :                           {
    1323           0 :                               diagnostics->warning(
    1324             :                                   getLine(),
    1325             :                                   "Zero divided by zero during constant folding generated NaN", "/",
    1326           0 :                                   "");
    1327           0 :                               resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
    1328             :                           }
    1329             :                           else
    1330             :                           {
    1331           0 :                               diagnostics->warning(
    1332           0 :                                   getLine(), "Divide by zero during constant folding", "/", "");
    1333           0 :                               bool negativeResult = std::signbit(dividend) != std::signbit(divisor);
    1334           0 :                               resultArray[i].setFConst(
    1335           0 :                                   negativeResult ? -std::numeric_limits<float>::infinity()
    1336           0 :                                                  : std::numeric_limits<float>::infinity());
    1337             :                           }
    1338             :                       }
    1339           0 :                       else if (gl::isInf(dividend) && gl::isInf(divisor))
    1340             :                       {
    1341           0 :                           diagnostics->warning(
    1342             :                               getLine(),
    1343             :                               "Infinity divided by infinity during constant folding generated NaN",
    1344           0 :                               "/", "");
    1345           0 :                           resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
    1346             :                       }
    1347             :                       else
    1348             :                       {
    1349           0 :                           float result = dividend / divisor;
    1350           0 :                           if (!gl::isInf(dividend) && gl::isInf(result))
    1351             :                           {
    1352           0 :                               diagnostics->warning(
    1353             :                                   getLine(), "Constant folded division overflowed to infinity", "/",
    1354           0 :                                   "");
    1355             :                           }
    1356           0 :                           resultArray[i].setFConst(result);
    1357             :                       }
    1358           0 :                       break;
    1359             :                   }
    1360             :                   case EbtInt:
    1361           0 :                     if (rightArray[i] == 0)
    1362             :                     {
    1363           0 :                         diagnostics->warning(
    1364           0 :                             getLine(), "Divide by zero error during constant folding", "/", "");
    1365           0 :                         resultArray[i].setIConst(INT_MAX);
    1366             :                     }
    1367             :                     else
    1368             :                     {
    1369           0 :                         int lhs     = leftArray[i].getIConst();
    1370           0 :                         int divisor = rightArray[i].getIConst();
    1371           0 :                         if (op == EOpDiv)
    1372             :                         {
    1373             :                             // Check for the special case where the minimum representable number is
    1374             :                             // divided by -1. If left alone this leads to integer overflow in C++.
    1375             :                             // ESSL 3.00.6 section 4.1.3 Integers:
    1376             :                             // "However, for the case where the minimum representable value is
    1377             :                             // divided by -1, it is allowed to return either the minimum
    1378             :                             // representable value or the maximum representable value."
    1379           0 :                             if (lhs == -0x7fffffff - 1 && divisor == -1)
    1380             :                             {
    1381           0 :                                 resultArray[i].setIConst(0x7fffffff);
    1382             :                             }
    1383             :                             else
    1384             :                             {
    1385           0 :                                 resultArray[i].setIConst(lhs / divisor);
    1386             :                             }
    1387             :                         }
    1388             :                         else
    1389             :                         {
    1390           0 :                             ASSERT(op == EOpIMod);
    1391           0 :                             if (lhs < 0 || divisor < 0)
    1392             :                             {
    1393             :                                 // ESSL 3.00.6 section 5.9: Results of modulus are undefined when
    1394             :                                 // either one of the operands is negative.
    1395           0 :                                 diagnostics->warning(getLine(),
    1396             :                                                      "Negative modulus operator operand "
    1397             :                                                      "encountered during constant folding",
    1398           0 :                                                      "%", "");
    1399           0 :                                 resultArray[i].setIConst(0);
    1400             :                             }
    1401             :                             else
    1402             :                             {
    1403           0 :                                 resultArray[i].setIConst(lhs % divisor);
    1404             :                             }
    1405             :                         }
    1406             :                     }
    1407           0 :                     break;
    1408             : 
    1409             :                   case EbtUInt:
    1410           0 :                     if (rightArray[i] == 0)
    1411             :                     {
    1412           0 :                         diagnostics->warning(
    1413           0 :                             getLine(), "Divide by zero error during constant folding", "/", "");
    1414           0 :                         resultArray[i].setUConst(UINT_MAX);
    1415             :                     }
    1416             :                     else
    1417             :                     {
    1418           0 :                         if (op == EOpDiv)
    1419             :                         {
    1420           0 :                             resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
    1421             :                         }
    1422             :                         else
    1423             :                         {
    1424           0 :                             ASSERT(op == EOpIMod);
    1425           0 :                             resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
    1426             :                         }
    1427             :                     }
    1428           0 :                     break;
    1429             : 
    1430             :                   default:
    1431           0 :                       UNREACHABLE();
    1432             :                       return nullptr;
    1433             :                 }
    1434             :             }
    1435             :         }
    1436           0 :         break;
    1437             : 
    1438             :       case EOpMatrixTimesVector:
    1439             :         {
    1440             :             // TODO(jmadll): This code should check for overflows.
    1441           0 :             ASSERT(rightNode->getBasicType() == EbtFloat);
    1442             : 
    1443           0 :             const int matrixCols = getCols();
    1444           0 :             const int matrixRows = getRows();
    1445             : 
    1446           0 :             resultArray = new TConstantUnion[matrixRows];
    1447             : 
    1448           0 :             for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
    1449             :             {
    1450           0 :                 resultArray[matrixRow].setFConst(0.0f);
    1451           0 :                 for (int col = 0; col < matrixCols; col++)
    1452             :                 {
    1453           0 :                     resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
    1454           0 :                                                      leftArray[col * matrixRows + matrixRow].getFConst() *
    1455           0 :                                                      rightArray[col].getFConst());
    1456             :                 }
    1457             :             }
    1458             :         }
    1459           0 :         break;
    1460             : 
    1461             :       case EOpVectorTimesMatrix:
    1462             :         {
    1463             :             // TODO(jmadll): This code should check for overflows.
    1464           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1465             : 
    1466           0 :             const int matrixCols = rightNode->getType().getCols();
    1467           0 :             const int matrixRows = rightNode->getType().getRows();
    1468             : 
    1469           0 :             resultArray = new TConstantUnion[matrixCols];
    1470             : 
    1471           0 :             for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
    1472             :             {
    1473           0 :                 resultArray[matrixCol].setFConst(0.0f);
    1474           0 :                 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
    1475             :                 {
    1476           0 :                     resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
    1477           0 :                                                      leftArray[matrixRow].getFConst() *
    1478           0 :                                                      rightArray[matrixCol * matrixRows + matrixRow].getFConst());
    1479             :                 }
    1480             :             }
    1481             :         }
    1482           0 :         break;
    1483             : 
    1484             :       case EOpLogicalAnd:
    1485             :         {
    1486           0 :             resultArray = new TConstantUnion[objectSize];
    1487           0 :             for (size_t i = 0; i < objectSize; i++)
    1488             :             {
    1489           0 :                 resultArray[i] = leftArray[i] && rightArray[i];
    1490             :             }
    1491             :         }
    1492           0 :         break;
    1493             : 
    1494             :       case EOpLogicalOr:
    1495             :         {
    1496           0 :             resultArray = new TConstantUnion[objectSize];
    1497           0 :             for (size_t i = 0; i < objectSize; i++)
    1498             :             {
    1499           0 :                 resultArray[i] = leftArray[i] || rightArray[i];
    1500             :             }
    1501             :         }
    1502           0 :         break;
    1503             : 
    1504             :       case EOpLogicalXor:
    1505             :         {
    1506           0 :             ASSERT(getType().getBasicType() == EbtBool);
    1507           0 :             resultArray = new TConstantUnion[objectSize];
    1508           0 :             for (size_t i = 0; i < objectSize; i++)
    1509             :             {
    1510           0 :                 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
    1511             :             }
    1512             :         }
    1513           0 :         break;
    1514             : 
    1515             :       case EOpBitwiseAnd:
    1516           0 :         resultArray = new TConstantUnion[objectSize];
    1517           0 :         for (size_t i = 0; i < objectSize; i++)
    1518           0 :             resultArray[i] = leftArray[i] & rightArray[i];
    1519           0 :         break;
    1520             :       case EOpBitwiseXor:
    1521           0 :         resultArray = new TConstantUnion[objectSize];
    1522           0 :         for (size_t i = 0; i < objectSize; i++)
    1523           0 :             resultArray[i] = leftArray[i] ^ rightArray[i];
    1524           0 :         break;
    1525             :       case EOpBitwiseOr:
    1526           0 :         resultArray = new TConstantUnion[objectSize];
    1527           0 :         for (size_t i = 0; i < objectSize; i++)
    1528           0 :             resultArray[i] = leftArray[i] | rightArray[i];
    1529           0 :         break;
    1530             :       case EOpBitShiftLeft:
    1531           0 :         resultArray = new TConstantUnion[objectSize];
    1532           0 :         for (size_t i = 0; i < objectSize; i++)
    1533           0 :             resultArray[i] = TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
    1534           0 :         break;
    1535             :       case EOpBitShiftRight:
    1536           0 :         resultArray = new TConstantUnion[objectSize];
    1537           0 :         for (size_t i = 0; i < objectSize; i++)
    1538           0 :             resultArray[i] = TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
    1539           0 :         break;
    1540             : 
    1541             :       case EOpLessThan:
    1542           0 :         ASSERT(objectSize == 1);
    1543           0 :         resultArray = new TConstantUnion[1];
    1544           0 :         resultArray->setBConst(*leftArray < *rightArray);
    1545           0 :         break;
    1546             : 
    1547             :       case EOpGreaterThan:
    1548           0 :         ASSERT(objectSize == 1);
    1549           0 :         resultArray = new TConstantUnion[1];
    1550           0 :         resultArray->setBConst(*leftArray > *rightArray);
    1551           0 :         break;
    1552             : 
    1553             :       case EOpLessThanEqual:
    1554           0 :         ASSERT(objectSize == 1);
    1555           0 :         resultArray = new TConstantUnion[1];
    1556           0 :         resultArray->setBConst(!(*leftArray > *rightArray));
    1557           0 :         break;
    1558             : 
    1559             :       case EOpGreaterThanEqual:
    1560           0 :         ASSERT(objectSize == 1);
    1561           0 :         resultArray = new TConstantUnion[1];
    1562           0 :         resultArray->setBConst(!(*leftArray < *rightArray));
    1563           0 :         break;
    1564             : 
    1565             :       case EOpEqual:
    1566             :       case EOpNotEqual:
    1567             :         {
    1568           0 :             resultArray = new TConstantUnion[1];
    1569           0 :             bool equal = true;
    1570           0 :             for (size_t i = 0; i < objectSize; i++)
    1571             :             {
    1572           0 :                 if (leftArray[i] != rightArray[i])
    1573             :                 {
    1574           0 :                     equal = false;
    1575           0 :                     break;  // break out of for loop
    1576             :                 }
    1577             :             }
    1578           0 :             if (op == EOpEqual)
    1579             :             {
    1580           0 :                 resultArray->setBConst(equal);
    1581             :             }
    1582             :             else
    1583             :             {
    1584           0 :                 resultArray->setBConst(!equal);
    1585             :             }
    1586             :         }
    1587           0 :         break;
    1588             : 
    1589             :       default:
    1590           0 :           UNREACHABLE();
    1591             :           return nullptr;
    1592             :     }
    1593           0 :     return resultArray;
    1594             : }
    1595             : 
    1596             : // The fold functions do operations on a constant at GLSL compile time, without generating run-time
    1597             : // code. Returns the constant value to keep using. Nullptr should not be returned.
    1598           0 : TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
    1599             : {
    1600             :     // Do operations where the return type may have a different number of components compared to the
    1601             :     // operand type.
    1602             : 
    1603           0 :     const TConstantUnion *operandArray = getUnionArrayPointer();
    1604           0 :     ASSERT(operandArray);
    1605             : 
    1606           0 :     size_t objectSize = getType().getObjectSize();
    1607           0 :     TConstantUnion *resultArray = nullptr;
    1608           0 :     switch (op)
    1609             :     {
    1610             :         case EOpAny:
    1611           0 :             ASSERT(getType().getBasicType() == EbtBool);
    1612           0 :             resultArray = new TConstantUnion();
    1613           0 :             resultArray->setBConst(false);
    1614           0 :             for (size_t i = 0; i < objectSize; i++)
    1615             :             {
    1616           0 :                 if (operandArray[i].getBConst())
    1617             :                 {
    1618           0 :                     resultArray->setBConst(true);
    1619           0 :                     break;
    1620             :                 }
    1621             :             }
    1622           0 :             break;
    1623             : 
    1624             :         case EOpAll:
    1625           0 :             ASSERT(getType().getBasicType() == EbtBool);
    1626           0 :             resultArray = new TConstantUnion();
    1627           0 :             resultArray->setBConst(true);
    1628           0 :             for (size_t i = 0; i < objectSize; i++)
    1629             :             {
    1630           0 :                 if (!operandArray[i].getBConst())
    1631             :                 {
    1632           0 :                     resultArray->setBConst(false);
    1633           0 :                     break;
    1634             :                 }
    1635             :             }
    1636           0 :             break;
    1637             : 
    1638             :         case EOpLength:
    1639           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1640           0 :             resultArray = new TConstantUnion();
    1641           0 :             resultArray->setFConst(VectorLength(operandArray, objectSize));
    1642           0 :             break;
    1643             : 
    1644             :         case EOpTranspose:
    1645             :         {
    1646           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1647           0 :             resultArray = new TConstantUnion[objectSize];
    1648             :             angle::Matrix<float> result =
    1649           0 :                 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
    1650           0 :             SetUnionArrayFromMatrix(result, resultArray);
    1651           0 :             break;
    1652             :         }
    1653             : 
    1654             :         case EOpDeterminant:
    1655             :         {
    1656           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1657           0 :             unsigned int size = getType().getNominalSize();
    1658           0 :             ASSERT(size >= 2 && size <= 4);
    1659           0 :             resultArray = new TConstantUnion();
    1660           0 :             resultArray->setFConst(GetMatrix(operandArray, size).determinant());
    1661           0 :             break;
    1662             :         }
    1663             : 
    1664             :         case EOpInverse:
    1665             :         {
    1666           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1667           0 :             unsigned int size = getType().getNominalSize();
    1668           0 :             ASSERT(size >= 2 && size <= 4);
    1669           0 :             resultArray                 = new TConstantUnion[objectSize];
    1670           0 :             angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
    1671           0 :             SetUnionArrayFromMatrix(result, resultArray);
    1672           0 :             break;
    1673             :         }
    1674             : 
    1675             :         case EOpPackSnorm2x16:
    1676           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1677           0 :             ASSERT(getType().getNominalSize() == 2);
    1678           0 :             resultArray = new TConstantUnion();
    1679           0 :             resultArray->setUConst(
    1680           0 :                 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
    1681           0 :             break;
    1682             : 
    1683             :         case EOpUnpackSnorm2x16:
    1684             :         {
    1685           0 :             ASSERT(getType().getBasicType() == EbtUInt);
    1686           0 :             resultArray = new TConstantUnion[2];
    1687             :             float f1, f2;
    1688           0 :             gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
    1689           0 :             resultArray[0].setFConst(f1);
    1690           0 :             resultArray[1].setFConst(f2);
    1691           0 :             break;
    1692             :         }
    1693             : 
    1694             :         case EOpPackUnorm2x16:
    1695           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1696           0 :             ASSERT(getType().getNominalSize() == 2);
    1697           0 :             resultArray = new TConstantUnion();
    1698           0 :             resultArray->setUConst(
    1699           0 :                 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
    1700           0 :             break;
    1701             : 
    1702             :         case EOpUnpackUnorm2x16:
    1703             :         {
    1704           0 :             ASSERT(getType().getBasicType() == EbtUInt);
    1705           0 :             resultArray = new TConstantUnion[2];
    1706             :             float f1, f2;
    1707           0 :             gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
    1708           0 :             resultArray[0].setFConst(f1);
    1709           0 :             resultArray[1].setFConst(f2);
    1710           0 :             break;
    1711             :         }
    1712             : 
    1713             :         case EOpPackHalf2x16:
    1714           0 :             ASSERT(getType().getBasicType() == EbtFloat);
    1715           0 :             ASSERT(getType().getNominalSize() == 2);
    1716           0 :             resultArray = new TConstantUnion();
    1717           0 :             resultArray->setUConst(
    1718           0 :                 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
    1719           0 :             break;
    1720             : 
    1721             :         case EOpUnpackHalf2x16:
    1722             :         {
    1723           0 :             ASSERT(getType().getBasicType() == EbtUInt);
    1724           0 :             resultArray = new TConstantUnion[2];
    1725             :             float f1, f2;
    1726           0 :             gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
    1727           0 :             resultArray[0].setFConst(f1);
    1728           0 :             resultArray[1].setFConst(f2);
    1729           0 :             break;
    1730             :         }
    1731             : 
    1732             :         default:
    1733           0 :             UNREACHABLE();
    1734             :             break;
    1735             :     }
    1736             : 
    1737           0 :     return resultArray;
    1738             : }
    1739             : 
    1740           0 : TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
    1741             :                                                              TDiagnostics *diagnostics)
    1742             : {
    1743             :     // Do unary operations where each component of the result is computed based on the corresponding
    1744             :     // component of the operand. Also folds normalize, though the divisor in that case takes all
    1745             :     // components into account.
    1746             : 
    1747           0 :     const TConstantUnion *operandArray = getUnionArrayPointer();
    1748           0 :     ASSERT(operandArray);
    1749             : 
    1750           0 :     size_t objectSize = getType().getObjectSize();
    1751             : 
    1752           0 :     TConstantUnion *resultArray = new TConstantUnion[objectSize];
    1753           0 :     for (size_t i = 0; i < objectSize; i++)
    1754             :     {
    1755           0 :         switch(op)
    1756             :         {
    1757             :             case EOpNegative:
    1758           0 :                 switch (getType().getBasicType())
    1759             :                 {
    1760             :                     case EbtFloat:
    1761           0 :                         resultArray[i].setFConst(-operandArray[i].getFConst());
    1762           0 :                         break;
    1763             :                     case EbtInt:
    1764           0 :                         if (operandArray[i] == std::numeric_limits<int>::min())
    1765             :                         {
    1766             :                             // The minimum representable integer doesn't have a positive
    1767             :                             // counterpart, rather the negation overflows and in ESSL is supposed to
    1768             :                             // wrap back to the minimum representable integer. Make sure that we
    1769             :                             // don't actually let the negation overflow, which has undefined
    1770             :                             // behavior in C++.
    1771           0 :                             resultArray[i].setIConst(std::numeric_limits<int>::min());
    1772             :                         }
    1773             :                         else
    1774             :                         {
    1775           0 :                             resultArray[i].setIConst(-operandArray[i].getIConst());
    1776             :                         }
    1777           0 :                         break;
    1778             :                     case EbtUInt:
    1779           0 :                         if (operandArray[i] == 0x80000000u)
    1780             :                         {
    1781           0 :                             resultArray[i].setUConst(0x80000000u);
    1782             :                         }
    1783             :                         else
    1784             :                         {
    1785           0 :                             resultArray[i].setUConst(static_cast<unsigned int>(
    1786           0 :                                 -static_cast<int>(operandArray[i].getUConst())));
    1787             :                         }
    1788           0 :                         break;
    1789             :                     default:
    1790           0 :                         UNREACHABLE();
    1791             :                         return nullptr;
    1792             :                 }
    1793           0 :                 break;
    1794             : 
    1795             :             case EOpPositive:
    1796           0 :                 switch (getType().getBasicType())
    1797             :                 {
    1798             :                     case EbtFloat:
    1799           0 :                         resultArray[i].setFConst(operandArray[i].getFConst());
    1800           0 :                         break;
    1801             :                     case EbtInt:
    1802           0 :                         resultArray[i].setIConst(operandArray[i].getIConst());
    1803           0 :                         break;
    1804             :                     case EbtUInt:
    1805           0 :                         resultArray[i].setUConst(static_cast<unsigned int>(
    1806           0 :                             static_cast<int>(operandArray[i].getUConst())));
    1807           0 :                         break;
    1808             :                     default:
    1809           0 :                         UNREACHABLE();
    1810             :                         return nullptr;
    1811             :                 }
    1812           0 :                 break;
    1813             : 
    1814             :             case EOpLogicalNot:
    1815           0 :                 switch (getType().getBasicType())
    1816             :                 {
    1817             :                     case EbtBool:
    1818           0 :                         resultArray[i].setBConst(!operandArray[i].getBConst());
    1819           0 :                         break;
    1820             :                     default:
    1821           0 :                         UNREACHABLE();
    1822             :                         return nullptr;
    1823             :                 }
    1824           0 :                 break;
    1825             : 
    1826             :             case EOpBitwiseNot:
    1827           0 :                 switch (getType().getBasicType())
    1828             :                 {
    1829             :                     case EbtInt:
    1830           0 :                         resultArray[i].setIConst(~operandArray[i].getIConst());
    1831           0 :                         break;
    1832             :                     case EbtUInt:
    1833           0 :                         resultArray[i].setUConst(~operandArray[i].getUConst());
    1834           0 :                         break;
    1835             :                     default:
    1836           0 :                         UNREACHABLE();
    1837             :                         return nullptr;
    1838             :                 }
    1839           0 :                 break;
    1840             : 
    1841             :             case EOpRadians:
    1842           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    1843           0 :                 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
    1844           0 :                 break;
    1845             : 
    1846             :             case EOpDegrees:
    1847           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    1848           0 :                 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
    1849           0 :                 break;
    1850             : 
    1851             :             case EOpSin:
    1852           0 :                 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
    1853           0 :                 break;
    1854             : 
    1855             :             case EOpCos:
    1856           0 :                 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
    1857           0 :                 break;
    1858             : 
    1859             :             case EOpTan:
    1860           0 :                 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
    1861           0 :                 break;
    1862             : 
    1863             :             case EOpAsin:
    1864             :                 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
    1865             :                 // 0.
    1866           0 :                 if (fabsf(operandArray[i].getFConst()) > 1.0f)
    1867           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    1868           0 :                                                   diagnostics, &resultArray[i]);
    1869             :                 else
    1870           0 :                     foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
    1871           0 :                 break;
    1872             : 
    1873             :             case EOpAcos:
    1874             :                 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
    1875             :                 // 0.
    1876           0 :                 if (fabsf(operandArray[i].getFConst()) > 1.0f)
    1877           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    1878           0 :                                                   diagnostics, &resultArray[i]);
    1879             :                 else
    1880           0 :                     foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
    1881           0 :                 break;
    1882             : 
    1883             :             case EOpAtan:
    1884           0 :                 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
    1885           0 :                 break;
    1886             : 
    1887             :             case EOpSinh:
    1888           0 :                 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
    1889           0 :                 break;
    1890             : 
    1891             :             case EOpCosh:
    1892           0 :                 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
    1893           0 :                 break;
    1894             : 
    1895             :             case EOpTanh:
    1896           0 :                 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
    1897           0 :                 break;
    1898             : 
    1899             :             case EOpAsinh:
    1900           0 :                 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
    1901           0 :                 break;
    1902             : 
    1903             :             case EOpAcosh:
    1904             :                 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
    1905           0 :                 if (operandArray[i].getFConst() < 1.0f)
    1906           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    1907           0 :                                                   diagnostics, &resultArray[i]);
    1908             :                 else
    1909           0 :                     foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
    1910           0 :                 break;
    1911             : 
    1912             :             case EOpAtanh:
    1913             :                 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
    1914             :                 // 0.
    1915           0 :                 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
    1916           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    1917           0 :                                                   diagnostics, &resultArray[i]);
    1918             :                 else
    1919           0 :                     foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
    1920           0 :                 break;
    1921             : 
    1922             :             case EOpAbs:
    1923           0 :                 switch (getType().getBasicType())
    1924             :                 {
    1925             :                     case EbtFloat:
    1926           0 :                         resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
    1927           0 :                         break;
    1928             :                     case EbtInt:
    1929           0 :                         resultArray[i].setIConst(abs(operandArray[i].getIConst()));
    1930           0 :                         break;
    1931             :                     default:
    1932           0 :                         UNREACHABLE();
    1933             :                         return nullptr;
    1934             :                 }
    1935           0 :                 break;
    1936             : 
    1937             :             case EOpSign:
    1938           0 :                 switch (getType().getBasicType())
    1939             :                 {
    1940             :                     case EbtFloat:
    1941             :                     {
    1942           0 :                         float fConst  = operandArray[i].getFConst();
    1943           0 :                         float fResult = 0.0f;
    1944           0 :                         if (fConst > 0.0f)
    1945           0 :                             fResult = 1.0f;
    1946           0 :                         else if (fConst < 0.0f)
    1947           0 :                             fResult = -1.0f;
    1948           0 :                         resultArray[i].setFConst(fResult);
    1949           0 :                         break;
    1950             :                     }
    1951             :                     case EbtInt:
    1952             :                     {
    1953           0 :                         int iConst  = operandArray[i].getIConst();
    1954           0 :                         int iResult = 0;
    1955           0 :                         if (iConst > 0)
    1956           0 :                             iResult = 1;
    1957           0 :                         else if (iConst < 0)
    1958           0 :                             iResult = -1;
    1959           0 :                         resultArray[i].setIConst(iResult);
    1960           0 :                         break;
    1961             :                     }
    1962             :                     default:
    1963           0 :                         UNREACHABLE();
    1964             :                         return nullptr;
    1965             :                 }
    1966           0 :                 break;
    1967             : 
    1968             :             case EOpFloor:
    1969           0 :                 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
    1970           0 :                 break;
    1971             : 
    1972             :             case EOpTrunc:
    1973           0 :                 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
    1974           0 :                 break;
    1975             : 
    1976             :             case EOpRound:
    1977           0 :                 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
    1978           0 :                 break;
    1979             : 
    1980             :             case EOpRoundEven:
    1981             :             {
    1982           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    1983           0 :                 float x = operandArray[i].getFConst();
    1984             :                 float result;
    1985           0 :                 float fractPart = modff(x, &result);
    1986           0 :                 if (fabsf(fractPart) == 0.5f)
    1987           0 :                     result = 2.0f * roundf(x / 2.0f);
    1988             :                 else
    1989           0 :                     result = roundf(x);
    1990           0 :                 resultArray[i].setFConst(result);
    1991           0 :                 break;
    1992             :             }
    1993             : 
    1994             :             case EOpCeil:
    1995           0 :                 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
    1996           0 :                 break;
    1997             : 
    1998             :             case EOpFract:
    1999             :             {
    2000           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    2001           0 :                 float x = operandArray[i].getFConst();
    2002           0 :                 resultArray[i].setFConst(x - floorf(x));
    2003           0 :                 break;
    2004             :             }
    2005             : 
    2006             :             case EOpIsNan:
    2007           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    2008           0 :                 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
    2009           0 :                 break;
    2010             : 
    2011             :             case EOpIsInf:
    2012           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    2013           0 :                 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
    2014           0 :                 break;
    2015             : 
    2016             :             case EOpFloatBitsToInt:
    2017           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    2018           0 :                 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
    2019           0 :                 break;
    2020             : 
    2021             :             case EOpFloatBitsToUint:
    2022           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    2023           0 :                 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
    2024           0 :                 break;
    2025             : 
    2026             :             case EOpIntBitsToFloat:
    2027           0 :                 ASSERT(getType().getBasicType() == EbtInt);
    2028           0 :                 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
    2029           0 :                 break;
    2030             : 
    2031             :             case EOpUintBitsToFloat:
    2032           0 :                 ASSERT(getType().getBasicType() == EbtUInt);
    2033           0 :                 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
    2034           0 :                 break;
    2035             : 
    2036             :             case EOpExp:
    2037           0 :                 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
    2038           0 :                 break;
    2039             : 
    2040             :             case EOpLog:
    2041             :                 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
    2042           0 :                 if (operandArray[i].getFConst() <= 0.0f)
    2043           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    2044           0 :                                                   diagnostics, &resultArray[i]);
    2045             :                 else
    2046           0 :                     foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
    2047           0 :                 break;
    2048             : 
    2049             :             case EOpExp2:
    2050           0 :                 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
    2051           0 :                 break;
    2052             : 
    2053             :             case EOpLog2:
    2054             :                 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
    2055             :                 // And log2f is not available on some plarforms like old android, so just using
    2056             :                 // log(x)/log(2) here.
    2057           0 :                 if (operandArray[i].getFConst() <= 0.0f)
    2058           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    2059           0 :                                                   diagnostics, &resultArray[i]);
    2060             :                 else
    2061             :                 {
    2062           0 :                     foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
    2063           0 :                     resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
    2064             :                 }
    2065           0 :                 break;
    2066             : 
    2067             :             case EOpSqrt:
    2068             :                 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
    2069           0 :                 if (operandArray[i].getFConst() < 0.0f)
    2070           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    2071           0 :                                                   diagnostics, &resultArray[i]);
    2072             :                 else
    2073           0 :                     foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
    2074           0 :                 break;
    2075             : 
    2076             :             case EOpInverseSqrt:
    2077             :                 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
    2078             :                 // so getting the square root first using builtin function sqrt() and then taking
    2079             :                 // its inverse.
    2080             :                 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
    2081             :                 // result to 0.
    2082           0 :                 if (operandArray[i].getFConst() <= 0.0f)
    2083           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    2084           0 :                                                   diagnostics, &resultArray[i]);
    2085             :                 else
    2086             :                 {
    2087           0 :                     foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
    2088           0 :                     resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
    2089             :                 }
    2090           0 :                 break;
    2091             : 
    2092             :             case EOpVectorLogicalNot:
    2093           0 :                 ASSERT(getType().getBasicType() == EbtBool);
    2094           0 :                 resultArray[i].setBConst(!operandArray[i].getBConst());
    2095           0 :                 break;
    2096             : 
    2097             :             case EOpNormalize:
    2098             :             {
    2099           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    2100           0 :                 float x      = operandArray[i].getFConst();
    2101           0 :                 float length = VectorLength(operandArray, objectSize);
    2102           0 :                 if (length)
    2103           0 :                     resultArray[i].setFConst(x / length);
    2104             :                 else
    2105           0 :                     UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
    2106           0 :                                                   diagnostics, &resultArray[i]);
    2107           0 :                 break;
    2108             :             }
    2109             : 
    2110             :             case EOpDFdx:
    2111             :             case EOpDFdy:
    2112             :             case EOpFwidth:
    2113           0 :                 ASSERT(getType().getBasicType() == EbtFloat);
    2114             :                 // Derivatives of constant arguments should be 0.
    2115           0 :                 resultArray[i].setFConst(0.0f);
    2116           0 :                 break;
    2117             : 
    2118             :             default:
    2119           0 :                 return nullptr;
    2120             :         }
    2121             :     }
    2122             : 
    2123           0 :     return resultArray;
    2124             : }
    2125             : 
    2126           0 : void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
    2127             :                                               FloatTypeUnaryFunc builtinFunc,
    2128             :                                               TConstantUnion *result) const
    2129             : {
    2130           0 :     ASSERT(builtinFunc);
    2131             : 
    2132           0 :     ASSERT(getType().getBasicType() == EbtFloat);
    2133           0 :     result->setFConst(builtinFunc(parameter.getFConst()));
    2134           0 : }
    2135             : 
    2136             : // static
    2137           0 : TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
    2138             : {
    2139           0 :     ASSERT(aggregate->getSequence()->size() > 0u);
    2140           0 :     size_t resultSize           = aggregate->getType().getObjectSize();
    2141           0 :     TConstantUnion *resultArray = new TConstantUnion[resultSize];
    2142           0 :     TBasicType basicType        = aggregate->getBasicType();
    2143             : 
    2144           0 :     size_t resultIndex = 0u;
    2145             : 
    2146           0 :     if (aggregate->getSequence()->size() == 1u)
    2147             :     {
    2148           0 :         TIntermNode *argument                    = aggregate->getSequence()->front();
    2149           0 :         TIntermConstantUnion *argumentConstant   = argument->getAsConstantUnion();
    2150           0 :         const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
    2151             :         // Check the special case of constructing a matrix diagonal from a single scalar,
    2152             :         // or a vector from a single scalar.
    2153           0 :         if (argumentConstant->getType().getObjectSize() == 1u)
    2154             :         {
    2155           0 :             if (aggregate->isMatrix())
    2156             :             {
    2157           0 :                 int resultCols = aggregate->getType().getCols();
    2158           0 :                 int resultRows = aggregate->getType().getRows();
    2159           0 :                 for (int col = 0; col < resultCols; ++col)
    2160             :                 {
    2161           0 :                     for (int row = 0; row < resultRows; ++row)
    2162             :                     {
    2163           0 :                         if (col == row)
    2164             :                         {
    2165           0 :                             resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
    2166             :                         }
    2167             :                         else
    2168             :                         {
    2169           0 :                             resultArray[resultIndex].setFConst(0.0f);
    2170             :                         }
    2171           0 :                         ++resultIndex;
    2172             :                     }
    2173             :                 }
    2174             :             }
    2175             :             else
    2176             :             {
    2177           0 :                 while (resultIndex < resultSize)
    2178             :                 {
    2179           0 :                     resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
    2180           0 :                     ++resultIndex;
    2181             :                 }
    2182             :             }
    2183           0 :             ASSERT(resultIndex == resultSize);
    2184           0 :             return resultArray;
    2185             :         }
    2186           0 :         else if (aggregate->isMatrix() && argumentConstant->isMatrix())
    2187             :         {
    2188             :             // The special case of constructing a matrix from a matrix.
    2189           0 :             int argumentCols = argumentConstant->getType().getCols();
    2190           0 :             int argumentRows = argumentConstant->getType().getRows();
    2191           0 :             int resultCols   = aggregate->getType().getCols();
    2192           0 :             int resultRows = aggregate->getType().getRows();
    2193           0 :             for (int col = 0; col < resultCols; ++col)
    2194             :             {
    2195           0 :                 for (int row = 0; row < resultRows; ++row)
    2196             :                 {
    2197           0 :                     if (col < argumentCols && row < argumentRows)
    2198             :                     {
    2199           0 :                         resultArray[resultIndex].cast(basicType,
    2200           0 :                                                       argumentUnionArray[col * argumentRows + row]);
    2201             :                     }
    2202           0 :                     else if (col == row)
    2203             :                     {
    2204           0 :                         resultArray[resultIndex].setFConst(1.0f);
    2205             :                     }
    2206             :                     else
    2207             :                     {
    2208           0 :                         resultArray[resultIndex].setFConst(0.0f);
    2209             :                     }
    2210           0 :                     ++resultIndex;
    2211             :                 }
    2212             :             }
    2213           0 :             ASSERT(resultIndex == resultSize);
    2214           0 :             return resultArray;
    2215             :         }
    2216             :     }
    2217             : 
    2218           0 :     for (TIntermNode *&argument : *aggregate->getSequence())
    2219             :     {
    2220           0 :         TIntermConstantUnion *argumentConstant   = argument->getAsConstantUnion();
    2221           0 :         size_t argumentSize                      = argumentConstant->getType().getObjectSize();
    2222           0 :         const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
    2223           0 :         for (size_t i = 0u; i < argumentSize; ++i)
    2224             :         {
    2225           0 :             if (resultIndex >= resultSize)
    2226           0 :                 break;
    2227           0 :             resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
    2228           0 :             ++resultIndex;
    2229             :         }
    2230             :     }
    2231           0 :     ASSERT(resultIndex == resultSize);
    2232           0 :     return resultArray;
    2233             : }
    2234             : 
    2235             : // static
    2236           0 : TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
    2237             :                                                            TDiagnostics *diagnostics)
    2238             : {
    2239           0 :     TOperator op = aggregate->getOp();
    2240           0 :     TIntermSequence *sequence = aggregate->getSequence();
    2241           0 :     unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
    2242           0 :     std::vector<const TConstantUnion *> unionArrays(paramsCount);
    2243           0 :     std::vector<size_t> objectSizes(paramsCount);
    2244           0 :     size_t maxObjectSize = 0;
    2245           0 :     TBasicType basicType = EbtVoid;
    2246             :     TSourceLoc loc;
    2247           0 :     for (unsigned int i = 0; i < paramsCount; i++)
    2248             :     {
    2249           0 :         TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
    2250           0 :         ASSERT(paramConstant != nullptr); // Should be checked already.
    2251             : 
    2252           0 :         if (i == 0)
    2253             :         {
    2254           0 :             basicType = paramConstant->getType().getBasicType();
    2255           0 :             loc = paramConstant->getLine();
    2256             :         }
    2257           0 :         unionArrays[i] = paramConstant->getUnionArrayPointer();
    2258           0 :         objectSizes[i] = paramConstant->getType().getObjectSize();
    2259           0 :         if (objectSizes[i] > maxObjectSize)
    2260           0 :             maxObjectSize = objectSizes[i];
    2261             :     }
    2262             : 
    2263           0 :     if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
    2264             :     {
    2265           0 :         for (unsigned int i = 0; i < paramsCount; i++)
    2266           0 :             if (objectSizes[i] != maxObjectSize)
    2267           0 :                 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
    2268             :     }
    2269             : 
    2270           0 :     TConstantUnion *resultArray = nullptr;
    2271           0 :     if (paramsCount == 2)
    2272             :     {
    2273             :         //
    2274             :         // Binary built-in
    2275             :         //
    2276           0 :         switch (op)
    2277             :         {
    2278             :             case EOpAtan:
    2279             :             {
    2280           0 :                 ASSERT(basicType == EbtFloat);
    2281           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2282           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2283             :                 {
    2284           0 :                     float y = unionArrays[0][i].getFConst();
    2285           0 :                     float x = unionArrays[1][i].getFConst();
    2286             :                     // Results are undefined if x and y are both 0.
    2287           0 :                     if (x == 0.0f && y == 0.0f)
    2288           0 :                         UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
    2289           0 :                                                       &resultArray[i]);
    2290             :                     else
    2291           0 :                         resultArray[i].setFConst(atan2f(y, x));
    2292             :                 }
    2293           0 :                 break;
    2294             :             }
    2295             : 
    2296             :             case EOpPow:
    2297             :             {
    2298           0 :                 ASSERT(basicType == EbtFloat);
    2299           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2300           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2301             :                 {
    2302           0 :                     float x = unionArrays[0][i].getFConst();
    2303           0 :                     float y = unionArrays[1][i].getFConst();
    2304             :                     // Results are undefined if x < 0.
    2305             :                     // Results are undefined if x = 0 and y <= 0.
    2306           0 :                     if (x < 0.0f)
    2307           0 :                         UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
    2308           0 :                                                       &resultArray[i]);
    2309           0 :                     else if (x == 0.0f && y <= 0.0f)
    2310           0 :                         UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
    2311           0 :                                                       &resultArray[i]);
    2312             :                     else
    2313           0 :                         resultArray[i].setFConst(powf(x, y));
    2314             :                 }
    2315           0 :                 break;
    2316             :             }
    2317             : 
    2318             :             case EOpMod:
    2319             :             {
    2320           0 :                 ASSERT(basicType == EbtFloat);
    2321           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2322           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2323             :                 {
    2324           0 :                     float x = unionArrays[0][i].getFConst();
    2325           0 :                     float y = unionArrays[1][i].getFConst();
    2326           0 :                     resultArray[i].setFConst(x - y * floorf(x / y));
    2327             :                 }
    2328           0 :                 break;
    2329             :             }
    2330             : 
    2331             :             case EOpMin:
    2332             :             {
    2333           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2334           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2335             :                 {
    2336           0 :                     switch (basicType)
    2337             :                     {
    2338             :                         case EbtFloat:
    2339           0 :                             resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
    2340           0 :                                                               unionArrays[1][i].getFConst()));
    2341           0 :                             break;
    2342             :                         case EbtInt:
    2343           0 :                             resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
    2344           0 :                                                               unionArrays[1][i].getIConst()));
    2345           0 :                             break;
    2346             :                         case EbtUInt:
    2347           0 :                             resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
    2348           0 :                                                               unionArrays[1][i].getUConst()));
    2349           0 :                             break;
    2350             :                         default:
    2351           0 :                             UNREACHABLE();
    2352             :                             break;
    2353             :                     }
    2354             :                 }
    2355           0 :                 break;
    2356             :             }
    2357             : 
    2358             :             case EOpMax:
    2359             :             {
    2360           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2361           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2362             :                 {
    2363           0 :                     switch (basicType)
    2364             :                     {
    2365             :                         case EbtFloat:
    2366           0 :                             resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
    2367           0 :                                                               unionArrays[1][i].getFConst()));
    2368           0 :                             break;
    2369             :                         case EbtInt:
    2370           0 :                             resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
    2371           0 :                                                               unionArrays[1][i].getIConst()));
    2372           0 :                             break;
    2373             :                         case EbtUInt:
    2374           0 :                             resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
    2375           0 :                                                               unionArrays[1][i].getUConst()));
    2376           0 :                             break;
    2377             :                         default:
    2378           0 :                             UNREACHABLE();
    2379             :                             break;
    2380             :                     }
    2381             :                 }
    2382           0 :                 break;
    2383             :             }
    2384             : 
    2385             :             case EOpStep:
    2386             :             {
    2387           0 :                 ASSERT(basicType == EbtFloat);
    2388           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2389           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2390           0 :                     resultArray[i].setFConst(
    2391           0 :                         unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
    2392           0 :                                                                                       : 1.0f);
    2393           0 :                 break;
    2394             :             }
    2395             : 
    2396             :             case EOpLessThan:
    2397             :             {
    2398           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2399           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2400             :                 {
    2401           0 :                     switch (basicType)
    2402             :                     {
    2403             :                         case EbtFloat:
    2404           0 :                             resultArray[i].setBConst(unionArrays[0][i].getFConst() <
    2405           0 :                                                      unionArrays[1][i].getFConst());
    2406           0 :                             break;
    2407             :                         case EbtInt:
    2408           0 :                             resultArray[i].setBConst(unionArrays[0][i].getIConst() <
    2409           0 :                                                      unionArrays[1][i].getIConst());
    2410           0 :                             break;
    2411             :                         case EbtUInt:
    2412           0 :                             resultArray[i].setBConst(unionArrays[0][i].getUConst() <
    2413           0 :                                                      unionArrays[1][i].getUConst());
    2414           0 :                             break;
    2415             :                         default:
    2416           0 :                             UNREACHABLE();
    2417             :                             break;
    2418             :                     }
    2419             :                 }
    2420           0 :                 break;
    2421             :             }
    2422             : 
    2423             :             case EOpLessThanEqual:
    2424             :             {
    2425           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2426           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2427             :                 {
    2428           0 :                     switch (basicType)
    2429             :                     {
    2430             :                         case EbtFloat:
    2431           0 :                             resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
    2432           0 :                                                      unionArrays[1][i].getFConst());
    2433           0 :                             break;
    2434             :                         case EbtInt:
    2435           0 :                             resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
    2436           0 :                                                      unionArrays[1][i].getIConst());
    2437           0 :                             break;
    2438             :                         case EbtUInt:
    2439           0 :                             resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
    2440           0 :                                                      unionArrays[1][i].getUConst());
    2441           0 :                             break;
    2442             :                         default:
    2443           0 :                             UNREACHABLE();
    2444             :                             break;
    2445             :                     }
    2446             :                 }
    2447           0 :                 break;
    2448             :             }
    2449             : 
    2450             :             case EOpGreaterThan:
    2451             :             {
    2452           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2453           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2454             :                 {
    2455           0 :                     switch (basicType)
    2456             :                     {
    2457             :                         case EbtFloat:
    2458           0 :                             resultArray[i].setBConst(unionArrays[0][i].getFConst() >
    2459           0 :                                                      unionArrays[1][i].getFConst());
    2460           0 :                             break;
    2461             :                         case EbtInt:
    2462           0 :                             resultArray[i].setBConst(unionArrays[0][i].getIConst() >
    2463           0 :                                                      unionArrays[1][i].getIConst());
    2464           0 :                             break;
    2465             :                         case EbtUInt:
    2466           0 :                             resultArray[i].setBConst(unionArrays[0][i].getUConst() >
    2467           0 :                                                      unionArrays[1][i].getUConst());
    2468           0 :                             break;
    2469             :                         default:
    2470           0 :                             UNREACHABLE();
    2471             :                             break;
    2472             :                     }
    2473             :                 }
    2474           0 :                 break;
    2475             :             }
    2476             :             case EOpGreaterThanEqual:
    2477             :             {
    2478           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2479           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2480             :                 {
    2481           0 :                     switch (basicType)
    2482             :                     {
    2483             :                         case EbtFloat:
    2484           0 :                             resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
    2485           0 :                                                      unionArrays[1][i].getFConst());
    2486           0 :                             break;
    2487             :                         case EbtInt:
    2488           0 :                             resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
    2489           0 :                                                      unionArrays[1][i].getIConst());
    2490           0 :                             break;
    2491             :                         case EbtUInt:
    2492           0 :                             resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
    2493           0 :                                                      unionArrays[1][i].getUConst());
    2494           0 :                             break;
    2495             :                         default:
    2496           0 :                             UNREACHABLE();
    2497             :                             break;
    2498             :                     }
    2499             :                 }
    2500             :             }
    2501           0 :             break;
    2502             : 
    2503             :             case EOpVectorEqual:
    2504             :             {
    2505           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2506           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2507             :                 {
    2508           0 :                     switch (basicType)
    2509             :                     {
    2510             :                         case EbtFloat:
    2511           0 :                             resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
    2512           0 :                                                      unionArrays[1][i].getFConst());
    2513           0 :                             break;
    2514             :                         case EbtInt:
    2515           0 :                             resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
    2516           0 :                                                      unionArrays[1][i].getIConst());
    2517           0 :                             break;
    2518             :                         case EbtUInt:
    2519           0 :                             resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
    2520           0 :                                                      unionArrays[1][i].getUConst());
    2521           0 :                             break;
    2522             :                         case EbtBool:
    2523           0 :                             resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
    2524           0 :                                                      unionArrays[1][i].getBConst());
    2525           0 :                             break;
    2526             :                         default:
    2527           0 :                             UNREACHABLE();
    2528             :                             break;
    2529             :                     }
    2530             :                 }
    2531           0 :                 break;
    2532             :             }
    2533             : 
    2534             :             case EOpVectorNotEqual:
    2535             :             {
    2536           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2537           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2538             :                 {
    2539           0 :                     switch (basicType)
    2540             :                     {
    2541             :                         case EbtFloat:
    2542           0 :                             resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
    2543           0 :                                                      unionArrays[1][i].getFConst());
    2544           0 :                             break;
    2545             :                         case EbtInt:
    2546           0 :                             resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
    2547           0 :                                                      unionArrays[1][i].getIConst());
    2548           0 :                             break;
    2549             :                         case EbtUInt:
    2550           0 :                             resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
    2551           0 :                                                      unionArrays[1][i].getUConst());
    2552           0 :                             break;
    2553             :                         case EbtBool:
    2554           0 :                             resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
    2555           0 :                                                      unionArrays[1][i].getBConst());
    2556           0 :                             break;
    2557             :                         default:
    2558           0 :                             UNREACHABLE();
    2559             :                             break;
    2560             :                     }
    2561             :                 }
    2562           0 :                 break;
    2563             :             }
    2564             : 
    2565             :             case EOpDistance:
    2566             :             {
    2567           0 :                 ASSERT(basicType == EbtFloat);
    2568           0 :                 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
    2569           0 :                 resultArray                   = new TConstantUnion();
    2570           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2571             :                 {
    2572           0 :                     float x = unionArrays[0][i].getFConst();
    2573           0 :                     float y = unionArrays[1][i].getFConst();
    2574           0 :                     distanceArray[i].setFConst(x - y);
    2575             :                 }
    2576           0 :                 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
    2577           0 :                 break;
    2578             :             }
    2579             : 
    2580             :             case EOpDot:
    2581           0 :                 ASSERT(basicType == EbtFloat);
    2582           0 :                 resultArray = new TConstantUnion();
    2583           0 :                 resultArray->setFConst(
    2584           0 :                     VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
    2585           0 :                 break;
    2586             : 
    2587             :             case EOpCross:
    2588             :             {
    2589           0 :                 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
    2590           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2591           0 :                 float x0    = unionArrays[0][0].getFConst();
    2592           0 :                 float x1    = unionArrays[0][1].getFConst();
    2593           0 :                 float x2    = unionArrays[0][2].getFConst();
    2594           0 :                 float y0    = unionArrays[1][0].getFConst();
    2595           0 :                 float y1    = unionArrays[1][1].getFConst();
    2596           0 :                 float y2    = unionArrays[1][2].getFConst();
    2597           0 :                 resultArray[0].setFConst(x1 * y2 - y1 * x2);
    2598           0 :                 resultArray[1].setFConst(x2 * y0 - y2 * x0);
    2599           0 :                 resultArray[2].setFConst(x0 * y1 - y0 * x1);
    2600           0 :                 break;
    2601             :             }
    2602             : 
    2603             :             case EOpReflect:
    2604             :             {
    2605           0 :                 ASSERT(basicType == EbtFloat);
    2606             :                 // genType reflect (genType I, genType N) :
    2607             :                 //     For the incident vector I and surface orientation N, returns the reflection
    2608             :                 //     direction:
    2609             :                 //     I - 2 * dot(N, I) * N.
    2610           0 :                 resultArray      = new TConstantUnion[maxObjectSize];
    2611           0 :                 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
    2612           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2613             :                 {
    2614           0 :                     float result = unionArrays[0][i].getFConst() -
    2615           0 :                                    2.0f * dotProduct * unionArrays[1][i].getFConst();
    2616           0 :                     resultArray[i].setFConst(result);
    2617             :                 }
    2618           0 :                 break;
    2619             :             }
    2620             : 
    2621             :             case EOpMul:
    2622             :             {
    2623           0 :                 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
    2624             :                        (*sequence)[1]->getAsTyped()->isMatrix());
    2625             :                 // Perform component-wise matrix multiplication.
    2626           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2627           0 :                 int size    = (*sequence)[0]->getAsTyped()->getNominalSize();
    2628             :                 angle::Matrix<float> result =
    2629           0 :                     GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
    2630           0 :                 SetUnionArrayFromMatrix(result, resultArray);
    2631           0 :                 break;
    2632             :             }
    2633             : 
    2634             :             case EOpOuterProduct:
    2635             :             {
    2636           0 :                 ASSERT(basicType == EbtFloat);
    2637           0 :                 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
    2638           0 :                 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
    2639           0 :                 resultArray    = new TConstantUnion[numRows * numCols];
    2640             :                 angle::Matrix<float> result =
    2641           0 :                     GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
    2642           0 :                         .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
    2643           0 :                 SetUnionArrayFromMatrix(result, resultArray);
    2644           0 :                 break;
    2645             :             }
    2646             : 
    2647             :             default:
    2648           0 :                 UNREACHABLE();
    2649             :                 // TODO: Add constant folding support for other built-in operations that take 2
    2650             :                 // parameters and not handled above.
    2651             :                 return nullptr;
    2652             :         }
    2653             :     }
    2654           0 :     else if (paramsCount == 3)
    2655             :     {
    2656             :         //
    2657             :         // Ternary built-in
    2658             :         //
    2659           0 :         switch (op)
    2660             :         {
    2661             :             case EOpClamp:
    2662             :             {
    2663           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2664           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2665             :                 {
    2666           0 :                     switch (basicType)
    2667             :                     {
    2668             :                         case EbtFloat:
    2669             :                         {
    2670           0 :                             float x   = unionArrays[0][i].getFConst();
    2671           0 :                             float min = unionArrays[1][i].getFConst();
    2672           0 :                             float max = unionArrays[2][i].getFConst();
    2673             :                             // Results are undefined if min > max.
    2674           0 :                             if (min > max)
    2675           0 :                                 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
    2676           0 :                                                               &resultArray[i]);
    2677             :                             else
    2678           0 :                                 resultArray[i].setFConst(gl::clamp(x, min, max));
    2679           0 :                             break;
    2680             :                         }
    2681             : 
    2682             :                         case EbtInt:
    2683             :                         {
    2684           0 :                             int x   = unionArrays[0][i].getIConst();
    2685           0 :                             int min = unionArrays[1][i].getIConst();
    2686           0 :                             int max = unionArrays[2][i].getIConst();
    2687             :                             // Results are undefined if min > max.
    2688           0 :                             if (min > max)
    2689           0 :                                 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
    2690           0 :                                                               &resultArray[i]);
    2691             :                             else
    2692           0 :                                 resultArray[i].setIConst(gl::clamp(x, min, max));
    2693           0 :                             break;
    2694             :                         }
    2695             :                         case EbtUInt:
    2696             :                         {
    2697           0 :                             unsigned int x   = unionArrays[0][i].getUConst();
    2698           0 :                             unsigned int min = unionArrays[1][i].getUConst();
    2699           0 :                             unsigned int max = unionArrays[2][i].getUConst();
    2700             :                             // Results are undefined if min > max.
    2701           0 :                             if (min > max)
    2702           0 :                                 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
    2703           0 :                                                               &resultArray[i]);
    2704             :                             else
    2705           0 :                                 resultArray[i].setUConst(gl::clamp(x, min, max));
    2706           0 :                             break;
    2707             :                         }
    2708             :                         default:
    2709           0 :                             UNREACHABLE();
    2710             :                             break;
    2711             :                     }
    2712             :                 }
    2713           0 :                 break;
    2714             :             }
    2715             : 
    2716             :             case EOpMix:
    2717             :             {
    2718           0 :                 ASSERT(basicType == EbtFloat);
    2719           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2720           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2721             :                 {
    2722           0 :                     float x         = unionArrays[0][i].getFConst();
    2723           0 :                     float y         = unionArrays[1][i].getFConst();
    2724           0 :                     TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
    2725           0 :                     if (type == EbtFloat)
    2726             :                     {
    2727             :                         // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
    2728           0 :                         float a = unionArrays[2][i].getFConst();
    2729           0 :                         resultArray[i].setFConst(x * (1.0f - a) + y * a);
    2730             :                     }
    2731             :                     else  // 3rd parameter is EbtBool
    2732             :                     {
    2733           0 :                         ASSERT(type == EbtBool);
    2734             :                         // Selects which vector each returned component comes from.
    2735             :                         // For a component of a that is false, the corresponding component of x is
    2736             :                         // returned.
    2737             :                         // For a component of a that is true, the corresponding component of y is
    2738             :                         // returned.
    2739           0 :                         bool a = unionArrays[2][i].getBConst();
    2740           0 :                         resultArray[i].setFConst(a ? y : x);
    2741             :                     }
    2742             :                 }
    2743           0 :                 break;
    2744             :             }
    2745             : 
    2746             :             case EOpSmoothStep:
    2747             :             {
    2748           0 :                 ASSERT(basicType == EbtFloat);
    2749           0 :                 resultArray = new TConstantUnion[maxObjectSize];
    2750           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2751             :                 {
    2752           0 :                     float edge0 = unionArrays[0][i].getFConst();
    2753           0 :                     float edge1 = unionArrays[1][i].getFConst();
    2754           0 :                     float x     = unionArrays[2][i].getFConst();
    2755             :                     // Results are undefined if edge0 >= edge1.
    2756           0 :                     if (edge0 >= edge1)
    2757             :                     {
    2758           0 :                         UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
    2759           0 :                                                       &resultArray[i]);
    2760             :                     }
    2761             :                     else
    2762             :                     {
    2763             :                         // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
    2764             :                         // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
    2765           0 :                         float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
    2766           0 :                         resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
    2767             :                     }
    2768             :                 }
    2769           0 :                 break;
    2770             :             }
    2771             : 
    2772             :             case EOpFaceForward:
    2773             :             {
    2774           0 :                 ASSERT(basicType == EbtFloat);
    2775             :                 // genType faceforward(genType N, genType I, genType Nref) :
    2776             :                 //     If dot(Nref, I) < 0 return N, otherwise return -N.
    2777           0 :                 resultArray      = new TConstantUnion[maxObjectSize];
    2778           0 :                 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
    2779           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2780             :                 {
    2781           0 :                     if (dotProduct < 0)
    2782           0 :                         resultArray[i].setFConst(unionArrays[0][i].getFConst());
    2783             :                     else
    2784           0 :                         resultArray[i].setFConst(-unionArrays[0][i].getFConst());
    2785             :                 }
    2786           0 :                 break;
    2787             :             }
    2788             : 
    2789             :             case EOpRefract:
    2790             :             {
    2791           0 :                 ASSERT(basicType == EbtFloat);
    2792             :                 // genType refract(genType I, genType N, float eta) :
    2793             :                 //     For the incident vector I and surface normal N, and the ratio of indices of
    2794             :                 //     refraction eta,
    2795             :                 //     return the refraction vector. The result is computed by
    2796             :                 //         k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
    2797             :                 //         if (k < 0.0)
    2798             :                 //             return genType(0.0)
    2799             :                 //         else
    2800             :                 //             return eta * I - (eta * dot(N, I) + sqrt(k)) * N
    2801           0 :                 resultArray      = new TConstantUnion[maxObjectSize];
    2802           0 :                 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
    2803           0 :                 for (size_t i = 0; i < maxObjectSize; i++)
    2804             :                 {
    2805           0 :                     float eta = unionArrays[2][i].getFConst();
    2806           0 :                     float k   = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
    2807           0 :                     if (k < 0.0f)
    2808           0 :                         resultArray[i].setFConst(0.0f);
    2809             :                     else
    2810           0 :                         resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
    2811           0 :                                                  (eta * dotProduct + sqrtf(k)) *
    2812           0 :                                                      unionArrays[1][i].getFConst());
    2813             :                 }
    2814           0 :                 break;
    2815             :             }
    2816             : 
    2817             :             default:
    2818           0 :                 UNREACHABLE();
    2819             :                 // TODO: Add constant folding support for other built-in operations that take 3
    2820             :                 // parameters and not handled above.
    2821             :                 return nullptr;
    2822             :         }
    2823             :     }
    2824           0 :     return resultArray;
    2825             : }
    2826             : 
    2827             : // static
    2828           0 : TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
    2829             : {
    2830           0 :     if (hashFunction == NULL || name.empty())
    2831           0 :         return name;
    2832           0 :     khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
    2833           0 :     TStringStream stream;
    2834           0 :     stream << HASHED_NAME_PREFIX << std::hex << number;
    2835           0 :     TString hashedName = stream.str();
    2836           0 :     return hashedName;
    2837             : }
    2838             : 
    2839           0 : void TIntermTraverser::updateTree()
    2840             : {
    2841           0 :     for (size_t ii = 0; ii < mInsertions.size(); ++ii)
    2842             :     {
    2843           0 :         const NodeInsertMultipleEntry &insertion = mInsertions[ii];
    2844           0 :         ASSERT(insertion.parent);
    2845           0 :         if (!insertion.insertionsAfter.empty())
    2846             :         {
    2847           0 :             bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
    2848           0 :                                                                insertion.insertionsAfter);
    2849           0 :             ASSERT(inserted);
    2850             :         }
    2851           0 :         if (!insertion.insertionsBefore.empty())
    2852             :         {
    2853             :             bool inserted =
    2854           0 :                 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
    2855           0 :             ASSERT(inserted);
    2856             :         }
    2857             :     }
    2858           0 :     for (size_t ii = 0; ii < mReplacements.size(); ++ii)
    2859             :     {
    2860           0 :         const NodeUpdateEntry &replacement = mReplacements[ii];
    2861           0 :         ASSERT(replacement.parent);
    2862           0 :         bool replaced = replacement.parent->replaceChildNode(
    2863           0 :             replacement.original, replacement.replacement);
    2864           0 :         ASSERT(replaced);
    2865             : 
    2866           0 :         if (!replacement.originalBecomesChildOfReplacement)
    2867             :         {
    2868             :             // In AST traversing, a parent is visited before its children.
    2869             :             // After we replace a node, if its immediate child is to
    2870             :             // be replaced, we need to make sure we don't update the replaced
    2871             :             // node; instead, we update the replacement node.
    2872           0 :             for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
    2873             :             {
    2874           0 :                 NodeUpdateEntry &replacement2 = mReplacements[jj];
    2875           0 :                 if (replacement2.parent == replacement.original)
    2876           0 :                     replacement2.parent = replacement.replacement;
    2877             :             }
    2878             :         }
    2879             :     }
    2880           0 :     for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
    2881             :     {
    2882           0 :         const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
    2883           0 :         ASSERT(replacement.parent);
    2884           0 :         bool replaced = replacement.parent->replaceChildNodeWithMultiple(
    2885           0 :             replacement.original, replacement.replacements);
    2886           0 :         ASSERT(replaced);
    2887             :     }
    2888             : 
    2889           0 :     clearReplacementQueue();
    2890           0 : }
    2891             : 
    2892           0 : void TIntermTraverser::clearReplacementQueue()
    2893             : {
    2894           0 :     mReplacements.clear();
    2895           0 :     mMultiReplacements.clear();
    2896           0 :     mInsertions.clear();
    2897           0 : }
    2898             : 
    2899           0 : void TIntermTraverser::queueReplacement(TIntermNode *original,
    2900             :                                         TIntermNode *replacement,
    2901             :                                         OriginalNode originalStatus)
    2902             : {
    2903           0 :     queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
    2904           0 : }
    2905             : 
    2906           0 : void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
    2907             :                                                   TIntermNode *original,
    2908             :                                                   TIntermNode *replacement,
    2909             :                                                   OriginalNode originalStatus)
    2910             : {
    2911           0 :     bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
    2912           0 :     mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
    2913           0 : }
    2914             : 
    2915             : }  // namespace sh

Generated by: LCOV version 1.13