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