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