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