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