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