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