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