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