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