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