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