1//
2// Copyright (c) 2002-2014 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
26namespace sh
27{
28
29namespace
30{
31
32const float kPi = 3.14159265358979323846f;
33const float kDegreesToRadiansMultiplier = kPi / 180.0f;
34const float kRadiansToDegreesMultiplier = 180.0f / kPi;
35
36TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
37{
38 return left > right ? left : right;
39}
40
41TConstantUnion *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
50void 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
78float 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
89float 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
99TIntermTyped *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
109angle::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
122angle::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
132void 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
142bool 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
186TIntermExpression::TIntermExpression(const TType &t) : TIntermTyped(), mType(t) {}
187
188void 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
206size_t TIntermSymbol::getChildCount() const
207{
208 return 0;
209}
210
211TIntermNode *TIntermSymbol::getChildNode(size_t index) const
212{
213 UNREACHABLE();
214 return nullptr;
215}
216
217size_t TIntermConstantUnion::getChildCount() const
218{
219 return 0;
220}
221
222TIntermNode *TIntermConstantUnion::getChildNode(size_t index) const
223{
224 UNREACHABLE();
225 return nullptr;
226}
227
228size_t TIntermLoop::getChildCount() const
229{
230 return (mInit ? 1 : 0) + (mCond ? 1 : 0) + (mExpr ? 1 : 0) + (mBody ? 1 : 0);
231}
232
233TIntermNode *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
261bool 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
271size_t TIntermBranch::getChildCount() const
272{
273 return (mExpression ? 1 : 0);
274}
275
276TIntermNode *TIntermBranch::getChildNode(size_t index) const
277{
278 ASSERT(mExpression);
279 ASSERT(index == 0);
280 return mExpression;
281}
282
283bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
284{
285 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
286 return false;
287}
288
289size_t TIntermSwizzle::getChildCount() const
290{
291 return 1;
292}
293
294TIntermNode *TIntermSwizzle::getChildNode(size_t index) const
295{
296 ASSERT(mOperand);
297 ASSERT(index == 0);
298 return mOperand;
299}
300
301bool 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
308size_t TIntermBinary::getChildCount() const
309{
310 return 2;
311}
312
313TIntermNode *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
323bool 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
330size_t TIntermUnary::getChildCount() const
331{
332 return 1;
333}
334
335TIntermNode *TIntermUnary::getChildNode(size_t index) const
336{
337 ASSERT(mOperand);
338 ASSERT(index == 0);
339 return mOperand;
340}
341
342bool 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
349size_t TIntermInvariantDeclaration::getChildCount() const
350{
351 return 1;
352}
353
354TIntermNode *TIntermInvariantDeclaration::getChildNode(size_t index) const
355{
356 ASSERT(mSymbol);
357 ASSERT(index == 0);
358 return mSymbol;
359}
360
361bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
362{
363 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
364 return false;
365}
366
367size_t TIntermFunctionDefinition::getChildCount() const
368{
369 return 2;
370}
371
372TIntermNode *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
382bool 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
389size_t TIntermAggregate::getChildCount() const
390{
391 return mArguments.size();
392}
393
394TIntermNode *TIntermAggregate::getChildNode(size_t index) const
395{
396 return mArguments[index];
397}
398
399bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
400{
401 return replaceChildNodeInternal(original, replacement);
402}
403
404size_t TIntermBlock::getChildCount() const
405{
406 return mStatements.size();
407}
408
409TIntermNode *TIntermBlock::getChildNode(size_t index) const
410{
411 return mStatements[index];
412}
413
414bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
415{
416 return replaceChildNodeInternal(original, replacement);
417}
418
419size_t TIntermFunctionPrototype::getChildCount() const
420{
421 return 0;
422}
423
424TIntermNode *TIntermFunctionPrototype::getChildNode(size_t index) const
425{
426 UNREACHABLE();
427 return nullptr;
428}
429
430bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
431{
432 return false;
433}
434
435size_t TIntermDeclaration::getChildCount() const
436{
437 return mDeclarators.size();
438}
439
440TIntermNode *TIntermDeclaration::getChildNode(size_t index) const
441{
442 return mDeclarators[index];
443}
444
445bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
446{
447 return replaceChildNodeInternal(original, replacement);
448}
449
450bool 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
459bool 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
474bool 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
486TIntermSymbol::TIntermSymbol(const TVariable *variable) : TIntermTyped(), mVariable(variable) {}
487
488bool TIntermSymbol::hasConstantValue() const
489{
490 return variable().getConstPointer() != nullptr;
491}
492
493const TConstantUnion *TIntermSymbol::getConstantValue() const
494{
495 return variable().getConstPointer();
496}
497
498const TSymbolUniqueId &TIntermSymbol::uniqueId() const
499{
500 return mVariable->uniqueId();
501}
502
503ImmutableString TIntermSymbol::getName() const
504{
505 return mVariable->name();
506}
507
508const TType &TIntermSymbol::getType() const
509{
510 return mVariable->getType();
511}
512
513TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
514 TIntermSequence *arguments)
515{
516 return new TIntermAggregate(&func, func.getReturnType(), EOpCallFunctionInAST, arguments);
517}
518
519TIntermAggregate *TIntermAggregate::CreateRawFunctionCall(const TFunction &func,
520 TIntermSequence *arguments)
521{
522 return new TIntermAggregate(&func, func.getReturnType(), EOpCallInternalRawFunction, arguments);
523}
524
525TIntermAggregate *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
533TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type, TIntermSequence *arguments)
534{
535 return new TIntermAggregate(nullptr, type, EOpConstruct, arguments);
536}
537
538TIntermAggregate::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
555void 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
584bool 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
597void 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
618void TIntermAggregate::setPrecisionForBuiltInOp()
619{
620 ASSERT(!isConstructor());
621 ASSERT(!isFunctionCall());
622 if (!setPrecisionForSpecialBuiltInOp())
623 {
624 setPrecisionFromChildren();
625 }
626}
627
628bool 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
650void 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
675const 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
689bool 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
705const 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
829bool 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
852void 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
864void TIntermBlock::insertStatement(size_t insertPosition, TIntermNode *statement)
865{
866 ASSERT(statement != nullptr);
867 mStatements.insert(mStatements.begin() + insertPosition, statement);
868}
869
870void 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
881size_t TIntermTernary::getChildCount() const
882{
883 return 3;
884}
885
886TIntermNode *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
900bool 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
908size_t TIntermIfElse::getChildCount() const
909{
910 return 1 + (mTrueBlock ? 1 : 0) + (mFalseBlock ? 1 : 0);
911}
912
913TIntermNode *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
926bool 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
934size_t TIntermSwitch::getChildCount() const
935{
936 return 2;
937}
938
939TIntermNode *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
949bool 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
957size_t TIntermCase::getChildCount() const
958{
959 return (mCondition ? 1 : 0);
960}
961
962TIntermNode *TIntermCase::getChildNode(size_t index) const
963{
964 ASSERT(index == 0);
965 ASSERT(mCondition);
966 return mCondition;
967}
968
969bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
970{
971 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
972 return false;
973}
974
975TIntermTyped::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
983bool TIntermTyped::hasConstantValue() const
984{
985 return false;
986}
987
988const TConstantUnion *TIntermTyped::getConstantValue() const
989{
990 return nullptr;
991}
992
993TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node)
994 : TIntermExpression(node)
995{
996 mUnionArrayPointer = node.mUnionArrayPointer;
997}
998
999TIntermFunctionPrototype::TIntermFunctionPrototype(const TFunction *function)
1000 : TIntermTyped(), mFunction(function)
1001{
1002 ASSERT(mFunction->symbolType() != SymbolType::Empty);
1003}
1004
1005const TType &TIntermFunctionPrototype::getType() const
1006{
1007 return mFunction->getReturnType();
1008}
1009
1010TIntermAggregate::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
1025TIntermAggregate *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
1034TIntermSwizzle::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
1043TIntermBinary::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
1053TIntermUnary::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
1063TIntermTernary::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
1074bool TIntermOperator::isAssignment() const
1075{
1076 return IsAssignment(mOp);
1077}
1078
1079bool 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
1095bool TIntermOperator::isConstructor() const
1096{
1097 return (mOp == EOpConstruct);
1098}
1099
1100bool 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
1113TOperator 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
1162TOperator 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//
1205void 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
1286TIntermSwizzle::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
1297TIntermUnary::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
1304TIntermBinary::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
1312TIntermBinary *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
1321TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol,
1322 const TSourceLoc &line)
1323 : TIntermNode(), mSymbol(symbol)
1324{
1325 ASSERT(symbol);
1326 setLine(line);
1327}
1328
1329TIntermTernary::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
1344TIntermLoop::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
1360TIntermIfElse::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
1371TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1372 : TIntermNode(), mInit(init), mStatementList(statementList)
1373{
1374 ASSERT(mInit);
1375 ASSERT(mStatementList);
1376}
1377
1378void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1379{
1380 ASSERT(statementList);
1381 mStatementList = statementList;
1382}
1383
1384// static
1385TQualifier 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
1397TIntermTyped *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
1413void 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
1424bool 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
1442void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
1443{
1444 mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
1445}
1446
1447bool TIntermSwizzle::offsetsMatch(int offset) const
1448{
1449 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1450}
1451
1452void 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
1476TQualifier 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.
1490void 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
1698bool TIntermConstantUnion::hasConstantValue() const
1699{
1700 return true;
1701}
1702
1703const TConstantUnion *TIntermConstantUnion::getConstantValue() const
1704{
1705 return mUnionArrayPointer;
1706}
1707
1708const 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
1738TIntermTyped *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
1773TIntermTyped *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
1847bool 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
1866const 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
1896const 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
1907TIntermTyped *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
1961TIntermTyped *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//
2022const 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 switch (leftType.getBasicType())
2109 {
2110 case EbtFloat:
2111 {
2112 ASSERT(op == EOpDiv);
2113 float dividend = leftArray[i].getFConst();
2114 float divisor = rightArray[i].getFConst();
2115 if (divisor == 0.0f)
2116 {
2117 if (dividend == 0.0f)
2118 {
2119 diagnostics->warning(
2120 line,
2121 "Zero divided by zero during constant 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 =
2130 std::signbit(dividend) != std::signbit(divisor);
2131 resultArray[i].setFConst(
2132 negativeResult ? -std::numeric_limits<float>::infinity()
2133 : std::numeric_limits<float>::infinity());
2134 }
2135 }
2136 else if (gl::isInf(dividend) && gl::isInf(divisor))
2137 {
2138 diagnostics->warning(line,
2139 "Infinity divided by infinity during constant "
2140 "folding generated NaN",
2141 "/");
2142 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
2143 }
2144 else
2145 {
2146 float result = dividend / divisor;
2147 if (!gl::isInf(dividend) && gl::isInf(result))
2148 {
2149 diagnostics->warning(
2150 line, "Constant folded division overflowed to infinity", "/");
2151 }
2152 resultArray[i].setFConst(result);
2153 }
2154 break;
2155 }
2156 case EbtInt:
2157 if (rightArray[i] == 0)
2158 {
2159 diagnostics->warning(
2160 line, "Divide by zero error during constant folding", "/");
2161 resultArray[i].setIConst(INT_MAX);
2162 }
2163 else
2164 {
2165 int lhs = leftArray[i].getIConst();
2166 int divisor = rightArray[i].getIConst();
2167 if (op == EOpDiv)
2168 {
2169 // Check for the special case where the minimum representable number
2170 // is
2171 // divided by -1. If left alone this leads to integer overflow in
2172 // C++.
2173 // ESSL 3.00.6 section 4.1.3 Integers:
2174 // "However, for the case where the minimum representable value is
2175 // divided by -1, it is allowed to return either the minimum
2176 // representable value or the maximum representable value."
2177 if (lhs == -0x7fffffff - 1 && divisor == -1)
2178 {
2179 resultArray[i].setIConst(0x7fffffff);
2180 }
2181 else
2182 {
2183 resultArray[i].setIConst(lhs / divisor);
2184 }
2185 }
2186 else
2187 {
2188 ASSERT(op == EOpIMod);
2189 if (lhs < 0 || divisor < 0)
2190 {
2191 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
2192 // when either one of the operands is negative.
2193 diagnostics->warning(line,
2194 "Negative modulus operator operand "
2195 "encountered during constant folding. "
2196 "Results are undefined.",
2197 "%");
2198 resultArray[i].setIConst(0);
2199 }
2200 else
2201 {
2202 resultArray[i].setIConst(lhs % divisor);
2203 }
2204 }
2205 }
2206 break;
2207
2208 case EbtUInt:
2209 if (rightArray[i] == 0)
2210 {
2211 diagnostics->warning(
2212 line, "Divide by zero error during constant folding", "/");
2213 resultArray[i].setUConst(UINT_MAX);
2214 }
2215 else
2216 {
2217 if (op == EOpDiv)
2218 {
2219 resultArray[i].setUConst(leftArray[i].getUConst() /
2220 rightArray[i].getUConst());
2221 }
2222 else
2223 {
2224 ASSERT(op == EOpIMod);
2225 resultArray[i].setUConst(leftArray[i].getUConst() %
2226 rightArray[i].getUConst());
2227 }
2228 }
2229 break;
2230
2231 default:
2232 UNREACHABLE();
2233 return nullptr;
2234 }
2235 }
2236 }
2237 break;
2238
2239 case EOpMatrixTimesVector:
2240 {
2241 // TODO(jmadll): This code should check for overflows.
2242 ASSERT(rightType.getBasicType() == EbtFloat);
2243
2244 const int matrixCols = leftType.getCols();
2245 const int matrixRows = leftType.getRows();
2246
2247 resultArray = new TConstantUnion[matrixRows];
2248
2249 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
2250 {
2251 resultArray[matrixRow].setFConst(0.0f);
2252 for (int col = 0; col < matrixCols; col++)
2253 {
2254 resultArray[matrixRow].setFConst(
2255 resultArray[matrixRow].getFConst() +
2256 leftArray[col * matrixRows + matrixRow].getFConst() *
2257 rightArray[col].getFConst());
2258 }
2259 }
2260 }
2261 break;
2262
2263 case EOpVectorTimesMatrix:
2264 {
2265 // TODO(jmadll): This code should check for overflows.
2266 ASSERT(leftType.getBasicType() == EbtFloat);
2267
2268 const int matrixCols = rightType.getCols();
2269 const int matrixRows = rightType.getRows();
2270
2271 resultArray = new TConstantUnion[matrixCols];
2272
2273 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
2274 {
2275 resultArray[matrixCol].setFConst(0.0f);
2276 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
2277 {
2278 resultArray[matrixCol].setFConst(
2279 resultArray[matrixCol].getFConst() +
2280 leftArray[matrixRow].getFConst() *
2281 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
2282 }
2283 }
2284 }
2285 break;
2286
2287 case EOpLogicalAnd:
2288 {
2289 resultArray = new TConstantUnion[objectSize];
2290 for (size_t i = 0; i < objectSize; i++)
2291 {
2292 resultArray[i] = leftArray[i] && rightArray[i];
2293 }
2294 }
2295 break;
2296
2297 case EOpLogicalOr:
2298 {
2299 resultArray = new TConstantUnion[objectSize];
2300 for (size_t i = 0; i < objectSize; i++)
2301 {
2302 resultArray[i] = leftArray[i] || rightArray[i];
2303 }
2304 }
2305 break;
2306
2307 case EOpLogicalXor:
2308 {
2309 ASSERT(leftType.getBasicType() == EbtBool);
2310 resultArray = new TConstantUnion[objectSize];
2311 for (size_t i = 0; i < objectSize; i++)
2312 {
2313 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
2314 }
2315 }
2316 break;
2317
2318 case EOpBitwiseAnd:
2319 resultArray = new TConstantUnion[objectSize];
2320 for (size_t i = 0; i < objectSize; i++)
2321 resultArray[i] = leftArray[i] & rightArray[i];
2322 break;
2323 case EOpBitwiseXor:
2324 resultArray = new TConstantUnion[objectSize];
2325 for (size_t i = 0; i < objectSize; i++)
2326 resultArray[i] = leftArray[i] ^ rightArray[i];
2327 break;
2328 case EOpBitwiseOr:
2329 resultArray = new TConstantUnion[objectSize];
2330 for (size_t i = 0; i < objectSize; i++)
2331 resultArray[i] = leftArray[i] | rightArray[i];
2332 break;
2333 case EOpBitShiftLeft:
2334 resultArray = new TConstantUnion[objectSize];
2335 for (size_t i = 0; i < objectSize; i++)
2336 resultArray[i] =
2337 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2338 break;
2339 case EOpBitShiftRight:
2340 resultArray = new TConstantUnion[objectSize];
2341 for (size_t i = 0; i < objectSize; i++)
2342 resultArray[i] =
2343 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2344 break;
2345
2346 case EOpLessThan:
2347 ASSERT(objectSize == 1);
2348 resultArray = new TConstantUnion[1];
2349 resultArray->setBConst(*leftArray < *rightArray);
2350 break;
2351
2352 case EOpGreaterThan:
2353 ASSERT(objectSize == 1);
2354 resultArray = new TConstantUnion[1];
2355 resultArray->setBConst(*leftArray > *rightArray);
2356 break;
2357
2358 case EOpLessThanEqual:
2359 ASSERT(objectSize == 1);
2360 resultArray = new TConstantUnion[1];
2361 resultArray->setBConst(!(*leftArray > *rightArray));
2362 break;
2363
2364 case EOpGreaterThanEqual:
2365 ASSERT(objectSize == 1);
2366 resultArray = new TConstantUnion[1];
2367 resultArray->setBConst(!(*leftArray < *rightArray));
2368 break;
2369
2370 case EOpEqual:
2371 case EOpNotEqual:
2372 {
2373 resultArray = new TConstantUnion[1];
2374 bool equal = true;
2375 for (size_t i = 0; i < objectSize; i++)
2376 {
2377 if (leftArray[i] != rightArray[i])
2378 {
2379 equal = false;
2380 break; // break out of for loop
2381 }
2382 }
2383 if (op == EOpEqual)
2384 {
2385 resultArray->setBConst(equal);
2386 }
2387 else
2388 {
2389 resultArray->setBConst(!equal);
2390 }
2391 }
2392 break;
2393
2394 default:
2395 UNREACHABLE();
2396 return nullptr;
2397 }
2398 return resultArray;
2399}
2400
2401// The fold functions do operations on a constant at GLSL compile time, without generating run-time
2402// code. Returns the constant value to keep using. Nullptr should not be returned.
2403TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
2404{
2405 // Do operations where the return type may have a different number of components compared to the
2406 // operand type.
2407
2408 const TConstantUnion *operandArray = getConstantValue();
2409 ASSERT(operandArray);
2410
2411 size_t objectSize = getType().getObjectSize();
2412 TConstantUnion *resultArray = nullptr;
2413 switch (op)
2414 {
2415 case EOpAny:
2416 ASSERT(getType().getBasicType() == EbtBool);
2417 resultArray = new TConstantUnion();
2418 resultArray->setBConst(false);
2419 for (size_t i = 0; i < objectSize; i++)
2420 {
2421 if (operandArray[i].getBConst())
2422 {
2423 resultArray->setBConst(true);
2424 break;
2425 }
2426 }
2427 break;
2428
2429 case EOpAll:
2430 ASSERT(getType().getBasicType() == EbtBool);
2431 resultArray = new TConstantUnion();
2432 resultArray->setBConst(true);
2433 for (size_t i = 0; i < objectSize; i++)
2434 {
2435 if (!operandArray[i].getBConst())
2436 {
2437 resultArray->setBConst(false);
2438 break;
2439 }
2440 }
2441 break;
2442
2443 case EOpLength:
2444 ASSERT(getType().getBasicType() == EbtFloat);
2445 resultArray = new TConstantUnion();
2446 resultArray->setFConst(VectorLength(operandArray, objectSize));
2447 break;
2448
2449 case EOpTranspose:
2450 {
2451 ASSERT(getType().getBasicType() == EbtFloat);
2452 resultArray = new TConstantUnion[objectSize];
2453 angle::Matrix<float> result =
2454 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
2455 SetUnionArrayFromMatrix(result, resultArray);
2456 break;
2457 }
2458
2459 case EOpDeterminant:
2460 {
2461 ASSERT(getType().getBasicType() == EbtFloat);
2462 unsigned int size = getType().getNominalSize();
2463 ASSERT(size >= 2 && size <= 4);
2464 resultArray = new TConstantUnion();
2465 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2466 break;
2467 }
2468
2469 case EOpInverse:
2470 {
2471 ASSERT(getType().getBasicType() == EbtFloat);
2472 unsigned int size = getType().getNominalSize();
2473 ASSERT(size >= 2 && size <= 4);
2474 resultArray = new TConstantUnion[objectSize];
2475 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2476 SetUnionArrayFromMatrix(result, resultArray);
2477 break;
2478 }
2479
2480 case EOpPackSnorm2x16:
2481 ASSERT(getType().getBasicType() == EbtFloat);
2482 ASSERT(getType().getNominalSize() == 2);
2483 resultArray = new TConstantUnion();
2484 resultArray->setUConst(
2485 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2486 break;
2487
2488 case EOpUnpackSnorm2x16:
2489 {
2490 ASSERT(getType().getBasicType() == EbtUInt);
2491 resultArray = new TConstantUnion[2];
2492 float f1, f2;
2493 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2494 resultArray[0].setFConst(f1);
2495 resultArray[1].setFConst(f2);
2496 break;
2497 }
2498
2499 case EOpPackUnorm2x16:
2500 ASSERT(getType().getBasicType() == EbtFloat);
2501 ASSERT(getType().getNominalSize() == 2);
2502 resultArray = new TConstantUnion();
2503 resultArray->setUConst(
2504 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2505 break;
2506
2507 case EOpUnpackUnorm2x16:
2508 {
2509 ASSERT(getType().getBasicType() == EbtUInt);
2510 resultArray = new TConstantUnion[2];
2511 float f1, f2;
2512 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2513 resultArray[0].setFConst(f1);
2514 resultArray[1].setFConst(f2);
2515 break;
2516 }
2517
2518 case EOpPackHalf2x16:
2519 ASSERT(getType().getBasicType() == EbtFloat);
2520 ASSERT(getType().getNominalSize() == 2);
2521 resultArray = new TConstantUnion();
2522 resultArray->setUConst(
2523 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2524 break;
2525
2526 case EOpUnpackHalf2x16:
2527 {
2528 ASSERT(getType().getBasicType() == EbtUInt);
2529 resultArray = new TConstantUnion[2];
2530 float f1, f2;
2531 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2532 resultArray[0].setFConst(f1);
2533 resultArray[1].setFConst(f2);
2534 break;
2535 }
2536
2537 case EOpPackUnorm4x8:
2538 {
2539 ASSERT(getType().getBasicType() == EbtFloat);
2540 resultArray = new TConstantUnion();
2541 resultArray->setUConst(
2542 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2543 operandArray[2].getFConst(), operandArray[3].getFConst()));
2544 break;
2545 }
2546 case EOpPackSnorm4x8:
2547 {
2548 ASSERT(getType().getBasicType() == EbtFloat);
2549 resultArray = new TConstantUnion();
2550 resultArray->setUConst(
2551 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2552 operandArray[2].getFConst(), operandArray[3].getFConst()));
2553 break;
2554 }
2555 case EOpUnpackUnorm4x8:
2556 {
2557 ASSERT(getType().getBasicType() == EbtUInt);
2558 resultArray = new TConstantUnion[4];
2559 float f[4];
2560 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2561 for (size_t i = 0; i < 4; ++i)
2562 {
2563 resultArray[i].setFConst(f[i]);
2564 }
2565 break;
2566 }
2567 case EOpUnpackSnorm4x8:
2568 {
2569 ASSERT(getType().getBasicType() == EbtUInt);
2570 resultArray = new TConstantUnion[4];
2571 float f[4];
2572 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2573 for (size_t i = 0; i < 4; ++i)
2574 {
2575 resultArray[i].setFConst(f[i]);
2576 }
2577 break;
2578 }
2579
2580 default:
2581 UNREACHABLE();
2582 break;
2583 }
2584
2585 return resultArray;
2586}
2587
2588TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2589 TDiagnostics *diagnostics)
2590{
2591 // Do unary operations where each component of the result is computed based on the corresponding
2592 // component of the operand. Also folds normalize, though the divisor in that case takes all
2593 // components into account.
2594
2595 const TConstantUnion *operandArray = getConstantValue();
2596 ASSERT(operandArray);
2597
2598 size_t objectSize = getType().getObjectSize();
2599
2600 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2601 for (size_t i = 0; i < objectSize; i++)
2602 {
2603 switch (op)
2604 {
2605 case EOpNegative:
2606 switch (getType().getBasicType())
2607 {
2608 case EbtFloat:
2609 resultArray[i].setFConst(-operandArray[i].getFConst());
2610 break;
2611 case EbtInt:
2612 if (operandArray[i] == std::numeric_limits<int>::min())
2613 {
2614 // The minimum representable integer doesn't have a positive
2615 // counterpart, rather the negation overflows and in ESSL is supposed to
2616 // wrap back to the minimum representable integer. Make sure that we
2617 // don't actually let the negation overflow, which has undefined
2618 // behavior in C++.
2619 resultArray[i].setIConst(std::numeric_limits<int>::min());
2620 }
2621 else
2622 {
2623 resultArray[i].setIConst(-operandArray[i].getIConst());
2624 }
2625 break;
2626 case EbtUInt:
2627 if (operandArray[i] == 0x80000000u)
2628 {
2629 resultArray[i].setUConst(0x80000000u);
2630 }
2631 else
2632 {
2633 resultArray[i].setUConst(static_cast<unsigned int>(
2634 -static_cast<int>(operandArray[i].getUConst())));
2635 }
2636 break;
2637 default:
2638 UNREACHABLE();
2639 return nullptr;
2640 }
2641 break;
2642
2643 case EOpPositive:
2644 switch (getType().getBasicType())
2645 {
2646 case EbtFloat:
2647 resultArray[i].setFConst(operandArray[i].getFConst());
2648 break;
2649 case EbtInt:
2650 resultArray[i].setIConst(operandArray[i].getIConst());
2651 break;
2652 case EbtUInt:
2653 resultArray[i].setUConst(static_cast<unsigned int>(
2654 static_cast<int>(operandArray[i].getUConst())));
2655 break;
2656 default:
2657 UNREACHABLE();
2658 return nullptr;
2659 }
2660 break;
2661
2662 case EOpLogicalNot:
2663 switch (getType().getBasicType())
2664 {
2665 case EbtBool:
2666 resultArray[i].setBConst(!operandArray[i].getBConst());
2667 break;
2668 default:
2669 UNREACHABLE();
2670 return nullptr;
2671 }
2672 break;
2673
2674 case EOpBitwiseNot:
2675 switch (getType().getBasicType())
2676 {
2677 case EbtInt:
2678 resultArray[i].setIConst(~operandArray[i].getIConst());
2679 break;
2680 case EbtUInt:
2681 resultArray[i].setUConst(~operandArray[i].getUConst());
2682 break;
2683 default:
2684 UNREACHABLE();
2685 return nullptr;
2686 }
2687 break;
2688
2689 case EOpRadians:
2690 ASSERT(getType().getBasicType() == EbtFloat);
2691 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2692 break;
2693
2694 case EOpDegrees:
2695 ASSERT(getType().getBasicType() == EbtFloat);
2696 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2697 break;
2698
2699 case EOpSin:
2700 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
2701 break;
2702
2703 case EOpCos:
2704 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2705 break;
2706
2707 case EOpTan:
2708 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2709 break;
2710
2711 case EOpAsin:
2712 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2713 // 0.
2714 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2715 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2716 diagnostics, &resultArray[i]);
2717 else
2718 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2719 break;
2720
2721 case EOpAcos:
2722 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2723 // 0.
2724 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2725 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2726 diagnostics, &resultArray[i]);
2727 else
2728 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2729 break;
2730
2731 case EOpAtan:
2732 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2733 break;
2734
2735 case EOpSinh:
2736 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2737 break;
2738
2739 case EOpCosh:
2740 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2741 break;
2742
2743 case EOpTanh:
2744 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2745 break;
2746
2747 case EOpAsinh:
2748 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2749 break;
2750
2751 case EOpAcosh:
2752 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2753 if (operandArray[i].getFConst() < 1.0f)
2754 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2755 diagnostics, &resultArray[i]);
2756 else
2757 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2758 break;
2759
2760 case EOpAtanh:
2761 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2762 // 0.
2763 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2764 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2765 diagnostics, &resultArray[i]);
2766 else
2767 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2768 break;
2769
2770 case EOpAbs:
2771 switch (getType().getBasicType())
2772 {
2773 case EbtFloat:
2774 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2775 break;
2776 case EbtInt:
2777 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2778 break;
2779 default:
2780 UNREACHABLE();
2781 return nullptr;
2782 }
2783 break;
2784
2785 case EOpSign:
2786 switch (getType().getBasicType())
2787 {
2788 case EbtFloat:
2789 {
2790 float fConst = operandArray[i].getFConst();
2791 float fResult = 0.0f;
2792 if (fConst > 0.0f)
2793 fResult = 1.0f;
2794 else if (fConst < 0.0f)
2795 fResult = -1.0f;
2796 resultArray[i].setFConst(fResult);
2797 break;
2798 }
2799 case EbtInt:
2800 {
2801 int iConst = operandArray[i].getIConst();
2802 int iResult = 0;
2803 if (iConst > 0)
2804 iResult = 1;
2805 else if (iConst < 0)
2806 iResult = -1;
2807 resultArray[i].setIConst(iResult);
2808 break;
2809 }
2810 default:
2811 UNREACHABLE();
2812 return nullptr;
2813 }
2814 break;
2815
2816 case EOpFloor:
2817 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2818 break;
2819
2820 case EOpTrunc:
2821 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2822 break;
2823
2824 case EOpRound:
2825 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2826 break;
2827
2828 case EOpRoundEven:
2829 {
2830 ASSERT(getType().getBasicType() == EbtFloat);
2831 float x = operandArray[i].getFConst();
2832 float result;
2833 float fractPart = modff(x, &result);
2834 if (fabsf(fractPart) == 0.5f)
2835 result = 2.0f * roundf(x / 2.0f);
2836 else
2837 result = roundf(x);
2838 resultArray[i].setFConst(result);
2839 break;
2840 }
2841
2842 case EOpCeil:
2843 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2844 break;
2845
2846 case EOpFract:
2847 {
2848 ASSERT(getType().getBasicType() == EbtFloat);
2849 float x = operandArray[i].getFConst();
2850 resultArray[i].setFConst(x - floorf(x));
2851 break;
2852 }
2853
2854 case EOpIsnan:
2855 ASSERT(getType().getBasicType() == EbtFloat);
2856 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2857 break;
2858
2859 case EOpIsinf:
2860 ASSERT(getType().getBasicType() == EbtFloat);
2861 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2862 break;
2863
2864 case EOpFloatBitsToInt:
2865 ASSERT(getType().getBasicType() == EbtFloat);
2866 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2867 break;
2868
2869 case EOpFloatBitsToUint:
2870 ASSERT(getType().getBasicType() == EbtFloat);
2871 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2872 break;
2873
2874 case EOpIntBitsToFloat:
2875 ASSERT(getType().getBasicType() == EbtInt);
2876 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2877 break;
2878
2879 case EOpUintBitsToFloat:
2880 ASSERT(getType().getBasicType() == EbtUInt);
2881 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2882 break;
2883
2884 case EOpExp:
2885 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2886 break;
2887
2888 case EOpLog:
2889 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2890 if (operandArray[i].getFConst() <= 0.0f)
2891 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2892 diagnostics, &resultArray[i]);
2893 else
2894 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2895 break;
2896
2897 case EOpExp2:
2898 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2899 break;
2900
2901 case EOpLog2:
2902 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2903 // And log2f is not available on some plarforms like old android, so just using
2904 // log(x)/log(2) here.
2905 if (operandArray[i].getFConst() <= 0.0f)
2906 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2907 diagnostics, &resultArray[i]);
2908 else
2909 {
2910 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2911 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2912 }
2913 break;
2914
2915 case EOpSqrt:
2916 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2917 if (operandArray[i].getFConst() < 0.0f)
2918 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2919 diagnostics, &resultArray[i]);
2920 else
2921 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2922 break;
2923
2924 case EOpInversesqrt:
2925 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2926 // so getting the square root first using builtin function sqrt() and then taking
2927 // its inverse.
2928 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2929 // result to 0.
2930 if (operandArray[i].getFConst() <= 0.0f)
2931 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2932 diagnostics, &resultArray[i]);
2933 else
2934 {
2935 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2936 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2937 }
2938 break;
2939
2940 case EOpLogicalNotComponentWise:
2941 ASSERT(getType().getBasicType() == EbtBool);
2942 resultArray[i].setBConst(!operandArray[i].getBConst());
2943 break;
2944
2945 case EOpNormalize:
2946 {
2947 ASSERT(getType().getBasicType() == EbtFloat);
2948 float x = operandArray[i].getFConst();
2949 float length = VectorLength(operandArray, objectSize);
2950 if (length)
2951 resultArray[i].setFConst(x / length);
2952 else
2953 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2954 diagnostics, &resultArray[i]);
2955 break;
2956 }
2957 case EOpBitfieldReverse:
2958 {
2959 uint32_t value;
2960 if (getType().getBasicType() == EbtInt)
2961 {
2962 value = static_cast<uint32_t>(operandArray[i].getIConst());
2963 }
2964 else
2965 {
2966 ASSERT(getType().getBasicType() == EbtUInt);
2967 value = operandArray[i].getUConst();
2968 }
2969 uint32_t result = gl::BitfieldReverse(value);
2970 if (getType().getBasicType() == EbtInt)
2971 {
2972 resultArray[i].setIConst(static_cast<int32_t>(result));
2973 }
2974 else
2975 {
2976 resultArray[i].setUConst(result);
2977 }
2978 break;
2979 }
2980 case EOpBitCount:
2981 {
2982 uint32_t value;
2983 if (getType().getBasicType() == EbtInt)
2984 {
2985 value = static_cast<uint32_t>(operandArray[i].getIConst());
2986 }
2987 else
2988 {
2989 ASSERT(getType().getBasicType() == EbtUInt);
2990 value = operandArray[i].getUConst();
2991 }
2992 int result = gl::BitCount(value);
2993 resultArray[i].setIConst(result);
2994 break;
2995 }
2996 case EOpFindLSB:
2997 {
2998 uint32_t value;
2999 if (getType().getBasicType() == EbtInt)
3000 {
3001 value = static_cast<uint32_t>(operandArray[i].getIConst());
3002 }
3003 else
3004 {
3005 ASSERT(getType().getBasicType() == EbtUInt);
3006 value = operandArray[i].getUConst();
3007 }
3008 resultArray[i].setIConst(gl::FindLSB(value));
3009 break;
3010 }
3011 case EOpFindMSB:
3012 {
3013 uint32_t value;
3014 if (getType().getBasicType() == EbtInt)
3015 {
3016 int intValue = operandArray[i].getIConst();
3017 value = static_cast<uint32_t>(intValue);
3018 if (intValue < 0)
3019 {
3020 // Look for zero instead of one in value. This also handles the intValue ==
3021 // -1 special case, where the return value needs to be -1.
3022 value = ~value;
3023 }
3024 }
3025 else
3026 {
3027 ASSERT(getType().getBasicType() == EbtUInt);
3028 value = operandArray[i].getUConst();
3029 }
3030 resultArray[i].setIConst(gl::FindMSB(value));
3031 break;
3032 }
3033 case EOpDFdx:
3034 case EOpDFdy:
3035 case EOpFwidth:
3036 ASSERT(getType().getBasicType() == EbtFloat);
3037 // Derivatives of constant arguments should be 0.
3038 resultArray[i].setFConst(0.0f);
3039 break;
3040
3041 default:
3042 return nullptr;
3043 }
3044 }
3045
3046 return resultArray;
3047}
3048
3049void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
3050 FloatTypeUnaryFunc builtinFunc,
3051 TConstantUnion *result) const
3052{
3053 ASSERT(builtinFunc);
3054
3055 ASSERT(getType().getBasicType() == EbtFloat);
3056 result->setFConst(builtinFunc(parameter.getFConst()));
3057}
3058
3059// static
3060TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
3061 TDiagnostics *diagnostics)
3062{
3063 TOperator op = aggregate->getOp();
3064 TIntermSequence *arguments = aggregate->getSequence();
3065 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
3066 std::vector<const TConstantUnion *> unionArrays(argsCount);
3067 std::vector<size_t> objectSizes(argsCount);
3068 size_t maxObjectSize = 0;
3069 TBasicType basicType = EbtVoid;
3070 TSourceLoc loc;
3071 for (unsigned int i = 0; i < argsCount; i++)
3072 {
3073 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
3074 ASSERT(argConstant != nullptr); // Should be checked already.
3075
3076 if (i == 0)
3077 {
3078 basicType = argConstant->getType().getBasicType();
3079 loc = argConstant->getLine();
3080 }
3081 unionArrays[i] = argConstant->getConstantValue();
3082 objectSizes[i] = argConstant->getType().getObjectSize();
3083 if (objectSizes[i] > maxObjectSize)
3084 maxObjectSize = objectSizes[i];
3085 }
3086
3087 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
3088 {
3089 for (unsigned int i = 0; i < argsCount; i++)
3090 if (objectSizes[i] != maxObjectSize)
3091 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
3092 }
3093
3094 TConstantUnion *resultArray = nullptr;
3095
3096 switch (op)
3097 {
3098 case EOpAtan:
3099 {
3100 ASSERT(basicType == EbtFloat);
3101 resultArray = new TConstantUnion[maxObjectSize];
3102 for (size_t i = 0; i < maxObjectSize; i++)
3103 {
3104 float y = unionArrays[0][i].getFConst();
3105 float x = unionArrays[1][i].getFConst();
3106 // Results are undefined if x and y are both 0.
3107 if (x == 0.0f && y == 0.0f)
3108 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3109 else
3110 resultArray[i].setFConst(atan2f(y, x));
3111 }
3112 break;
3113 }
3114
3115 case EOpPow:
3116 {
3117 ASSERT(basicType == EbtFloat);
3118 resultArray = new TConstantUnion[maxObjectSize];
3119 for (size_t i = 0; i < maxObjectSize; i++)
3120 {
3121 float x = unionArrays[0][i].getFConst();
3122 float y = unionArrays[1][i].getFConst();
3123 // Results are undefined if x < 0.
3124 // Results are undefined if x = 0 and y <= 0.
3125 if (x < 0.0f)
3126 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3127 else if (x == 0.0f && y <= 0.0f)
3128 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3129 else
3130 resultArray[i].setFConst(powf(x, y));
3131 }
3132 break;
3133 }
3134
3135 case EOpMod:
3136 {
3137 ASSERT(basicType == EbtFloat);
3138 resultArray = new TConstantUnion[maxObjectSize];
3139 for (size_t i = 0; i < maxObjectSize; i++)
3140 {
3141 float x = unionArrays[0][i].getFConst();
3142 float y = unionArrays[1][i].getFConst();
3143 resultArray[i].setFConst(x - y * floorf(x / y));
3144 }
3145 break;
3146 }
3147
3148 case EOpMin:
3149 {
3150 resultArray = new TConstantUnion[maxObjectSize];
3151 for (size_t i = 0; i < maxObjectSize; i++)
3152 {
3153 switch (basicType)
3154 {
3155 case EbtFloat:
3156 resultArray[i].setFConst(
3157 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
3158 break;
3159 case EbtInt:
3160 resultArray[i].setIConst(
3161 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
3162 break;
3163 case EbtUInt:
3164 resultArray[i].setUConst(
3165 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
3166 break;
3167 default:
3168 UNREACHABLE();
3169 break;
3170 }
3171 }
3172 break;
3173 }
3174
3175 case EOpMax:
3176 {
3177 resultArray = new TConstantUnion[maxObjectSize];
3178 for (size_t i = 0; i < maxObjectSize; i++)
3179 {
3180 switch (basicType)
3181 {
3182 case EbtFloat:
3183 resultArray[i].setFConst(
3184 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
3185 break;
3186 case EbtInt:
3187 resultArray[i].setIConst(
3188 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
3189 break;
3190 case EbtUInt:
3191 resultArray[i].setUConst(
3192 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
3193 break;
3194 default:
3195 UNREACHABLE();
3196 break;
3197 }
3198 }
3199 break;
3200 }
3201
3202 case EOpStep:
3203 {
3204 ASSERT(basicType == EbtFloat);
3205 resultArray = new TConstantUnion[maxObjectSize];
3206 for (size_t i = 0; i < maxObjectSize; i++)
3207 resultArray[i].setFConst(
3208 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
3209 break;
3210 }
3211
3212 case EOpLessThanComponentWise:
3213 {
3214 resultArray = new TConstantUnion[maxObjectSize];
3215 for (size_t i = 0; i < maxObjectSize; i++)
3216 {
3217 switch (basicType)
3218 {
3219 case EbtFloat:
3220 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
3221 unionArrays[1][i].getFConst());
3222 break;
3223 case EbtInt:
3224 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
3225 unionArrays[1][i].getIConst());
3226 break;
3227 case EbtUInt:
3228 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
3229 unionArrays[1][i].getUConst());
3230 break;
3231 default:
3232 UNREACHABLE();
3233 break;
3234 }
3235 }
3236 break;
3237 }
3238
3239 case EOpLessThanEqualComponentWise:
3240 {
3241 resultArray = new TConstantUnion[maxObjectSize];
3242 for (size_t i = 0; i < maxObjectSize; i++)
3243 {
3244 switch (basicType)
3245 {
3246 case EbtFloat:
3247 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
3248 unionArrays[1][i].getFConst());
3249 break;
3250 case EbtInt:
3251 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
3252 unionArrays[1][i].getIConst());
3253 break;
3254 case EbtUInt:
3255 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
3256 unionArrays[1][i].getUConst());
3257 break;
3258 default:
3259 UNREACHABLE();
3260 break;
3261 }
3262 }
3263 break;
3264 }
3265
3266 case EOpGreaterThanComponentWise:
3267 {
3268 resultArray = new TConstantUnion[maxObjectSize];
3269 for (size_t i = 0; i < maxObjectSize; i++)
3270 {
3271 switch (basicType)
3272 {
3273 case EbtFloat:
3274 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
3275 unionArrays[1][i].getFConst());
3276 break;
3277 case EbtInt:
3278 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
3279 unionArrays[1][i].getIConst());
3280 break;
3281 case EbtUInt:
3282 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
3283 unionArrays[1][i].getUConst());
3284 break;
3285 default:
3286 UNREACHABLE();
3287 break;
3288 }
3289 }
3290 break;
3291 }
3292 case EOpGreaterThanEqualComponentWise:
3293 {
3294 resultArray = new TConstantUnion[maxObjectSize];
3295 for (size_t i = 0; i < maxObjectSize; i++)
3296 {
3297 switch (basicType)
3298 {
3299 case EbtFloat:
3300 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
3301 unionArrays[1][i].getFConst());
3302 break;
3303 case EbtInt:
3304 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3305 unionArrays[1][i].getIConst());
3306 break;
3307 case EbtUInt:
3308 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3309 unionArrays[1][i].getUConst());
3310 break;
3311 default:
3312 UNREACHABLE();
3313 break;
3314 }
3315 }
3316 }
3317 break;
3318
3319 case EOpEqualComponentWise:
3320 {
3321 resultArray = new TConstantUnion[maxObjectSize];
3322 for (size_t i = 0; i < maxObjectSize; i++)
3323 {
3324 switch (basicType)
3325 {
3326 case EbtFloat:
3327 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3328 unionArrays[1][i].getFConst());
3329 break;
3330 case EbtInt:
3331 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3332 unionArrays[1][i].getIConst());
3333 break;
3334 case EbtUInt:
3335 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3336 unionArrays[1][i].getUConst());
3337 break;
3338 case EbtBool:
3339 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3340 unionArrays[1][i].getBConst());
3341 break;
3342 default:
3343 UNREACHABLE();
3344 break;
3345 }
3346 }
3347 break;
3348 }
3349
3350 case EOpNotEqualComponentWise:
3351 {
3352 resultArray = new TConstantUnion[maxObjectSize];
3353 for (size_t i = 0; i < maxObjectSize; i++)
3354 {
3355 switch (basicType)
3356 {
3357 case EbtFloat:
3358 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3359 unionArrays[1][i].getFConst());
3360 break;
3361 case EbtInt:
3362 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3363 unionArrays[1][i].getIConst());
3364 break;
3365 case EbtUInt:
3366 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3367 unionArrays[1][i].getUConst());
3368 break;
3369 case EbtBool:
3370 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3371 unionArrays[1][i].getBConst());
3372 break;
3373 default:
3374 UNREACHABLE();
3375 break;
3376 }
3377 }
3378 break;
3379 }
3380
3381 case EOpDistance:
3382 {
3383 ASSERT(basicType == EbtFloat);
3384 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3385 resultArray = new TConstantUnion();
3386 for (size_t i = 0; i < maxObjectSize; i++)
3387 {
3388 float x = unionArrays[0][i].getFConst();
3389 float y = unionArrays[1][i].getFConst();
3390 distanceArray[i].setFConst(x - y);
3391 }
3392 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3393 break;
3394 }
3395
3396 case EOpDot:
3397 ASSERT(basicType == EbtFloat);
3398 resultArray = new TConstantUnion();
3399 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3400 break;
3401
3402 case EOpCross:
3403 {
3404 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3405 resultArray = new TConstantUnion[maxObjectSize];
3406 float x0 = unionArrays[0][0].getFConst();
3407 float x1 = unionArrays[0][1].getFConst();
3408 float x2 = unionArrays[0][2].getFConst();
3409 float y0 = unionArrays[1][0].getFConst();
3410 float y1 = unionArrays[1][1].getFConst();
3411 float y2 = unionArrays[1][2].getFConst();
3412 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3413 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3414 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3415 break;
3416 }
3417
3418 case EOpReflect:
3419 {
3420 ASSERT(basicType == EbtFloat);
3421 // genType reflect (genType I, genType N) :
3422 // For the incident vector I and surface orientation N, returns the reflection
3423 // direction:
3424 // I - 2 * dot(N, I) * N.
3425 resultArray = new TConstantUnion[maxObjectSize];
3426 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3427 for (size_t i = 0; i < maxObjectSize; i++)
3428 {
3429 float result = unionArrays[0][i].getFConst() -
3430 2.0f * dotProduct * unionArrays[1][i].getFConst();
3431 resultArray[i].setFConst(result);
3432 }
3433 break;
3434 }
3435
3436 case EOpMulMatrixComponentWise:
3437 {
3438 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3439 (*arguments)[1]->getAsTyped()->isMatrix());
3440 // Perform component-wise matrix multiplication.
3441 resultArray = new TConstantUnion[maxObjectSize];
3442 int rows = (*arguments)[0]->getAsTyped()->getRows();
3443 int cols = (*arguments)[0]->getAsTyped()->getCols();
3444 angle::Matrix<float> lhs = GetMatrix(unionArrays[0], rows, cols);
3445 angle::Matrix<float> rhs = GetMatrix(unionArrays[1], rows, cols);
3446 angle::Matrix<float> result = lhs.compMult(rhs);
3447 SetUnionArrayFromMatrix(result, resultArray);
3448 break;
3449 }
3450
3451 case EOpOuterProduct:
3452 {
3453 ASSERT(basicType == EbtFloat);
3454 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3455 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
3456 resultArray = new TConstantUnion[numRows * numCols];
3457 angle::Matrix<float> result =
3458 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3459 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3460 SetUnionArrayFromMatrix(result, resultArray);
3461 break;
3462 }
3463
3464 case EOpClamp:
3465 {
3466 resultArray = new TConstantUnion[maxObjectSize];
3467 for (size_t i = 0; i < maxObjectSize; i++)
3468 {
3469 switch (basicType)
3470 {
3471 case EbtFloat:
3472 {
3473 float x = unionArrays[0][i].getFConst();
3474 float min = unionArrays[1][i].getFConst();
3475 float max = unionArrays[2][i].getFConst();
3476 // Results are undefined if min > max.
3477 if (min > max)
3478 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3479 &resultArray[i]);
3480 else
3481 resultArray[i].setFConst(gl::clamp(x, min, max));
3482 break;
3483 }
3484
3485 case EbtInt:
3486 {
3487 int x = unionArrays[0][i].getIConst();
3488 int min = unionArrays[1][i].getIConst();
3489 int max = unionArrays[2][i].getIConst();
3490 // Results are undefined if min > max.
3491 if (min > max)
3492 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3493 &resultArray[i]);
3494 else
3495 resultArray[i].setIConst(gl::clamp(x, min, max));
3496 break;
3497 }
3498 case EbtUInt:
3499 {
3500 unsigned int x = unionArrays[0][i].getUConst();
3501 unsigned int min = unionArrays[1][i].getUConst();
3502 unsigned int max = unionArrays[2][i].getUConst();
3503 // Results are undefined if min > max.
3504 if (min > max)
3505 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3506 &resultArray[i]);
3507 else
3508 resultArray[i].setUConst(gl::clamp(x, min, max));
3509 break;
3510 }
3511 default:
3512 UNREACHABLE();
3513 break;
3514 }
3515 }
3516 break;
3517 }
3518
3519 case EOpMix:
3520 {
3521 ASSERT(basicType == EbtFloat);
3522 resultArray = new TConstantUnion[maxObjectSize];
3523 for (size_t i = 0; i < maxObjectSize; i++)
3524 {
3525 float x = unionArrays[0][i].getFConst();
3526 float y = unionArrays[1][i].getFConst();
3527 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
3528 if (type == EbtFloat)
3529 {
3530 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3531 float a = unionArrays[2][i].getFConst();
3532 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3533 }
3534 else // 3rd parameter is EbtBool
3535 {
3536 ASSERT(type == EbtBool);
3537 // Selects which vector each returned component comes from.
3538 // For a component of a that is false, the corresponding component of x is
3539 // returned.
3540 // For a component of a that is true, the corresponding component of y is
3541 // returned.
3542 bool a = unionArrays[2][i].getBConst();
3543 resultArray[i].setFConst(a ? y : x);
3544 }
3545 }
3546 break;
3547 }
3548
3549 case EOpSmoothstep:
3550 {
3551 ASSERT(basicType == EbtFloat);
3552 resultArray = new TConstantUnion[maxObjectSize];
3553 for (size_t i = 0; i < maxObjectSize; i++)
3554 {
3555 float edge0 = unionArrays[0][i].getFConst();
3556 float edge1 = unionArrays[1][i].getFConst();
3557 float x = unionArrays[2][i].getFConst();
3558 // Results are undefined if edge0 >= edge1.
3559 if (edge0 >= edge1)
3560 {
3561 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3562 }
3563 else
3564 {
3565 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3566 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3567 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3568 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3569 }
3570 }
3571 break;
3572 }
3573
3574 case EOpLdexp:
3575 {
3576 resultArray = new TConstantUnion[maxObjectSize];
3577 for (size_t i = 0; i < maxObjectSize; i++)
3578 {
3579 float x = unionArrays[0][i].getFConst();
3580 int exp = unionArrays[1][i].getIConst();
3581 if (exp > 128)
3582 {
3583 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3584 }
3585 else
3586 {
3587 resultArray[i].setFConst(gl::Ldexp(x, exp));
3588 }
3589 }
3590 break;
3591 }
3592
3593 case EOpFaceforward:
3594 {
3595 ASSERT(basicType == EbtFloat);
3596 // genType faceforward(genType N, genType I, genType Nref) :
3597 // If dot(Nref, I) < 0 return N, otherwise return -N.
3598 resultArray = new TConstantUnion[maxObjectSize];
3599 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3600 for (size_t i = 0; i < maxObjectSize; i++)
3601 {
3602 if (dotProduct < 0)
3603 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3604 else
3605 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3606 }
3607 break;
3608 }
3609
3610 case EOpRefract:
3611 {
3612 ASSERT(basicType == EbtFloat);
3613 // genType refract(genType I, genType N, float eta) :
3614 // For the incident vector I and surface normal N, and the ratio of indices of
3615 // refraction eta,
3616 // return the refraction vector. The result is computed by
3617 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3618 // if (k < 0.0)
3619 // return genType(0.0)
3620 // else
3621 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3622 resultArray = new TConstantUnion[maxObjectSize];
3623 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3624 for (size_t i = 0; i < maxObjectSize; i++)
3625 {
3626 float eta = unionArrays[2][i].getFConst();
3627 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3628 if (k < 0.0f)
3629 resultArray[i].setFConst(0.0f);
3630 else
3631 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3632 (eta * dotProduct + sqrtf(k)) *
3633 unionArrays[1][i].getFConst());
3634 }
3635 break;
3636 }
3637 case EOpBitfieldExtract:
3638 {
3639 resultArray = new TConstantUnion[maxObjectSize];
3640 for (size_t i = 0; i < maxObjectSize; ++i)
3641 {
3642 int offset = unionArrays[1][0].getIConst();
3643 int bits = unionArrays[2][0].getIConst();
3644 if (bits == 0)
3645 {
3646 if (aggregate->getBasicType() == EbtInt)
3647 {
3648 resultArray[i].setIConst(0);
3649 }
3650 else
3651 {
3652 ASSERT(aggregate->getBasicType() == EbtUInt);
3653 resultArray[i].setUConst(0);
3654 }
3655 }
3656 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3657 {
3658 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3659 &resultArray[i]);
3660 }
3661 else
3662 {
3663 // bits can be 32 here, so we need to avoid bit shift overflow.
3664 uint32_t maskMsb = 1u << (bits - 1);
3665 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3666 if (aggregate->getBasicType() == EbtInt)
3667 {
3668 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3669 uint32_t resultUnsigned = (value & mask) >> offset;
3670 if ((resultUnsigned & maskMsb) != 0)
3671 {
3672 // The most significant bits (from bits+1 to the most significant bit)
3673 // should be set to 1.
3674 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3675 resultUnsigned |= higherBitsMask;
3676 }
3677 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3678 }
3679 else
3680 {
3681 ASSERT(aggregate->getBasicType() == EbtUInt);
3682 uint32_t value = unionArrays[0][i].getUConst();
3683 resultArray[i].setUConst((value & mask) >> offset);
3684 }
3685 }
3686 }
3687 break;
3688 }
3689 case EOpBitfieldInsert:
3690 {
3691 resultArray = new TConstantUnion[maxObjectSize];
3692 for (size_t i = 0; i < maxObjectSize; ++i)
3693 {
3694 int offset = unionArrays[2][0].getIConst();
3695 int bits = unionArrays[3][0].getIConst();
3696 if (bits == 0)
3697 {
3698 if (aggregate->getBasicType() == EbtInt)
3699 {
3700 int32_t base = unionArrays[0][i].getIConst();
3701 resultArray[i].setIConst(base);
3702 }
3703 else
3704 {
3705 ASSERT(aggregate->getBasicType() == EbtUInt);
3706 uint32_t base = unionArrays[0][i].getUConst();
3707 resultArray[i].setUConst(base);
3708 }
3709 }
3710 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3711 {
3712 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3713 &resultArray[i]);
3714 }
3715 else
3716 {
3717 // bits can be 32 here, so we need to avoid bit shift overflow.
3718 uint32_t maskMsb = 1u << (bits - 1);
3719 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3720 uint32_t baseMask = ~insertMask;
3721 if (aggregate->getBasicType() == EbtInt)
3722 {
3723 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3724 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3725 uint32_t resultUnsigned =
3726 (base & baseMask) | ((insert << offset) & insertMask);
3727 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3728 }
3729 else
3730 {
3731 ASSERT(aggregate->getBasicType() == EbtUInt);
3732 uint32_t base = unionArrays[0][i].getUConst();
3733 uint32_t insert = unionArrays[1][i].getUConst();
3734 resultArray[i].setUConst((base & baseMask) |
3735 ((insert << offset) & insertMask));
3736 }
3737 }
3738 }
3739 break;
3740 }
3741
3742 default:
3743 UNREACHABLE();
3744 return nullptr;
3745 }
3746 return resultArray;
3747}
3748
3749// TIntermPreprocessorDirective implementation.
3750TIntermPreprocessorDirective::TIntermPreprocessorDirective(PreprocessorDirective directive,
3751 ImmutableString command)
3752 : mDirective(directive), mCommand(std::move(command))
3753{}
3754
3755TIntermPreprocessorDirective::~TIntermPreprocessorDirective() = default;
3756
3757size_t TIntermPreprocessorDirective::getChildCount() const
3758{
3759 return 0;
3760}
3761
3762TIntermNode *TIntermPreprocessorDirective::getChildNode(size_t index) const
3763{
3764 UNREACHABLE();
3765 return nullptr;
3766}
3767} // namespace sh
3768