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