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