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 const uint8_t resultCols = getType().getCols();
879 const uint8_t resultRows = getType().getRows();
880 for (uint8_t col = 0; col < resultCols; ++col)
881 {
882 for (uint8_t 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 const uint8_t argumentCols = argumentTyped->getType().getCols();
911 const uint8_t argumentRows = argumentTyped->getType().getRows();
912 const uint8_t resultCols = getType().getCols();
913 const uint8_t resultRows = getType().getRows();
914 for (uint8_t col = 0; col < resultCols; ++col)
915 {
916 for (uint8_t 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(mOperand->getType().getRows());
1421 resultType.setSecondarySize(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(mOperand->getType().isVector());
1525 ASSERT(mSwizzleOffsets.size() <= 4);
1526 promote();
1527 }
1528
TIntermUnary(TOperator op,TIntermTyped * operand,const TFunction * function)1529 TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand, const TFunction *function)
1530 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false), mFunction(function)
1531 {
1532 ASSERT(mOperand);
1533 ASSERT(!BuiltInGroup::IsBuiltIn(op) || (function != nullptr && function->getBuiltInOp() == op));
1534 promote();
1535 }
1536
TIntermBinary(TOperator op,TIntermTyped * left,TIntermTyped * right)1537 TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
1538 : TIntermOperator(op), mLeft(left), mRight(right)
1539 {
1540 ASSERT(mLeft);
1541 ASSERT(mRight);
1542 promote();
1543 }
1544
CreateComma(TIntermTyped * left,TIntermTyped * right,int shaderVersion)1545 TIntermBinary *TIntermBinary::CreateComma(TIntermTyped *left,
1546 TIntermTyped *right,
1547 int shaderVersion)
1548 {
1549 TIntermBinary *node = new TIntermBinary(EOpComma, left, right);
1550 node->getTypePointer()->setQualifier(GetCommaQualifier(shaderVersion, left, right));
1551 return node;
1552 }
1553
TIntermGlobalQualifierDeclaration(TIntermSymbol * symbol,bool isPrecise,const TSourceLoc & line)1554 TIntermGlobalQualifierDeclaration::TIntermGlobalQualifierDeclaration(TIntermSymbol *symbol,
1555 bool isPrecise,
1556 const TSourceLoc &line)
1557 : TIntermNode(), mSymbol(symbol), mIsPrecise(isPrecise)
1558 {
1559 ASSERT(symbol);
1560 setLine(line);
1561 }
1562
TIntermGlobalQualifierDeclaration(const TIntermGlobalQualifierDeclaration & node)1563 TIntermGlobalQualifierDeclaration::TIntermGlobalQualifierDeclaration(
1564 const TIntermGlobalQualifierDeclaration &node)
1565 : TIntermGlobalQualifierDeclaration(static_cast<TIntermSymbol *>(node.mSymbol->deepCopy()),
1566 node.mIsPrecise,
1567 node.mLine)
1568 {}
1569
TIntermTernary(TIntermTyped * cond,TIntermTyped * trueExpression,TIntermTyped * falseExpression)1570 TIntermTernary::TIntermTernary(TIntermTyped *cond,
1571 TIntermTyped *trueExpression,
1572 TIntermTyped *falseExpression)
1573 : TIntermExpression(trueExpression->getType()),
1574 mCondition(cond),
1575 mTrueExpression(trueExpression),
1576 mFalseExpression(falseExpression)
1577 {
1578 ASSERT(mCondition);
1579 ASSERT(mTrueExpression);
1580 ASSERT(mFalseExpression);
1581 getTypePointer()->setQualifier(
1582 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
1583
1584 propagatePrecision(derivePrecision());
1585 }
1586
TIntermLoop(TLoopType type,TIntermNode * init,TIntermTyped * cond,TIntermTyped * expr,TIntermBlock * body)1587 TIntermLoop::TIntermLoop(TLoopType type,
1588 TIntermNode *init,
1589 TIntermTyped *cond,
1590 TIntermTyped *expr,
1591 TIntermBlock *body)
1592 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
1593 {
1594 // Declaration nodes with no children can appear if all the declarators just added constants to
1595 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
1596 if (mInit && mInit->getAsDeclarationNode() &&
1597 mInit->getAsDeclarationNode()->getSequence()->empty())
1598 {
1599 mInit = nullptr;
1600 }
1601 }
1602
TIntermLoop(const TIntermLoop & node)1603 TIntermLoop::TIntermLoop(const TIntermLoop &node)
1604 : TIntermLoop(node.mType,
1605 node.mInit->deepCopy(),
1606 node.mCond->deepCopy(),
1607 node.mExpr->deepCopy(),
1608 node.mBody->deepCopy())
1609 {}
1610
TIntermIfElse(TIntermTyped * cond,TIntermBlock * trueB,TIntermBlock * falseB)1611 TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
1612 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
1613 {
1614 ASSERT(mCondition);
1615 // Prune empty false blocks so that there won't be unnecessary operations done on it.
1616 if (mFalseBlock && mFalseBlock->getSequence()->empty())
1617 {
1618 mFalseBlock = nullptr;
1619 }
1620 }
1621
TIntermIfElse(const TIntermIfElse & node)1622 TIntermIfElse::TIntermIfElse(const TIntermIfElse &node)
1623 : TIntermIfElse(node.mCondition->deepCopy(),
1624 node.mTrueBlock->deepCopy(),
1625 node.mFalseBlock ? node.mFalseBlock->deepCopy() : nullptr)
1626 {}
1627
TIntermSwitch(TIntermTyped * init,TIntermBlock * statementList)1628 TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
1629 : TIntermNode(), mInit(init), mStatementList(statementList)
1630 {
1631 ASSERT(mInit);
1632 ASSERT(mStatementList);
1633 }
1634
TIntermSwitch(const TIntermSwitch & node)1635 TIntermSwitch::TIntermSwitch(const TIntermSwitch &node)
1636 : TIntermSwitch(node.mInit->deepCopy(), node.mStatementList->deepCopy())
1637 {}
1638
setStatementList(TIntermBlock * statementList)1639 void TIntermSwitch::setStatementList(TIntermBlock *statementList)
1640 {
1641 ASSERT(statementList);
1642 mStatementList = statementList;
1643 }
1644
1645 // static
DetermineQualifier(TIntermTyped * cond,TIntermTyped * trueExpression,TIntermTyped * falseExpression)1646 TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
1647 TIntermTyped *trueExpression,
1648 TIntermTyped *falseExpression)
1649 {
1650 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
1651 falseExpression->getQualifier() == EvqConst)
1652 {
1653 return EvqConst;
1654 }
1655 return EvqTemporary;
1656 }
1657
1658 // Derive precision from children nodes
derivePrecision() const1659 TPrecision TIntermTernary::derivePrecision() const
1660 {
1661 return GetHigherPrecision(mTrueExpression->getPrecision(), mFalseExpression->getPrecision());
1662 }
1663
propagatePrecision(TPrecision precision)1664 void TIntermTernary::propagatePrecision(TPrecision precision)
1665 {
1666 mType.setPrecision(precision);
1667
1668 PropagatePrecisionIfApplicable(mTrueExpression, precision);
1669 PropagatePrecisionIfApplicable(mFalseExpression, precision);
1670 }
1671
fold(TDiagnostics *)1672 TIntermTyped *TIntermTernary::fold(TDiagnostics * /* diagnostics */)
1673 {
1674 if (mCondition->getAsConstantUnion())
1675 {
1676 if (mCondition->getAsConstantUnion()->getBConst(0))
1677 {
1678 return mTrueExpression;
1679 }
1680 else
1681 {
1682 return mFalseExpression;
1683 }
1684 }
1685 return this;
1686 }
1687
promote()1688 void TIntermSwizzle::promote()
1689 {
1690 TQualifier resultQualifier = EvqTemporary;
1691 if (mOperand->getQualifier() == EvqConst)
1692 resultQualifier = EvqConst;
1693
1694 size_t numFields = mSwizzleOffsets.size();
1695 setType(TType(mOperand->getBasicType(), EbpUndefined, resultQualifier,
1696 static_cast<uint8_t>(numFields)));
1697 propagatePrecision(derivePrecision());
1698 }
1699
1700 // Derive precision from children nodes
derivePrecision() const1701 TPrecision TIntermSwizzle::derivePrecision() const
1702 {
1703 return mOperand->getPrecision();
1704 }
1705
propagatePrecision(TPrecision precision)1706 void TIntermSwizzle::propagatePrecision(TPrecision precision)
1707 {
1708 mType.setPrecision(precision);
1709
1710 PropagatePrecisionIfApplicable(mOperand, precision);
1711 }
1712
hasDuplicateOffsets() const1713 bool TIntermSwizzle::hasDuplicateOffsets() const
1714 {
1715 if (mHasFoldedDuplicateOffsets)
1716 {
1717 return true;
1718 }
1719 int offsetCount[4] = {0u, 0u, 0u, 0u};
1720 for (const auto offset : mSwizzleOffsets)
1721 {
1722 offsetCount[offset]++;
1723 if (offsetCount[offset] > 1)
1724 {
1725 return true;
1726 }
1727 }
1728 return false;
1729 }
1730
setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)1731 void TIntermSwizzle::setHasFoldedDuplicateOffsets(bool hasFoldedDuplicateOffsets)
1732 {
1733 mHasFoldedDuplicateOffsets = hasFoldedDuplicateOffsets;
1734 }
1735
offsetsMatch(int offset) const1736 bool TIntermSwizzle::offsetsMatch(int offset) const
1737 {
1738 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1739 }
1740
writeOffsetsAsXYZW(TInfoSinkBase * out) const1741 void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1742 {
1743 for (const int offset : mSwizzleOffsets)
1744 {
1745 switch (offset)
1746 {
1747 case 0:
1748 *out << "x";
1749 break;
1750 case 1:
1751 *out << "y";
1752 break;
1753 case 2:
1754 *out << "z";
1755 break;
1756 case 3:
1757 *out << "w";
1758 break;
1759 default:
1760 UNREACHABLE();
1761 }
1762 }
1763 }
1764
GetCommaQualifier(int shaderVersion,const TIntermTyped * left,const TIntermTyped * right)1765 TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1766 const TIntermTyped *left,
1767 const TIntermTyped *right)
1768 {
1769 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1770 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1771 right->getQualifier() != EvqConst)
1772 {
1773 return EvqTemporary;
1774 }
1775 return EvqConst;
1776 }
1777
1778 // Establishes the type of the result of the binary operation.
promote()1779 void TIntermBinary::promote()
1780 {
1781 ASSERT(!isMultiplication() ||
1782 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1783
1784 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1785 // version and so is not being set here.
1786 if (mOp == EOpComma)
1787 {
1788 setType(mRight->getType());
1789 return;
1790 }
1791
1792 // Base assumption: just make the type the same as the left
1793 // operand. Then only deviations from this need be coded.
1794 setType(mLeft->getType());
1795
1796 TQualifier resultQualifier = EvqConst;
1797 // Binary operations results in temporary variables unless both
1798 // operands are const. If initializing a specialization constant, make the declarator also
1799 // EvqSpecConst.
1800 const bool isSpecConstInit = mOp == EOpInitialize && mLeft->getQualifier() == EvqSpecConst;
1801 const bool isEitherNonConst =
1802 mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst;
1803 if (!isSpecConstInit && isEitherNonConst)
1804 {
1805 resultQualifier = EvqTemporary;
1806 getTypePointer()->setQualifier(EvqTemporary);
1807 }
1808
1809 // Result is an intermediate value, so make sure it's identified as such. That's not true for
1810 // interface block arrays being indexed.
1811 if (mOp != EOpIndexDirect && mOp != EOpIndexIndirect)
1812 {
1813 getTypePointer()->setInterfaceBlock(nullptr);
1814 }
1815
1816 // Handle indexing ops.
1817 switch (mOp)
1818 {
1819 case EOpIndexDirect:
1820 case EOpIndexIndirect:
1821 if (mLeft->isArray())
1822 {
1823 mType.toArrayElementType();
1824 }
1825 else if (mLeft->isMatrix())
1826 {
1827 mType.toMatrixColumnType();
1828 }
1829 else if (mLeft->isVector())
1830 {
1831 mType.toComponentType();
1832 }
1833 else
1834 {
1835 UNREACHABLE();
1836 }
1837 return;
1838 case EOpIndexDirectStruct:
1839 {
1840 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1841 const int fieldIndex = mRight->getAsConstantUnion()->getIConst(0);
1842 setType(*fields[fieldIndex]->type());
1843 getTypePointer()->setQualifier(resultQualifier);
1844 return;
1845 }
1846 case EOpIndexDirectInterfaceBlock:
1847 {
1848 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1849 const int fieldIndex = mRight->getAsConstantUnion()->getIConst(0);
1850 setType(*fields[fieldIndex]->type());
1851 getTypePointer()->setQualifier(resultQualifier);
1852 return;
1853 }
1854 default:
1855 break;
1856 }
1857
1858 ASSERT(mLeft->isArray() == mRight->isArray());
1859
1860 const uint8_t nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
1861
1862 switch (mOp)
1863 {
1864 case EOpMul:
1865 break;
1866 case EOpMatrixTimesScalar:
1867 if (mRight->isMatrix())
1868 {
1869 getTypePointer()->setPrimarySize(mRight->getCols());
1870 getTypePointer()->setSecondarySize(mRight->getRows());
1871 }
1872 break;
1873 case EOpMatrixTimesVector:
1874 getTypePointer()->setPrimarySize(mLeft->getRows());
1875 getTypePointer()->setSecondarySize(1);
1876 break;
1877 case EOpMatrixTimesMatrix:
1878 getTypePointer()->setPrimarySize(mRight->getCols());
1879 getTypePointer()->setSecondarySize(mLeft->getRows());
1880 break;
1881 case EOpVectorTimesScalar:
1882 getTypePointer()->setPrimarySize(nominalSize);
1883 break;
1884 case EOpVectorTimesMatrix:
1885 getTypePointer()->setPrimarySize(mRight->getCols());
1886 ASSERT(getType().getSecondarySize() == 1);
1887 break;
1888 case EOpMulAssign:
1889 case EOpVectorTimesScalarAssign:
1890 case EOpVectorTimesMatrixAssign:
1891 case EOpMatrixTimesScalarAssign:
1892 case EOpMatrixTimesMatrixAssign:
1893 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1894 break;
1895 case EOpAssign:
1896 case EOpInitialize:
1897 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1898 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1899 break;
1900 case EOpAdd:
1901 case EOpSub:
1902 case EOpDiv:
1903 case EOpIMod:
1904 case EOpBitShiftLeft:
1905 case EOpBitShiftRight:
1906 case EOpBitwiseAnd:
1907 case EOpBitwiseXor:
1908 case EOpBitwiseOr:
1909 case EOpAddAssign:
1910 case EOpSubAssign:
1911 case EOpDivAssign:
1912 case EOpIModAssign:
1913 case EOpBitShiftLeftAssign:
1914 case EOpBitShiftRightAssign:
1915 case EOpBitwiseAndAssign:
1916 case EOpBitwiseXorAssign:
1917 case EOpBitwiseOrAssign:
1918 {
1919 ASSERT(!mLeft->isArray() && !mRight->isArray());
1920 const uint8_t secondarySize =
1921 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1922 getTypePointer()->setPrimarySize(nominalSize);
1923 getTypePointer()->setSecondarySize(secondarySize);
1924 break;
1925 }
1926 case EOpEqual:
1927 case EOpNotEqual:
1928 case EOpLessThan:
1929 case EOpGreaterThan:
1930 case EOpLessThanEqual:
1931 case EOpGreaterThanEqual:
1932 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1933 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1934 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1935 break;
1936
1937 //
1938 // And and Or operate on conditionals
1939 //
1940 case EOpLogicalAnd:
1941 case EOpLogicalXor:
1942 case EOpLogicalOr:
1943 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1944 break;
1945
1946 case EOpIndexDirect:
1947 case EOpIndexIndirect:
1948 case EOpIndexDirectInterfaceBlock:
1949 case EOpIndexDirectStruct:
1950 // These ops should be already fully handled.
1951 UNREACHABLE();
1952 break;
1953 default:
1954 UNREACHABLE();
1955 break;
1956 }
1957
1958 propagatePrecision(derivePrecision());
1959 }
1960
1961 // Derive precision from children nodes
derivePrecision() const1962 TPrecision TIntermBinary::derivePrecision() const
1963 {
1964 // Assignments use the type and precision of the lvalue-expression
1965 // GLSL ES spec section 5.8: Assignments
1966 // "The assignment operator stores the value of rvalue-expression into the l-value and returns
1967 // an r-value with the type and precision of lvalue-expression."
1968 if (IsAssignment(mOp))
1969 {
1970 return mLeft->getPrecision();
1971 }
1972
1973 const TPrecision higherPrecision =
1974 GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1975
1976 switch (mOp)
1977 {
1978 case EOpComma:
1979 // Comma takes the right node's value.
1980 return mRight->getPrecision();
1981
1982 case EOpIndexDirect:
1983 case EOpIndexIndirect:
1984 case EOpBitShiftLeft:
1985 case EOpBitShiftRight:
1986 // When indexing an array, the precision of the array is preserved (which is the left
1987 // node).
1988 // For shift operations, the precision is derived from the expression being shifted
1989 // (which is also the left node).
1990 return mLeft->getPrecision();
1991
1992 case EOpIndexDirectStruct:
1993 case EOpIndexDirectInterfaceBlock:
1994 {
1995 // When selecting the field of a block, the precision is taken from the field's
1996 // declaration.
1997 const TFieldList &fields = mOp == EOpIndexDirectStruct
1998 ? mLeft->getType().getStruct()->fields()
1999 : mLeft->getType().getInterfaceBlock()->fields();
2000 const int fieldIndex = mRight->getAsConstantUnion()->getIConst(0);
2001 return fields[fieldIndex]->type()->getPrecision();
2002 }
2003
2004 case EOpEqual:
2005 case EOpNotEqual:
2006 case EOpLessThan:
2007 case EOpGreaterThan:
2008 case EOpLessThanEqual:
2009 case EOpGreaterThanEqual:
2010 case EOpLogicalAnd:
2011 case EOpLogicalXor:
2012 case EOpLogicalOr:
2013 // No precision specified on bool results.
2014 return EbpUndefined;
2015
2016 default:
2017 // All other operations are evaluated at the higher of the two operands' precisions.
2018 return higherPrecision;
2019 }
2020 }
2021
propagatePrecision(TPrecision precision)2022 void TIntermBinary::propagatePrecision(TPrecision precision)
2023 {
2024 getTypePointer()->setPrecision(precision);
2025
2026 if (mOp != EOpComma)
2027 {
2028 PropagatePrecisionIfApplicable(mLeft, precision);
2029 }
2030
2031 if (mOp != EOpIndexDirect && mOp != EOpIndexIndirect && mOp != EOpIndexDirectStruct &&
2032 mOp != EOpIndexDirectInterfaceBlock)
2033 {
2034 PropagatePrecisionIfApplicable(mRight, precision);
2035 }
2036
2037 // For indices, always apply highp. This is purely for the purpose of making sure constant and
2038 // constructor nodes are also given a precision, so if they are hoisted to a temp variable,
2039 // there would be a precision to apply to that variable.
2040 if (mOp == EOpIndexDirect || mOp == EOpIndexIndirect)
2041 {
2042 PropagatePrecisionIfApplicable(mRight, EbpHigh);
2043 }
2044 }
2045
hasConstantValue() const2046 bool TIntermConstantUnion::hasConstantValue() const
2047 {
2048 return true;
2049 }
2050
isConstantNullValue() const2051 bool TIntermConstantUnion::isConstantNullValue() const
2052 {
2053 const size_t size = mType.getObjectSize();
2054 for (size_t index = 0; index < size; ++index)
2055 {
2056 if (!mUnionArrayPointer[index].isZero())
2057 {
2058 return false;
2059 }
2060 }
2061 return true;
2062 }
2063
getConstantValue() const2064 const TConstantUnion *TIntermConstantUnion::getConstantValue() const
2065 {
2066 return mUnionArrayPointer;
2067 }
2068
FoldIndexing(const TType & type,const TConstantUnion * constArray,int index)2069 const TConstantUnion *TIntermConstantUnion::FoldIndexing(const TType &type,
2070 const TConstantUnion *constArray,
2071 int index)
2072 {
2073 if (type.isArray())
2074 {
2075 ASSERT(index < static_cast<int>(type.getOutermostArraySize()));
2076 TType arrayElementType(type);
2077 arrayElementType.toArrayElementType();
2078 size_t arrayElementSize = arrayElementType.getObjectSize();
2079 return &constArray[arrayElementSize * index];
2080 }
2081 else if (type.isMatrix())
2082 {
2083 ASSERT(index < type.getCols());
2084 const uint8_t size = type.getRows();
2085 return &constArray[size * index];
2086 }
2087 else if (type.isVector())
2088 {
2089 ASSERT(index < type.getNominalSize());
2090 return &constArray[index];
2091 }
2092 else
2093 {
2094 UNREACHABLE();
2095 return nullptr;
2096 }
2097 }
2098
fold(TDiagnostics *)2099 TIntermTyped *TIntermSwizzle::fold(TDiagnostics * /* diagnostics */)
2100 {
2101 TIntermSwizzle *operandSwizzle = mOperand->getAsSwizzleNode();
2102 if (operandSwizzle)
2103 {
2104 // We need to fold the two swizzles into one, so that repeated swizzling can't cause stack
2105 // overflow in ParseContext::checkCanBeLValue().
2106 bool hadDuplicateOffsets = operandSwizzle->hasDuplicateOffsets();
2107 TVector<int> foldedOffsets;
2108 for (int offset : mSwizzleOffsets)
2109 {
2110 // Offset should already be validated.
2111 ASSERT(static_cast<size_t>(offset) < operandSwizzle->mSwizzleOffsets.size());
2112 foldedOffsets.push_back(operandSwizzle->mSwizzleOffsets[offset]);
2113 }
2114 operandSwizzle->mSwizzleOffsets = foldedOffsets;
2115 operandSwizzle->setType(getType());
2116 operandSwizzle->setHasFoldedDuplicateOffsets(hadDuplicateOffsets);
2117 return operandSwizzle;
2118 }
2119 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
2120 if (operandConstant == nullptr)
2121 {
2122 return this;
2123 }
2124
2125 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
2126 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
2127 {
2128 constArray[i] = *TIntermConstantUnion::FoldIndexing(
2129 operandConstant->getType(), operandConstant->getConstantValue(), mSwizzleOffsets.at(i));
2130 }
2131 return CreateFoldedNode(constArray, this);
2132 }
2133
fold(TDiagnostics * diagnostics)2134 TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
2135 {
2136 const TConstantUnion *rightConstant = mRight->getConstantValue();
2137 switch (mOp)
2138 {
2139 case EOpComma:
2140 {
2141 if (mLeft->hasSideEffects())
2142 {
2143 return this;
2144 }
2145 return mRight;
2146 }
2147 case EOpIndexDirect:
2148 case EOpIndexDirectStruct:
2149 {
2150 if (rightConstant == nullptr)
2151 {
2152 return this;
2153 }
2154 size_t index = static_cast<size_t>(rightConstant->getIConst());
2155 TIntermAggregate *leftAggregate = mLeft->getAsAggregate();
2156 if (leftAggregate && leftAggregate->isConstructor() && leftAggregate->isArray() &&
2157 !leftAggregate->hasSideEffects())
2158 {
2159 ASSERT(index < leftAggregate->getSequence()->size());
2160 // This transformation can't add complexity as we're eliminating the constructor
2161 // entirely.
2162 return leftAggregate->getSequence()->at(index)->getAsTyped();
2163 }
2164
2165 // If the indexed value is already a constant union, we can't increase duplication of
2166 // data by folding the indexing. Also fold the node in case it's generally beneficial to
2167 // replace this type of node with a constant union even if that would mean duplicating
2168 // data.
2169 if (mLeft->getAsConstantUnion() || getType().canReplaceWithConstantUnion())
2170 {
2171 const TConstantUnion *constantValue = getConstantValue();
2172 if (constantValue == nullptr)
2173 {
2174 return this;
2175 }
2176 return CreateFoldedNode(constantValue, this);
2177 }
2178 return this;
2179 }
2180 case EOpIndexIndirect:
2181 case EOpIndexDirectInterfaceBlock:
2182 case EOpInitialize:
2183 // Can never be constant folded.
2184 return this;
2185 default:
2186 {
2187 if (rightConstant == nullptr)
2188 {
2189 return this;
2190 }
2191 const TConstantUnion *leftConstant = mLeft->getConstantValue();
2192 if (leftConstant == nullptr)
2193 {
2194 return this;
2195 }
2196 const TConstantUnion *constArray =
2197 TIntermConstantUnion::FoldBinary(mOp, leftConstant, mLeft->getType(), rightConstant,
2198 mRight->getType(), diagnostics, mLeft->getLine());
2199 if (!constArray)
2200 {
2201 return this;
2202 }
2203 return CreateFoldedNode(constArray, this);
2204 }
2205 }
2206 }
2207
hasConstantValue() const2208 bool TIntermBinary::hasConstantValue() const
2209 {
2210 switch (mOp)
2211 {
2212 case EOpIndexDirect:
2213 case EOpIndexDirectStruct:
2214 {
2215 if (mLeft->hasConstantValue() && mRight->hasConstantValue())
2216 {
2217 return true;
2218 }
2219 break;
2220 }
2221 default:
2222 break;
2223 }
2224 return false;
2225 }
2226
getConstantValue() const2227 const TConstantUnion *TIntermBinary::getConstantValue() const
2228 {
2229 if (!hasConstantValue())
2230 {
2231 return nullptr;
2232 }
2233
2234 const TConstantUnion *leftConstantValue = mLeft->getConstantValue();
2235 int index = mRight->getConstantValue()->getIConst();
2236 const TConstantUnion *constIndexingResult = nullptr;
2237 if (mOp == EOpIndexDirect)
2238 {
2239 constIndexingResult =
2240 TIntermConstantUnion::FoldIndexing(mLeft->getType(), leftConstantValue, index);
2241 }
2242 else
2243 {
2244 ASSERT(mOp == EOpIndexDirectStruct);
2245 const TFieldList &fields = mLeft->getType().getStruct()->fields();
2246
2247 size_t previousFieldsSize = 0;
2248 for (int i = 0; i < index; ++i)
2249 {
2250 previousFieldsSize += fields[i]->type()->getObjectSize();
2251 }
2252 constIndexingResult = leftConstantValue + previousFieldsSize;
2253 }
2254 return constIndexingResult;
2255 }
2256
getIndexStructFieldName() const2257 const ImmutableString &TIntermBinary::getIndexStructFieldName() const
2258 {
2259 ASSERT(mOp == EOpIndexDirectStruct);
2260
2261 const TType &lhsType = mLeft->getType();
2262 const TStructure *structure = lhsType.getStruct();
2263 const int index = mRight->getAsConstantUnion()->getIConst(0);
2264
2265 return structure->fields()[index]->name();
2266 }
2267
fold(TDiagnostics * diagnostics)2268 TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
2269 {
2270 TConstantUnion *constArray = nullptr;
2271
2272 if (mOp == EOpArrayLength)
2273 {
2274 // The size of runtime-sized arrays may only be determined at runtime.
2275 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
2276 {
2277 return this;
2278 }
2279 constArray = new TConstantUnion[1];
2280 constArray->setIConst(mOperand->getOutermostArraySize());
2281 }
2282 else
2283 {
2284 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
2285 if (operandConstant == nullptr)
2286 {
2287 return this;
2288 }
2289
2290 switch (mOp)
2291 {
2292 case EOpAny:
2293 case EOpAll:
2294 case EOpLength:
2295 case EOpTranspose:
2296 case EOpDeterminant:
2297 case EOpInverse:
2298 case EOpPackSnorm2x16:
2299 case EOpUnpackSnorm2x16:
2300 case EOpPackUnorm2x16:
2301 case EOpUnpackUnorm2x16:
2302 case EOpPackHalf2x16:
2303 case EOpUnpackHalf2x16:
2304 case EOpPackUnorm4x8:
2305 case EOpPackSnorm4x8:
2306 case EOpUnpackUnorm4x8:
2307 case EOpUnpackSnorm4x8:
2308 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
2309 break;
2310 default:
2311 constArray = operandConstant->foldUnaryComponentWise(mOp, mFunction, diagnostics);
2312 break;
2313 }
2314 }
2315 if (constArray == nullptr)
2316 {
2317 return this;
2318 }
2319 return CreateFoldedNode(constArray, this);
2320 }
2321
fold(TDiagnostics * diagnostics)2322 TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
2323 {
2324 // Make sure that all params are constant before actual constant folding.
2325 for (auto *param : *getSequence())
2326 {
2327 if (param->getAsConstantUnion() == nullptr)
2328 {
2329 return this;
2330 }
2331 }
2332 const TConstantUnion *constArray = nullptr;
2333 if (isConstructor())
2334 {
2335 if (mType.canReplaceWithConstantUnion())
2336 {
2337 constArray = getConstantValue();
2338 if (constArray && mType.getBasicType() == EbtUInt)
2339 {
2340 // Check if we converted a negative float to uint and issue a warning in that case.
2341 size_t sizeRemaining = mType.getObjectSize();
2342 for (TIntermNode *arg : mArguments)
2343 {
2344 TIntermTyped *typedArg = arg->getAsTyped();
2345 if (typedArg->getBasicType() == EbtFloat)
2346 {
2347 const TConstantUnion *argValue = typedArg->getConstantValue();
2348 size_t castSize =
2349 std::min(typedArg->getType().getObjectSize(), sizeRemaining);
2350 for (size_t i = 0; i < castSize; ++i)
2351 {
2352 if (argValue[i].getFConst() < 0.0f)
2353 {
2354 // ESSL 3.00.6 section 5.4.1.
2355 diagnostics->warning(
2356 mLine, "casting a negative float to uint is undefined",
2357 mType.getBuiltInTypeNameString());
2358 }
2359 }
2360 }
2361 sizeRemaining -= typedArg->getType().getObjectSize();
2362 }
2363 }
2364 }
2365 }
2366 else if (CanFoldAggregateBuiltInOp(mOp))
2367 {
2368 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
2369 }
2370 if (constArray == nullptr)
2371 {
2372 return this;
2373 }
2374 return CreateFoldedNode(constArray, this);
2375 }
2376
2377 //
2378 // The fold functions see if an operation on a constant can be done in place,
2379 // without generating run-time code.
2380 //
2381 // Returns the constant value to keep using or nullptr.
2382 //
FoldBinary(TOperator op,const TConstantUnion * leftArray,const TType & leftType,const TConstantUnion * rightArray,const TType & rightType,TDiagnostics * diagnostics,const TSourceLoc & line)2383 const TConstantUnion *TIntermConstantUnion::FoldBinary(TOperator op,
2384 const TConstantUnion *leftArray,
2385 const TType &leftType,
2386 const TConstantUnion *rightArray,
2387 const TType &rightType,
2388 TDiagnostics *diagnostics,
2389 const TSourceLoc &line)
2390 {
2391 ASSERT(leftArray && rightArray);
2392
2393 size_t objectSize = leftType.getObjectSize();
2394
2395 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
2396 if (rightType.getObjectSize() == 1 && objectSize > 1)
2397 {
2398 rightArray = Vectorize(*rightArray, objectSize);
2399 }
2400 else if (rightType.getObjectSize() > 1 && objectSize == 1)
2401 {
2402 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
2403 leftArray = Vectorize(*leftArray, rightType.getObjectSize());
2404 objectSize = rightType.getObjectSize();
2405 }
2406
2407 TConstantUnion *resultArray = nullptr;
2408
2409 switch (op)
2410 {
2411 case EOpAdd:
2412 resultArray = new TConstantUnion[objectSize];
2413 for (size_t i = 0; i < objectSize; i++)
2414 resultArray[i] =
2415 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
2416 break;
2417 case EOpSub:
2418 resultArray = new TConstantUnion[objectSize];
2419 for (size_t i = 0; i < objectSize; i++)
2420 resultArray[i] =
2421 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
2422 break;
2423
2424 case EOpMul:
2425 case EOpVectorTimesScalar:
2426 case EOpMatrixTimesScalar:
2427 resultArray = new TConstantUnion[objectSize];
2428 for (size_t i = 0; i < objectSize; i++)
2429 resultArray[i] =
2430 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
2431 break;
2432
2433 case EOpMatrixTimesMatrix:
2434 {
2435 // TODO(jmadll): This code should check for overflows.
2436 ASSERT(leftType.getBasicType() == EbtFloat && rightType.getBasicType() == EbtFloat);
2437
2438 const uint8_t leftCols = leftType.getCols();
2439 const uint8_t leftRows = leftType.getRows();
2440 const uint8_t rightCols = rightType.getCols();
2441 const uint8_t rightRows = rightType.getRows();
2442 const uint8_t resultCols = rightCols;
2443 const uint8_t resultRows = leftRows;
2444
2445 resultArray = new TConstantUnion[resultCols * resultRows];
2446 for (uint8_t row = 0; row < resultRows; row++)
2447 {
2448 for (uint8_t column = 0; column < resultCols; column++)
2449 {
2450 resultArray[resultRows * column + row].setFConst(0.0f);
2451 for (uint8_t i = 0; i < leftCols; i++)
2452 {
2453 resultArray[resultRows * column + row].setFConst(
2454 resultArray[resultRows * column + row].getFConst() +
2455 leftArray[i * leftRows + row].getFConst() *
2456 rightArray[column * rightRows + i].getFConst());
2457 }
2458 }
2459 }
2460 }
2461 break;
2462
2463 case EOpDiv:
2464 case EOpIMod:
2465 {
2466 resultArray = new TConstantUnion[objectSize];
2467 for (size_t i = 0; i < objectSize; i++)
2468 {
2469 if (IsFloatDivision(leftType.getBasicType(), rightType.getBasicType()))
2470 {
2471 // Float division requested, possibly with implicit conversion
2472 ASSERT(op == EOpDiv);
2473 float dividend = leftArray[i].getFConst();
2474 float divisor = rightArray[i].getFConst();
2475
2476 if (divisor == 0.0f)
2477 {
2478 if (dividend == 0.0f)
2479 {
2480 diagnostics->warning(line,
2481 "Zero divided by zero during constant "
2482 "folding generated NaN",
2483 "/");
2484 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
2485 }
2486 else
2487 {
2488 diagnostics->warning(line, "Divide by zero during constant folding",
2489 "/");
2490 bool negativeResult = std::signbit(dividend) != std::signbit(divisor);
2491 resultArray[i].setFConst(negativeResult
2492 ? -std::numeric_limits<float>::infinity()
2493 : std::numeric_limits<float>::infinity());
2494 }
2495 }
2496 else if (gl::isInf(dividend) && gl::isInf(divisor))
2497 {
2498 diagnostics->warning(line,
2499 "Infinity divided by infinity during constant "
2500 "folding generated NaN",
2501 "/");
2502 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
2503 }
2504 else
2505 {
2506 float result = dividend / divisor;
2507 if (!gl::isInf(dividend) && gl::isInf(result))
2508 {
2509 diagnostics->warning(
2510 line, "Constant folded division overflowed to infinity", "/");
2511 }
2512 resultArray[i].setFConst(result);
2513 }
2514 }
2515 else
2516 {
2517 // Types are either both int or both uint
2518 switch (leftType.getBasicType())
2519 {
2520 case EbtInt:
2521 {
2522 if (rightArray[i] == 0)
2523 {
2524 diagnostics->warning(
2525 line, "Divide by zero error during constant folding", "/");
2526 resultArray[i].setIConst(INT_MAX);
2527 }
2528 else
2529 {
2530 int lhs = leftArray[i].getIConst();
2531 int divisor = rightArray[i].getIConst();
2532 if (op == EOpDiv)
2533 {
2534 // Check for the special case where the minimum
2535 // representable number is divided by -1. If left alone this
2536 // leads to integer overflow in C++. ESSL 3.00.6
2537 // section 4.1.3 Integers: "However, for the case where the
2538 // minimum representable value is divided by -1, it is
2539 // allowed to return either the minimum representable value
2540 // or the maximum representable value."
2541 if (lhs == -0x7fffffff - 1 && divisor == -1)
2542 {
2543 resultArray[i].setIConst(0x7fffffff);
2544 }
2545 else
2546 {
2547 resultArray[i].setIConst(lhs / divisor);
2548 }
2549 }
2550 else
2551 {
2552 ASSERT(op == EOpIMod);
2553 if (lhs < 0 || divisor < 0)
2554 {
2555 // ESSL 3.00.6 section 5.9: Results of modulus are
2556 // undefined when either one of the operands is
2557 // negative.
2558 diagnostics->warning(line,
2559 "Negative modulus operator operand "
2560 "encountered during constant folding. "
2561 "Results are undefined.",
2562 "%");
2563 resultArray[i].setIConst(0);
2564 }
2565 else
2566 {
2567 resultArray[i].setIConst(lhs % divisor);
2568 }
2569 }
2570 }
2571 break;
2572 }
2573 case EbtUInt:
2574 {
2575 if (rightArray[i] == 0)
2576 {
2577 diagnostics->warning(
2578 line, "Divide by zero error during constant folding", "/");
2579 resultArray[i].setUConst(UINT_MAX);
2580 }
2581 else
2582 {
2583 if (op == EOpDiv)
2584 {
2585 resultArray[i].setUConst(leftArray[i].getUConst() /
2586 rightArray[i].getUConst());
2587 }
2588 else
2589 {
2590 ASSERT(op == EOpIMod);
2591 resultArray[i].setUConst(leftArray[i].getUConst() %
2592 rightArray[i].getUConst());
2593 }
2594 }
2595 break;
2596 }
2597 default:
2598 UNREACHABLE();
2599 return nullptr;
2600 }
2601 }
2602 }
2603 }
2604 break;
2605
2606 case EOpMatrixTimesVector:
2607 {
2608 // TODO(jmadll): This code should check for overflows.
2609 ASSERT(rightType.getBasicType() == EbtFloat);
2610
2611 const uint8_t matrixCols = leftType.getCols();
2612 const uint8_t matrixRows = leftType.getRows();
2613
2614 resultArray = new TConstantUnion[matrixRows];
2615
2616 for (uint8_t matrixRow = 0; matrixRow < matrixRows; matrixRow++)
2617 {
2618 resultArray[matrixRow].setFConst(0.0f);
2619 for (uint8_t col = 0; col < matrixCols; col++)
2620 {
2621 resultArray[matrixRow].setFConst(
2622 resultArray[matrixRow].getFConst() +
2623 leftArray[col * matrixRows + matrixRow].getFConst() *
2624 rightArray[col].getFConst());
2625 }
2626 }
2627 }
2628 break;
2629
2630 case EOpVectorTimesMatrix:
2631 {
2632 // TODO(jmadll): This code should check for overflows.
2633 ASSERT(leftType.getBasicType() == EbtFloat);
2634
2635 const uint8_t matrixCols = rightType.getCols();
2636 const uint8_t matrixRows = rightType.getRows();
2637
2638 resultArray = new TConstantUnion[matrixCols];
2639
2640 for (uint8_t matrixCol = 0; matrixCol < matrixCols; matrixCol++)
2641 {
2642 resultArray[matrixCol].setFConst(0.0f);
2643 for (uint8_t matrixRow = 0; matrixRow < matrixRows; matrixRow++)
2644 {
2645 resultArray[matrixCol].setFConst(
2646 resultArray[matrixCol].getFConst() +
2647 leftArray[matrixRow].getFConst() *
2648 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
2649 }
2650 }
2651 }
2652 break;
2653
2654 case EOpLogicalAnd:
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 EOpLogicalOr:
2665 {
2666 resultArray = new TConstantUnion[objectSize];
2667 for (size_t i = 0; i < objectSize; i++)
2668 {
2669 resultArray[i] = leftArray[i] || rightArray[i];
2670 }
2671 }
2672 break;
2673
2674 case EOpLogicalXor:
2675 {
2676 ASSERT(leftType.getBasicType() == EbtBool);
2677 resultArray = new TConstantUnion[objectSize];
2678 for (size_t i = 0; i < objectSize; i++)
2679 {
2680 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
2681 }
2682 }
2683 break;
2684
2685 case EOpBitwiseAnd:
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 EOpBitwiseXor:
2691 resultArray = new TConstantUnion[objectSize];
2692 for (size_t i = 0; i < objectSize; i++)
2693 resultArray[i] = leftArray[i] ^ rightArray[i];
2694 break;
2695 case EOpBitwiseOr:
2696 resultArray = new TConstantUnion[objectSize];
2697 for (size_t i = 0; i < objectSize; i++)
2698 resultArray[i] = leftArray[i] | rightArray[i];
2699 break;
2700 case EOpBitShiftLeft:
2701 resultArray = new TConstantUnion[objectSize];
2702 for (size_t i = 0; i < objectSize; i++)
2703 resultArray[i] =
2704 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
2705 break;
2706 case EOpBitShiftRight:
2707 resultArray = new TConstantUnion[objectSize];
2708 for (size_t i = 0; i < objectSize; i++)
2709 resultArray[i] =
2710 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
2711 break;
2712
2713 case EOpLessThan:
2714 ASSERT(objectSize == 1);
2715 resultArray = new TConstantUnion[1];
2716 resultArray->setBConst(*leftArray < *rightArray);
2717 break;
2718
2719 case EOpGreaterThan:
2720 ASSERT(objectSize == 1);
2721 resultArray = new TConstantUnion[1];
2722 resultArray->setBConst(*leftArray > *rightArray);
2723 break;
2724
2725 case EOpLessThanEqual:
2726 ASSERT(objectSize == 1);
2727 resultArray = new TConstantUnion[1];
2728 resultArray->setBConst(!(*leftArray > *rightArray));
2729 break;
2730
2731 case EOpGreaterThanEqual:
2732 ASSERT(objectSize == 1);
2733 resultArray = new TConstantUnion[1];
2734 resultArray->setBConst(!(*leftArray < *rightArray));
2735 break;
2736
2737 case EOpEqual:
2738 case EOpNotEqual:
2739 {
2740 resultArray = new TConstantUnion[1];
2741 bool equal = true;
2742 for (size_t i = 0; i < objectSize; i++)
2743 {
2744 if (leftArray[i] != rightArray[i])
2745 {
2746 equal = false;
2747 break; // break out of for loop
2748 }
2749 }
2750 if (op == EOpEqual)
2751 {
2752 resultArray->setBConst(equal);
2753 }
2754 else
2755 {
2756 resultArray->setBConst(!equal);
2757 }
2758 }
2759 break;
2760
2761 default:
2762 UNREACHABLE();
2763 return nullptr;
2764 }
2765 return resultArray;
2766 }
2767
2768 // The fold functions do operations on a constant at GLSL compile time, without generating run-time
2769 // code. Returns the constant value to keep using. Nullptr should not be returned.
foldUnaryNonComponentWise(TOperator op)2770 TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
2771 {
2772 // Do operations where the return type may have a different number of components compared to the
2773 // operand type.
2774
2775 const TConstantUnion *operandArray = getConstantValue();
2776 ASSERT(operandArray);
2777
2778 size_t objectSize = getType().getObjectSize();
2779 TConstantUnion *resultArray = nullptr;
2780 switch (op)
2781 {
2782 case EOpAny:
2783 ASSERT(getType().getBasicType() == EbtBool);
2784 resultArray = new TConstantUnion();
2785 resultArray->setBConst(false);
2786 for (size_t i = 0; i < objectSize; i++)
2787 {
2788 if (operandArray[i].getBConst())
2789 {
2790 resultArray->setBConst(true);
2791 break;
2792 }
2793 }
2794 break;
2795
2796 case EOpAll:
2797 ASSERT(getType().getBasicType() == EbtBool);
2798 resultArray = new TConstantUnion();
2799 resultArray->setBConst(true);
2800 for (size_t i = 0; i < objectSize; i++)
2801 {
2802 if (!operandArray[i].getBConst())
2803 {
2804 resultArray->setBConst(false);
2805 break;
2806 }
2807 }
2808 break;
2809
2810 case EOpLength:
2811 ASSERT(getType().getBasicType() == EbtFloat);
2812 resultArray = new TConstantUnion();
2813 resultArray->setFConst(VectorLength(operandArray, objectSize));
2814 break;
2815
2816 case EOpTranspose:
2817 {
2818 ASSERT(getType().getBasicType() == EbtFloat);
2819 resultArray = new TConstantUnion[objectSize];
2820 angle::Matrix<float> result =
2821 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
2822 SetUnionArrayFromMatrix(result, resultArray);
2823 break;
2824 }
2825
2826 case EOpDeterminant:
2827 {
2828 ASSERT(getType().getBasicType() == EbtFloat);
2829 const uint8_t size = getType().getNominalSize();
2830 ASSERT(size >= 2 && size <= 4);
2831 resultArray = new TConstantUnion();
2832 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
2833 break;
2834 }
2835
2836 case EOpInverse:
2837 {
2838 ASSERT(getType().getBasicType() == EbtFloat);
2839 const uint8_t size = getType().getNominalSize();
2840 ASSERT(size >= 2 && size <= 4);
2841 resultArray = new TConstantUnion[objectSize];
2842 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
2843 SetUnionArrayFromMatrix(result, resultArray);
2844 break;
2845 }
2846
2847 case EOpPackSnorm2x16:
2848 ASSERT(getType().getBasicType() == EbtFloat);
2849 ASSERT(getType().getNominalSize() == 2);
2850 resultArray = new TConstantUnion();
2851 resultArray->setUConst(
2852 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2853 break;
2854
2855 case EOpUnpackSnorm2x16:
2856 {
2857 ASSERT(getType().getBasicType() == EbtUInt);
2858 resultArray = new TConstantUnion[2];
2859 float f1, f2;
2860 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2861 resultArray[0].setFConst(f1);
2862 resultArray[1].setFConst(f2);
2863 break;
2864 }
2865
2866 case EOpPackUnorm2x16:
2867 ASSERT(getType().getBasicType() == EbtFloat);
2868 ASSERT(getType().getNominalSize() == 2);
2869 resultArray = new TConstantUnion();
2870 resultArray->setUConst(
2871 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2872 break;
2873
2874 case EOpUnpackUnorm2x16:
2875 {
2876 ASSERT(getType().getBasicType() == EbtUInt);
2877 resultArray = new TConstantUnion[2];
2878 float f1, f2;
2879 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
2880 resultArray[0].setFConst(f1);
2881 resultArray[1].setFConst(f2);
2882 break;
2883 }
2884
2885 case EOpPackHalf2x16:
2886 ASSERT(getType().getBasicType() == EbtFloat);
2887 ASSERT(getType().getNominalSize() == 2);
2888 resultArray = new TConstantUnion();
2889 resultArray->setUConst(
2890 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
2891 break;
2892
2893 case EOpUnpackHalf2x16:
2894 {
2895 ASSERT(getType().getBasicType() == EbtUInt);
2896 resultArray = new TConstantUnion[2];
2897 float f1, f2;
2898 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
2899 resultArray[0].setFConst(f1);
2900 resultArray[1].setFConst(f2);
2901 break;
2902 }
2903
2904 case EOpPackUnorm4x8:
2905 {
2906 ASSERT(getType().getBasicType() == EbtFloat);
2907 resultArray = new TConstantUnion();
2908 resultArray->setUConst(
2909 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2910 operandArray[2].getFConst(), operandArray[3].getFConst()));
2911 break;
2912 }
2913 case EOpPackSnorm4x8:
2914 {
2915 ASSERT(getType().getBasicType() == EbtFloat);
2916 resultArray = new TConstantUnion();
2917 resultArray->setUConst(
2918 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2919 operandArray[2].getFConst(), operandArray[3].getFConst()));
2920 break;
2921 }
2922 case EOpUnpackUnorm4x8:
2923 {
2924 ASSERT(getType().getBasicType() == EbtUInt);
2925 resultArray = new TConstantUnion[4];
2926 float f[4];
2927 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2928 for (size_t i = 0; i < 4; ++i)
2929 {
2930 resultArray[i].setFConst(f[i]);
2931 }
2932 break;
2933 }
2934 case EOpUnpackSnorm4x8:
2935 {
2936 ASSERT(getType().getBasicType() == EbtUInt);
2937 resultArray = new TConstantUnion[4];
2938 float f[4];
2939 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2940 for (size_t i = 0; i < 4; ++i)
2941 {
2942 resultArray[i].setFConst(f[i]);
2943 }
2944 break;
2945 }
2946
2947 default:
2948 UNREACHABLE();
2949 break;
2950 }
2951
2952 return resultArray;
2953 }
2954
foldUnaryComponentWise(TOperator op,const TFunction * function,TDiagnostics * diagnostics)2955 TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2956 const TFunction *function,
2957 TDiagnostics *diagnostics)
2958 {
2959 // Do unary operations where each component of the result is computed based on the corresponding
2960 // component of the operand. Also folds normalize, though the divisor in that case takes all
2961 // components into account.
2962
2963 const TConstantUnion *operandArray = getConstantValue();
2964 ASSERT(operandArray);
2965
2966 size_t objectSize = getType().getObjectSize();
2967
2968 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2969 for (size_t i = 0; i < objectSize; i++)
2970 {
2971 switch (op)
2972 {
2973 case EOpNegative:
2974 switch (getType().getBasicType())
2975 {
2976 case EbtFloat:
2977 resultArray[i].setFConst(-operandArray[i].getFConst());
2978 break;
2979 case EbtInt:
2980 if (operandArray[i] == std::numeric_limits<int>::min())
2981 {
2982 // The minimum representable integer doesn't have a positive
2983 // counterpart, rather the negation overflows and in ESSL is supposed to
2984 // wrap back to the minimum representable integer. Make sure that we
2985 // don't actually let the negation overflow, which has undefined
2986 // behavior in C++.
2987 resultArray[i].setIConst(std::numeric_limits<int>::min());
2988 }
2989 else
2990 {
2991 resultArray[i].setIConst(-operandArray[i].getIConst());
2992 }
2993 break;
2994 case EbtUInt:
2995 if (operandArray[i] == 0x80000000u)
2996 {
2997 resultArray[i].setUConst(0x80000000u);
2998 }
2999 else
3000 {
3001 resultArray[i].setUConst(static_cast<unsigned int>(
3002 -static_cast<int>(operandArray[i].getUConst())));
3003 }
3004 break;
3005 default:
3006 UNREACHABLE();
3007 return nullptr;
3008 }
3009 break;
3010
3011 case EOpPositive:
3012 switch (getType().getBasicType())
3013 {
3014 case EbtFloat:
3015 resultArray[i].setFConst(operandArray[i].getFConst());
3016 break;
3017 case EbtInt:
3018 resultArray[i].setIConst(operandArray[i].getIConst());
3019 break;
3020 case EbtUInt:
3021 resultArray[i].setUConst(static_cast<unsigned int>(
3022 static_cast<int>(operandArray[i].getUConst())));
3023 break;
3024 default:
3025 UNREACHABLE();
3026 return nullptr;
3027 }
3028 break;
3029
3030 case EOpLogicalNot:
3031 switch (getType().getBasicType())
3032 {
3033 case EbtBool:
3034 resultArray[i].setBConst(!operandArray[i].getBConst());
3035 break;
3036 default:
3037 UNREACHABLE();
3038 return nullptr;
3039 }
3040 break;
3041
3042 case EOpBitwiseNot:
3043 switch (getType().getBasicType())
3044 {
3045 case EbtInt:
3046 resultArray[i].setIConst(~operandArray[i].getIConst());
3047 break;
3048 case EbtUInt:
3049 resultArray[i].setUConst(~operandArray[i].getUConst());
3050 break;
3051 default:
3052 UNREACHABLE();
3053 return nullptr;
3054 }
3055 break;
3056
3057 case EOpRadians:
3058 ASSERT(getType().getBasicType() == EbtFloat);
3059 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
3060 break;
3061
3062 case EOpDegrees:
3063 ASSERT(getType().getBasicType() == EbtFloat);
3064 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
3065 break;
3066
3067 case EOpSin:
3068 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
3069 break;
3070
3071 case EOpCos:
3072 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
3073 break;
3074
3075 case EOpTan:
3076 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
3077 break;
3078
3079 case EOpAsin:
3080 // For asin(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], &asinf, &resultArray[i]);
3087 break;
3088
3089 case EOpAcos:
3090 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
3091 // 0.
3092 if (fabsf(operandArray[i].getFConst()) > 1.0f)
3093 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3094 diagnostics, &resultArray[i]);
3095 else
3096 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
3097 break;
3098
3099 case EOpAtan:
3100 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
3101 break;
3102
3103 case EOpSinh:
3104 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
3105 break;
3106
3107 case EOpCosh:
3108 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
3109 break;
3110
3111 case EOpTanh:
3112 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
3113 break;
3114
3115 case EOpAsinh:
3116 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
3117 break;
3118
3119 case EOpAcosh:
3120 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
3121 if (operandArray[i].getFConst() < 1.0f)
3122 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3123 diagnostics, &resultArray[i]);
3124 else
3125 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
3126 break;
3127
3128 case EOpAtanh:
3129 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
3130 // 0.
3131 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
3132 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3133 diagnostics, &resultArray[i]);
3134 else
3135 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
3136 break;
3137
3138 case EOpAbs:
3139 switch (getType().getBasicType())
3140 {
3141 case EbtFloat:
3142 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
3143 break;
3144 case EbtInt:
3145 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
3146 break;
3147 default:
3148 UNREACHABLE();
3149 return nullptr;
3150 }
3151 break;
3152
3153 case EOpSign:
3154 switch (getType().getBasicType())
3155 {
3156 case EbtFloat:
3157 {
3158 float fConst = operandArray[i].getFConst();
3159 float fResult = 0.0f;
3160 if (fConst > 0.0f)
3161 fResult = 1.0f;
3162 else if (fConst < 0.0f)
3163 fResult = -1.0f;
3164 resultArray[i].setFConst(fResult);
3165 break;
3166 }
3167 case EbtInt:
3168 {
3169 int iConst = operandArray[i].getIConst();
3170 int iResult = 0;
3171 if (iConst > 0)
3172 iResult = 1;
3173 else if (iConst < 0)
3174 iResult = -1;
3175 resultArray[i].setIConst(iResult);
3176 break;
3177 }
3178 default:
3179 UNREACHABLE();
3180 return nullptr;
3181 }
3182 break;
3183
3184 case EOpFloor:
3185 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
3186 break;
3187
3188 case EOpTrunc:
3189 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
3190 break;
3191
3192 case EOpRound:
3193 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
3194 break;
3195
3196 case EOpRoundEven:
3197 {
3198 ASSERT(getType().getBasicType() == EbtFloat);
3199 float x = operandArray[i].getFConst();
3200 float result;
3201 float fractPart = modff(x, &result);
3202 if (fabsf(fractPart) == 0.5f)
3203 result = 2.0f * roundf(x / 2.0f);
3204 else
3205 result = roundf(x);
3206 resultArray[i].setFConst(result);
3207 break;
3208 }
3209
3210 case EOpCeil:
3211 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
3212 break;
3213
3214 case EOpFract:
3215 {
3216 ASSERT(getType().getBasicType() == EbtFloat);
3217 float x = operandArray[i].getFConst();
3218 resultArray[i].setFConst(x - floorf(x));
3219 break;
3220 }
3221
3222 case EOpIsnan:
3223 ASSERT(getType().getBasicType() == EbtFloat);
3224 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
3225 break;
3226
3227 case EOpIsinf:
3228 ASSERT(getType().getBasicType() == EbtFloat);
3229 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
3230 break;
3231
3232 case EOpFloatBitsToInt:
3233 ASSERT(getType().getBasicType() == EbtFloat);
3234 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
3235 break;
3236
3237 case EOpFloatBitsToUint:
3238 ASSERT(getType().getBasicType() == EbtFloat);
3239 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
3240 break;
3241
3242 case EOpIntBitsToFloat:
3243 ASSERT(getType().getBasicType() == EbtInt);
3244 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
3245 break;
3246
3247 case EOpUintBitsToFloat:
3248 ASSERT(getType().getBasicType() == EbtUInt);
3249 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
3250 break;
3251
3252 case EOpExp:
3253 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
3254 break;
3255
3256 case EOpLog:
3257 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
3258 if (operandArray[i].getFConst() <= 0.0f)
3259 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3260 diagnostics, &resultArray[i]);
3261 else
3262 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
3263 break;
3264
3265 case EOpExp2:
3266 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
3267 break;
3268
3269 case EOpLog2:
3270 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
3271 // And log2f is not available on some plarforms like old android, so just using
3272 // log(x)/log(2) here.
3273 if (operandArray[i].getFConst() <= 0.0f)
3274 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3275 diagnostics, &resultArray[i]);
3276 else
3277 {
3278 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
3279 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
3280 }
3281 break;
3282
3283 case EOpSqrt:
3284 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
3285 if (operandArray[i].getFConst() < 0.0f)
3286 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3287 diagnostics, &resultArray[i]);
3288 else
3289 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
3290 break;
3291
3292 case EOpInversesqrt:
3293 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
3294 // so getting the square root first using builtin function sqrt() and then taking
3295 // its inverse.
3296 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
3297 // result to 0.
3298 if (operandArray[i].getFConst() <= 0.0f)
3299 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3300 diagnostics, &resultArray[i]);
3301 else
3302 {
3303 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
3304 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
3305 }
3306 break;
3307
3308 case EOpNotComponentWise:
3309 ASSERT(getType().getBasicType() == EbtBool);
3310 resultArray[i].setBConst(!operandArray[i].getBConst());
3311 break;
3312
3313 case EOpNormalize:
3314 {
3315 ASSERT(getType().getBasicType() == EbtFloat);
3316 float x = operandArray[i].getFConst();
3317 float length = VectorLength(operandArray, objectSize);
3318 if (length != 0.0f)
3319 resultArray[i].setFConst(x / length);
3320 else
3321 UndefinedConstantFoldingError(getLine(), function, getType().getBasicType(),
3322 diagnostics, &resultArray[i]);
3323 break;
3324 }
3325 case EOpBitfieldReverse:
3326 {
3327 uint32_t value;
3328 if (getType().getBasicType() == EbtInt)
3329 {
3330 value = static_cast<uint32_t>(operandArray[i].getIConst());
3331 }
3332 else
3333 {
3334 ASSERT(getType().getBasicType() == EbtUInt);
3335 value = operandArray[i].getUConst();
3336 }
3337 uint32_t result = gl::BitfieldReverse(value);
3338 if (getType().getBasicType() == EbtInt)
3339 {
3340 resultArray[i].setIConst(static_cast<int32_t>(result));
3341 }
3342 else
3343 {
3344 resultArray[i].setUConst(result);
3345 }
3346 break;
3347 }
3348 case EOpBitCount:
3349 {
3350 uint32_t value;
3351 if (getType().getBasicType() == EbtInt)
3352 {
3353 value = static_cast<uint32_t>(operandArray[i].getIConst());
3354 }
3355 else
3356 {
3357 ASSERT(getType().getBasicType() == EbtUInt);
3358 value = operandArray[i].getUConst();
3359 }
3360 int result = gl::BitCount(value);
3361 resultArray[i].setIConst(result);
3362 break;
3363 }
3364 case EOpFindLSB:
3365 {
3366 uint32_t value;
3367 if (getType().getBasicType() == EbtInt)
3368 {
3369 value = static_cast<uint32_t>(operandArray[i].getIConst());
3370 }
3371 else
3372 {
3373 ASSERT(getType().getBasicType() == EbtUInt);
3374 value = operandArray[i].getUConst();
3375 }
3376 resultArray[i].setIConst(gl::FindLSB(value));
3377 break;
3378 }
3379 case EOpFindMSB:
3380 {
3381 uint32_t value;
3382 if (getType().getBasicType() == EbtInt)
3383 {
3384 int intValue = operandArray[i].getIConst();
3385 value = static_cast<uint32_t>(intValue);
3386 if (intValue < 0)
3387 {
3388 // Look for zero instead of one in value. This also handles the intValue ==
3389 // -1 special case, where the return value needs to be -1.
3390 value = ~value;
3391 }
3392 }
3393 else
3394 {
3395 ASSERT(getType().getBasicType() == EbtUInt);
3396 value = operandArray[i].getUConst();
3397 }
3398 resultArray[i].setIConst(gl::FindMSB(value));
3399 break;
3400 }
3401
3402 default:
3403 return nullptr;
3404 }
3405 }
3406
3407 return resultArray;
3408 }
3409
foldFloatTypeUnary(const TConstantUnion & parameter,FloatTypeUnaryFunc builtinFunc,TConstantUnion * result) const3410 void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter,
3411 FloatTypeUnaryFunc builtinFunc,
3412 TConstantUnion *result) const
3413 {
3414 ASSERT(builtinFunc);
3415
3416 ASSERT(getType().getBasicType() == EbtFloat);
3417 result->setFConst(builtinFunc(parameter.getFConst()));
3418 }
3419
propagatePrecision(TPrecision precision)3420 void TIntermConstantUnion::propagatePrecision(TPrecision precision)
3421 {
3422 mType.setPrecision(precision);
3423 }
3424
3425 // static
FoldAggregateBuiltIn(TIntermAggregate * aggregate,TDiagnostics * diagnostics)3426 TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
3427 TDiagnostics *diagnostics)
3428 {
3429 const TOperator op = aggregate->getOp();
3430 const TFunction *function = aggregate->getFunction();
3431 TIntermSequence *arguments = aggregate->getSequence();
3432 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
3433 std::vector<const TConstantUnion *> unionArrays(argsCount);
3434 std::vector<size_t> objectSizes(argsCount);
3435 size_t maxObjectSize = 0;
3436 TBasicType basicType = EbtVoid;
3437 TSourceLoc loc;
3438 for (unsigned int i = 0; i < argsCount; i++)
3439 {
3440 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
3441 ASSERT(argConstant != nullptr); // Should be checked already.
3442
3443 if (i == 0)
3444 {
3445 basicType = argConstant->getType().getBasicType();
3446 loc = argConstant->getLine();
3447 }
3448 unionArrays[i] = argConstant->getConstantValue();
3449 objectSizes[i] = argConstant->getType().getObjectSize();
3450 if (objectSizes[i] > maxObjectSize)
3451 maxObjectSize = objectSizes[i];
3452 }
3453
3454 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
3455 {
3456 for (unsigned int i = 0; i < argsCount; i++)
3457 if (objectSizes[i] != maxObjectSize)
3458 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
3459 }
3460
3461 TConstantUnion *resultArray = nullptr;
3462
3463 switch (op)
3464 {
3465 case EOpAtan:
3466 {
3467 ASSERT(basicType == EbtFloat);
3468 resultArray = new TConstantUnion[maxObjectSize];
3469 for (size_t i = 0; i < maxObjectSize; i++)
3470 {
3471 float y = unionArrays[0][i].getFConst();
3472 float x = unionArrays[1][i].getFConst();
3473 // Results are undefined if x and y are both 0.
3474 if (x == 0.0f && y == 0.0f)
3475 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3476 &resultArray[i]);
3477 else
3478 resultArray[i].setFConst(atan2f(y, x));
3479 }
3480 break;
3481 }
3482
3483 case EOpPow:
3484 {
3485 ASSERT(basicType == EbtFloat);
3486 resultArray = new TConstantUnion[maxObjectSize];
3487 for (size_t i = 0; i < maxObjectSize; i++)
3488 {
3489 float x = unionArrays[0][i].getFConst();
3490 float y = unionArrays[1][i].getFConst();
3491 // Results are undefined if x < 0.
3492 // Results are undefined if x = 0 and y <= 0.
3493 if (x < 0.0f)
3494 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3495 &resultArray[i]);
3496 else if (x == 0.0f && y <= 0.0f)
3497 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3498 &resultArray[i]);
3499 else
3500 resultArray[i].setFConst(powf(x, y));
3501 }
3502 break;
3503 }
3504
3505 case EOpMod:
3506 {
3507 ASSERT(basicType == EbtFloat);
3508 resultArray = new TConstantUnion[maxObjectSize];
3509 for (size_t i = 0; i < maxObjectSize; i++)
3510 {
3511 float x = unionArrays[0][i].getFConst();
3512 float y = unionArrays[1][i].getFConst();
3513 resultArray[i].setFConst(x - y * floorf(x / y));
3514 }
3515 break;
3516 }
3517
3518 case EOpMin:
3519 {
3520 resultArray = new TConstantUnion[maxObjectSize];
3521 for (size_t i = 0; i < maxObjectSize; i++)
3522 {
3523 switch (basicType)
3524 {
3525 case EbtFloat:
3526 resultArray[i].setFConst(
3527 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
3528 break;
3529 case EbtInt:
3530 resultArray[i].setIConst(
3531 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
3532 break;
3533 case EbtUInt:
3534 resultArray[i].setUConst(
3535 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
3536 break;
3537 default:
3538 UNREACHABLE();
3539 break;
3540 }
3541 }
3542 break;
3543 }
3544
3545 case EOpMax:
3546 {
3547 resultArray = new TConstantUnion[maxObjectSize];
3548 for (size_t i = 0; i < maxObjectSize; i++)
3549 {
3550 switch (basicType)
3551 {
3552 case EbtFloat:
3553 resultArray[i].setFConst(
3554 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
3555 break;
3556 case EbtInt:
3557 resultArray[i].setIConst(
3558 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
3559 break;
3560 case EbtUInt:
3561 resultArray[i].setUConst(
3562 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
3563 break;
3564 default:
3565 UNREACHABLE();
3566 break;
3567 }
3568 }
3569 break;
3570 }
3571
3572 case EOpStep:
3573 {
3574 ASSERT(basicType == EbtFloat);
3575 resultArray = new TConstantUnion[maxObjectSize];
3576 for (size_t i = 0; i < maxObjectSize; i++)
3577 resultArray[i].setFConst(
3578 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
3579 break;
3580 }
3581
3582 case EOpLessThanComponentWise:
3583 {
3584 resultArray = new TConstantUnion[maxObjectSize];
3585 for (size_t i = 0; i < maxObjectSize; i++)
3586 {
3587 switch (basicType)
3588 {
3589 case EbtFloat:
3590 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
3591 unionArrays[1][i].getFConst());
3592 break;
3593 case EbtInt:
3594 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
3595 unionArrays[1][i].getIConst());
3596 break;
3597 case EbtUInt:
3598 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
3599 unionArrays[1][i].getUConst());
3600 break;
3601 default:
3602 UNREACHABLE();
3603 break;
3604 }
3605 }
3606 break;
3607 }
3608
3609 case EOpLessThanEqualComponentWise:
3610 {
3611 resultArray = new TConstantUnion[maxObjectSize];
3612 for (size_t i = 0; i < maxObjectSize; i++)
3613 {
3614 switch (basicType)
3615 {
3616 case EbtFloat:
3617 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
3618 unionArrays[1][i].getFConst());
3619 break;
3620 case EbtInt:
3621 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
3622 unionArrays[1][i].getIConst());
3623 break;
3624 case EbtUInt:
3625 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
3626 unionArrays[1][i].getUConst());
3627 break;
3628 default:
3629 UNREACHABLE();
3630 break;
3631 }
3632 }
3633 break;
3634 }
3635
3636 case EOpGreaterThanComponentWise:
3637 {
3638 resultArray = new TConstantUnion[maxObjectSize];
3639 for (size_t i = 0; i < maxObjectSize; i++)
3640 {
3641 switch (basicType)
3642 {
3643 case EbtFloat:
3644 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
3645 unionArrays[1][i].getFConst());
3646 break;
3647 case EbtInt:
3648 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
3649 unionArrays[1][i].getIConst());
3650 break;
3651 case EbtUInt:
3652 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
3653 unionArrays[1][i].getUConst());
3654 break;
3655 default:
3656 UNREACHABLE();
3657 break;
3658 }
3659 }
3660 break;
3661 }
3662 case EOpGreaterThanEqualComponentWise:
3663 {
3664 resultArray = new TConstantUnion[maxObjectSize];
3665 for (size_t i = 0; i < maxObjectSize; i++)
3666 {
3667 switch (basicType)
3668 {
3669 case EbtFloat:
3670 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
3671 unionArrays[1][i].getFConst());
3672 break;
3673 case EbtInt:
3674 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
3675 unionArrays[1][i].getIConst());
3676 break;
3677 case EbtUInt:
3678 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
3679 unionArrays[1][i].getUConst());
3680 break;
3681 default:
3682 UNREACHABLE();
3683 break;
3684 }
3685 }
3686 }
3687 break;
3688
3689 case EOpEqualComponentWise:
3690 {
3691 resultArray = new TConstantUnion[maxObjectSize];
3692 for (size_t i = 0; i < maxObjectSize; i++)
3693 {
3694 switch (basicType)
3695 {
3696 case EbtFloat:
3697 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
3698 unionArrays[1][i].getFConst());
3699 break;
3700 case EbtInt:
3701 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
3702 unionArrays[1][i].getIConst());
3703 break;
3704 case EbtUInt:
3705 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
3706 unionArrays[1][i].getUConst());
3707 break;
3708 case EbtBool:
3709 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
3710 unionArrays[1][i].getBConst());
3711 break;
3712 default:
3713 UNREACHABLE();
3714 break;
3715 }
3716 }
3717 break;
3718 }
3719
3720 case EOpNotEqualComponentWise:
3721 {
3722 resultArray = new TConstantUnion[maxObjectSize];
3723 for (size_t i = 0; i < maxObjectSize; i++)
3724 {
3725 switch (basicType)
3726 {
3727 case EbtFloat:
3728 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
3729 unionArrays[1][i].getFConst());
3730 break;
3731 case EbtInt:
3732 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
3733 unionArrays[1][i].getIConst());
3734 break;
3735 case EbtUInt:
3736 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
3737 unionArrays[1][i].getUConst());
3738 break;
3739 case EbtBool:
3740 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
3741 unionArrays[1][i].getBConst());
3742 break;
3743 default:
3744 UNREACHABLE();
3745 break;
3746 }
3747 }
3748 break;
3749 }
3750
3751 case EOpDistance:
3752 {
3753 ASSERT(basicType == EbtFloat);
3754 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
3755 resultArray = new TConstantUnion();
3756 for (size_t i = 0; i < maxObjectSize; i++)
3757 {
3758 float x = unionArrays[0][i].getFConst();
3759 float y = unionArrays[1][i].getFConst();
3760 distanceArray[i].setFConst(x - y);
3761 }
3762 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
3763 break;
3764 }
3765
3766 case EOpDot:
3767 ASSERT(basicType == EbtFloat);
3768 resultArray = new TConstantUnion();
3769 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
3770 break;
3771
3772 case EOpCross:
3773 {
3774 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
3775 resultArray = new TConstantUnion[maxObjectSize];
3776 float x0 = unionArrays[0][0].getFConst();
3777 float x1 = unionArrays[0][1].getFConst();
3778 float x2 = unionArrays[0][2].getFConst();
3779 float y0 = unionArrays[1][0].getFConst();
3780 float y1 = unionArrays[1][1].getFConst();
3781 float y2 = unionArrays[1][2].getFConst();
3782 resultArray[0].setFConst(x1 * y2 - y1 * x2);
3783 resultArray[1].setFConst(x2 * y0 - y2 * x0);
3784 resultArray[2].setFConst(x0 * y1 - y0 * x1);
3785 break;
3786 }
3787
3788 case EOpReflect:
3789 {
3790 ASSERT(basicType == EbtFloat);
3791 // genType reflect (genType I, genType N) :
3792 // For the incident vector I and surface orientation N, returns the reflection
3793 // direction:
3794 // I - 2 * dot(N, I) * N.
3795 resultArray = new TConstantUnion[maxObjectSize];
3796 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3797 for (size_t i = 0; i < maxObjectSize; i++)
3798 {
3799 float result = unionArrays[0][i].getFConst() -
3800 2.0f * dotProduct * unionArrays[1][i].getFConst();
3801 resultArray[i].setFConst(result);
3802 }
3803 break;
3804 }
3805
3806 case EOpMatrixCompMult:
3807 {
3808 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3809 (*arguments)[1]->getAsTyped()->isMatrix());
3810 // Perform component-wise matrix multiplication.
3811 resultArray = new TConstantUnion[maxObjectSize];
3812 const uint8_t rows = (*arguments)[0]->getAsTyped()->getRows();
3813 const uint8_t cols = (*arguments)[0]->getAsTyped()->getCols();
3814 angle::Matrix<float> lhs = GetMatrix(unionArrays[0], rows, cols);
3815 angle::Matrix<float> rhs = GetMatrix(unionArrays[1], rows, cols);
3816 angle::Matrix<float> result = lhs.compMult(rhs);
3817 SetUnionArrayFromMatrix(result, resultArray);
3818 break;
3819 }
3820
3821 case EOpOuterProduct:
3822 {
3823 ASSERT(basicType == EbtFloat);
3824 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3825 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
3826 resultArray = new TConstantUnion[numRows * numCols];
3827 angle::Matrix<float> result =
3828 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3829 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3830 SetUnionArrayFromMatrix(result, resultArray);
3831 break;
3832 }
3833
3834 case EOpClamp:
3835 {
3836 resultArray = new TConstantUnion[maxObjectSize];
3837 for (size_t i = 0; i < maxObjectSize; i++)
3838 {
3839 switch (basicType)
3840 {
3841 case EbtFloat:
3842 {
3843 float x = unionArrays[0][i].getFConst();
3844 float min = unionArrays[1][i].getFConst();
3845 float max = unionArrays[2][i].getFConst();
3846 // Results are undefined if min > max.
3847 if (min > max)
3848 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3849 &resultArray[i]);
3850 else
3851 resultArray[i].setFConst(gl::clamp(x, min, max));
3852 break;
3853 }
3854
3855 case EbtInt:
3856 {
3857 int x = unionArrays[0][i].getIConst();
3858 int min = unionArrays[1][i].getIConst();
3859 int max = unionArrays[2][i].getIConst();
3860 // Results are undefined if min > max.
3861 if (min > max)
3862 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3863 &resultArray[i]);
3864 else
3865 resultArray[i].setIConst(gl::clamp(x, min, max));
3866 break;
3867 }
3868 case EbtUInt:
3869 {
3870 unsigned int x = unionArrays[0][i].getUConst();
3871 unsigned int min = unionArrays[1][i].getUConst();
3872 unsigned int max = unionArrays[2][i].getUConst();
3873 // Results are undefined if min > max.
3874 if (min > max)
3875 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3876 &resultArray[i]);
3877 else
3878 resultArray[i].setUConst(gl::clamp(x, min, max));
3879 break;
3880 }
3881 default:
3882 UNREACHABLE();
3883 break;
3884 }
3885 }
3886 break;
3887 }
3888
3889 case EOpMix:
3890 {
3891 resultArray = new TConstantUnion[maxObjectSize];
3892 for (size_t i = 0; i < maxObjectSize; i++)
3893 {
3894 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
3895 if (type == EbtFloat)
3896 {
3897 ASSERT(basicType == EbtFloat);
3898 float x = unionArrays[0][i].getFConst();
3899 float y = unionArrays[1][i].getFConst();
3900
3901 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3902 float a = unionArrays[2][i].getFConst();
3903 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3904 }
3905 else // 3rd parameter is EbtBool
3906 {
3907 ASSERT(type == EbtBool);
3908 // Selects which vector each returned component comes from.
3909 // For a component of a that is false, the corresponding component of x is
3910 // returned.
3911 // For a component of a that is true, the corresponding component of y is
3912 // returned.
3913 bool a = unionArrays[2][i].getBConst();
3914 switch (basicType)
3915 {
3916 case EbtFloat:
3917 {
3918 float x = unionArrays[0][i].getFConst();
3919 float y = unionArrays[1][i].getFConst();
3920 resultArray[i].setFConst(a ? y : x);
3921 }
3922 break;
3923 case EbtInt:
3924 {
3925 int x = unionArrays[0][i].getIConst();
3926 int y = unionArrays[1][i].getIConst();
3927 resultArray[i].setIConst(a ? y : x);
3928 }
3929 break;
3930 case EbtUInt:
3931 {
3932 unsigned int x = unionArrays[0][i].getUConst();
3933 unsigned int y = unionArrays[1][i].getUConst();
3934 resultArray[i].setUConst(a ? y : x);
3935 }
3936 break;
3937 case EbtBool:
3938 {
3939 bool x = unionArrays[0][i].getBConst();
3940 bool y = unionArrays[1][i].getBConst();
3941 resultArray[i].setBConst(a ? y : x);
3942 }
3943 break;
3944 default:
3945 UNREACHABLE();
3946 break;
3947 }
3948 }
3949 }
3950 break;
3951 }
3952
3953 case EOpSmoothstep:
3954 {
3955 ASSERT(basicType == EbtFloat);
3956 resultArray = new TConstantUnion[maxObjectSize];
3957 for (size_t i = 0; i < maxObjectSize; i++)
3958 {
3959 float edge0 = unionArrays[0][i].getFConst();
3960 float edge1 = unionArrays[1][i].getFConst();
3961 float x = unionArrays[2][i].getFConst();
3962 // Results are undefined if edge0 >= edge1.
3963 if (edge0 >= edge1)
3964 {
3965 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
3966 &resultArray[i]);
3967 }
3968 else
3969 {
3970 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3971 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3972 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3973 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3974 }
3975 }
3976 break;
3977 }
3978
3979 case EOpFma:
3980 {
3981 ASSERT(basicType == EbtFloat);
3982 resultArray = new TConstantUnion[maxObjectSize];
3983 for (size_t i = 0; i < maxObjectSize; i++)
3984 {
3985 float a = unionArrays[0][i].getFConst();
3986 float b = unionArrays[1][i].getFConst();
3987 float c = unionArrays[2][i].getFConst();
3988
3989 // Returns a * b + c.
3990 resultArray[i].setFConst(a * b + c);
3991 }
3992 break;
3993 }
3994
3995 case EOpLdexp:
3996 {
3997 resultArray = new TConstantUnion[maxObjectSize];
3998 for (size_t i = 0; i < maxObjectSize; i++)
3999 {
4000 float x = unionArrays[0][i].getFConst();
4001 int exp = unionArrays[1][i].getIConst();
4002 if (exp > 128)
4003 {
4004 UndefinedConstantFoldingError(loc, function, basicType, diagnostics,
4005 &resultArray[i]);
4006 }
4007 else
4008 {
4009 resultArray[i].setFConst(gl::Ldexp(x, exp));
4010 }
4011 }
4012 break;
4013 }
4014
4015 case EOpFaceforward:
4016 {
4017 ASSERT(basicType == EbtFloat);
4018 // genType faceforward(genType N, genType I, genType Nref) :
4019 // If dot(Nref, I) < 0 return N, otherwise return -N.
4020 resultArray = new TConstantUnion[maxObjectSize];
4021 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
4022 for (size_t i = 0; i < maxObjectSize; i++)
4023 {
4024 if (dotProduct < 0)
4025 resultArray[i].setFConst(unionArrays[0][i].getFConst());
4026 else
4027 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
4028 }
4029 break;
4030 }
4031
4032 case EOpRefract:
4033 {
4034 ASSERT(basicType == EbtFloat);
4035 // genType refract(genType I, genType N, float eta) :
4036 // For the incident vector I and surface normal N, and the ratio of indices of
4037 // refraction eta,
4038 // return the refraction vector. The result is computed by
4039 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
4040 // if (k < 0.0)
4041 // return genType(0.0)
4042 // else
4043 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
4044 resultArray = new TConstantUnion[maxObjectSize];
4045 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
4046 for (size_t i = 0; i < maxObjectSize; i++)
4047 {
4048 float eta = unionArrays[2][i].getFConst();
4049 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
4050 if (k < 0.0f)
4051 resultArray[i].setFConst(0.0f);
4052 else
4053 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
4054 (eta * dotProduct + sqrtf(k)) *
4055 unionArrays[1][i].getFConst());
4056 }
4057 break;
4058 }
4059 case EOpBitfieldExtract:
4060 {
4061 resultArray = new TConstantUnion[maxObjectSize];
4062 for (size_t i = 0; i < maxObjectSize; ++i)
4063 {
4064 int offset = unionArrays[1][0].getIConst();
4065 int bits = unionArrays[2][0].getIConst();
4066 if (bits == 0)
4067 {
4068 if (aggregate->getBasicType() == EbtInt)
4069 {
4070 resultArray[i].setIConst(0);
4071 }
4072 else
4073 {
4074 ASSERT(aggregate->getBasicType() == EbtUInt);
4075 resultArray[i].setUConst(0);
4076 }
4077 }
4078 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
4079 {
4080 UndefinedConstantFoldingError(loc, function, aggregate->getBasicType(),
4081 diagnostics, &resultArray[i]);
4082 }
4083 else
4084 {
4085 // bits can be 32 here, so we need to avoid bit shift overflow.
4086 uint32_t maskMsb = 1u << (bits - 1);
4087 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
4088 if (aggregate->getBasicType() == EbtInt)
4089 {
4090 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
4091 uint32_t resultUnsigned = (value & mask) >> offset;
4092 if ((resultUnsigned & maskMsb) != 0)
4093 {
4094 // The most significant bits (from bits+1 to the most significant bit)
4095 // should be set to 1.
4096 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
4097 resultUnsigned |= higherBitsMask;
4098 }
4099 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
4100 }
4101 else
4102 {
4103 ASSERT(aggregate->getBasicType() == EbtUInt);
4104 uint32_t value = unionArrays[0][i].getUConst();
4105 resultArray[i].setUConst((value & mask) >> offset);
4106 }
4107 }
4108 }
4109 break;
4110 }
4111 case EOpBitfieldInsert:
4112 {
4113 resultArray = new TConstantUnion[maxObjectSize];
4114 for (size_t i = 0; i < maxObjectSize; ++i)
4115 {
4116 int offset = unionArrays[2][0].getIConst();
4117 int bits = unionArrays[3][0].getIConst();
4118 if (bits == 0)
4119 {
4120 if (aggregate->getBasicType() == EbtInt)
4121 {
4122 int32_t base = unionArrays[0][i].getIConst();
4123 resultArray[i].setIConst(base);
4124 }
4125 else
4126 {
4127 ASSERT(aggregate->getBasicType() == EbtUInt);
4128 uint32_t base = unionArrays[0][i].getUConst();
4129 resultArray[i].setUConst(base);
4130 }
4131 }
4132 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
4133 {
4134 UndefinedConstantFoldingError(loc, function, aggregate->getBasicType(),
4135 diagnostics, &resultArray[i]);
4136 }
4137 else
4138 {
4139 // bits can be 32 here, so we need to avoid bit shift overflow.
4140 uint32_t maskMsb = 1u << (bits - 1);
4141 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
4142 uint32_t baseMask = ~insertMask;
4143 if (aggregate->getBasicType() == EbtInt)
4144 {
4145 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
4146 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
4147 uint32_t resultUnsigned =
4148 (base & baseMask) | ((insert << offset) & insertMask);
4149 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
4150 }
4151 else
4152 {
4153 ASSERT(aggregate->getBasicType() == EbtUInt);
4154 uint32_t base = unionArrays[0][i].getUConst();
4155 uint32_t insert = unionArrays[1][i].getUConst();
4156 resultArray[i].setUConst((base & baseMask) |
4157 ((insert << offset) & insertMask));
4158 }
4159 }
4160 }
4161 break;
4162 }
4163 case EOpDFdx:
4164 case EOpDFdy:
4165 case EOpFwidth:
4166 ASSERT(basicType == EbtFloat);
4167 resultArray = new TConstantUnion[maxObjectSize];
4168 for (size_t i = 0; i < maxObjectSize; i++)
4169 {
4170 // Derivatives of constant arguments should be 0.
4171 resultArray[i].setFConst(0.0f);
4172 }
4173 break;
4174
4175 default:
4176 UNREACHABLE();
4177 return nullptr;
4178 }
4179 return resultArray;
4180 }
4181
IsFloatDivision(TBasicType t1,TBasicType t2)4182 bool TIntermConstantUnion::IsFloatDivision(TBasicType t1, TBasicType t2)
4183 {
4184 ImplicitTypeConversion conversion = GetConversion(t1, t2);
4185 ASSERT(conversion != ImplicitTypeConversion::Invalid);
4186 if (conversion == ImplicitTypeConversion::Same)
4187 {
4188 if (t1 == EbtFloat)
4189 return true;
4190 return false;
4191 }
4192 ASSERT(t1 == EbtFloat || t2 == EbtFloat);
4193 return true;
4194 }
4195
4196 // TIntermPreprocessorDirective implementation.
TIntermPreprocessorDirective(PreprocessorDirective directive,ImmutableString command)4197 TIntermPreprocessorDirective::TIntermPreprocessorDirective(PreprocessorDirective directive,
4198 ImmutableString command)
4199 : mDirective(directive), mCommand(std::move(command))
4200 {}
4201
TIntermPreprocessorDirective(const TIntermPreprocessorDirective & node)4202 TIntermPreprocessorDirective::TIntermPreprocessorDirective(const TIntermPreprocessorDirective &node)
4203 : TIntermPreprocessorDirective(node.mDirective, node.mCommand)
4204 {}
4205
4206 TIntermPreprocessorDirective::~TIntermPreprocessorDirective() = default;
4207
getChildCount() const4208 size_t TIntermPreprocessorDirective::getChildCount() const
4209 {
4210 return 0;
4211 }
4212
getChildNode(size_t index) const4213 TIntermNode *TIntermPreprocessorDirective::getChildNode(size_t index) const
4214 {
4215 UNREACHABLE();
4216 return nullptr;
4217 }
4218 } // namespace sh
4219