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