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