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