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