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