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