• 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                 int resultCols = getType().getCols();
879                 int resultRows = getType().getRows();
880                 for (int col = 0; col < resultCols; ++col)
881                 {
882                     for (int 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             int argumentCols = argumentTyped->getType().getCols();
911             int argumentRows = argumentTyped->getType().getRows();
912             int resultCols   = getType().getCols();
913             int resultRows   = getType().getRows();
914             for (int col = 0; col < resultCols; ++col)
915             {
916                 for (int 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(static_cast<unsigned char>(mOperand->getType().getRows()));
1421             resultType.setSecondarySize(static_cast<unsigned char>(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(mSwizzleOffsets.size() <= 4);
1525     promote();
1526 }
1527 
TIntermUnary(TOperator op,TIntermTyped * operand,const TFunction * function)1528 TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function)
1529     : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false), mFunction(function)
1530 {
1531     ASSERT(mOperand);
1532     ASSERT(!BuiltInGroup::IsBuiltIn(op) || (function != nullptr && function->getBuiltInOp() == op));
1533     promote();
1534 }
1535 
TIntermBinary(TOperator op,TIntermTyped * left,TIntermTyped * right)1536 TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1537     : TIntermOperator(op), mLeft(left), mRight(right)
1538 {
1539     ASSERT(mLeft);
1540     ASSERT(mRight);
1541     promote();
1542 }
1543 
CreateComma(TIntermTyped * left,TIntermTyped * right,int shaderVersion)1544 TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1545                                           TIntermTyped *right,
1546                                           int shaderVersion)
1547 {
1548     TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1549     node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1550     return node;
1551 }
1552 
TIntermGlobalQualifierDeclaration(TIntermSymbol * symbol,bool isPrecise,const TSourceLoc & line)1553 TIntermGlobalQualifierDeclaration::TIntermGlobalQualifierDeclaration(TIntermSymbol *symbol,
1554                                                                      bool isPrecise,
1555                                                                      const TSourceLoc &line)
1556     : TIntermNode(), mSymbol(symbol), mIsPrecise(isPrecise)
1557 {
1558     ASSERT(symbol);
1559     setLine(line);
1560 }
1561 
TIntermGlobalQualifierDeclaration(const TIntermGlobalQualifierDeclaration & node)1562 TIntermGlobalQualifierDeclaration::TIntermGlobalQualifierDeclaration(
1563     const TIntermGlobalQualifierDeclaration &node)
1564     : TIntermGlobalQualifierDeclaration(static_cast<TIntermSymbol *>(node.mSymbol->deepCopy()),
1565                                         node.mIsPrecise,
1566                                         node.mLine)
1567 {}
1568 
TIntermTernary(TIntermTyped * cond,TIntermTyped * trueExpression,TIntermTyped * falseExpression)1569 TIntermTernary::TIntermTernary(TIntermTyped *cond,
1570                                TIntermTyped *trueExpression,
1571                                TIntermTyped *falseExpression)
1572     : TIntermExpression(trueExpression->getType()),
1573       mCondition(cond),
1574       mTrueExpression(trueExpression),
1575       mFalseExpression(falseExpression)
1576 {
1577     ASSERT(mCondition);
1578     ASSERT(mTrueExpression);
1579     ASSERT(mFalseExpression);
1580     getTypePointer()->setQualifier(
1581         TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1582 
1583     propagatePrecision(derivePrecision());
1584 }
1585 
TIntermLoop(TLoopType type,TIntermNode * init,TIntermTyped * cond,TIntermTyped * expr,TIntermBlock * body)1586 TIntermLoop::TIntermLoop(TLoopType type,
1587                          TIntermNode *init,
1588                          TIntermTyped *cond,
1589                          TIntermTyped *expr,
1590                          TIntermBlock *body)
1591     : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1592 {
1593     // Declaration nodes with no children can appear if all the declarators just added constants to
1594     // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1595     if (mInit && mInit->getAsDeclarationNode() &&
1596         mInit->getAsDeclarationNode()->getSequence()->empty())
1597     {
1598         mInit = nullptr;
1599     }
1600 }
1601 
TIntermLoop(const TIntermLoop & node)1602 TIntermLoop::TIntermLoop(const TIntermLoop &node)
1603     : TIntermLoop(node.mType,
1604                   node.mInit->deepCopy(),
1605                   node.mCond->deepCopy(),
1606                   node.mExpr->deepCopy(),
1607                   node.mBody->deepCopy())
1608 {}
1609 
TIntermIfElse(TIntermTyped * cond,TIntermBlock * trueB,TIntermBlock * falseB)1610 TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1611     : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1612 {
1613     ASSERT(mCondition);
1614     // Prune empty false blocks so that there won't be unnecessary operations done on it.
1615     if (mFalseBlock && mFalseBlock->getSequence()->empty())
1616     {
1617         mFalseBlock = nullptr;
1618     }
1619 }
1620 
TIntermIfElse(const TIntermIfElse & node)1621 TIntermIfElse::TIntermIfElse(const TIntermIfElse &node)
1622     : TIntermIfElse(node.mCondition->deepCopy(),
1623                     node.mTrueBlock->deepCopy(),
1624                     node.mFalseBlock ? node.mFalseBlock->deepCopy() : nullptr)
1625 {}
1626 
TIntermSwitch(TIntermTyped * init,TIntermBlock * statementList)1627 TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1628     : TIntermNode(), mInit(init), mStatementList(statementList)
1629 {
1630     ASSERT(mInit);
1631     ASSERT(mStatementList);
1632 }
1633 
TIntermSwitch(const TIntermSwitch & node)1634 TIntermSwitch::TIntermSwitch(const TIntermSwitch &node)
1635     : TIntermSwitch(node.mInit->deepCopy(), node.mStatementList->deepCopy())
1636 {}
1637 
setStatementList(TIntermBlock * statementList)1638 void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1639 {
1640     ASSERT(statementList);
1641     mStatementList = statementList;
1642 }
1643 
1644 // static
DetermineQualifier(TIntermTyped * cond,TIntermTyped * trueExpression,TIntermTyped * falseExpression)1645 TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1646                                               TIntermTyped *trueExpression,
1647                                               TIntermTyped *falseExpression)
1648 {
1649     if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1650         falseExpression->getQualifier() == EvqConst)
1651     {
1652         return EvqConst;
1653     }
1654     return EvqTemporary;
1655 }
1656 
1657 // Derive precision from children nodes
derivePrecision() const1658 TPrecision TIntermTernary::derivePrecision() const
1659 {
1660     return GetHigherPrecision(mTrueExpression->getPrecision(), mFalseExpression->getPrecision());
1661 }
1662 
propagatePrecision(TPrecision precision)1663 void TIntermTernary::propagatePrecision(TPrecision precision)
1664 {
1665     mType.setPrecision(precision);
1666 
1667     PropagatePrecisionIfApplicable(mTrueExpression, precision);
1668     PropagatePrecisionIfApplicable(mFalseExpression, precision);
1669 }
1670 
fold(TDiagnostics *)1671 TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
1672 {
1673     if (mCondition->getAsConstantUnion())
1674     {
1675         if (mCondition->getAsConstantUnion()->getBConst(0))
1676         {
1677             return mTrueExpression;
1678         }
1679         else
1680         {
1681             return mFalseExpression;
1682         }
1683     }
1684     return this;
1685 }
1686 
promote()1687 void TIntermSwizzle::promote()
1688 {
1689     TQualifier resultQualifier = EvqTemporary;
1690     if (mOperand->getQualifier() == EvqConst)
1691         resultQualifier = EvqConst;
1692 
1693     auto numFields = mSwizzleOffsets.size();
1694     setType(TType(mOperand->getBasicType(), EbpUndefined, resultQualifier,
1695                   static_cast<unsigned char>(numFields)));
1696     propagatePrecision(derivePrecision());
1697 }
1698 
1699 // Derive precision from children nodes
derivePrecision() const1700 TPrecision TIntermSwizzle::derivePrecision() const
1701 {
1702     return mOperand->getPrecision();
1703 }
1704 
propagatePrecision(TPrecision precision)1705 void TIntermSwizzle::propagatePrecision(TPrecision precision)
1706 {
1707     mType.setPrecision(precision);
1708 
1709     PropagatePrecisionIfApplicable(mOperand, precision);
1710 }
1711 
hasDuplicateOffsets() const1712 bool TIntermSwizzle::hasDuplicateOffsets() const
1713 {
1714     if (mHasFoldedDuplicateOffsets)
1715     {
1716         return true;
1717     }
1718     int offsetCount[4] = {0u, 0u, 0u, 0u};
1719     for (const auto offset : mSwizzleOffsets)
1720     {
1721         offsetCount[offset]++;
1722         if (offsetCount[offset] > 1)
1723         {
1724             return true;
1725         }
1726     }
1727     return false;
1728 }
1729 
setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)1730 void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
1731 {
1732     mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
1733 }
1734 
offsetsMatch(int offset) const1735 bool TIntermSwizzle::offsetsMatch(int offset) const
1736 {
1737     return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1738 }
1739 
writeOffsetsAsXYZW(TInfoSinkBase * out) const1740 void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1741 {
1742     for (const int offset : mSwizzleOffsets)
1743     {
1744         switch (offset)
1745         {
1746             case 0:
1747                 *out << "x";
1748                 break;
1749             case 1:
1750                 *out << "y";
1751                 break;
1752             case 2:
1753                 *out << "z";
1754                 break;
1755             case 3:
1756                 *out << "w";
1757                 break;
1758             default:
1759                 UNREACHABLE();
1760         }
1761     }
1762 }
1763 
GetCommaQualifier(int shaderVersion,const TIntermTyped * left,const TIntermTyped * right)1764 TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1765                                             const TIntermTyped *left,
1766                                             const TIntermTyped *right)
1767 {
1768     // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1769     if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1770         right->getQualifier() != EvqConst)
1771     {
1772         return EvqTemporary;
1773     }
1774     return EvqConst;
1775 }
1776 
1777 // Establishes the type of the result of the binary operation.
promote()1778 void TIntermBinary::promote()
1779 {
1780     ASSERT(!isMultiplication() ||
1781            mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1782 
1783     // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1784     // version and so is not being set here.
1785     if (mOp == EOpComma)
1786     {
1787         setType(mRight->getType());
1788         return;
1789     }
1790 
1791     // Base assumption:  just make the type the same as the left
1792     // operand.  Then only deviations from this need be coded.
1793     setType(mLeft->getType());
1794 
1795     TQualifier resultQualifier = EvqConst;
1796     // Binary operations results in temporary variables unless both
1797     // operands are const.  If initializing a specialization constant, make the declarator also
1798     // EvqSpecConst.
1799     const bool isSpecConstInit = mOp == EOpInitialize && mLeft->getQualifier() == EvqSpecConst;
1800     const bool isEitherNonConst =
1801         mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst;
1802     if (!isSpecConstInit && isEitherNonConst)
1803     {
1804         resultQualifier = EvqTemporary;
1805         getTypePointer()->setQualifier(EvqTemporary);
1806     }
1807 
1808     // Result is an intermediate value, so make sure it's identified as such.  That's not true for
1809     // interface block arrays being indexed.
1810     if (mOp != EOpIndexDirect && mOp != EOpIndexIndirect)
1811     {
1812         getTypePointer()->setInterfaceBlock(nullptr);
1813     }
1814 
1815     // Handle indexing ops.
1816     switch (mOp)
1817     {
1818         case EOpIndexDirect:
1819         case EOpIndexIndirect:
1820             if (mLeft->isArray())
1821             {
1822                 mType.toArrayElementType();
1823             }
1824             else if (mLeft->isMatrix())
1825             {
1826                 mType.toMatrixColumnType();
1827             }
1828             else if (mLeft->isVector())
1829             {
1830                 mType.toComponentType();
1831             }
1832             else
1833             {
1834                 UNREACHABLE();
1835             }
1836             return;
1837         case EOpIndexDirectStruct:
1838         {
1839             const TFieldList &fields = mLeft->getType().getStruct()->fields();
1840             const int fieldIndex     = mRight->getAsConstantUnion()->getIConst(0);
1841             setType(*fields[fieldIndex]->type());
1842             getTypePointer()->setQualifier(resultQualifier);
1843             return;
1844         }
1845         case EOpIndexDirectInterfaceBlock:
1846         {
1847             const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1848             const int fieldIndex     = mRight->getAsConstantUnion()->getIConst(0);
1849             setType(*fields[fieldIndex]->type());
1850             getTypePointer()->setQualifier(resultQualifier);
1851             return;
1852         }
1853         default:
1854             break;
1855     }
1856 
1857     ASSERT(mLeft->isArray() == mRight->isArray());
1858 
1859     const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
1860 
1861     switch (mOp)
1862     {
1863         case EOpMul:
1864             break;
1865         case EOpMatrixTimesScalar:
1866             if (mRight->isMatrix())
1867             {
1868                 getTypePointer()->setPrimarySize(static_cast<unsigned char>(mRight->getCols()));
1869                 getTypePointer()->setSecondarySize(static_cast<unsigned char>(mRight->getRows()));
1870             }
1871             break;
1872         case EOpMatrixTimesVector:
1873             getTypePointer()->setPrimarySize(static_cast<unsigned char>(mLeft->getRows()));
1874             getTypePointer()->setSecondarySize(1);
1875             break;
1876         case EOpMatrixTimesMatrix:
1877             getTypePointer()->setPrimarySize(static_cast<unsigned char>(mRight->getCols()));
1878             getTypePointer()->setSecondarySize(static_cast<unsigned char>(mLeft->getRows()));
1879             break;
1880         case EOpVectorTimesScalar:
1881             getTypePointer()->setPrimarySize(static_cast<unsigned char>(nominalSize));
1882             break;
1883         case EOpVectorTimesMatrix:
1884             getTypePointer()->setPrimarySize(static_cast<unsigned char>(mRight->getCols()));
1885             ASSERT(getType().getSecondarySize() == 1);
1886             break;
1887         case EOpMulAssign:
1888         case EOpVectorTimesScalarAssign:
1889         case EOpVectorTimesMatrixAssign:
1890         case EOpMatrixTimesScalarAssign:
1891         case EOpMatrixTimesMatrixAssign:
1892             ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1893             break;
1894         case EOpAssign:
1895         case EOpInitialize:
1896             ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1897                    (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1898             break;
1899         case EOpAdd:
1900         case EOpSub:
1901         case EOpDiv:
1902         case EOpIMod:
1903         case EOpBitShiftLeft:
1904         case EOpBitShiftRight:
1905         case EOpBitwiseAnd:
1906         case EOpBitwiseXor:
1907         case EOpBitwiseOr:
1908         case EOpAddAssign:
1909         case EOpSubAssign:
1910         case EOpDivAssign:
1911         case EOpIModAssign:
1912         case EOpBitShiftLeftAssign:
1913         case EOpBitShiftRightAssign:
1914         case EOpBitwiseAndAssign:
1915         case EOpBitwiseXorAssign:
1916         case EOpBitwiseOrAssign:
1917         {
1918             ASSERT(!mLeft->isArray() && !mRight->isArray());
1919             const int secondarySize =
1920                 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1921             getTypePointer()->setPrimarySize(static_cast<unsigned char>(nominalSize));
1922             getTypePointer()->setSecondarySize(static_cast<unsigned char>(secondarySize));
1923             break;
1924         }
1925         case EOpEqual:
1926         case EOpNotEqual:
1927         case EOpLessThan:
1928         case EOpGreaterThan:
1929         case EOpLessThanEqual:
1930         case EOpGreaterThanEqual:
1931             ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1932                    (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1933             setType(TType(EbtBool, EbpUndefined, resultQualifier));
1934             break;
1935 
1936         //
1937         // And and Or operate on conditionals
1938         //
1939         case EOpLogicalAnd:
1940         case EOpLogicalXor:
1941         case EOpLogicalOr:
1942             ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1943             break;
1944 
1945         case EOpIndexDirect:
1946         case EOpIndexIndirect:
1947         case EOpIndexDirectInterfaceBlock:
1948         case EOpIndexDirectStruct:
1949             // These ops should be already fully handled.
1950             UNREACHABLE();
1951             break;
1952         default:
1953             UNREACHABLE();
1954             break;
1955     }
1956 
1957     propagatePrecision(derivePrecision());
1958 }
1959 
1960 // Derive precision from children nodes
derivePrecision() const1961 TPrecision TIntermBinary::derivePrecision() const
1962 {
1963     const TPrecision higherPrecision =
1964         GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1965 
1966     switch (mOp)
1967     {
1968         case EOpComma:
1969             // Comma takes the right node's value.
1970             return mRight->getPrecision();
1971 
1972         case EOpIndexDirect:
1973         case EOpIndexIndirect:
1974         case EOpBitShiftLeft:
1975         case EOpBitShiftRight:
1976             // When indexing an array, the precision of the array is preserved (which is the left
1977             // node).
1978             // For shift operations, the precision is derived from the expression being shifted
1979             // (which is also the left node).
1980             return mLeft->getPrecision();
1981 
1982         case EOpIndexDirectStruct:
1983         case EOpIndexDirectInterfaceBlock:
1984         {
1985             // When selecting the field of a block, the precision is taken from the field's
1986             // declaration.
1987             const TFieldList &fields = mOp == EOpIndexDirectStruct
1988                                            ? mLeft->getType().getStruct()->fields()
1989                                            : mLeft->getType().getInterfaceBlock()->fields();
1990             const int fieldIndex = mRight->getAsConstantUnion()->getIConst(0);
1991             return fields[fieldIndex]->type()->getPrecision();
1992         }
1993 
1994         case EOpEqual:
1995         case EOpNotEqual:
1996         case EOpLessThan:
1997         case EOpGreaterThan:
1998         case EOpLessThanEqual:
1999         case EOpGreaterThanEqual:
2000         case EOpLogicalAnd:
2001         case EOpLogicalXor:
2002         case EOpLogicalOr:
2003             // No precision specified on bool results.
2004             return EbpUndefined;
2005 
2006         default:
2007             // All other operations are evaluated at the higher of the two operands' precisions.
2008             return higherPrecision;
2009     }
2010 }
2011 
propagatePrecision(TPrecision precision)2012 void TIntermBinary::propagatePrecision(TPrecision precision)
2013 {
2014     getTypePointer()->setPrecision(precision);
2015 
2016     if (mOp != EOpComma)
2017     {
2018         PropagatePrecisionIfApplicable(mLeft, precision);
2019     }
2020 
2021     if (mOp != EOpIndexDirect && mOp != EOpIndexIndirect && mOp != EOpIndexDirectStruct &&
2022         mOp != EOpIndexDirectInterfaceBlock)
2023     {
2024         PropagatePrecisionIfApplicable(mRight, precision);
2025     }
2026 
2027     // For indices, always apply highp.  This is purely for the purpose of making sure constant and
2028     // constructor nodes are also given a precision, so if they are hoisted to a temp variable,
2029     // there would be a precision to apply to that variable.
2030     if (mOp == EOpIndexDirect || mOp == EOpIndexIndirect)
2031     {
2032         PropagatePrecisionIfApplicable(mRight, EbpHigh);
2033     }
2034 }
2035 
hasConstantValue() const2036 bool TIntermConstantUnion::hasConstantValue() const
2037 {
2038     return true;
2039 }
2040 
isConstantNullValue() const2041 bool TIntermConstantUnion::isConstantNullValue() const
2042 {
2043     const size_t size = mType.getObjectSize();
2044     for (size_t index = 0; index < size; ++index)
2045     {
2046         if (!mUnionArrayPointer[index].isZero())
2047         {
2048             return false;
2049         }
2050     }
2051     return true;
2052 }
2053 
getConstantValue() const2054 const TConstantUnion *TIntermConstantUnion::getConstantValue() const
2055 {
2056     return mUnionArrayPointer;
2057 }
2058 
FoldIndexing(const TType & type,const TConstantUnion * constArray,int index)2059 const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
2060                                                          const TConstantUnion *constArray,
2061                                                          int index)
2062 {
2063     if (type.isArray())
2064     {
2065         ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
2066         TType arrayElementType(type);
2067         arrayElementType.toArrayElementType();
2068         size_t arrayElementSize = arrayElementType.getObjectSize();
2069         return &constArray[arrayElementSize * index];
2070     }
2071     else if (type.isMatrix())
2072     {
2073         ASSERT(index < type.getCols());
2074         int size = type.getRows();
2075         return &constArray[size * index];
2076     }
2077     else if (type.isVector())
2078     {
2079         ASSERT(index < type.getNominalSize());
2080         return &constArray[index];
2081     }
2082     else
2083     {
2084         UNREACHABLE();
2085         return nullptr;
2086     }
2087 }
2088 
fold(TDiagnostics *)2089 TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
2090 {
2091     TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
2092     if (operandSwizzle)
2093     {
2094         // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
2095         // overflow in ParseContext::checkCanBeLValue().
2096         bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
2097         TVector<int> foldedOffsets;
2098         for (int offset : mSwizzleOffsets)
2099         {
2100             // Offset should already be validated.
2101             ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
2102             foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
2103         }
2104         operandSwizzle->mSwizzleOffsets = foldedOffsets;
2105         operandSwizzle->setType(getType());
2106         operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
2107         return operandSwizzle;
2108     }
2109     TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
2110     if (operandConstant == nullptr)
2111     {
2112         return this;
2113     }
2114 
2115     TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
2116     for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
2117     {
2118         constArray[i] = *TIntermConstantUnion::FoldIndexing(
2119             operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
2120     }
2121     return CreateFoldedNode(constArray, this);
2122 }
2123 
fold(TDiagnostics * diagnostics)2124 TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
2125 {
2126     const TConstantUnion *rightConstant = mRight->getConstantValue();
2127     switch (mOp)
2128     {
2129         case EOpComma:
2130         {
2131             if (mLeft->hasSideEffects())
2132             {
2133                 return this;
2134             }
2135             return mRight;
2136         }
2137         case EOpIndexDirect:
2138         case EOpIndexDirectStruct:
2139         {
2140             if (rightConstant == nullptr)
2141             {
2142                 return this;
2143             }
2144             size_t index                    = static_cast<size_t>(rightConstant->getIConst());
2145             TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
2146             if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
2147                 !leftAggregate->hasSideEffects())
2148             {
2149                 ASSERT(index < leftAggregate->getSequence()->size());
2150                 // This transformation can't add complexity as we're eliminating the constructor
2151                 // entirely.
2152                 return leftAggregate->getSequence()->at(index)->getAsTyped();
2153             }
2154 
2155             // If the indexed value is already a constant union, we can't increase duplication of
2156             // data by folding the indexing. Also fold the node in case it's generally beneficial to
2157             // replace this type of node with a constant union even if that would mean duplicating
2158             // data.
2159             if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
2160             {
2161                 const TConstantUnion *constantValue = getConstantValue();
2162                 if (constantValue == nullptr)
2163                 {
2164                     return this;
2165                 }
2166                 return CreateFoldedNode(constantValue, this);
2167             }
2168             return this;
2169         }
2170         case EOpIndexIndirect:
2171         case EOpIndexDirectInterfaceBlock:
2172         case EOpInitialize:
2173             // Can never be constant folded.
2174             return this;
2175         default:
2176         {
2177             if (rightConstant == nullptr)
2178             {
2179                 return this;
2180             }
2181             const TConstantUnion *leftConstant = mLeft->getConstantValue();
2182             if (leftConstant == nullptr)
2183             {
2184                 return this;
2185             }
2186             const TConstantUnion *constArray =
2187                 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
2188                                                  mRight->getType(), diagnostics, mLeft->getLine());
2189             if (!constArray)
2190             {
2191                 return this;
2192             }
2193             return CreateFoldedNode(constArray, this);
2194         }
2195     }
2196 }
2197 
hasConstantValue() const2198 bool TIntermBinary::hasConstantValue() const
2199 {
2200     switch (mOp)
2201     {
2202         case EOpIndexDirect:
2203         case EOpIndexDirectStruct:
2204         {
2205             if (mLeft->hasConstantValue() && mRight->hasConstantValue())
2206             {
2207                 return true;
2208             }
2209             break;
2210         }
2211         default:
2212             break;
2213     }
2214     return false;
2215 }
2216 
getConstantValue() const2217 const TConstantUnion *TIntermBinary::getConstantValue() const
2218 {
2219     if (!hasConstantValue())
2220     {
2221         return nullptr;
2222     }
2223 
2224     const TConstantUnion *leftConstantValue   = mLeft->getConstantValue();
2225     int index                                 = mRight->getConstantValue()->getIConst();
2226     const TConstantUnion *constIndexingResult = nullptr;
2227     if (mOp == EOpIndexDirect)
2228     {
2229         constIndexingResult =
2230             TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
2231     }
2232     else
2233     {
2234         ASSERT(mOp == EOpIndexDirectStruct);
2235         const TFieldList &fields = mLeft->getType().getStruct()->fields();
2236 
2237         size_t previousFieldsSize = 0;
2238         for (int i = 0; i < index; ++i)
2239         {
2240             previousFieldsSize += fields[i]->type()->getObjectSize();
2241         }
2242         constIndexingResult = leftConstantValue + previousFieldsSize;
2243     }
2244     return constIndexingResult;
2245 }
2246 
getIndexStructFieldName() const2247 const ImmutableString &TIntermBinary::getIndexStructFieldName() const
2248 {
2249     ASSERT(mOp == EOpIndexDirectStruct);
2250 
2251     const TType &lhsType        = mLeft->getType();
2252     const TStructure *structure = lhsType.getStruct();
2253     const int index             = mRight->getAsConstantUnion()->getIConst(0);
2254 
2255     return structure->fields()[index]->name();
2256 }
2257 
fold(TDiagnostics * diagnostics)2258 TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
2259 {
2260     TConstantUnion *constArray = nullptr;
2261 
2262     if (mOp == EOpArrayLength)
2263     {
2264         // The size of runtime-sized arrays may only be determined at runtime.
2265         if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
2266         {
2267             return this;
2268         }
2269         constArray = new TConstantUnion[1];
2270         constArray->setIConst(mOperand->getOutermostArraySize());
2271     }
2272     else
2273     {
2274         TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
2275         if (operandConstant == nullptr)
2276         {
2277             return this;
2278         }
2279 
2280         switch (mOp)
2281         {
2282             case EOpAny:
2283             case EOpAll:
2284             case EOpLength:
2285             case EOpTranspose:
2286             case EOpDeterminant:
2287             case EOpInverse:
2288             case EOpPackSnorm2x16:
2289             case EOpUnpackSnorm2x16:
2290             case EOpPackUnorm2x16:
2291             case EOpUnpackUnorm2x16:
2292             case EOpPackHalf2x16:
2293             case EOpUnpackHalf2x16:
2294             case EOpPackUnorm4x8:
2295             case EOpPackSnorm4x8:
2296             case EOpUnpackUnorm4x8:
2297             case EOpUnpackSnorm4x8:
2298                 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
2299                 break;
2300             default:
2301                 constArray = operandConstant->foldUnaryComponentWise(mOp, mFunction, diagnostics);
2302                 break;
2303         }
2304     }
2305     if (constArray == nullptr)
2306     {
2307         return this;
2308     }
2309     return CreateFoldedNode(constArray, this);
2310 }
2311 
fold(TDiagnostics * diagnostics)2312 TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
2313 {
2314     // Make sure that all params are constant before actual constant folding.
2315     for (auto *param : *getSequence())
2316     {
2317         if (param->getAsConstantUnion() == nullptr)
2318         {
2319             return this;
2320         }
2321     }
2322     const TConstantUnion *constArray = nullptr;
2323     if (isConstructor())
2324     {
2325         if (mType.canReplaceWithConstantUnion())
2326         {
2327             constArray = getConstantValue();
2328             if (constArray && mType.getBasicType() == EbtUInt)
2329             {
2330                 // Check if we converted a negative float to uint and issue a warning in that case.
2331                 size_t sizeRemaining = mType.getObjectSize();
2332                 for (TIntermNode *arg : mArguments)
2333                 {
2334                     TIntermTyped *typedArg = arg->getAsTyped();
2335                     if (typedArg->getBasicType() == EbtFloat)
2336                     {
2337                         const TConstantUnion *argValue = typedArg->getConstantValue();
2338                         size_t castSize =
2339                             std::min(typedArg->getType().getObjectSize(), sizeRemaining);
2340                         for (size_t i = 0; i < castSize; ++i)
2341                         {
2342                             if (argValue[i].getFConst() < 0.0f)
2343                             {
2344                                 // ESSL 3.00.6 section 5.4.1.
2345                                 diagnostics->warning(
2346                                     mLine, "casting a negative float to uint is undefined",
2347                                     mType.getBuiltInTypeNameString());
2348                             }
2349                         }
2350                     }
2351                     sizeRemaining -= typedArg->getType().getObjectSize();
2352                 }
2353             }
2354         }
2355     }
2356     else if (CanFoldAggregateBuiltInOp(mOp))
2357     {
2358         constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
2359     }
2360     if (constArray == nullptr)
2361     {
2362         return this;
2363     }
2364     return CreateFoldedNode(constArray, this);
2365 }
2366 
2367 //
2368 // The fold functions see if an operation on a constant can be done in place,
2369 // without generating run-time code.
2370 //
2371 // Returns the constant value to keep using or nullptr.
2372 //
FoldBinary(TOperator op,const TConstantUnion * leftArray,const TType & leftType,const TConstantUnion * rightArray,const TType & rightType,TDiagnostics * diagnostics,const TSourceLoc & line)2373 const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
2374                                                        const TConstantUnion *leftArray,
2375                                                        const TType &leftType,
2376                                                        const TConstantUnion *rightArray,
2377                                                        const TType &rightType,
2378                                                        TDiagnostics *diagnostics,
2379                                                        const TSourceLoc &line)
2380 {
2381     ASSERT(leftArray && rightArray);
2382 
2383     size_t objectSize = leftType.getObjectSize();
2384 
2385     // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
2386     if (rightType.getObjectSize() == 1 && objectSize > 1)
2387     {
2388         rightArray = Vectorize(*rightArray, objectSize);
2389     }
2390     else if (rightType.getObjectSize() > 1 && objectSize == 1)
2391     {
2392         // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
2393         leftArray  = Vectorize(*leftArray, rightType.getObjectSize());
2394         objectSize = rightType.getObjectSize();
2395     }
2396 
2397     TConstantUnion *resultArray = nullptr;
2398 
2399     switch (op)
2400     {
2401         case EOpAdd:
2402             resultArray = new TConstantUnion[objectSize];
2403             for (size_t i = 0; i < objectSize; i++)
2404                 resultArray[i] =
2405                     TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
2406             break;
2407         case EOpSub:
2408             resultArray = new TConstantUnion[objectSize];
2409             for (size_t i = 0; i < objectSize; i++)
2410                 resultArray[i] =
2411                     TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
2412             break;
2413 
2414         case EOpMul:
2415         case EOpVectorTimesScalar:
2416         case EOpMatrixTimesScalar:
2417             resultArray = new TConstantUnion[objectSize];
2418             for (size_t i = 0; i < objectSize; i++)
2419                 resultArray[i] =
2420                     TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
2421             break;
2422 
2423         case EOpMatrixTimesMatrix:
2424         {
2425             // TODO(jmadll): This code should check for overflows.
2426             ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
2427 
2428             const int leftCols   = leftType.getCols();
2429             const int leftRows   = leftType.getRows();
2430             const int rightCols  = rightType.getCols();
2431             const int rightRows  = rightType.getRows();
2432             const int resultCols = rightCols;
2433             const int resultRows = leftRows;
2434 
2435             resultArray = new TConstantUnion[resultCols * resultRows];
2436             for (int row = 0; row < resultRows; row++)
2437             {
2438                 for (int column = 0; column < resultCols; column++)
2439                 {
2440                     resultArray[resultRows * column + row].setFConst(0.0f);
2441                     for (int i = 0; i < leftCols; i++)
2442                     {
2443                         resultArray[resultRows * column + row].setFConst(
2444                             resultArray[resultRows * column + row].getFConst() +
2445                             leftArray[i * leftRows + row].getFConst() *
2446                                 rightArray[column * rightRows + i].getFConst());
2447                     }
2448                 }
2449             }
2450         }
2451         break;
2452 
2453         case EOpDiv:
2454         case EOpIMod:
2455         {
2456             resultArray = new TConstantUnion[objectSize];
2457             for (size_t i = 0; i < objectSize; i++)
2458             {
2459                 if (IsFloatDivision(leftType.getBasicType(), rightType.getBasicType()))
2460                 {
2461                     // Float division requested, possibly with implicit conversion
2462                     ASSERT(op == EOpDiv);
2463                     float dividend = leftArray[i].getFConst();
2464                     float divisor  = rightArray[i].getFConst();
2465 
2466                     if (divisor == 0.0f)
2467                     {
2468                         if (dividend == 0.0f)
2469                         {
2470                             diagnostics->warning(line,
2471                                                  "Zero divided by zero during constant "
2472                                                  "folding generated NaN",
2473                                                  "/");
2474                             resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
2475                         }
2476                         else
2477                         {
2478                             diagnostics->warning(line, "Divide by zero during constant folding",
2479                                                  "/");
2480                             bool negativeResult = std::signbit(dividend) != std::signbit(divisor);
2481                             resultArray[i].setFConst(negativeResult
2482                                                          ? -std::numeric_limits<float>::infinity()
2483                                                          : std::numeric_limits<float>::infinity());
2484                         }
2485                     }
2486                     else if (gl::isInf(dividend) && gl::isInf(divisor))
2487                     {
2488                         diagnostics->warning(line,
2489                                              "Infinity divided by infinity during constant "
2490                                              "folding generated NaN",
2491                                              "/");
2492                         resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
2493                     }
2494                     else
2495                     {
2496                         float result = dividend / divisor;
2497                         if (!gl::isInf(dividend) && gl::isInf(result))
2498                         {
2499                             diagnostics->warning(
2500                                 line, "Constant folded division overflowed to infinity", "/");
2501                         }
2502                         resultArray[i].setFConst(result);
2503                     }
2504                 }
2505                 else
2506                 {
2507                     // Types are either both int or both uint
2508                     switch (leftType.getBasicType())
2509                     {
2510                         case EbtInt:
2511                         {
2512                             if (rightArray[i] == 0)
2513                             {
2514                                 diagnostics->warning(
2515                                     line, "Divide by zero error during constant folding", "/");
2516                                 resultArray[i].setIConst(INT_MAX);
2517                             }
2518                             else
2519                             {
2520                                 int lhs     = leftArray[i].getIConst();
2521                                 int divisor = rightArray[i].getIConst();
2522                                 if (op == EOpDiv)
2523                                 {
2524                                     // Check for the special case where the minimum
2525                                     // representable number is divided by -1. If left alone this
2526                                     // leads to integer overflow in C++. ESSL 3.00.6
2527                                     // section 4.1.3 Integers: "However, for the case where the
2528                                     // minimum representable value is divided by -1, it is
2529                                     // allowed to return either the minimum representable value
2530                                     // or the maximum representable value."
2531                                     if (lhs == -0x7fffffff - 1 && divisor == -1)
2532                                     {
2533                                         resultArray[i].setIConst(0x7fffffff);
2534                                     }
2535                                     else
2536                                     {
2537                                         resultArray[i].setIConst(lhs / divisor);
2538                                     }
2539                                 }
2540                                 else
2541                                 {
2542                                     ASSERT(op == EOpIMod);
2543                                     if (lhs < 0 || divisor < 0)
2544                                     {
2545                                         // ESSL 3.00.6 section 5.9: Results of modulus are
2546                                         // undefined when either one of the operands is
2547                                         // negative.
2548                                         diagnostics->warning(line,
2549                                                              "Negative modulus operator operand "
2550                                                              "encountered during constant folding. "
2551                                                              "Results are undefined.",
2552                                                              "%");
2553                                         resultArray[i].setIConst(0);
2554                                     }
2555                                     else
2556                                     {
2557                                         resultArray[i].setIConst(lhs % divisor);
2558                                     }
2559                                 }
2560                             }
2561                             break;
2562                         }
2563                         case EbtUInt:
2564                         {
2565                             if (rightArray[i] == 0)
2566                             {
2567                                 diagnostics->warning(
2568                                     line, "Divide by zero error during constant folding", "/");
2569                                 resultArray[i].setUConst(UINT_MAX);
2570                             }
2571                             else
2572                             {
2573                                 if (op == EOpDiv)
2574                                 {
2575                                     resultArray[i].setUConst(leftArray[i].getUConst() /
2576                                                              rightArray[i].getUConst());
2577                                 }
2578                                 else
2579                                 {
2580                                     ASSERT(op == EOpIMod);
2581                                     resultArray[i].setUConst(leftArray[i].getUConst() %
2582                                                              rightArray[i].getUConst());
2583                                 }
2584                             }
2585                             break;
2586                         }
2587                         default:
2588                             UNREACHABLE();
2589                             return nullptr;
2590                     }
2591                 }
2592             }
2593         }
2594         break;
2595 
2596         case EOpMatrixTimesVector:
2597         {
2598             // TODO(jmadll): This code should check for overflows.
2599             ASSERT(rightType.getBasicType() == EbtFloat);
2600 
2601             const int matrixCols = leftType.getCols();
2602             const int matrixRows = leftType.getRows();
2603 
2604             resultArray = new TConstantUnion[matrixRows];
2605 
2606             for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
2607             {
2608                 resultArray[matrixRow].setFConst(0.0f);
2609                 for (int col = 0; col < matrixCols; col++)
2610                 {
2611                     resultArray[matrixRow].setFConst(
2612                         resultArray[matrixRow].getFConst() +
2613                         leftArray[col * matrixRows + matrixRow].getFConst() *
2614                             rightArray[col].getFConst());
2615                 }
2616             }
2617         }
2618         break;
2619 
2620         case EOpVectorTimesMatrix:
2621         {
2622             // TODO(jmadll): This code should check for overflows.
2623             ASSERT(leftType.getBasicType() == EbtFloat);
2624 
2625             const int matrixCols = rightType.getCols();
2626             const int matrixRows = rightType.getRows();
2627 
2628             resultArray = new TConstantUnion[matrixCols];
2629 
2630             for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
2631             {
2632                 resultArray[matrixCol].setFConst(0.0f);
2633                 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
2634                 {
2635                     resultArray[matrixCol].setFConst(
2636                         resultArray[matrixCol].getFConst() +
2637                         leftArray[matrixRow].getFConst() *
2638                             rightArray[matrixCol * matrixRows + matrixRow].getFConst());
2639                 }
2640             }
2641         }
2642         break;
2643 
2644         case EOpLogicalAnd:
2645         {
2646             resultArray = new TConstantUnion[objectSize];
2647             for (size_t i = 0; i < objectSize; i++)
2648             {
2649                 resultArray[i] = leftArray[i] && rightArray[i];
2650             }
2651         }
2652         break;
2653 
2654         case EOpLogicalOr:
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 EOpLogicalXor:
2665         {
2666             ASSERT(leftType.getBasicType() == EbtBool);
2667             resultArray = new TConstantUnion[objectSize];
2668             for (size_t i = 0; i < objectSize; i++)
2669             {
2670                 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
2671             }
2672         }
2673         break;
2674 
2675         case EOpBitwiseAnd:
2676             resultArray = new TConstantUnion[objectSize];
2677             for (size_t i = 0; i < objectSize; i++)
2678                 resultArray[i] = leftArray[i] & rightArray[i];
2679             break;
2680         case EOpBitwiseXor:
2681             resultArray = new TConstantUnion[objectSize];
2682             for (size_t i = 0; i < objectSize; i++)
2683                 resultArray[i] = leftArray[i] ^ rightArray[i];
2684             break;
2685         case EOpBitwiseOr:
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 EOpBitShiftLeft:
2691             resultArray = new TConstantUnion[objectSize];
2692             for (size_t i = 0; i < objectSize; i++)
2693                 resultArray[i] =
2694                     TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2695             break;
2696         case EOpBitShiftRight:
2697             resultArray = new TConstantUnion[objectSize];
2698             for (size_t i = 0; i < objectSize; i++)
2699                 resultArray[i] =
2700                     TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2701             break;
2702 
2703         case EOpLessThan:
2704             ASSERT(objectSize == 1);
2705             resultArray = new TConstantUnion[1];
2706             resultArray->setBConst(*leftArray < *rightArray);
2707             break;
2708 
2709         case EOpGreaterThan:
2710             ASSERT(objectSize == 1);
2711             resultArray = new TConstantUnion[1];
2712             resultArray->setBConst(*leftArray > *rightArray);
2713             break;
2714 
2715         case EOpLessThanEqual:
2716             ASSERT(objectSize == 1);
2717             resultArray = new TConstantUnion[1];
2718             resultArray->setBConst(!(*leftArray > *rightArray));
2719             break;
2720 
2721         case EOpGreaterThanEqual:
2722             ASSERT(objectSize == 1);
2723             resultArray = new TConstantUnion[1];
2724             resultArray->setBConst(!(*leftArray < *rightArray));
2725             break;
2726 
2727         case EOpEqual:
2728         case EOpNotEqual:
2729         {
2730             resultArray = new TConstantUnion[1];
2731             bool equal  = true;
2732             for (size_t i = 0; i < objectSize; i++)
2733             {
2734                 if (leftArray[i] != rightArray[i])
2735                 {
2736                     equal = false;
2737                     break;  // break out of for loop
2738                 }
2739             }
2740             if (op == EOpEqual)
2741             {
2742                 resultArray->setBConst(equal);
2743             }
2744             else
2745             {
2746                 resultArray->setBConst(!equal);
2747             }
2748         }
2749         break;
2750 
2751         default:
2752             UNREACHABLE();
2753             return nullptr;
2754     }
2755     return resultArray;
2756 }
2757 
2758 // The fold functions do operations on a constant at GLSL compile time, without generating run-time
2759 // code. Returns the constant value to keep using. Nullptr should not be returned.
foldUnaryNonComponentWise(TOperator op)2760 TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
2761 {
2762     // Do operations where the return type may have a different number of components compared to the
2763     // operand type.
2764 
2765     const TConstantUnion *operandArray = getConstantValue();
2766     ASSERT(operandArray);
2767 
2768     size_t objectSize           = getType().getObjectSize();
2769     TConstantUnion *resultArray = nullptr;
2770     switch (op)
2771     {
2772         case EOpAny:
2773             ASSERT(getType().getBasicType() == EbtBool);
2774             resultArray = new TConstantUnion();
2775             resultArray->setBConst(false);
2776             for (size_t i = 0; i < objectSize; i++)
2777             {
2778                 if (operandArray[i].getBConst())
2779                 {
2780                     resultArray->setBConst(true);
2781                     break;
2782                 }
2783             }
2784             break;
2785 
2786         case EOpAll:
2787             ASSERT(getType().getBasicType() == EbtBool);
2788             resultArray = new TConstantUnion();
2789             resultArray->setBConst(true);
2790             for (size_t i = 0; i < objectSize; i++)
2791             {
2792                 if (!operandArray[i].getBConst())
2793                 {
2794                     resultArray->setBConst(false);
2795                     break;
2796                 }
2797             }
2798             break;
2799 
2800         case EOpLength:
2801             ASSERT(getType().getBasicType() == EbtFloat);
2802             resultArray = new TConstantUnion();
2803             resultArray->setFConst(VectorLength(operandArray, objectSize));
2804             break;
2805 
2806         case EOpTranspose:
2807         {
2808             ASSERT(getType().getBasicType() == EbtFloat);
2809             resultArray = new TConstantUnion[objectSize];
2810             angle::Matrix<float> result =
2811                 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
2812             SetUnionArrayFromMatrix(result, resultArray);
2813             break;
2814         }
2815 
2816         case EOpDeterminant:
2817         {
2818             ASSERT(getType().getBasicType() == EbtFloat);
2819             unsigned int size = getType().getNominalSize();
2820             ASSERT(size >= 2 && size <= 4);
2821             resultArray = new TConstantUnion();
2822             resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2823             break;
2824         }
2825 
2826         case EOpInverse:
2827         {
2828             ASSERT(getType().getBasicType() == EbtFloat);
2829             unsigned int size = getType().getNominalSize();
2830             ASSERT(size >= 2 && size <= 4);
2831             resultArray                 = new TConstantUnion[objectSize];
2832             angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2833             SetUnionArrayFromMatrix(result, resultArray);
2834             break;
2835         }
2836 
2837         case EOpPackSnorm2x16:
2838             ASSERT(getType().getBasicType() == EbtFloat);
2839             ASSERT(getType().getNominalSize() == 2);
2840             resultArray = new TConstantUnion();
2841             resultArray->setUConst(
2842                 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2843             break;
2844 
2845         case EOpUnpackSnorm2x16:
2846         {
2847             ASSERT(getType().getBasicType() == EbtUInt);
2848             resultArray = new TConstantUnion[2];
2849             float f1, f2;
2850             gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2851             resultArray[0].setFConst(f1);
2852             resultArray[1].setFConst(f2);
2853             break;
2854         }
2855 
2856         case EOpPackUnorm2x16:
2857             ASSERT(getType().getBasicType() == EbtFloat);
2858             ASSERT(getType().getNominalSize() == 2);
2859             resultArray = new TConstantUnion();
2860             resultArray->setUConst(
2861                 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2862             break;
2863 
2864         case EOpUnpackUnorm2x16:
2865         {
2866             ASSERT(getType().getBasicType() == EbtUInt);
2867             resultArray = new TConstantUnion[2];
2868             float f1, f2;
2869             gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2870             resultArray[0].setFConst(f1);
2871             resultArray[1].setFConst(f2);
2872             break;
2873         }
2874 
2875         case EOpPackHalf2x16:
2876             ASSERT(getType().getBasicType() == EbtFloat);
2877             ASSERT(getType().getNominalSize() == 2);
2878             resultArray = new TConstantUnion();
2879             resultArray->setUConst(
2880                 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2881             break;
2882 
2883         case EOpUnpackHalf2x16:
2884         {
2885             ASSERT(getType().getBasicType() == EbtUInt);
2886             resultArray = new TConstantUnion[2];
2887             float f1, f2;
2888             gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2889             resultArray[0].setFConst(f1);
2890             resultArray[1].setFConst(f2);
2891             break;
2892         }
2893 
2894         case EOpPackUnorm4x8:
2895         {
2896             ASSERT(getType().getBasicType() == EbtFloat);
2897             resultArray = new TConstantUnion();
2898             resultArray->setUConst(
2899                 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2900                                  operandArray[2].getFConst(), operandArray[3].getFConst()));
2901             break;
2902         }
2903         case EOpPackSnorm4x8:
2904         {
2905             ASSERT(getType().getBasicType() == EbtFloat);
2906             resultArray = new TConstantUnion();
2907             resultArray->setUConst(
2908                 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2909                                  operandArray[2].getFConst(), operandArray[3].getFConst()));
2910             break;
2911         }
2912         case EOpUnpackUnorm4x8:
2913         {
2914             ASSERT(getType().getBasicType() == EbtUInt);
2915             resultArray = new TConstantUnion[4];
2916             float f[4];
2917             gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2918             for (size_t i = 0; i < 4; ++i)
2919             {
2920                 resultArray[i].setFConst(f[i]);
2921             }
2922             break;
2923         }
2924         case EOpUnpackSnorm4x8:
2925         {
2926             ASSERT(getType().getBasicType() == EbtUInt);
2927             resultArray = new TConstantUnion[4];
2928             float f[4];
2929             gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2930             for (size_t i = 0; i < 4; ++i)
2931             {
2932                 resultArray[i].setFConst(f[i]);
2933             }
2934             break;
2935         }
2936 
2937         default:
2938             UNREACHABLE();
2939             break;
2940     }
2941 
2942     return resultArray;
2943 }
2944 
foldUnaryComponentWise(TOperator op,const TFunction * function,TDiagnostics * diagnostics)2945 TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2946                                                              const TFunction *function,
2947                                                              TDiagnostics *diagnostics)
2948 {
2949     // Do unary operations where each component of the result is computed based on the corresponding
2950     // component of the operand. Also folds normalize, though the divisor in that case takes all
2951     // components into account.
2952 
2953     const TConstantUnion *operandArray = getConstantValue();
2954     ASSERT(operandArray);
2955 
2956     size_t objectSize = getType().getObjectSize();
2957 
2958     TConstantUnion *resultArray = new TConstantUnion[objectSize];
2959     for (size_t i = 0; i < objectSize; i++)
2960     {
2961         switch (op)
2962         {
2963             case EOpNegative:
2964                 switch (getType().getBasicType())
2965                 {
2966                     case EbtFloat:
2967                         resultArray[i].setFConst(-operandArray[i].getFConst());
2968                         break;
2969                     case EbtInt:
2970                         if (operandArray[i] == std::numeric_limits<int>::min())
2971                         {
2972                             // The minimum representable integer doesn't have a positive
2973                             // counterpart, rather the negation overflows and in ESSL is supposed to
2974                             // wrap back to the minimum representable integer. Make sure that we
2975                             // don't actually let the negation overflow, which has undefined
2976                             // behavior in C++.
2977                             resultArray[i].setIConst(std::numeric_limits<int>::min());
2978                         }
2979                         else
2980                         {
2981                             resultArray[i].setIConst(-operandArray[i].getIConst());
2982                         }
2983                         break;
2984                     case EbtUInt:
2985                         if (operandArray[i] == 0x80000000u)
2986                         {
2987                             resultArray[i].setUConst(0x80000000u);
2988                         }
2989                         else
2990                         {
2991                             resultArray[i].setUConst(static_cast<unsigned int>(
2992                                 -static_cast<int>(operandArray[i].getUConst())));
2993                         }
2994                         break;
2995                     default:
2996                         UNREACHABLE();
2997                         return nullptr;
2998                 }
2999                 break;
3000 
3001             case EOpPositive:
3002                 switch (getType().getBasicType())
3003                 {
3004                     case EbtFloat:
3005                         resultArray[i].setFConst(operandArray[i].getFConst());
3006                         break;
3007                     case EbtInt:
3008                         resultArray[i].setIConst(operandArray[i].getIConst());
3009                         break;
3010                     case EbtUInt:
3011                         resultArray[i].setUConst(static_cast<unsigned int>(
3012                             static_cast<int>(operandArray[i].getUConst())));
3013                         break;
3014                     default:
3015                         UNREACHABLE();
3016                         return nullptr;
3017                 }
3018                 break;
3019 
3020             case EOpLogicalNot:
3021                 switch (getType().getBasicType())
3022                 {
3023                     case EbtBool:
3024                         resultArray[i].setBConst(!operandArray[i].getBConst());
3025                         break;
3026                     default:
3027                         UNREACHABLE();
3028                         return nullptr;
3029                 }
3030                 break;
3031 
3032             case EOpBitwiseNot:
3033                 switch (getType().getBasicType())
3034                 {
3035                     case EbtInt:
3036                         resultArray[i].setIConst(~operandArray[i].getIConst());
3037                         break;
3038                     case EbtUInt:
3039                         resultArray[i].setUConst(~operandArray[i].getUConst());
3040                         break;
3041                     default:
3042                         UNREACHABLE();
3043                         return nullptr;
3044                 }
3045                 break;
3046 
3047             case EOpRadians:
3048                 ASSERT(getType().getBasicType() == EbtFloat);
3049                 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
3050                 break;
3051 
3052             case EOpDegrees:
3053                 ASSERT(getType().getBasicType() == EbtFloat);
3054                 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
3055                 break;
3056 
3057             case EOpSin:
3058                 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
3059                 break;
3060 
3061             case EOpCos:
3062                 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
3063                 break;
3064 
3065             case EOpTan:
3066                 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
3067                 break;
3068 
3069             case EOpAsin:
3070                 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
3071                 // 0.
3072                 if (fabsf(operandArray[i].getFConst()) > 1.0f)
3073                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3074                                                   diagnostics, &resultArray[i]);
3075                 else
3076                     foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
3077                 break;
3078 
3079             case EOpAcos:
3080                 // For acos(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], &acosf, &resultArray[i]);
3087                 break;
3088 
3089             case EOpAtan:
3090                 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
3091                 break;
3092 
3093             case EOpSinh:
3094                 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
3095                 break;
3096 
3097             case EOpCosh:
3098                 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
3099                 break;
3100 
3101             case EOpTanh:
3102                 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
3103                 break;
3104 
3105             case EOpAsinh:
3106                 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
3107                 break;
3108 
3109             case EOpAcosh:
3110                 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
3111                 if (operandArray[i].getFConst() < 1.0f)
3112                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3113                                                   diagnostics, &resultArray[i]);
3114                 else
3115                     foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
3116                 break;
3117 
3118             case EOpAtanh:
3119                 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
3120                 // 0.
3121                 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
3122                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3123                                                   diagnostics, &resultArray[i]);
3124                 else
3125                     foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
3126                 break;
3127 
3128             case EOpAbs:
3129                 switch (getType().getBasicType())
3130                 {
3131                     case EbtFloat:
3132                         resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
3133                         break;
3134                     case EbtInt:
3135                         resultArray[i].setIConst(abs(operandArray[i].getIConst()));
3136                         break;
3137                     default:
3138                         UNREACHABLE();
3139                         return nullptr;
3140                 }
3141                 break;
3142 
3143             case EOpSign:
3144                 switch (getType().getBasicType())
3145                 {
3146                     case EbtFloat:
3147                     {
3148                         float fConst  = operandArray[i].getFConst();
3149                         float fResult = 0.0f;
3150                         if (fConst > 0.0f)
3151                             fResult = 1.0f;
3152                         else if (fConst < 0.0f)
3153                             fResult = -1.0f;
3154                         resultArray[i].setFConst(fResult);
3155                         break;
3156                     }
3157                     case EbtInt:
3158                     {
3159                         int iConst  = operandArray[i].getIConst();
3160                         int iResult = 0;
3161                         if (iConst > 0)
3162                             iResult = 1;
3163                         else if (iConst < 0)
3164                             iResult = -1;
3165                         resultArray[i].setIConst(iResult);
3166                         break;
3167                     }
3168                     default:
3169                         UNREACHABLE();
3170                         return nullptr;
3171                 }
3172                 break;
3173 
3174             case EOpFloor:
3175                 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
3176                 break;
3177 
3178             case EOpTrunc:
3179                 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
3180                 break;
3181 
3182             case EOpRound:
3183                 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
3184                 break;
3185 
3186             case EOpRoundEven:
3187             {
3188                 ASSERT(getType().getBasicType() == EbtFloat);
3189                 float x = operandArray[i].getFConst();
3190                 float result;
3191                 float fractPart = modff(x, &result);
3192                 if (fabsf(fractPart) == 0.5f)
3193                     result = 2.0f * roundf(x / 2.0f);
3194                 else
3195                     result = roundf(x);
3196                 resultArray[i].setFConst(result);
3197                 break;
3198             }
3199 
3200             case EOpCeil:
3201                 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
3202                 break;
3203 
3204             case EOpFract:
3205             {
3206                 ASSERT(getType().getBasicType() == EbtFloat);
3207                 float x = operandArray[i].getFConst();
3208                 resultArray[i].setFConst(x - floorf(x));
3209                 break;
3210             }
3211 
3212             case EOpIsnan:
3213                 ASSERT(getType().getBasicType() == EbtFloat);
3214                 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
3215                 break;
3216 
3217             case EOpIsinf:
3218                 ASSERT(getType().getBasicType() == EbtFloat);
3219                 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
3220                 break;
3221 
3222             case EOpFloatBitsToInt:
3223                 ASSERT(getType().getBasicType() == EbtFloat);
3224                 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
3225                 break;
3226 
3227             case EOpFloatBitsToUint:
3228                 ASSERT(getType().getBasicType() == EbtFloat);
3229                 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
3230                 break;
3231 
3232             case EOpIntBitsToFloat:
3233                 ASSERT(getType().getBasicType() == EbtInt);
3234                 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
3235                 break;
3236 
3237             case EOpUintBitsToFloat:
3238                 ASSERT(getType().getBasicType() == EbtUInt);
3239                 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
3240                 break;
3241 
3242             case EOpExp:
3243                 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
3244                 break;
3245 
3246             case EOpLog:
3247                 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
3248                 if (operandArray[i].getFConst() <= 0.0f)
3249                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3250                                                   diagnostics, &resultArray[i]);
3251                 else
3252                     foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
3253                 break;
3254 
3255             case EOpExp2:
3256                 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
3257                 break;
3258 
3259             case EOpLog2:
3260                 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
3261                 // And log2f is not available on some plarforms like old android, so just using
3262                 // log(x)/log(2) here.
3263                 if (operandArray[i].getFConst() <= 0.0f)
3264                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3265                                                   diagnostics, &resultArray[i]);
3266                 else
3267                 {
3268                     foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
3269                     resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
3270                 }
3271                 break;
3272 
3273             case EOpSqrt:
3274                 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
3275                 if (operandArray[i].getFConst() < 0.0f)
3276                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3277                                                   diagnostics, &resultArray[i]);
3278                 else
3279                     foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
3280                 break;
3281 
3282             case EOpInversesqrt:
3283                 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
3284                 // so getting the square root first using builtin function sqrt() and then taking
3285                 // its inverse.
3286                 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
3287                 // result to 0.
3288                 if (operandArray[i].getFConst() <= 0.0f)
3289                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3290                                                   diagnostics, &resultArray[i]);
3291                 else
3292                 {
3293                     foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
3294                     resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
3295                 }
3296                 break;
3297 
3298             case EOpNotComponentWise:
3299                 ASSERT(getType().getBasicType() == EbtBool);
3300                 resultArray[i].setBConst(!operandArray[i].getBConst());
3301                 break;
3302 
3303             case EOpNormalize:
3304             {
3305                 ASSERT(getType().getBasicType() == EbtFloat);
3306                 float x      = operandArray[i].getFConst();
3307                 float length = VectorLength(operandArray, objectSize);
3308                 if (length != 0.0f)
3309                     resultArray[i].setFConst(x / length);
3310                 else
3311                     UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3312                                                   diagnostics, &resultArray[i]);
3313                 break;
3314             }
3315             case EOpBitfieldReverse:
3316             {
3317                 uint32_t value;
3318                 if (getType().getBasicType() == EbtInt)
3319                 {
3320                     value = static_cast<uint32_t>(operandArray[i].getIConst());
3321                 }
3322                 else
3323                 {
3324                     ASSERT(getType().getBasicType() == EbtUInt);
3325                     value = operandArray[i].getUConst();
3326                 }
3327                 uint32_t result = gl::BitfieldReverse(value);
3328                 if (getType().getBasicType() == EbtInt)
3329                 {
3330                     resultArray[i].setIConst(static_cast<int32_t>(result));
3331                 }
3332                 else
3333                 {
3334                     resultArray[i].setUConst(result);
3335                 }
3336                 break;
3337             }
3338             case EOpBitCount:
3339             {
3340                 uint32_t value;
3341                 if (getType().getBasicType() == EbtInt)
3342                 {
3343                     value = static_cast<uint32_t>(operandArray[i].getIConst());
3344                 }
3345                 else
3346                 {
3347                     ASSERT(getType().getBasicType() == EbtUInt);
3348                     value = operandArray[i].getUConst();
3349                 }
3350                 int result = gl::BitCount(value);
3351                 resultArray[i].setIConst(result);
3352                 break;
3353             }
3354             case EOpFindLSB:
3355             {
3356                 uint32_t value;
3357                 if (getType().getBasicType() == EbtInt)
3358                 {
3359                     value = static_cast<uint32_t>(operandArray[i].getIConst());
3360                 }
3361                 else
3362                 {
3363                     ASSERT(getType().getBasicType() == EbtUInt);
3364                     value = operandArray[i].getUConst();
3365                 }
3366                 resultArray[i].setIConst(gl::FindLSB(value));
3367                 break;
3368             }
3369             case EOpFindMSB:
3370             {
3371                 uint32_t value;
3372                 if (getType().getBasicType() == EbtInt)
3373                 {
3374                     int intValue = operandArray[i].getIConst();
3375                     value        = static_cast<uint32_t>(intValue);
3376                     if (intValue < 0)
3377                     {
3378                         // Look for zero instead of one in value. This also handles the intValue ==
3379                         // -1 special case, where the return value needs to be -1.
3380                         value = ~value;
3381                     }
3382                 }
3383                 else
3384                 {
3385                     ASSERT(getType().getBasicType() == EbtUInt);
3386                     value = operandArray[i].getUConst();
3387                 }
3388                 resultArray[i].setIConst(gl::FindMSB(value));
3389                 break;
3390             }
3391 
3392             default:
3393                 return nullptr;
3394         }
3395     }
3396 
3397     return resultArray;
3398 }
3399 
foldFloatTypeUnary(const TConstantUnion & parameter,FloatTypeUnaryFunc builtinFunc,TConstantUnion * result) const3400 void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
3401                                               FloatTypeUnaryFunc builtinFunc,
3402                                               TConstantUnion *result) const
3403 {
3404     ASSERT(builtinFunc);
3405 
3406     ASSERT(getType().getBasicType() == EbtFloat);
3407     result->setFConst(builtinFunc(parameter.getFConst()));
3408 }
3409 
propagatePrecision(TPrecision precision)3410 void TIntermConstantUnion::propagatePrecision(TPrecision precision)
3411 {
3412     mType.setPrecision(precision);
3413 }
3414 
3415 // static
FoldAggregateBuiltIn(TIntermAggregate * aggregate,TDiagnostics * diagnostics)3416 TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
3417                                                            TDiagnostics *diagnostics)
3418 {
3419     const TOperator op         = aggregate->getOp();
3420     const TFunction *function  = aggregate->getFunction();
3421     TIntermSequence *arguments = aggregate->getSequence();
3422     unsigned int argsCount     = static_cast<unsigned int>(arguments->size());
3423     std::vector<const TConstantUnion *> unionArrays(argsCount);
3424     std::vector<size_t> objectSizes(argsCount);
3425     size_t maxObjectSize = 0;
3426     TBasicType basicType = EbtVoid;
3427     TSourceLoc loc;
3428     for (unsigned int i = 0; i < argsCount; i++)
3429     {
3430         TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
3431         ASSERT(argConstant != nullptr);  // Should be checked already.
3432 
3433         if (i == 0)
3434         {
3435             basicType = argConstant->getType().getBasicType();
3436             loc       = argConstant->getLine();
3437         }
3438         unionArrays[i] = argConstant->getConstantValue();
3439         objectSizes[i] = argConstant->getType().getObjectSize();
3440         if (objectSizes[i] > maxObjectSize)
3441             maxObjectSize = objectSizes[i];
3442     }
3443 
3444     if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
3445     {
3446         for (unsigned int i = 0; i < argsCount; i++)
3447             if (objectSizes[i] != maxObjectSize)
3448                 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
3449     }
3450 
3451     TConstantUnion *resultArray = nullptr;
3452 
3453     switch (op)
3454     {
3455         case EOpAtan:
3456         {
3457             ASSERT(basicType == EbtFloat);
3458             resultArray = new TConstantUnion[maxObjectSize];
3459             for (size_t i = 0; i < maxObjectSize; i++)
3460             {
3461                 float y = unionArrays[0][i].getFConst();
3462                 float x = unionArrays[1][i].getFConst();
3463                 // Results are undefined if x and y are both 0.
3464                 if (x == 0.0f && y == 0.0f)
3465                     UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3466                                                   &resultArray[i]);
3467                 else
3468                     resultArray[i].setFConst(atan2f(y, x));
3469             }
3470             break;
3471         }
3472 
3473         case EOpPow:
3474         {
3475             ASSERT(basicType == EbtFloat);
3476             resultArray = new TConstantUnion[maxObjectSize];
3477             for (size_t i = 0; i < maxObjectSize; i++)
3478             {
3479                 float x = unionArrays[0][i].getFConst();
3480                 float y = unionArrays[1][i].getFConst();
3481                 // Results are undefined if x < 0.
3482                 // Results are undefined if x = 0 and y <= 0.
3483                 if (x < 0.0f)
3484                     UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3485                                                   &resultArray[i]);
3486                 else if (x == 0.0f && y <= 0.0f)
3487                     UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3488                                                   &resultArray[i]);
3489                 else
3490                     resultArray[i].setFConst(powf(x, y));
3491             }
3492             break;
3493         }
3494 
3495         case EOpMod:
3496         {
3497             ASSERT(basicType == EbtFloat);
3498             resultArray = new TConstantUnion[maxObjectSize];
3499             for (size_t i = 0; i < maxObjectSize; i++)
3500             {
3501                 float x = unionArrays[0][i].getFConst();
3502                 float y = unionArrays[1][i].getFConst();
3503                 resultArray[i].setFConst(x - y * floorf(x / y));
3504             }
3505             break;
3506         }
3507 
3508         case EOpMin:
3509         {
3510             resultArray = new TConstantUnion[maxObjectSize];
3511             for (size_t i = 0; i < maxObjectSize; i++)
3512             {
3513                 switch (basicType)
3514                 {
3515                     case EbtFloat:
3516                         resultArray[i].setFConst(
3517                             std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
3518                         break;
3519                     case EbtInt:
3520                         resultArray[i].setIConst(
3521                             std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
3522                         break;
3523                     case EbtUInt:
3524                         resultArray[i].setUConst(
3525                             std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
3526                         break;
3527                     default:
3528                         UNREACHABLE();
3529                         break;
3530                 }
3531             }
3532             break;
3533         }
3534 
3535         case EOpMax:
3536         {
3537             resultArray = new TConstantUnion[maxObjectSize];
3538             for (size_t i = 0; i < maxObjectSize; i++)
3539             {
3540                 switch (basicType)
3541                 {
3542                     case EbtFloat:
3543                         resultArray[i].setFConst(
3544                             std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
3545                         break;
3546                     case EbtInt:
3547                         resultArray[i].setIConst(
3548                             std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
3549                         break;
3550                     case EbtUInt:
3551                         resultArray[i].setUConst(
3552                             std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
3553                         break;
3554                     default:
3555                         UNREACHABLE();
3556                         break;
3557                 }
3558             }
3559             break;
3560         }
3561 
3562         case EOpStep:
3563         {
3564             ASSERT(basicType == EbtFloat);
3565             resultArray = new TConstantUnion[maxObjectSize];
3566             for (size_t i = 0; i < maxObjectSize; i++)
3567                 resultArray[i].setFConst(
3568                     unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
3569             break;
3570         }
3571 
3572         case EOpLessThanComponentWise:
3573         {
3574             resultArray = new TConstantUnion[maxObjectSize];
3575             for (size_t i = 0; i < maxObjectSize; i++)
3576             {
3577                 switch (basicType)
3578                 {
3579                     case EbtFloat:
3580                         resultArray[i].setBConst(unionArrays[0][i].getFConst() <
3581                                                  unionArrays[1][i].getFConst());
3582                         break;
3583                     case EbtInt:
3584                         resultArray[i].setBConst(unionArrays[0][i].getIConst() <
3585                                                  unionArrays[1][i].getIConst());
3586                         break;
3587                     case EbtUInt:
3588                         resultArray[i].setBConst(unionArrays[0][i].getUConst() <
3589                                                  unionArrays[1][i].getUConst());
3590                         break;
3591                     default:
3592                         UNREACHABLE();
3593                         break;
3594                 }
3595             }
3596             break;
3597         }
3598 
3599         case EOpLessThanEqualComponentWise:
3600         {
3601             resultArray = new TConstantUnion[maxObjectSize];
3602             for (size_t i = 0; i < maxObjectSize; i++)
3603             {
3604                 switch (basicType)
3605                 {
3606                     case EbtFloat:
3607                         resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
3608                                                  unionArrays[1][i].getFConst());
3609                         break;
3610                     case EbtInt:
3611                         resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
3612                                                  unionArrays[1][i].getIConst());
3613                         break;
3614                     case EbtUInt:
3615                         resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
3616                                                  unionArrays[1][i].getUConst());
3617                         break;
3618                     default:
3619                         UNREACHABLE();
3620                         break;
3621                 }
3622             }
3623             break;
3624         }
3625 
3626         case EOpGreaterThanComponentWise:
3627         {
3628             resultArray = new TConstantUnion[maxObjectSize];
3629             for (size_t i = 0; i < maxObjectSize; i++)
3630             {
3631                 switch (basicType)
3632                 {
3633                     case EbtFloat:
3634                         resultArray[i].setBConst(unionArrays[0][i].getFConst() >
3635                                                  unionArrays[1][i].getFConst());
3636                         break;
3637                     case EbtInt:
3638                         resultArray[i].setBConst(unionArrays[0][i].getIConst() >
3639                                                  unionArrays[1][i].getIConst());
3640                         break;
3641                     case EbtUInt:
3642                         resultArray[i].setBConst(unionArrays[0][i].getUConst() >
3643                                                  unionArrays[1][i].getUConst());
3644                         break;
3645                     default:
3646                         UNREACHABLE();
3647                         break;
3648                 }
3649             }
3650             break;
3651         }
3652         case EOpGreaterThanEqualComponentWise:
3653         {
3654             resultArray = new TConstantUnion[maxObjectSize];
3655             for (size_t i = 0; i < maxObjectSize; i++)
3656             {
3657                 switch (basicType)
3658                 {
3659                     case EbtFloat:
3660                         resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
3661                                                  unionArrays[1][i].getFConst());
3662                         break;
3663                     case EbtInt:
3664                         resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3665                                                  unionArrays[1][i].getIConst());
3666                         break;
3667                     case EbtUInt:
3668                         resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3669                                                  unionArrays[1][i].getUConst());
3670                         break;
3671                     default:
3672                         UNREACHABLE();
3673                         break;
3674                 }
3675             }
3676         }
3677         break;
3678 
3679         case EOpEqualComponentWise:
3680         {
3681             resultArray = new TConstantUnion[maxObjectSize];
3682             for (size_t i = 0; i < maxObjectSize; i++)
3683             {
3684                 switch (basicType)
3685                 {
3686                     case EbtFloat:
3687                         resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3688                                                  unionArrays[1][i].getFConst());
3689                         break;
3690                     case EbtInt:
3691                         resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3692                                                  unionArrays[1][i].getIConst());
3693                         break;
3694                     case EbtUInt:
3695                         resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3696                                                  unionArrays[1][i].getUConst());
3697                         break;
3698                     case EbtBool:
3699                         resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3700                                                  unionArrays[1][i].getBConst());
3701                         break;
3702                     default:
3703                         UNREACHABLE();
3704                         break;
3705                 }
3706             }
3707             break;
3708         }
3709 
3710         case EOpNotEqualComponentWise:
3711         {
3712             resultArray = new TConstantUnion[maxObjectSize];
3713             for (size_t i = 0; i < maxObjectSize; i++)
3714             {
3715                 switch (basicType)
3716                 {
3717                     case EbtFloat:
3718                         resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3719                                                  unionArrays[1][i].getFConst());
3720                         break;
3721                     case EbtInt:
3722                         resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3723                                                  unionArrays[1][i].getIConst());
3724                         break;
3725                     case EbtUInt:
3726                         resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3727                                                  unionArrays[1][i].getUConst());
3728                         break;
3729                     case EbtBool:
3730                         resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3731                                                  unionArrays[1][i].getBConst());
3732                         break;
3733                     default:
3734                         UNREACHABLE();
3735                         break;
3736                 }
3737             }
3738             break;
3739         }
3740 
3741         case EOpDistance:
3742         {
3743             ASSERT(basicType == EbtFloat);
3744             TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3745             resultArray                   = new TConstantUnion();
3746             for (size_t i = 0; i < maxObjectSize; i++)
3747             {
3748                 float x = unionArrays[0][i].getFConst();
3749                 float y = unionArrays[1][i].getFConst();
3750                 distanceArray[i].setFConst(x - y);
3751             }
3752             resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3753             break;
3754         }
3755 
3756         case EOpDot:
3757             ASSERT(basicType == EbtFloat);
3758             resultArray = new TConstantUnion();
3759             resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3760             break;
3761 
3762         case EOpCross:
3763         {
3764             ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3765             resultArray = new TConstantUnion[maxObjectSize];
3766             float x0    = unionArrays[0][0].getFConst();
3767             float x1    = unionArrays[0][1].getFConst();
3768             float x2    = unionArrays[0][2].getFConst();
3769             float y0    = unionArrays[1][0].getFConst();
3770             float y1    = unionArrays[1][1].getFConst();
3771             float y2    = unionArrays[1][2].getFConst();
3772             resultArray[0].setFConst(x1 * y2 - y1 * x2);
3773             resultArray[1].setFConst(x2 * y0 - y2 * x0);
3774             resultArray[2].setFConst(x0 * y1 - y0 * x1);
3775             break;
3776         }
3777 
3778         case EOpReflect:
3779         {
3780             ASSERT(basicType == EbtFloat);
3781             // genType reflect (genType I, genType N) :
3782             //     For the incident vector I and surface orientation N, returns the reflection
3783             //     direction:
3784             //     I - 2 * dot(N, I) * N.
3785             resultArray      = new TConstantUnion[maxObjectSize];
3786             float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3787             for (size_t i = 0; i < maxObjectSize; i++)
3788             {
3789                 float result = unionArrays[0][i].getFConst() -
3790                                2.0f * dotProduct * unionArrays[1][i].getFConst();
3791                 resultArray[i].setFConst(result);
3792             }
3793             break;
3794         }
3795 
3796         case EOpMatrixCompMult:
3797         {
3798             ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3799                    (*arguments)[1]->getAsTyped()->isMatrix());
3800             // Perform component-wise matrix multiplication.
3801             resultArray                 = new TConstantUnion[maxObjectSize];
3802             int rows                    = (*arguments)[0]->getAsTyped()->getRows();
3803             int cols                    = (*arguments)[0]->getAsTyped()->getCols();
3804             angle::Matrix<float> lhs    = GetMatrix(unionArrays[0], rows, cols);
3805             angle::Matrix<float> rhs    = GetMatrix(unionArrays[1], rows, cols);
3806             angle::Matrix<float> result = lhs.compMult(rhs);
3807             SetUnionArrayFromMatrix(result, resultArray);
3808             break;
3809         }
3810 
3811         case EOpOuterProduct:
3812         {
3813             ASSERT(basicType == EbtFloat);
3814             size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3815             size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
3816             resultArray    = new TConstantUnion[numRows * numCols];
3817             angle::Matrix<float> result =
3818                 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3819                     .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3820             SetUnionArrayFromMatrix(result, resultArray);
3821             break;
3822         }
3823 
3824         case EOpClamp:
3825         {
3826             resultArray = new TConstantUnion[maxObjectSize];
3827             for (size_t i = 0; i < maxObjectSize; i++)
3828             {
3829                 switch (basicType)
3830                 {
3831                     case EbtFloat:
3832                     {
3833                         float x   = unionArrays[0][i].getFConst();
3834                         float min = unionArrays[1][i].getFConst();
3835                         float max = unionArrays[2][i].getFConst();
3836                         // Results are undefined if min > max.
3837                         if (min > max)
3838                             UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3839                                                           &resultArray[i]);
3840                         else
3841                             resultArray[i].setFConst(gl::clamp(x, min, max));
3842                         break;
3843                     }
3844 
3845                     case EbtInt:
3846                     {
3847                         int x   = unionArrays[0][i].getIConst();
3848                         int min = unionArrays[1][i].getIConst();
3849                         int max = unionArrays[2][i].getIConst();
3850                         // Results are undefined if min > max.
3851                         if (min > max)
3852                             UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3853                                                           &resultArray[i]);
3854                         else
3855                             resultArray[i].setIConst(gl::clamp(x, min, max));
3856                         break;
3857                     }
3858                     case EbtUInt:
3859                     {
3860                         unsigned int x   = unionArrays[0][i].getUConst();
3861                         unsigned int min = unionArrays[1][i].getUConst();
3862                         unsigned int max = unionArrays[2][i].getUConst();
3863                         // Results are undefined if min > max.
3864                         if (min > max)
3865                             UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3866                                                           &resultArray[i]);
3867                         else
3868                             resultArray[i].setUConst(gl::clamp(x, min, max));
3869                         break;
3870                     }
3871                     default:
3872                         UNREACHABLE();
3873                         break;
3874                 }
3875             }
3876             break;
3877         }
3878 
3879         case EOpMix:
3880         {
3881             resultArray = new TConstantUnion[maxObjectSize];
3882             for (size_t i = 0; i < maxObjectSize; i++)
3883             {
3884                 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
3885                 if (type == EbtFloat)
3886                 {
3887                     ASSERT(basicType == EbtFloat);
3888                     float x = unionArrays[0][i].getFConst();
3889                     float y = unionArrays[1][i].getFConst();
3890 
3891                     // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3892                     float a = unionArrays[2][i].getFConst();
3893                     resultArray[i].setFConst(x * (1.0f - a) + y * a);
3894                 }
3895                 else  // 3rd parameter is EbtBool
3896                 {
3897                     ASSERT(type == EbtBool);
3898                     // Selects which vector each returned component comes from.
3899                     // For a component of a that is false, the corresponding component of x is
3900                     // returned.
3901                     // For a component of a that is true, the corresponding component of y is
3902                     // returned.
3903                     bool a = unionArrays[2][i].getBConst();
3904                     switch (basicType)
3905                     {
3906                         case EbtFloat:
3907                         {
3908                             float x = unionArrays[0][i].getFConst();
3909                             float y = unionArrays[1][i].getFConst();
3910                             resultArray[i].setFConst(a ? y : x);
3911                         }
3912                         break;
3913                         case EbtInt:
3914                         {
3915                             int x = unionArrays[0][i].getIConst();
3916                             int y = unionArrays[1][i].getIConst();
3917                             resultArray[i].setIConst(a ? y : x);
3918                         }
3919                         break;
3920                         case EbtUInt:
3921                         {
3922                             unsigned int x = unionArrays[0][i].getUConst();
3923                             unsigned int y = unionArrays[1][i].getUConst();
3924                             resultArray[i].setUConst(a ? y : x);
3925                         }
3926                         break;
3927                         case EbtBool:
3928                         {
3929                             bool x = unionArrays[0][i].getBConst();
3930                             bool y = unionArrays[1][i].getBConst();
3931                             resultArray[i].setBConst(a ? y : x);
3932                         }
3933                         break;
3934                         default:
3935                             UNREACHABLE();
3936                             break;
3937                     }
3938                 }
3939             }
3940             break;
3941         }
3942 
3943         case EOpSmoothstep:
3944         {
3945             ASSERT(basicType == EbtFloat);
3946             resultArray = new TConstantUnion[maxObjectSize];
3947             for (size_t i = 0; i < maxObjectSize; i++)
3948             {
3949                 float edge0 = unionArrays[0][i].getFConst();
3950                 float edge1 = unionArrays[1][i].getFConst();
3951                 float x     = unionArrays[2][i].getFConst();
3952                 // Results are undefined if edge0 >= edge1.
3953                 if (edge0 >= edge1)
3954                 {
3955                     UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3956                                                   &resultArray[i]);
3957                 }
3958                 else
3959                 {
3960                     // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3961                     // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3962                     float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3963                     resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3964                 }
3965             }
3966             break;
3967         }
3968 
3969         case EOpFma:
3970         {
3971             ASSERT(basicType == EbtFloat);
3972             resultArray = new TConstantUnion[maxObjectSize];
3973             for (size_t i = 0; i < maxObjectSize; i++)
3974             {
3975                 float a = unionArrays[0][i].getFConst();
3976                 float b = unionArrays[1][i].getFConst();
3977                 float c = unionArrays[2][i].getFConst();
3978 
3979                 // Returns a * b + c.
3980                 resultArray[i].setFConst(a * b + c);
3981             }
3982             break;
3983         }
3984 
3985         case EOpLdexp:
3986         {
3987             resultArray = new TConstantUnion[maxObjectSize];
3988             for (size_t i = 0; i < maxObjectSize; i++)
3989             {
3990                 float x = unionArrays[0][i].getFConst();
3991                 int exp = unionArrays[1][i].getIConst();
3992                 if (exp > 128)
3993                 {
3994                     UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3995                                                   &resultArray[i]);
3996                 }
3997                 else
3998                 {
3999                     resultArray[i].setFConst(gl::Ldexp(x, exp));
4000                 }
4001             }
4002             break;
4003         }
4004 
4005         case EOpFaceforward:
4006         {
4007             ASSERT(basicType == EbtFloat);
4008             // genType faceforward(genType N, genType I, genType Nref) :
4009             //     If dot(Nref, I) < 0 return N, otherwise return -N.
4010             resultArray      = new TConstantUnion[maxObjectSize];
4011             float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
4012             for (size_t i = 0; i < maxObjectSize; i++)
4013             {
4014                 if (dotProduct < 0)
4015                     resultArray[i].setFConst(unionArrays[0][i].getFConst());
4016                 else
4017                     resultArray[i].setFConst(-unionArrays[0][i].getFConst());
4018             }
4019             break;
4020         }
4021 
4022         case EOpRefract:
4023         {
4024             ASSERT(basicType == EbtFloat);
4025             // genType refract(genType I, genType N, float eta) :
4026             //     For the incident vector I and surface normal N, and the ratio of indices of
4027             //     refraction eta,
4028             //     return the refraction vector. The result is computed by
4029             //         k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
4030             //         if (k < 0.0)
4031             //             return genType(0.0)
4032             //         else
4033             //             return eta * I - (eta * dot(N, I) + sqrt(k)) * N
4034             resultArray      = new TConstantUnion[maxObjectSize];
4035             float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
4036             for (size_t i = 0; i < maxObjectSize; i++)
4037             {
4038                 float eta = unionArrays[2][i].getFConst();
4039                 float k   = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
4040                 if (k < 0.0f)
4041                     resultArray[i].setFConst(0.0f);
4042                 else
4043                     resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
4044                                              (eta * dotProduct + sqrtf(k)) *
4045                                                  unionArrays[1][i].getFConst());
4046             }
4047             break;
4048         }
4049         case EOpBitfieldExtract:
4050         {
4051             resultArray = new TConstantUnion[maxObjectSize];
4052             for (size_t i = 0; i < maxObjectSize; ++i)
4053             {
4054                 int offset = unionArrays[1][0].getIConst();
4055                 int bits   = unionArrays[2][0].getIConst();
4056                 if (bits == 0)
4057                 {
4058                     if (aggregate->getBasicType() == EbtInt)
4059                     {
4060                         resultArray[i].setIConst(0);
4061                     }
4062                     else
4063                     {
4064                         ASSERT(aggregate->getBasicType() == EbtUInt);
4065                         resultArray[i].setUConst(0);
4066                     }
4067                 }
4068                 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
4069                 {
4070                     UndefinedConstantFoldingError(loc, function, aggregate->getBasicType(),
4071                                                   diagnostics, &resultArray[i]);
4072                 }
4073                 else
4074                 {
4075                     // bits can be 32 here, so we need to avoid bit shift overflow.
4076                     uint32_t maskMsb = 1u << (bits - 1);
4077                     uint32_t mask    = ((maskMsb - 1u) | maskMsb) << offset;
4078                     if (aggregate->getBasicType() == EbtInt)
4079                     {
4080                         uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
4081                         uint32_t resultUnsigned = (value & mask) >> offset;
4082                         if ((resultUnsigned & maskMsb) != 0)
4083                         {
4084                             // The most significant bits (from bits+1 to the most significant bit)
4085                             // should be set to 1.
4086                             uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
4087                             resultUnsigned |= higherBitsMask;
4088                         }
4089                         resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
4090                     }
4091                     else
4092                     {
4093                         ASSERT(aggregate->getBasicType() == EbtUInt);
4094                         uint32_t value = unionArrays[0][i].getUConst();
4095                         resultArray[i].setUConst((value & mask) >> offset);
4096                     }
4097                 }
4098             }
4099             break;
4100         }
4101         case EOpBitfieldInsert:
4102         {
4103             resultArray = new TConstantUnion[maxObjectSize];
4104             for (size_t i = 0; i < maxObjectSize; ++i)
4105             {
4106                 int offset = unionArrays[2][0].getIConst();
4107                 int bits   = unionArrays[3][0].getIConst();
4108                 if (bits == 0)
4109                 {
4110                     if (aggregate->getBasicType() == EbtInt)
4111                     {
4112                         int32_t base = unionArrays[0][i].getIConst();
4113                         resultArray[i].setIConst(base);
4114                     }
4115                     else
4116                     {
4117                         ASSERT(aggregate->getBasicType() == EbtUInt);
4118                         uint32_t base = unionArrays[0][i].getUConst();
4119                         resultArray[i].setUConst(base);
4120                     }
4121                 }
4122                 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
4123                 {
4124                     UndefinedConstantFoldingError(loc, function, aggregate->getBasicType(),
4125                                                   diagnostics, &resultArray[i]);
4126                 }
4127                 else
4128                 {
4129                     // bits can be 32 here, so we need to avoid bit shift overflow.
4130                     uint32_t maskMsb    = 1u << (bits - 1);
4131                     uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
4132                     uint32_t baseMask   = ~insertMask;
4133                     if (aggregate->getBasicType() == EbtInt)
4134                     {
4135                         uint32_t base   = static_cast<uint32_t>(unionArrays[0][i].getIConst());
4136                         uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
4137                         uint32_t resultUnsigned =
4138                             (base & baseMask) | ((insert << offset) & insertMask);
4139                         resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
4140                     }
4141                     else
4142                     {
4143                         ASSERT(aggregate->getBasicType() == EbtUInt);
4144                         uint32_t base   = unionArrays[0][i].getUConst();
4145                         uint32_t insert = unionArrays[1][i].getUConst();
4146                         resultArray[i].setUConst((base & baseMask) |
4147                                                  ((insert << offset) & insertMask));
4148                     }
4149                 }
4150             }
4151             break;
4152         }
4153         case EOpDFdx:
4154         case EOpDFdy:
4155         case EOpFwidth:
4156             ASSERT(basicType == EbtFloat);
4157             resultArray = new TConstantUnion[maxObjectSize];
4158             for (size_t i = 0; i < maxObjectSize; i++)
4159             {
4160                 // Derivatives of constant arguments should be 0.
4161                 resultArray[i].setFConst(0.0f);
4162             }
4163             break;
4164 
4165         default:
4166             UNREACHABLE();
4167             return nullptr;
4168     }
4169     return resultArray;
4170 }
4171 
IsFloatDivision(TBasicType t1,TBasicType t2)4172 bool TIntermConstantUnion::IsFloatDivision(TBasicType t1, TBasicType t2)
4173 {
4174     ImplicitTypeConversion conversion = GetConversion(t1, t2);
4175     ASSERT(conversion != ImplicitTypeConversion::Invalid);
4176     if (conversion == ImplicitTypeConversion::Same)
4177     {
4178         if (t1 == EbtFloat)
4179             return true;
4180         return false;
4181     }
4182     ASSERT(t1 == EbtFloat || t2 == EbtFloat);
4183     return true;
4184 }
4185 
4186 // TIntermPreprocessorDirective implementation.
TIntermPreprocessorDirective(PreprocessorDirective directive,ImmutableString command)4187 TIntermPreprocessorDirective::TIntermPreprocessorDirective(PreprocessorDirective directive,
4188                                                            ImmutableString command)
4189     : mDirective(directive), mCommand(std::move(command))
4190 {}
4191 
TIntermPreprocessorDirective(const TIntermPreprocessorDirective & node)4192 TIntermPreprocessorDirective::TIntermPreprocessorDirective(const TIntermPreprocessorDirective &node)
4193     : TIntermPreprocessorDirective(node.mDirective, node.mCommand)
4194 {}
4195 
4196 TIntermPreprocessorDirective::~TIntermPreprocessorDirective() = default;
4197 
getChildCount() const4198 size_t TIntermPreprocessorDirective::getChildCount() const
4199 {
4200     return 0;
4201 }
4202 
getChildNode(size_t index) const4203 TIntermNode *TIntermPreprocessorDirective::getChildNode(size_t index) const
4204 {
4205     UNREACHABLE();
4206     return nullptr;
4207 }
4208 }  // namespace sh
4209