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