1 //
2 // Copyright (c) 2002-2014 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 "compiler/translator/Diagnostics.h"
21 #include "compiler/translator/IntermNode.h"
22 #include "compiler/translator/SymbolTable.h"
23 #include "compiler/translator/util.h"
24
25 namespace sh
26 {
27
28 namespace
29 {
30
31 const float kPi = 3.14159265358979323846f;
32 const float kDegreesToRadiansMultiplier = kPi / 180.0f;
33 const float kRadiansToDegreesMultiplier = 180.0f / kPi;
34
GetHigherPrecision(TPrecision left,TPrecision right)35 TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
36 {
37 return left > right ? left : right;
38 }
39
Vectorize(const TConstantUnion & constant,size_t size)40 TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
41 {
42 TConstantUnion *constUnion = new TConstantUnion[size];
43 for (unsigned int i = 0; i < size; ++i)
44 constUnion[i] = constant;
45
46 return constUnion;
47 }
48
UndefinedConstantFoldingError(const TSourceLoc & loc,TOperator op,TBasicType basicType,TDiagnostics * diagnostics,TConstantUnion * result)49 void UndefinedConstantFoldingError(const TSourceLoc &loc,
50 TOperator op,
51 TBasicType basicType,
52 TDiagnostics *diagnostics,
53 TConstantUnion *result)
54 {
55 diagnostics->warning(loc, "operation result is undefined for the values passed in",
56 GetOperatorString(op));
57
58 switch (basicType)
59 {
60 case EbtFloat:
61 result->setFConst(0.0f);
62 break;
63 case EbtInt:
64 result->setIConst(0);
65 break;
66 case EbtUInt:
67 result->setUConst(0u);
68 break;
69 case EbtBool:
70 result->setBConst(false);
71 break;
72 default:
73 break;
74 }
75 }
76
VectorLength(const TConstantUnion * paramArray,size_t paramArraySize)77 float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
78 {
79 float result = 0.0f;
80 for (size_t i = 0; i < paramArraySize; i++)
81 {
82 float f = paramArray[i].getFConst();
83 result += f * f;
84 }
85 return sqrtf(result);
86 }
87
VectorDotProduct(const TConstantUnion * paramArray1,const TConstantUnion * paramArray2,size_t paramArraySize)88 float VectorDotProduct(const TConstantUnion *paramArray1,
89 const TConstantUnion *paramArray2,
90 size_t paramArraySize)
91 {
92 float result = 0.0f;
93 for (size_t i = 0; i < paramArraySize; i++)
94 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
95 return result;
96 }
97
CreateFoldedNode(const TConstantUnion * constArray,const TIntermTyped * originalNode,TQualifier qualifier)98 TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
99 const TIntermTyped *originalNode,
100 TQualifier qualifier)
101 {
102 if (constArray == nullptr)
103 {
104 return nullptr;
105 }
106 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
107 folded->getTypePointer()->setQualifier(qualifier);
108 folded->setLine(originalNode->getLine());
109 return folded;
110 }
111
GetMatrix(const TConstantUnion * paramArray,const unsigned int & rows,const unsigned int & cols)112 angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
113 const unsigned int &rows,
114 const unsigned int &cols)
115 {
116 std::vector<float> elements;
117 for (size_t i = 0; i < rows * cols; i++)
118 elements.push_back(paramArray[i].getFConst());
119 // Transpose is used since the Matrix constructor expects arguments in row-major order,
120 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
121 // so that the created matrix will have the expected dimensions after the transpose.
122 return angle::Matrix<float>(elements, cols, rows).transpose();
123 }
124
GetMatrix(const TConstantUnion * paramArray,const unsigned int & size)125 angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
126 {
127 std::vector<float> elements;
128 for (size_t i = 0; i < size * size; i++)
129 elements.push_back(paramArray[i].getFConst());
130 // Transpose is used since the Matrix constructor expects arguments in row-major order,
131 // whereas the paramArray is in column-major order.
132 return angle::Matrix<float>(elements, size).transpose();
133 }
134
SetUnionArrayFromMatrix(const angle::Matrix<float> & m,TConstantUnion * resultArray)135 void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
136 {
137 // Transpose is used since the input Matrix is in row-major order,
138 // whereas the actual result should be in column-major order.
139 angle::Matrix<float> result = m.transpose();
140 std::vector<float> resultElements = result.elements();
141 for (size_t i = 0; i < resultElements.size(); i++)
142 resultArray[i].setFConst(resultElements[i]);
143 }
144
145 } // namespace anonymous
146
147 ////////////////////////////////////////////////////////////////
148 //
149 // Member functions of the nodes used for building the tree.
150 //
151 ////////////////////////////////////////////////////////////////
152
setTypePreservePrecision(const TType & t)153 void TIntermTyped::setTypePreservePrecision(const TType &t)
154 {
155 TPrecision precision = getPrecision();
156 mType = t;
157 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
158 mType.setPrecision(precision);
159 }
160
161 #define REPLACE_IF_IS(node, type, original, replacement) \
162 if (node == original) \
163 { \
164 node = static_cast<type *>(replacement); \
165 return true; \
166 }
167
replaceChildNode(TIntermNode * original,TIntermNode * replacement)168 bool TIntermLoop::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
169 {
170 ASSERT(original != nullptr); // This risks replacing multiple children.
171 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
172 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
173 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
174 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
175 return false;
176 }
177
replaceChildNode(TIntermNode * original,TIntermNode * replacement)178 bool TIntermBranch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
179 {
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182 }
183
replaceChildNode(TIntermNode * original,TIntermNode * replacement)184 bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
185 {
186 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
187 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
188 return false;
189 }
190
replaceChildNode(TIntermNode * original,TIntermNode * replacement)191 bool TIntermBinary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
192 {
193 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
194 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
195 return false;
196 }
197
replaceChildNode(TIntermNode * original,TIntermNode * replacement)198 bool TIntermUnary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
199 {
200 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
201 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
202 return false;
203 }
204
replaceChildNode(TIntermNode * original,TIntermNode * replacement)205 bool TIntermInvariantDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
206 {
207 REPLACE_IF_IS(mSymbol, TIntermSymbol, original, replacement);
208 return false;
209 }
210
replaceChildNode(TIntermNode * original,TIntermNode * replacement)211 bool TIntermFunctionDefinition::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
212 {
213 REPLACE_IF_IS(mPrototype, TIntermFunctionPrototype, original, replacement);
214 REPLACE_IF_IS(mBody, TIntermBlock, original, replacement);
215 return false;
216 }
217
replaceChildNode(TIntermNode * original,TIntermNode * replacement)218 bool TIntermAggregate::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
219 {
220 return replaceChildNodeInternal(original, replacement);
221 }
222
replaceChildNode(TIntermNode * original,TIntermNode * replacement)223 bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
224 {
225 return replaceChildNodeInternal(original, replacement);
226 }
227
replaceChildNode(TIntermNode * original,TIntermNode * replacement)228 bool TIntermFunctionPrototype::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
229 {
230 return replaceChildNodeInternal(original, replacement);
231 }
232
replaceChildNode(TIntermNode * original,TIntermNode * replacement)233 bool TIntermDeclaration::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
234 {
235 return replaceChildNodeInternal(original, replacement);
236 }
237
replaceChildNodeInternal(TIntermNode * original,TIntermNode * replacement)238 bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
239 {
240 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
241 {
242 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
243 }
244 return false;
245 }
246
replaceChildNodeWithMultiple(TIntermNode * original,const TIntermSequence & replacements)247 bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
248 const TIntermSequence &replacements)
249 {
250 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
251 {
252 if (*it == original)
253 {
254 it = getSequence()->erase(it);
255 getSequence()->insert(it, replacements.begin(), replacements.end());
256 return true;
257 }
258 }
259 return false;
260 }
261
insertChildNodes(TIntermSequence::size_type position,const TIntermSequence & insertions)262 bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
263 const TIntermSequence &insertions)
264 {
265 if (position > getSequence()->size())
266 {
267 return false;
268 }
269 auto it = getSequence()->begin() + position;
270 getSequence()->insert(it, insertions.begin(), insertions.end());
271 return true;
272 }
273
CreateFunctionCall(const TFunction & func,TIntermSequence * arguments)274 TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TFunction &func,
275 TIntermSequence *arguments)
276 {
277 TIntermAggregate *callNode =
278 new TIntermAggregate(func.getReturnType(), EOpCallFunctionInAST, arguments);
279 callNode->getFunctionSymbolInfo()->setFromFunction(func);
280 return callNode;
281 }
282
CreateFunctionCall(const TType & type,const TSymbolUniqueId & id,const TName & name,TIntermSequence * arguments)283 TIntermAggregate *TIntermAggregate::CreateFunctionCall(const TType &type,
284 const TSymbolUniqueId &id,
285 const TName &name,
286 TIntermSequence *arguments)
287 {
288 TIntermAggregate *callNode = new TIntermAggregate(type, EOpCallFunctionInAST, arguments);
289 callNode->getFunctionSymbolInfo()->setId(id);
290 callNode->getFunctionSymbolInfo()->setNameObj(name);
291 return callNode;
292 }
293
CreateBuiltInFunctionCall(const TFunction & func,TIntermSequence * arguments)294 TIntermAggregate *TIntermAggregate::CreateBuiltInFunctionCall(const TFunction &func,
295 TIntermSequence *arguments)
296 {
297 TIntermAggregate *callNode =
298 new TIntermAggregate(func.getReturnType(), EOpCallBuiltInFunction, arguments);
299 callNode->getFunctionSymbolInfo()->setFromFunction(func);
300 // Note that name needs to be set before texture function type is determined.
301 callNode->setBuiltInFunctionPrecision();
302 return callNode;
303 }
304
CreateConstructor(const TType & type,TIntermSequence * arguments)305 TIntermAggregate *TIntermAggregate::CreateConstructor(const TType &type,
306 TIntermSequence *arguments)
307 {
308 return new TIntermAggregate(type, EOpConstruct, arguments);
309 }
310
Create(const TType & type,TOperator op,TIntermSequence * arguments)311 TIntermAggregate *TIntermAggregate::Create(const TType &type,
312 TOperator op,
313 TIntermSequence *arguments)
314 {
315 TIntermAggregate *node = new TIntermAggregate(type, op, arguments);
316 ASSERT(op != EOpCallFunctionInAST); // Should use CreateFunctionCall
317 ASSERT(op != EOpCallBuiltInFunction); // Should use CreateBuiltInFunctionCall
318 ASSERT(!node->isConstructor()); // Should use CreateConstructor
319 return node;
320 }
321
TIntermAggregate(const TType & type,TOperator op,TIntermSequence * arguments)322 TIntermAggregate::TIntermAggregate(const TType &type, TOperator op, TIntermSequence *arguments)
323 : TIntermOperator(op), mUseEmulatedFunction(false), mGotPrecisionFromChildren(false)
324 {
325 if (arguments != nullptr)
326 {
327 mArguments.swap(*arguments);
328 }
329 setTypePrecisionAndQualifier(type);
330 }
331
setTypePrecisionAndQualifier(const TType & type)332 void TIntermAggregate::setTypePrecisionAndQualifier(const TType &type)
333 {
334 setType(type);
335 mType.setQualifier(EvqTemporary);
336 if (!isFunctionCall())
337 {
338 if (isConstructor())
339 {
340 // Structs should not be precision qualified, the individual members may be.
341 // Built-in types on the other hand should be precision qualified.
342 if (getBasicType() != EbtStruct)
343 {
344 setPrecisionFromChildren();
345 }
346 }
347 else
348 {
349 setPrecisionForBuiltInOp();
350 }
351 if (areChildrenConstQualified())
352 {
353 mType.setQualifier(EvqConst);
354 }
355 }
356 }
357
areChildrenConstQualified()358 bool TIntermAggregate::areChildrenConstQualified()
359 {
360 for (TIntermNode *&arg : mArguments)
361 {
362 TIntermTyped *typedArg = arg->getAsTyped();
363 if (typedArg && typedArg->getQualifier() != EvqConst)
364 {
365 return false;
366 }
367 }
368 return true;
369 }
370
setPrecisionFromChildren()371 void TIntermAggregate::setPrecisionFromChildren()
372 {
373 mGotPrecisionFromChildren = true;
374 if (getBasicType() == EbtBool)
375 {
376 mType.setPrecision(EbpUndefined);
377 return;
378 }
379
380 TPrecision precision = EbpUndefined;
381 TIntermSequence::iterator childIter = mArguments.begin();
382 while (childIter != mArguments.end())
383 {
384 TIntermTyped *typed = (*childIter)->getAsTyped();
385 if (typed)
386 precision = GetHigherPrecision(typed->getPrecision(), precision);
387 ++childIter;
388 }
389 mType.setPrecision(precision);
390 }
391
setPrecisionForBuiltInOp()392 void TIntermAggregate::setPrecisionForBuiltInOp()
393 {
394 ASSERT(!isConstructor());
395 ASSERT(!isFunctionCall());
396 if (!setPrecisionForSpecialBuiltInOp())
397 {
398 setPrecisionFromChildren();
399 }
400 }
401
setPrecisionForSpecialBuiltInOp()402 bool TIntermAggregate::setPrecisionForSpecialBuiltInOp()
403 {
404 switch (mOp)
405 {
406 case EOpBitfieldExtract:
407 mType.setPrecision(mArguments[0]->getAsTyped()->getPrecision());
408 mGotPrecisionFromChildren = true;
409 return true;
410 case EOpBitfieldInsert:
411 mType.setPrecision(GetHigherPrecision(mArguments[0]->getAsTyped()->getPrecision(),
412 mArguments[1]->getAsTyped()->getPrecision()));
413 mGotPrecisionFromChildren = true;
414 return true;
415 case EOpUaddCarry:
416 case EOpUsubBorrow:
417 mType.setPrecision(EbpHigh);
418 return true;
419 default:
420 return false;
421 }
422 }
423
setBuiltInFunctionPrecision()424 void TIntermAggregate::setBuiltInFunctionPrecision()
425 {
426 // All built-ins returning bool should be handled as ops, not functions.
427 ASSERT(getBasicType() != EbtBool);
428 ASSERT(mOp == EOpCallBuiltInFunction);
429
430 TPrecision precision = EbpUndefined;
431 for (TIntermNode *arg : mArguments)
432 {
433 TIntermTyped *typed = arg->getAsTyped();
434 // ESSL spec section 8: texture functions get their precision from the sampler.
435 if (typed && IsSampler(typed->getBasicType()))
436 {
437 precision = typed->getPrecision();
438 break;
439 }
440 }
441 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
442 // All other functions that take a sampler are assumed to be texture functions.
443 if (mFunctionInfo.getName().find("textureSize") == 0)
444 mType.setPrecision(EbpHigh);
445 else
446 mType.setPrecision(precision);
447 }
448
getSymbolTableMangledName() const449 TString TIntermAggregate::getSymbolTableMangledName() const
450 {
451 ASSERT(!isConstructor());
452 switch (mOp)
453 {
454 case EOpCallInternalRawFunction:
455 case EOpCallBuiltInFunction:
456 case EOpCallFunctionInAST:
457 return TFunction::GetMangledNameFromCall(mFunctionInfo.getName(), mArguments);
458 default:
459 TString opString = GetOperatorString(mOp);
460 return TFunction::GetMangledNameFromCall(opString, mArguments);
461 }
462 }
463
hasSideEffects() const464 bool TIntermAggregate::hasSideEffects() const
465 {
466 if (isFunctionCall() && mFunctionInfo.isKnownToNotHaveSideEffects())
467 {
468 for (TIntermNode *arg : mArguments)
469 {
470 if (arg->getAsTyped()->hasSideEffects())
471 {
472 return true;
473 }
474 }
475 return false;
476 }
477 // Conservatively assume most aggregate operators have side-effects
478 return true;
479 }
480
appendStatement(TIntermNode * statement)481 void TIntermBlock::appendStatement(TIntermNode *statement)
482 {
483 // Declaration nodes with no children can appear if it was an empty declaration or if all the
484 // declarators just added constants to the symbol table instead of generating code. We still
485 // need to add the declaration to the AST in that case because it might be relevant to the
486 // validity of switch/case.
487 if (statement != nullptr)
488 {
489 mStatements.push_back(statement);
490 }
491 }
492
appendParameter(TIntermSymbol * parameter)493 void TIntermFunctionPrototype::appendParameter(TIntermSymbol *parameter)
494 {
495 ASSERT(parameter != nullptr);
496 mParameters.push_back(parameter);
497 }
498
appendDeclarator(TIntermTyped * declarator)499 void TIntermDeclaration::appendDeclarator(TIntermTyped *declarator)
500 {
501 ASSERT(declarator != nullptr);
502 ASSERT(declarator->getAsSymbolNode() != nullptr ||
503 (declarator->getAsBinaryNode() != nullptr &&
504 declarator->getAsBinaryNode()->getOp() == EOpInitialize));
505 ASSERT(mDeclarators.empty() ||
506 declarator->getType().sameNonArrayType(mDeclarators.back()->getAsTyped()->getType()));
507 mDeclarators.push_back(declarator);
508 }
509
replaceChildNode(TIntermNode * original,TIntermNode * replacement)510 bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
511 {
512 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
513 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
514 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
515 return false;
516 }
517
replaceChildNode(TIntermNode * original,TIntermNode * replacement)518 bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
519 {
520 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
521 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
522 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
523 return false;
524 }
525
replaceChildNode(TIntermNode * original,TIntermNode * replacement)526 bool TIntermSwitch::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
527 {
528 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
529 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
530 ASSERT(mStatementList);
531 return false;
532 }
533
replaceChildNode(TIntermNode * original,TIntermNode * replacement)534 bool TIntermCase::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
535 {
536 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
537 return false;
538 }
539
TIntermTyped(const TIntermTyped & node)540 TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
541 {
542 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
543 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
544 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
545 mLine = node.mLine;
546 }
547
isConstructorWithOnlyConstantUnionParameters()548 bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
549 {
550 TIntermAggregate *constructor = getAsAggregate();
551 if (!constructor || !constructor->isConstructor())
552 {
553 return false;
554 }
555 for (TIntermNode *&node : *constructor->getSequence())
556 {
557 if (!node->getAsConstantUnion())
558 return false;
559 }
560 return true;
561 }
562
TIntermConstantUnion(const TIntermConstantUnion & node)563 TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
564 {
565 mUnionArrayPointer = node.mUnionArrayPointer;
566 }
567
setFromFunction(const TFunction & function)568 void TFunctionSymbolInfo::setFromFunction(const TFunction &function)
569 {
570 setName(function.getName());
571 setId(TSymbolUniqueId(function));
572 }
573
TFunctionSymbolInfo(const TSymbolUniqueId & id)574 TFunctionSymbolInfo::TFunctionSymbolInfo(const TSymbolUniqueId &id)
575 : mId(new TSymbolUniqueId(id)), mKnownToNotHaveSideEffects(false)
576 {
577 }
578
TFunctionSymbolInfo(const TFunctionSymbolInfo & info)579 TFunctionSymbolInfo::TFunctionSymbolInfo(const TFunctionSymbolInfo &info)
580 : mName(info.mName), mId(nullptr), mKnownToNotHaveSideEffects(info.mKnownToNotHaveSideEffects)
581 {
582 if (info.mId)
583 {
584 mId = new TSymbolUniqueId(*info.mId);
585 }
586 }
587
operator =(const TFunctionSymbolInfo & info)588 TFunctionSymbolInfo &TFunctionSymbolInfo::operator=(const TFunctionSymbolInfo &info)
589 {
590 mName = info.mName;
591 if (info.mId)
592 {
593 mId = new TSymbolUniqueId(*info.mId);
594 }
595 else
596 {
597 mId = nullptr;
598 }
599 return *this;
600 }
601
setId(const TSymbolUniqueId & id)602 void TFunctionSymbolInfo::setId(const TSymbolUniqueId &id)
603 {
604 mId = new TSymbolUniqueId(id);
605 }
606
getId() const607 const TSymbolUniqueId &TFunctionSymbolInfo::getId() const
608 {
609 ASSERT(mId);
610 return *mId;
611 }
612
TIntermAggregate(const TIntermAggregate & node)613 TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
614 : TIntermOperator(node),
615 mUseEmulatedFunction(node.mUseEmulatedFunction),
616 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren),
617 mFunctionInfo(node.mFunctionInfo)
618 {
619 for (TIntermNode *arg : node.mArguments)
620 {
621 TIntermTyped *typedArg = arg->getAsTyped();
622 ASSERT(typedArg != nullptr);
623 TIntermTyped *argCopy = typedArg->deepCopy();
624 mArguments.push_back(argCopy);
625 }
626 }
627
shallowCopy() const628 TIntermAggregate *TIntermAggregate::shallowCopy() const
629 {
630 TIntermSequence *copySeq = new TIntermSequence();
631 copySeq->insert(copySeq->begin(), getSequence()->begin(), getSequence()->end());
632 TIntermAggregate *copyNode = new TIntermAggregate(mType, mOp, copySeq);
633 *copyNode->getFunctionSymbolInfo() = mFunctionInfo;
634 copyNode->setLine(mLine);
635 return copyNode;
636 }
637
TIntermSwizzle(const TIntermSwizzle & node)638 TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
639 {
640 TIntermTyped *operandCopy = node.mOperand->deepCopy();
641 ASSERT(operandCopy != nullptr);
642 mOperand = operandCopy;
643 mSwizzleOffsets = node.mSwizzleOffsets;
644 }
645
TIntermBinary(const TIntermBinary & node)646 TIntermBinary::TIntermBinary(const TIntermBinary &node)
647 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
648 {
649 TIntermTyped *leftCopy = node.mLeft->deepCopy();
650 TIntermTyped *rightCopy = node.mRight->deepCopy();
651 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
652 mLeft = leftCopy;
653 mRight = rightCopy;
654 }
655
TIntermUnary(const TIntermUnary & node)656 TIntermUnary::TIntermUnary(const TIntermUnary &node)
657 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
658 {
659 TIntermTyped *operandCopy = node.mOperand->deepCopy();
660 ASSERT(operandCopy != nullptr);
661 mOperand = operandCopy;
662 }
663
TIntermTernary(const TIntermTernary & node)664 TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
665 {
666 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
667 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
668 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
669 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
670 mCondition = conditionCopy;
671 mTrueExpression = trueCopy;
672 mFalseExpression = falseCopy;
673 }
674
isAssignment() const675 bool TIntermOperator::isAssignment() const
676 {
677 return IsAssignment(mOp);
678 }
679
isMultiplication() const680 bool TIntermOperator::isMultiplication() const
681 {
682 switch (mOp)
683 {
684 case EOpMul:
685 case EOpMatrixTimesMatrix:
686 case EOpMatrixTimesVector:
687 case EOpMatrixTimesScalar:
688 case EOpVectorTimesMatrix:
689 case EOpVectorTimesScalar:
690 return true;
691 default:
692 return false;
693 }
694 }
695
isConstructor() const696 bool TIntermOperator::isConstructor() const
697 {
698 return (mOp == EOpConstruct);
699 }
700
isFunctionCall() const701 bool TIntermOperator::isFunctionCall() const
702 {
703 switch (mOp)
704 {
705 case EOpCallFunctionInAST:
706 case EOpCallBuiltInFunction:
707 case EOpCallInternalRawFunction:
708 return true;
709 default:
710 return false;
711 }
712 }
713
GetMulOpBasedOnOperands(const TType & left,const TType & right)714 TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
715 {
716 if (left.isMatrix())
717 {
718 if (right.isMatrix())
719 {
720 return EOpMatrixTimesMatrix;
721 }
722 else
723 {
724 if (right.isVector())
725 {
726 return EOpMatrixTimesVector;
727 }
728 else
729 {
730 return EOpMatrixTimesScalar;
731 }
732 }
733 }
734 else
735 {
736 if (right.isMatrix())
737 {
738 if (left.isVector())
739 {
740 return EOpVectorTimesMatrix;
741 }
742 else
743 {
744 return EOpMatrixTimesScalar;
745 }
746 }
747 else
748 {
749 // Neither operand is a matrix.
750 if (left.isVector() == right.isVector())
751 {
752 // Leave as component product.
753 return EOpMul;
754 }
755 else
756 {
757 return EOpVectorTimesScalar;
758 }
759 }
760 }
761 }
762
GetMulAssignOpBasedOnOperands(const TType & left,const TType & right)763 TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
764 {
765 if (left.isMatrix())
766 {
767 if (right.isMatrix())
768 {
769 return EOpMatrixTimesMatrixAssign;
770 }
771 else
772 {
773 // right should be scalar, but this may not be validated yet.
774 return EOpMatrixTimesScalarAssign;
775 }
776 }
777 else
778 {
779 if (right.isMatrix())
780 {
781 // Left should be a vector, but this may not be validated yet.
782 return EOpVectorTimesMatrixAssign;
783 }
784 else
785 {
786 // Neither operand is a matrix.
787 if (left.isVector() == right.isVector())
788 {
789 // Leave as component product.
790 return EOpMulAssign;
791 }
792 else
793 {
794 // left should be vector and right should be scalar, but this may not be validated
795 // yet.
796 return EOpVectorTimesScalarAssign;
797 }
798 }
799 }
800 }
801
802 //
803 // Make sure the type of a unary operator is appropriate for its
804 // combination of operation and operand type.
805 //
promote()806 void TIntermUnary::promote()
807 {
808 if (mOp == EOpArrayLength)
809 {
810 // Special case: the qualifier of .length() doesn't depend on the operand qualifier.
811 setType(TType(EbtInt, EbpUndefined, EvqConst));
812 return;
813 }
814
815 TQualifier resultQualifier = EvqTemporary;
816 if (mOperand->getQualifier() == EvqConst)
817 resultQualifier = EvqConst;
818
819 unsigned char operandPrimarySize =
820 static_cast<unsigned char>(mOperand->getType().getNominalSize());
821 switch (mOp)
822 {
823 case EOpFloatBitsToInt:
824 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
825 break;
826 case EOpFloatBitsToUint:
827 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
828 break;
829 case EOpIntBitsToFloat:
830 case EOpUintBitsToFloat:
831 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
832 break;
833 case EOpPackSnorm2x16:
834 case EOpPackUnorm2x16:
835 case EOpPackHalf2x16:
836 case EOpPackUnorm4x8:
837 case EOpPackSnorm4x8:
838 setType(TType(EbtUInt, EbpHigh, resultQualifier));
839 break;
840 case EOpUnpackSnorm2x16:
841 case EOpUnpackUnorm2x16:
842 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
843 break;
844 case EOpUnpackHalf2x16:
845 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
846 break;
847 case EOpUnpackUnorm4x8:
848 case EOpUnpackSnorm4x8:
849 setType(TType(EbtFloat, EbpMedium, resultQualifier, 4));
850 break;
851 case EOpAny:
852 case EOpAll:
853 setType(TType(EbtBool, EbpUndefined, resultQualifier));
854 break;
855 case EOpLength:
856 case EOpDeterminant:
857 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
858 break;
859 case EOpTranspose:
860 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
861 static_cast<unsigned char>(mOperand->getType().getRows()),
862 static_cast<unsigned char>(mOperand->getType().getCols())));
863 break;
864 case EOpIsInf:
865 case EOpIsNan:
866 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
867 break;
868 case EOpBitfieldReverse:
869 setType(TType(mOperand->getBasicType(), EbpHigh, resultQualifier, operandPrimarySize));
870 break;
871 case EOpBitCount:
872 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
873 break;
874 case EOpFindLSB:
875 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
876 break;
877 case EOpFindMSB:
878 setType(TType(EbtInt, EbpLow, resultQualifier, operandPrimarySize));
879 break;
880 default:
881 setType(mOperand->getType());
882 mType.setQualifier(resultQualifier);
883 break;
884 }
885 }
886
TIntermSwizzle(TIntermTyped * operand,const TVector<int> & swizzleOffsets)887 TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
888 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
889 mOperand(operand),
890 mSwizzleOffsets(swizzleOffsets)
891 {
892 ASSERT(mSwizzleOffsets.size() <= 4);
893 promote();
894 }
895
TIntermUnary(TOperator op,TIntermTyped * operand)896 TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
897 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
898 {
899 promote();
900 }
901
TIntermBinary(TOperator op,TIntermTyped * left,TIntermTyped * right)902 TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
903 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
904 {
905 promote();
906 }
907
TIntermInvariantDeclaration(TIntermSymbol * symbol,const TSourceLoc & line)908 TIntermInvariantDeclaration::TIntermInvariantDeclaration(TIntermSymbol *symbol, const TSourceLoc &line)
909 : TIntermNode(), mSymbol(symbol)
910 {
911 ASSERT(symbol);
912 setLine(line);
913 }
914
TIntermTernary(TIntermTyped * cond,TIntermTyped * trueExpression,TIntermTyped * falseExpression)915 TIntermTernary::TIntermTernary(TIntermTyped *cond,
916 TIntermTyped *trueExpression,
917 TIntermTyped *falseExpression)
918 : TIntermTyped(trueExpression->getType()),
919 mCondition(cond),
920 mTrueExpression(trueExpression),
921 mFalseExpression(falseExpression)
922 {
923 getTypePointer()->setQualifier(
924 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
925 }
926
TIntermLoop(TLoopType type,TIntermNode * init,TIntermTyped * cond,TIntermTyped * expr,TIntermBlock * body)927 TIntermLoop::TIntermLoop(TLoopType type,
928 TIntermNode *init,
929 TIntermTyped *cond,
930 TIntermTyped *expr,
931 TIntermBlock *body)
932 : mType(type), mInit(init), mCond(cond), mExpr(expr), mBody(body)
933 {
934 // Declaration nodes with no children can appear if all the declarators just added constants to
935 // the symbol table instead of generating code. They're no-ops so don't add them to the tree.
936 if (mInit && mInit->getAsDeclarationNode() &&
937 mInit->getAsDeclarationNode()->getSequence()->empty())
938 {
939 mInit = nullptr;
940 }
941 }
942
TIntermIfElse(TIntermTyped * cond,TIntermBlock * trueB,TIntermBlock * falseB)943 TIntermIfElse::TIntermIfElse(TIntermTyped *cond, TIntermBlock *trueB, TIntermBlock *falseB)
944 : TIntermNode(), mCondition(cond), mTrueBlock(trueB), mFalseBlock(falseB)
945 {
946 // Prune empty false blocks so that there won't be unnecessary operations done on it.
947 if (mFalseBlock && mFalseBlock->getSequence()->empty())
948 {
949 mFalseBlock = nullptr;
950 }
951 }
952
TIntermSwitch(TIntermTyped * init,TIntermBlock * statementList)953 TIntermSwitch::TIntermSwitch(TIntermTyped *init, TIntermBlock *statementList)
954 : TIntermNode(), mInit(init), mStatementList(statementList)
955 {
956 ASSERT(mStatementList);
957 }
958
setStatementList(TIntermBlock * statementList)959 void TIntermSwitch::setStatementList(TIntermBlock *statementList)
960 {
961 ASSERT(statementList);
962 mStatementList = statementList;
963 }
964
965 // static
DetermineQualifier(TIntermTyped * cond,TIntermTyped * trueExpression,TIntermTyped * falseExpression)966 TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
967 TIntermTyped *trueExpression,
968 TIntermTyped *falseExpression)
969 {
970 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
971 falseExpression->getQualifier() == EvqConst)
972 {
973 return EvqConst;
974 }
975 return EvqTemporary;
976 }
977
fold()978 TIntermTyped *TIntermTernary::fold()
979 {
980 if (mCondition->getAsConstantUnion())
981 {
982 if (mCondition->getAsConstantUnion()->getBConst(0))
983 {
984 mTrueExpression->getTypePointer()->setQualifier(mType.getQualifier());
985 return mTrueExpression;
986 }
987 else
988 {
989 mFalseExpression->getTypePointer()->setQualifier(mType.getQualifier());
990 return mFalseExpression;
991 }
992 }
993 return this;
994 }
995
promote()996 void TIntermSwizzle::promote()
997 {
998 TQualifier resultQualifier = EvqTemporary;
999 if (mOperand->getQualifier() == EvqConst)
1000 resultQualifier = EvqConst;
1001
1002 auto numFields = mSwizzleOffsets.size();
1003 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
1004 static_cast<unsigned char>(numFields)));
1005 }
1006
hasDuplicateOffsets() const1007 bool TIntermSwizzle::hasDuplicateOffsets() const
1008 {
1009 int offsetCount[4] = {0u, 0u, 0u, 0u};
1010 for (const auto offset : mSwizzleOffsets)
1011 {
1012 offsetCount[offset]++;
1013 if (offsetCount[offset] > 1)
1014 {
1015 return true;
1016 }
1017 }
1018 return false;
1019 }
1020
offsetsMatch(int offset) const1021 bool TIntermSwizzle::offsetsMatch(int offset) const
1022 {
1023 return mSwizzleOffsets.size() == 1 && mSwizzleOffsets[0] == offset;
1024 }
1025
writeOffsetsAsXYZW(TInfoSinkBase * out) const1026 void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
1027 {
1028 for (const int offset : mSwizzleOffsets)
1029 {
1030 switch (offset)
1031 {
1032 case 0:
1033 *out << "x";
1034 break;
1035 case 1:
1036 *out << "y";
1037 break;
1038 case 2:
1039 *out << "z";
1040 break;
1041 case 3:
1042 *out << "w";
1043 break;
1044 default:
1045 UNREACHABLE();
1046 }
1047 }
1048 }
1049
GetCommaQualifier(int shaderVersion,const TIntermTyped * left,const TIntermTyped * right)1050 TQualifier TIntermBinary::GetCommaQualifier(int shaderVersion,
1051 const TIntermTyped *left,
1052 const TIntermTyped *right)
1053 {
1054 // ESSL3.00 section 12.43: The result of a sequence operator is not a constant-expression.
1055 if (shaderVersion >= 300 || left->getQualifier() != EvqConst ||
1056 right->getQualifier() != EvqConst)
1057 {
1058 return EvqTemporary;
1059 }
1060 return EvqConst;
1061 }
1062
1063 // Establishes the type of the result of the binary operation.
promote()1064 void TIntermBinary::promote()
1065 {
1066 ASSERT(!isMultiplication() ||
1067 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1068
1069 // Comma is handled as a special case. Note that the comma node qualifier depends on the shader
1070 // version and so is not being set here.
1071 if (mOp == EOpComma)
1072 {
1073 setType(mRight->getType());
1074 return;
1075 }
1076
1077 // Base assumption: just make the type the same as the left
1078 // operand. Then only deviations from this need be coded.
1079 setType(mLeft->getType());
1080
1081 TQualifier resultQualifier = EvqConst;
1082 // Binary operations results in temporary variables unless both
1083 // operands are const.
1084 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
1085 {
1086 resultQualifier = EvqTemporary;
1087 getTypePointer()->setQualifier(EvqTemporary);
1088 }
1089
1090 // Handle indexing ops.
1091 switch (mOp)
1092 {
1093 case EOpIndexDirect:
1094 case EOpIndexIndirect:
1095 if (mLeft->isArray())
1096 {
1097 mType.toArrayElementType();
1098 }
1099 else if (mLeft->isMatrix())
1100 {
1101 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
1102 static_cast<unsigned char>(mLeft->getRows())));
1103 }
1104 else if (mLeft->isVector())
1105 {
1106 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
1107 }
1108 else
1109 {
1110 UNREACHABLE();
1111 }
1112 return;
1113 case EOpIndexDirectStruct:
1114 {
1115 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1116 const int i = mRight->getAsConstantUnion()->getIConst(0);
1117 setType(*fields[i]->type());
1118 getTypePointer()->setQualifier(resultQualifier);
1119 return;
1120 }
1121 case EOpIndexDirectInterfaceBlock:
1122 {
1123 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
1124 const int i = mRight->getAsConstantUnion()->getIConst(0);
1125 setType(*fields[i]->type());
1126 getTypePointer()->setQualifier(resultQualifier);
1127 return;
1128 }
1129 default:
1130 break;
1131 }
1132
1133 ASSERT(mLeft->isArray() == mRight->isArray());
1134
1135 // The result gets promoted to the highest precision.
1136 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
1137 getTypePointer()->setPrecision(higherPrecision);
1138
1139 const int nominalSize = std::max(mLeft->getNominalSize(), mRight->getNominalSize());
1140
1141 //
1142 // All scalars or structs. Code after this test assumes this case is removed!
1143 //
1144 if (nominalSize == 1)
1145 {
1146 switch (mOp)
1147 {
1148 //
1149 // Promote to conditional
1150 //
1151 case EOpEqual:
1152 case EOpNotEqual:
1153 case EOpLessThan:
1154 case EOpGreaterThan:
1155 case EOpLessThanEqual:
1156 case EOpGreaterThanEqual:
1157 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1158 break;
1159
1160 //
1161 // And and Or operate on conditionals
1162 //
1163 case EOpLogicalAnd:
1164 case EOpLogicalXor:
1165 case EOpLogicalOr:
1166 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
1167 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1168 break;
1169
1170 default:
1171 break;
1172 }
1173 return;
1174 }
1175
1176 // If we reach here, at least one of the operands is vector or matrix.
1177 // The other operand could be a scalar, vector, or matrix.
1178 TBasicType basicType = mLeft->getBasicType();
1179
1180 switch (mOp)
1181 {
1182 case EOpMul:
1183 break;
1184 case EOpMatrixTimesScalar:
1185 if (mRight->isMatrix())
1186 {
1187 setType(TType(basicType, higherPrecision, resultQualifier,
1188 static_cast<unsigned char>(mRight->getCols()),
1189 static_cast<unsigned char>(mRight->getRows())));
1190 }
1191 break;
1192 case EOpMatrixTimesVector:
1193 setType(TType(basicType, higherPrecision, resultQualifier,
1194 static_cast<unsigned char>(mLeft->getRows()), 1));
1195 break;
1196 case EOpMatrixTimesMatrix:
1197 setType(TType(basicType, higherPrecision, resultQualifier,
1198 static_cast<unsigned char>(mRight->getCols()),
1199 static_cast<unsigned char>(mLeft->getRows())));
1200 break;
1201 case EOpVectorTimesScalar:
1202 setType(TType(basicType, higherPrecision, resultQualifier,
1203 static_cast<unsigned char>(nominalSize), 1));
1204 break;
1205 case EOpVectorTimesMatrix:
1206 setType(TType(basicType, higherPrecision, resultQualifier,
1207 static_cast<unsigned char>(mRight->getCols()), 1));
1208 break;
1209 case EOpMulAssign:
1210 case EOpVectorTimesScalarAssign:
1211 case EOpVectorTimesMatrixAssign:
1212 case EOpMatrixTimesScalarAssign:
1213 case EOpMatrixTimesMatrixAssign:
1214 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
1215 break;
1216 case EOpAssign:
1217 case EOpInitialize:
1218 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1219 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1220 break;
1221 case EOpAdd:
1222 case EOpSub:
1223 case EOpDiv:
1224 case EOpIMod:
1225 case EOpBitShiftLeft:
1226 case EOpBitShiftRight:
1227 case EOpBitwiseAnd:
1228 case EOpBitwiseXor:
1229 case EOpBitwiseOr:
1230 case EOpAddAssign:
1231 case EOpSubAssign:
1232 case EOpDivAssign:
1233 case EOpIModAssign:
1234 case EOpBitShiftLeftAssign:
1235 case EOpBitShiftRightAssign:
1236 case EOpBitwiseAndAssign:
1237 case EOpBitwiseXorAssign:
1238 case EOpBitwiseOrAssign:
1239 {
1240 const int secondarySize =
1241 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
1242 setType(TType(basicType, higherPrecision, resultQualifier,
1243 static_cast<unsigned char>(nominalSize),
1244 static_cast<unsigned char>(secondarySize)));
1245 ASSERT(!mLeft->isArray() && !mRight->isArray());
1246 break;
1247 }
1248 case EOpEqual:
1249 case EOpNotEqual:
1250 case EOpLessThan:
1251 case EOpGreaterThan:
1252 case EOpLessThanEqual:
1253 case EOpGreaterThanEqual:
1254 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1255 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
1256 setType(TType(EbtBool, EbpUndefined, resultQualifier));
1257 break;
1258
1259 case EOpIndexDirect:
1260 case EOpIndexIndirect:
1261 case EOpIndexDirectInterfaceBlock:
1262 case EOpIndexDirectStruct:
1263 // These ops should be already fully handled.
1264 UNREACHABLE();
1265 break;
1266 default:
1267 UNREACHABLE();
1268 break;
1269 }
1270 }
1271
foldIndexing(int index)1272 const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
1273 {
1274 if (isArray())
1275 {
1276 ASSERT(index < static_cast<int>(getType().getOutermostArraySize()));
1277 TType arrayElementType = getType();
1278 arrayElementType.toArrayElementType();
1279 size_t arrayElementSize = arrayElementType.getObjectSize();
1280 return &mUnionArrayPointer[arrayElementSize * index];
1281 }
1282 else if (isMatrix())
1283 {
1284 ASSERT(index < getType().getCols());
1285 int size = getType().getRows();
1286 return &mUnionArrayPointer[size * index];
1287 }
1288 else if (isVector())
1289 {
1290 ASSERT(index < getType().getNominalSize());
1291 return &mUnionArrayPointer[index];
1292 }
1293 else
1294 {
1295 UNREACHABLE();
1296 return nullptr;
1297 }
1298 }
1299
fold()1300 TIntermTyped *TIntermSwizzle::fold()
1301 {
1302 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1303 if (operandConstant == nullptr)
1304 {
1305 return this;
1306 }
1307
1308 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1309 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1310 {
1311 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1312 }
1313 return CreateFoldedNode(constArray, this, mType.getQualifier());
1314 }
1315
fold(TDiagnostics * diagnostics)1316 TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1317 {
1318 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1319 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1320 switch (mOp)
1321 {
1322 case EOpComma:
1323 {
1324 if (mLeft->hasSideEffects())
1325 {
1326 return this;
1327 }
1328 mRight->getTypePointer()->setQualifier(mType.getQualifier());
1329 return mRight;
1330 }
1331 case EOpIndexDirect:
1332 {
1333 if (leftConstant == nullptr || rightConstant == nullptr)
1334 {
1335 return this;
1336 }
1337 int index = rightConstant->getIConst(0);
1338
1339 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1340 if (!constArray)
1341 {
1342 return this;
1343 }
1344 return CreateFoldedNode(constArray, this, mType.getQualifier());
1345 }
1346 case EOpIndexDirectStruct:
1347 {
1348 if (leftConstant == nullptr || rightConstant == nullptr)
1349 {
1350 return this;
1351 }
1352 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1353 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1354
1355 size_t previousFieldsSize = 0;
1356 for (size_t i = 0; i < index; ++i)
1357 {
1358 previousFieldsSize += fields[i]->type()->getObjectSize();
1359 }
1360
1361 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1362 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1363 }
1364 case EOpIndexIndirect:
1365 case EOpIndexDirectInterfaceBlock:
1366 // Can never be constant folded.
1367 return this;
1368 default:
1369 {
1370 if (leftConstant == nullptr || rightConstant == nullptr)
1371 {
1372 return this;
1373 }
1374 TConstantUnion *constArray =
1375 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
1376 if (!constArray)
1377 {
1378 return this;
1379 }
1380
1381 // Nodes may be constant folded without being qualified as constant.
1382 return CreateFoldedNode(constArray, this, mType.getQualifier());
1383 }
1384 }
1385 }
1386
fold(TDiagnostics * diagnostics)1387 TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
1388 {
1389 TConstantUnion *constArray = nullptr;
1390
1391 if (mOp == EOpArrayLength)
1392 {
1393 // The size of runtime-sized arrays may only be determined at runtime.
1394 if (mOperand->hasSideEffects() || mOperand->getType().isUnsizedArray())
1395 {
1396 return this;
1397 }
1398 constArray = new TConstantUnion[1];
1399 constArray->setIConst(mOperand->getOutermostArraySize());
1400 }
1401 else
1402 {
1403 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1404 if (operandConstant == nullptr)
1405 {
1406 return this;
1407 }
1408
1409 switch (mOp)
1410 {
1411 case EOpAny:
1412 case EOpAll:
1413 case EOpLength:
1414 case EOpTranspose:
1415 case EOpDeterminant:
1416 case EOpInverse:
1417 case EOpPackSnorm2x16:
1418 case EOpUnpackSnorm2x16:
1419 case EOpPackUnorm2x16:
1420 case EOpUnpackUnorm2x16:
1421 case EOpPackHalf2x16:
1422 case EOpUnpackHalf2x16:
1423 case EOpPackUnorm4x8:
1424 case EOpPackSnorm4x8:
1425 case EOpUnpackUnorm4x8:
1426 case EOpUnpackSnorm4x8:
1427 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1428 break;
1429 default:
1430 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1431 break;
1432 }
1433 }
1434 if (constArray == nullptr)
1435 {
1436 return this;
1437 }
1438
1439 // Nodes may be constant folded without being qualified as constant.
1440 return CreateFoldedNode(constArray, this, mType.getQualifier());
1441 }
1442
fold(TDiagnostics * diagnostics)1443 TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
1444 {
1445 // Make sure that all params are constant before actual constant folding.
1446 for (auto *param : *getSequence())
1447 {
1448 if (param->getAsConstantUnion() == nullptr)
1449 {
1450 return this;
1451 }
1452 }
1453 TConstantUnion *constArray = nullptr;
1454 if (isConstructor())
1455 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
1456 else
1457 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
1458
1459 // Nodes may be constant folded without being qualified as constant.
1460 return CreateFoldedNode(constArray, this, getQualifier());
1461 }
1462
1463 //
1464 // The fold functions see if an operation on a constant can be done in place,
1465 // without generating run-time code.
1466 //
1467 // Returns the constant value to keep using or nullptr.
1468 //
foldBinary(TOperator op,TIntermConstantUnion * rightNode,TDiagnostics * diagnostics,const TSourceLoc & line)1469 TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1470 TIntermConstantUnion *rightNode,
1471 TDiagnostics *diagnostics,
1472 const TSourceLoc &line)
1473 {
1474 const TConstantUnion *leftArray = getUnionArrayPointer();
1475 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
1476
1477 ASSERT(leftArray && rightArray);
1478
1479 size_t objectSize = getType().getObjectSize();
1480
1481 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1482 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1483 {
1484 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1485 }
1486 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1487 {
1488 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1489 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1490 objectSize = rightNode->getType().getObjectSize();
1491 }
1492
1493 TConstantUnion *resultArray = nullptr;
1494
1495 switch (op)
1496 {
1497 case EOpAdd:
1498 resultArray = new TConstantUnion[objectSize];
1499 for (size_t i = 0; i < objectSize; i++)
1500 resultArray[i] =
1501 TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
1502 break;
1503 case EOpSub:
1504 resultArray = new TConstantUnion[objectSize];
1505 for (size_t i = 0; i < objectSize; i++)
1506 resultArray[i] =
1507 TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
1508 break;
1509
1510 case EOpMul:
1511 case EOpVectorTimesScalar:
1512 case EOpMatrixTimesScalar:
1513 resultArray = new TConstantUnion[objectSize];
1514 for (size_t i = 0; i < objectSize; i++)
1515 resultArray[i] =
1516 TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
1517 break;
1518
1519 case EOpMatrixTimesMatrix:
1520 {
1521 // TODO(jmadll): This code should check for overflows.
1522 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
1523
1524 const int leftCols = getCols();
1525 const int leftRows = getRows();
1526 const int rightCols = rightNode->getType().getCols();
1527 const int rightRows = rightNode->getType().getRows();
1528 const int resultCols = rightCols;
1529 const int resultRows = leftRows;
1530
1531 resultArray = new TConstantUnion[resultCols * resultRows];
1532 for (int row = 0; row < resultRows; row++)
1533 {
1534 for (int column = 0; column < resultCols; column++)
1535 {
1536 resultArray[resultRows * column + row].setFConst(0.0f);
1537 for (int i = 0; i < leftCols; i++)
1538 {
1539 resultArray[resultRows * column + row].setFConst(
1540 resultArray[resultRows * column + row].getFConst() +
1541 leftArray[i * leftRows + row].getFConst() *
1542 rightArray[column * rightRows + i].getFConst());
1543 }
1544 }
1545 }
1546 }
1547 break;
1548
1549 case EOpDiv:
1550 case EOpIMod:
1551 {
1552 resultArray = new TConstantUnion[objectSize];
1553 for (size_t i = 0; i < objectSize; i++)
1554 {
1555 switch (getType().getBasicType())
1556 {
1557 case EbtFloat:
1558 {
1559 ASSERT(op == EOpDiv);
1560 float dividend = leftArray[i].getFConst();
1561 float divisor = rightArray[i].getFConst();
1562 if (divisor == 0.0f)
1563 {
1564 if (dividend == 0.0f)
1565 {
1566 diagnostics->warning(
1567 getLine(),
1568 "Zero divided by zero during constant folding generated NaN",
1569 "/");
1570 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1571 }
1572 else
1573 {
1574 diagnostics->warning(getLine(),
1575 "Divide by zero during constant folding", "/");
1576 bool negativeResult =
1577 std::signbit(dividend) != std::signbit(divisor);
1578 resultArray[i].setFConst(
1579 negativeResult ? -std::numeric_limits<float>::infinity()
1580 : std::numeric_limits<float>::infinity());
1581 }
1582 }
1583 else if (gl::isInf(dividend) && gl::isInf(divisor))
1584 {
1585 diagnostics->warning(getLine(),
1586 "Infinity divided by infinity during constant "
1587 "folding generated NaN",
1588 "/");
1589 resultArray[i].setFConst(std::numeric_limits<float>::quiet_NaN());
1590 }
1591 else
1592 {
1593 float result = dividend / divisor;
1594 if (!gl::isInf(dividend) && gl::isInf(result))
1595 {
1596 diagnostics->warning(
1597 getLine(), "Constant folded division overflowed to infinity",
1598 "/");
1599 }
1600 resultArray[i].setFConst(result);
1601 }
1602 break;
1603 }
1604 case EbtInt:
1605 if (rightArray[i] == 0)
1606 {
1607 diagnostics->warning(
1608 getLine(), "Divide by zero error during constant folding", "/");
1609 resultArray[i].setIConst(INT_MAX);
1610 }
1611 else
1612 {
1613 int lhs = leftArray[i].getIConst();
1614 int divisor = rightArray[i].getIConst();
1615 if (op == EOpDiv)
1616 {
1617 // Check for the special case where the minimum representable number
1618 // is
1619 // divided by -1. If left alone this leads to integer overflow in
1620 // C++.
1621 // ESSL 3.00.6 section 4.1.3 Integers:
1622 // "However, for the case where the minimum representable value is
1623 // divided by -1, it is allowed to return either the minimum
1624 // representable value or the maximum representable value."
1625 if (lhs == -0x7fffffff - 1 && divisor == -1)
1626 {
1627 resultArray[i].setIConst(0x7fffffff);
1628 }
1629 else
1630 {
1631 resultArray[i].setIConst(lhs / divisor);
1632 }
1633 }
1634 else
1635 {
1636 ASSERT(op == EOpIMod);
1637 if (lhs < 0 || divisor < 0)
1638 {
1639 // ESSL 3.00.6 section 5.9: Results of modulus are undefined
1640 // when
1641 // either one of the operands is negative.
1642 diagnostics->warning(getLine(),
1643 "Negative modulus operator operand "
1644 "encountered during constant folding",
1645 "%");
1646 resultArray[i].setIConst(0);
1647 }
1648 else
1649 {
1650 resultArray[i].setIConst(lhs % divisor);
1651 }
1652 }
1653 }
1654 break;
1655
1656 case EbtUInt:
1657 if (rightArray[i] == 0)
1658 {
1659 diagnostics->warning(
1660 getLine(), "Divide by zero error during constant folding", "/");
1661 resultArray[i].setUConst(UINT_MAX);
1662 }
1663 else
1664 {
1665 if (op == EOpDiv)
1666 {
1667 resultArray[i].setUConst(leftArray[i].getUConst() /
1668 rightArray[i].getUConst());
1669 }
1670 else
1671 {
1672 ASSERT(op == EOpIMod);
1673 resultArray[i].setUConst(leftArray[i].getUConst() %
1674 rightArray[i].getUConst());
1675 }
1676 }
1677 break;
1678
1679 default:
1680 UNREACHABLE();
1681 return nullptr;
1682 }
1683 }
1684 }
1685 break;
1686
1687 case EOpMatrixTimesVector:
1688 {
1689 // TODO(jmadll): This code should check for overflows.
1690 ASSERT(rightNode->getBasicType() == EbtFloat);
1691
1692 const int matrixCols = getCols();
1693 const int matrixRows = getRows();
1694
1695 resultArray = new TConstantUnion[matrixRows];
1696
1697 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1698 {
1699 resultArray[matrixRow].setFConst(0.0f);
1700 for (int col = 0; col < matrixCols; col++)
1701 {
1702 resultArray[matrixRow].setFConst(
1703 resultArray[matrixRow].getFConst() +
1704 leftArray[col * matrixRows + matrixRow].getFConst() *
1705 rightArray[col].getFConst());
1706 }
1707 }
1708 }
1709 break;
1710
1711 case EOpVectorTimesMatrix:
1712 {
1713 // TODO(jmadll): This code should check for overflows.
1714 ASSERT(getType().getBasicType() == EbtFloat);
1715
1716 const int matrixCols = rightNode->getType().getCols();
1717 const int matrixRows = rightNode->getType().getRows();
1718
1719 resultArray = new TConstantUnion[matrixCols];
1720
1721 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1722 {
1723 resultArray[matrixCol].setFConst(0.0f);
1724 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1725 {
1726 resultArray[matrixCol].setFConst(
1727 resultArray[matrixCol].getFConst() +
1728 leftArray[matrixRow].getFConst() *
1729 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1730 }
1731 }
1732 }
1733 break;
1734
1735 case EOpLogicalAnd:
1736 {
1737 resultArray = new TConstantUnion[objectSize];
1738 for (size_t i = 0; i < objectSize; i++)
1739 {
1740 resultArray[i] = leftArray[i] && rightArray[i];
1741 }
1742 }
1743 break;
1744
1745 case EOpLogicalOr:
1746 {
1747 resultArray = new TConstantUnion[objectSize];
1748 for (size_t i = 0; i < objectSize; i++)
1749 {
1750 resultArray[i] = leftArray[i] || rightArray[i];
1751 }
1752 }
1753 break;
1754
1755 case EOpLogicalXor:
1756 {
1757 ASSERT(getType().getBasicType() == EbtBool);
1758 resultArray = new TConstantUnion[objectSize];
1759 for (size_t i = 0; i < objectSize; i++)
1760 {
1761 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1762 }
1763 }
1764 break;
1765
1766 case EOpBitwiseAnd:
1767 resultArray = new TConstantUnion[objectSize];
1768 for (size_t i = 0; i < objectSize; i++)
1769 resultArray[i] = leftArray[i] & rightArray[i];
1770 break;
1771 case EOpBitwiseXor:
1772 resultArray = new TConstantUnion[objectSize];
1773 for (size_t i = 0; i < objectSize; i++)
1774 resultArray[i] = leftArray[i] ^ rightArray[i];
1775 break;
1776 case EOpBitwiseOr:
1777 resultArray = new TConstantUnion[objectSize];
1778 for (size_t i = 0; i < objectSize; i++)
1779 resultArray[i] = leftArray[i] | rightArray[i];
1780 break;
1781 case EOpBitShiftLeft:
1782 resultArray = new TConstantUnion[objectSize];
1783 for (size_t i = 0; i < objectSize; i++)
1784 resultArray[i] =
1785 TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
1786 break;
1787 case EOpBitShiftRight:
1788 resultArray = new TConstantUnion[objectSize];
1789 for (size_t i = 0; i < objectSize; i++)
1790 resultArray[i] =
1791 TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
1792 break;
1793
1794 case EOpLessThan:
1795 ASSERT(objectSize == 1);
1796 resultArray = new TConstantUnion[1];
1797 resultArray->setBConst(*leftArray < *rightArray);
1798 break;
1799
1800 case EOpGreaterThan:
1801 ASSERT(objectSize == 1);
1802 resultArray = new TConstantUnion[1];
1803 resultArray->setBConst(*leftArray > *rightArray);
1804 break;
1805
1806 case EOpLessThanEqual:
1807 ASSERT(objectSize == 1);
1808 resultArray = new TConstantUnion[1];
1809 resultArray->setBConst(!(*leftArray > *rightArray));
1810 break;
1811
1812 case EOpGreaterThanEqual:
1813 ASSERT(objectSize == 1);
1814 resultArray = new TConstantUnion[1];
1815 resultArray->setBConst(!(*leftArray < *rightArray));
1816 break;
1817
1818 case EOpEqual:
1819 case EOpNotEqual:
1820 {
1821 resultArray = new TConstantUnion[1];
1822 bool equal = true;
1823 for (size_t i = 0; i < objectSize; i++)
1824 {
1825 if (leftArray[i] != rightArray[i])
1826 {
1827 equal = false;
1828 break; // break out of for loop
1829 }
1830 }
1831 if (op == EOpEqual)
1832 {
1833 resultArray->setBConst(equal);
1834 }
1835 else
1836 {
1837 resultArray->setBConst(!equal);
1838 }
1839 }
1840 break;
1841
1842 default:
1843 UNREACHABLE();
1844 return nullptr;
1845 }
1846 return resultArray;
1847 }
1848
1849 // The fold functions do operations on a constant at GLSL compile time, without generating run-time
1850 // code. Returns the constant value to keep using. Nullptr should not be returned.
foldUnaryNonComponentWise(TOperator op)1851 TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
1852 {
1853 // Do operations where the return type may have a different number of components compared to the
1854 // operand type.
1855
1856 const TConstantUnion *operandArray = getUnionArrayPointer();
1857 ASSERT(operandArray);
1858
1859 size_t objectSize = getType().getObjectSize();
1860 TConstantUnion *resultArray = nullptr;
1861 switch (op)
1862 {
1863 case EOpAny:
1864 ASSERT(getType().getBasicType() == EbtBool);
1865 resultArray = new TConstantUnion();
1866 resultArray->setBConst(false);
1867 for (size_t i = 0; i < objectSize; i++)
1868 {
1869 if (operandArray[i].getBConst())
1870 {
1871 resultArray->setBConst(true);
1872 break;
1873 }
1874 }
1875 break;
1876
1877 case EOpAll:
1878 ASSERT(getType().getBasicType() == EbtBool);
1879 resultArray = new TConstantUnion();
1880 resultArray->setBConst(true);
1881 for (size_t i = 0; i < objectSize; i++)
1882 {
1883 if (!operandArray[i].getBConst())
1884 {
1885 resultArray->setBConst(false);
1886 break;
1887 }
1888 }
1889 break;
1890
1891 case EOpLength:
1892 ASSERT(getType().getBasicType() == EbtFloat);
1893 resultArray = new TConstantUnion();
1894 resultArray->setFConst(VectorLength(operandArray, objectSize));
1895 break;
1896
1897 case EOpTranspose:
1898 {
1899 ASSERT(getType().getBasicType() == EbtFloat);
1900 resultArray = new TConstantUnion[objectSize];
1901 angle::Matrix<float> result =
1902 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
1903 SetUnionArrayFromMatrix(result, resultArray);
1904 break;
1905 }
1906
1907 case EOpDeterminant:
1908 {
1909 ASSERT(getType().getBasicType() == EbtFloat);
1910 unsigned int size = getType().getNominalSize();
1911 ASSERT(size >= 2 && size <= 4);
1912 resultArray = new TConstantUnion();
1913 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1914 break;
1915 }
1916
1917 case EOpInverse:
1918 {
1919 ASSERT(getType().getBasicType() == EbtFloat);
1920 unsigned int size = getType().getNominalSize();
1921 ASSERT(size >= 2 && size <= 4);
1922 resultArray = new TConstantUnion[objectSize];
1923 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1924 SetUnionArrayFromMatrix(result, resultArray);
1925 break;
1926 }
1927
1928 case EOpPackSnorm2x16:
1929 ASSERT(getType().getBasicType() == EbtFloat);
1930 ASSERT(getType().getNominalSize() == 2);
1931 resultArray = new TConstantUnion();
1932 resultArray->setUConst(
1933 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1934 break;
1935
1936 case EOpUnpackSnorm2x16:
1937 {
1938 ASSERT(getType().getBasicType() == EbtUInt);
1939 resultArray = new TConstantUnion[2];
1940 float f1, f2;
1941 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1942 resultArray[0].setFConst(f1);
1943 resultArray[1].setFConst(f2);
1944 break;
1945 }
1946
1947 case EOpPackUnorm2x16:
1948 ASSERT(getType().getBasicType() == EbtFloat);
1949 ASSERT(getType().getNominalSize() == 2);
1950 resultArray = new TConstantUnion();
1951 resultArray->setUConst(
1952 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1953 break;
1954
1955 case EOpUnpackUnorm2x16:
1956 {
1957 ASSERT(getType().getBasicType() == EbtUInt);
1958 resultArray = new TConstantUnion[2];
1959 float f1, f2;
1960 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1961 resultArray[0].setFConst(f1);
1962 resultArray[1].setFConst(f2);
1963 break;
1964 }
1965
1966 case EOpPackHalf2x16:
1967 ASSERT(getType().getBasicType() == EbtFloat);
1968 ASSERT(getType().getNominalSize() == 2);
1969 resultArray = new TConstantUnion();
1970 resultArray->setUConst(
1971 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1972 break;
1973
1974 case EOpUnpackHalf2x16:
1975 {
1976 ASSERT(getType().getBasicType() == EbtUInt);
1977 resultArray = new TConstantUnion[2];
1978 float f1, f2;
1979 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1980 resultArray[0].setFConst(f1);
1981 resultArray[1].setFConst(f2);
1982 break;
1983 }
1984
1985 case EOpPackUnorm4x8:
1986 {
1987 ASSERT(getType().getBasicType() == EbtFloat);
1988 resultArray = new TConstantUnion();
1989 resultArray->setUConst(
1990 gl::PackUnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
1991 operandArray[2].getFConst(), operandArray[3].getFConst()));
1992 break;
1993 }
1994 case EOpPackSnorm4x8:
1995 {
1996 ASSERT(getType().getBasicType() == EbtFloat);
1997 resultArray = new TConstantUnion();
1998 resultArray->setUConst(
1999 gl::PackSnorm4x8(operandArray[0].getFConst(), operandArray[1].getFConst(),
2000 operandArray[2].getFConst(), operandArray[3].getFConst()));
2001 break;
2002 }
2003 case EOpUnpackUnorm4x8:
2004 {
2005 ASSERT(getType().getBasicType() == EbtUInt);
2006 resultArray = new TConstantUnion[4];
2007 float f[4];
2008 gl::UnpackUnorm4x8(operandArray[0].getUConst(), f);
2009 for (size_t i = 0; i < 4; ++i)
2010 {
2011 resultArray[i].setFConst(f[i]);
2012 }
2013 break;
2014 }
2015 case EOpUnpackSnorm4x8:
2016 {
2017 ASSERT(getType().getBasicType() == EbtUInt);
2018 resultArray = new TConstantUnion[4];
2019 float f[4];
2020 gl::UnpackSnorm4x8(operandArray[0].getUConst(), f);
2021 for (size_t i = 0; i < 4; ++i)
2022 {
2023 resultArray[i].setFConst(f[i]);
2024 }
2025 break;
2026 }
2027
2028 default:
2029 UNREACHABLE();
2030 break;
2031 }
2032
2033 return resultArray;
2034 }
2035
foldUnaryComponentWise(TOperator op,TDiagnostics * diagnostics)2036 TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
2037 TDiagnostics *diagnostics)
2038 {
2039 // Do unary operations where each component of the result is computed based on the corresponding
2040 // component of the operand. Also folds normalize, though the divisor in that case takes all
2041 // components into account.
2042
2043 const TConstantUnion *operandArray = getUnionArrayPointer();
2044 ASSERT(operandArray);
2045
2046 size_t objectSize = getType().getObjectSize();
2047
2048 TConstantUnion *resultArray = new TConstantUnion[objectSize];
2049 for (size_t i = 0; i < objectSize; i++)
2050 {
2051 switch (op)
2052 {
2053 case EOpNegative:
2054 switch (getType().getBasicType())
2055 {
2056 case EbtFloat:
2057 resultArray[i].setFConst(-operandArray[i].getFConst());
2058 break;
2059 case EbtInt:
2060 if (operandArray[i] == std::numeric_limits<int>::min())
2061 {
2062 // The minimum representable integer doesn't have a positive
2063 // counterpart, rather the negation overflows and in ESSL is supposed to
2064 // wrap back to the minimum representable integer. Make sure that we
2065 // don't actually let the negation overflow, which has undefined
2066 // behavior in C++.
2067 resultArray[i].setIConst(std::numeric_limits<int>::min());
2068 }
2069 else
2070 {
2071 resultArray[i].setIConst(-operandArray[i].getIConst());
2072 }
2073 break;
2074 case EbtUInt:
2075 if (operandArray[i] == 0x80000000u)
2076 {
2077 resultArray[i].setUConst(0x80000000u);
2078 }
2079 else
2080 {
2081 resultArray[i].setUConst(static_cast<unsigned int>(
2082 -static_cast<int>(operandArray[i].getUConst())));
2083 }
2084 break;
2085 default:
2086 UNREACHABLE();
2087 return nullptr;
2088 }
2089 break;
2090
2091 case EOpPositive:
2092 switch (getType().getBasicType())
2093 {
2094 case EbtFloat:
2095 resultArray[i].setFConst(operandArray[i].getFConst());
2096 break;
2097 case EbtInt:
2098 resultArray[i].setIConst(operandArray[i].getIConst());
2099 break;
2100 case EbtUInt:
2101 resultArray[i].setUConst(static_cast<unsigned int>(
2102 static_cast<int>(operandArray[i].getUConst())));
2103 break;
2104 default:
2105 UNREACHABLE();
2106 return nullptr;
2107 }
2108 break;
2109
2110 case EOpLogicalNot:
2111 switch (getType().getBasicType())
2112 {
2113 case EbtBool:
2114 resultArray[i].setBConst(!operandArray[i].getBConst());
2115 break;
2116 default:
2117 UNREACHABLE();
2118 return nullptr;
2119 }
2120 break;
2121
2122 case EOpBitwiseNot:
2123 switch (getType().getBasicType())
2124 {
2125 case EbtInt:
2126 resultArray[i].setIConst(~operandArray[i].getIConst());
2127 break;
2128 case EbtUInt:
2129 resultArray[i].setUConst(~operandArray[i].getUConst());
2130 break;
2131 default:
2132 UNREACHABLE();
2133 return nullptr;
2134 }
2135 break;
2136
2137 case EOpRadians:
2138 ASSERT(getType().getBasicType() == EbtFloat);
2139 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
2140 break;
2141
2142 case EOpDegrees:
2143 ASSERT(getType().getBasicType() == EbtFloat);
2144 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
2145 break;
2146
2147 case EOpSin:
2148 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
2149 break;
2150
2151 case EOpCos:
2152 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
2153 break;
2154
2155 case EOpTan:
2156 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
2157 break;
2158
2159 case EOpAsin:
2160 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
2161 // 0.
2162 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2163 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2164 diagnostics, &resultArray[i]);
2165 else
2166 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
2167 break;
2168
2169 case EOpAcos:
2170 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
2171 // 0.
2172 if (fabsf(operandArray[i].getFConst()) > 1.0f)
2173 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2174 diagnostics, &resultArray[i]);
2175 else
2176 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
2177 break;
2178
2179 case EOpAtan:
2180 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
2181 break;
2182
2183 case EOpSinh:
2184 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
2185 break;
2186
2187 case EOpCosh:
2188 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
2189 break;
2190
2191 case EOpTanh:
2192 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
2193 break;
2194
2195 case EOpAsinh:
2196 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
2197 break;
2198
2199 case EOpAcosh:
2200 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
2201 if (operandArray[i].getFConst() < 1.0f)
2202 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2203 diagnostics, &resultArray[i]);
2204 else
2205 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
2206 break;
2207
2208 case EOpAtanh:
2209 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
2210 // 0.
2211 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
2212 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2213 diagnostics, &resultArray[i]);
2214 else
2215 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
2216 break;
2217
2218 case EOpAbs:
2219 switch (getType().getBasicType())
2220 {
2221 case EbtFloat:
2222 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
2223 break;
2224 case EbtInt:
2225 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
2226 break;
2227 default:
2228 UNREACHABLE();
2229 return nullptr;
2230 }
2231 break;
2232
2233 case EOpSign:
2234 switch (getType().getBasicType())
2235 {
2236 case EbtFloat:
2237 {
2238 float fConst = operandArray[i].getFConst();
2239 float fResult = 0.0f;
2240 if (fConst > 0.0f)
2241 fResult = 1.0f;
2242 else if (fConst < 0.0f)
2243 fResult = -1.0f;
2244 resultArray[i].setFConst(fResult);
2245 break;
2246 }
2247 case EbtInt:
2248 {
2249 int iConst = operandArray[i].getIConst();
2250 int iResult = 0;
2251 if (iConst > 0)
2252 iResult = 1;
2253 else if (iConst < 0)
2254 iResult = -1;
2255 resultArray[i].setIConst(iResult);
2256 break;
2257 }
2258 default:
2259 UNREACHABLE();
2260 return nullptr;
2261 }
2262 break;
2263
2264 case EOpFloor:
2265 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
2266 break;
2267
2268 case EOpTrunc:
2269 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
2270 break;
2271
2272 case EOpRound:
2273 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
2274 break;
2275
2276 case EOpRoundEven:
2277 {
2278 ASSERT(getType().getBasicType() == EbtFloat);
2279 float x = operandArray[i].getFConst();
2280 float result;
2281 float fractPart = modff(x, &result);
2282 if (fabsf(fractPart) == 0.5f)
2283 result = 2.0f * roundf(x / 2.0f);
2284 else
2285 result = roundf(x);
2286 resultArray[i].setFConst(result);
2287 break;
2288 }
2289
2290 case EOpCeil:
2291 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
2292 break;
2293
2294 case EOpFract:
2295 {
2296 ASSERT(getType().getBasicType() == EbtFloat);
2297 float x = operandArray[i].getFConst();
2298 resultArray[i].setFConst(x - floorf(x));
2299 break;
2300 }
2301
2302 case EOpIsNan:
2303 ASSERT(getType().getBasicType() == EbtFloat);
2304 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
2305 break;
2306
2307 case EOpIsInf:
2308 ASSERT(getType().getBasicType() == EbtFloat);
2309 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
2310 break;
2311
2312 case EOpFloatBitsToInt:
2313 ASSERT(getType().getBasicType() == EbtFloat);
2314 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
2315 break;
2316
2317 case EOpFloatBitsToUint:
2318 ASSERT(getType().getBasicType() == EbtFloat);
2319 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
2320 break;
2321
2322 case EOpIntBitsToFloat:
2323 ASSERT(getType().getBasicType() == EbtInt);
2324 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
2325 break;
2326
2327 case EOpUintBitsToFloat:
2328 ASSERT(getType().getBasicType() == EbtUInt);
2329 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
2330 break;
2331
2332 case EOpExp:
2333 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
2334 break;
2335
2336 case EOpLog:
2337 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
2338 if (operandArray[i].getFConst() <= 0.0f)
2339 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2340 diagnostics, &resultArray[i]);
2341 else
2342 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2343 break;
2344
2345 case EOpExp2:
2346 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
2347 break;
2348
2349 case EOpLog2:
2350 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
2351 // And log2f is not available on some plarforms like old android, so just using
2352 // log(x)/log(2) here.
2353 if (operandArray[i].getFConst() <= 0.0f)
2354 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2355 diagnostics, &resultArray[i]);
2356 else
2357 {
2358 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
2359 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
2360 }
2361 break;
2362
2363 case EOpSqrt:
2364 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
2365 if (operandArray[i].getFConst() < 0.0f)
2366 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2367 diagnostics, &resultArray[i]);
2368 else
2369 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2370 break;
2371
2372 case EOpInverseSqrt:
2373 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
2374 // so getting the square root first using builtin function sqrt() and then taking
2375 // its inverse.
2376 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
2377 // result to 0.
2378 if (operandArray[i].getFConst() <= 0.0f)
2379 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2380 diagnostics, &resultArray[i]);
2381 else
2382 {
2383 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2384 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2385 }
2386 break;
2387
2388 case EOpLogicalNotComponentWise:
2389 ASSERT(getType().getBasicType() == EbtBool);
2390 resultArray[i].setBConst(!operandArray[i].getBConst());
2391 break;
2392
2393 case EOpNormalize:
2394 {
2395 ASSERT(getType().getBasicType() == EbtFloat);
2396 float x = operandArray[i].getFConst();
2397 float length = VectorLength(operandArray, objectSize);
2398 if (length)
2399 resultArray[i].setFConst(x / length);
2400 else
2401 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2402 diagnostics, &resultArray[i]);
2403 break;
2404 }
2405 case EOpBitfieldReverse:
2406 {
2407 uint32_t value;
2408 if (getType().getBasicType() == EbtInt)
2409 {
2410 value = static_cast<uint32_t>(operandArray[i].getIConst());
2411 }
2412 else
2413 {
2414 ASSERT(getType().getBasicType() == EbtUInt);
2415 value = operandArray[i].getUConst();
2416 }
2417 uint32_t result = gl::BitfieldReverse(value);
2418 if (getType().getBasicType() == EbtInt)
2419 {
2420 resultArray[i].setIConst(static_cast<int32_t>(result));
2421 }
2422 else
2423 {
2424 resultArray[i].setUConst(result);
2425 }
2426 break;
2427 }
2428 case EOpBitCount:
2429 {
2430 uint32_t value;
2431 if (getType().getBasicType() == EbtInt)
2432 {
2433 value = static_cast<uint32_t>(operandArray[i].getIConst());
2434 }
2435 else
2436 {
2437 ASSERT(getType().getBasicType() == EbtUInt);
2438 value = operandArray[i].getUConst();
2439 }
2440 int result = gl::BitCount(value);
2441 resultArray[i].setIConst(result);
2442 break;
2443 }
2444 case EOpFindLSB:
2445 {
2446 uint32_t value;
2447 if (getType().getBasicType() == EbtInt)
2448 {
2449 value = static_cast<uint32_t>(operandArray[i].getIConst());
2450 }
2451 else
2452 {
2453 ASSERT(getType().getBasicType() == EbtUInt);
2454 value = operandArray[i].getUConst();
2455 }
2456 resultArray[i].setIConst(gl::FindLSB(value));
2457 break;
2458 }
2459 case EOpFindMSB:
2460 {
2461 uint32_t value;
2462 if (getType().getBasicType() == EbtInt)
2463 {
2464 int intValue = operandArray[i].getIConst();
2465 value = static_cast<uint32_t>(intValue);
2466 if (intValue < 0)
2467 {
2468 // Look for zero instead of one in value. This also handles the intValue ==
2469 // -1 special case, where the return value needs to be -1.
2470 value = ~value;
2471 }
2472 }
2473 else
2474 {
2475 ASSERT(getType().getBasicType() == EbtUInt);
2476 value = operandArray[i].getUConst();
2477 }
2478 resultArray[i].setIConst(gl::FindMSB(value));
2479 break;
2480 }
2481 case EOpDFdx:
2482 case EOpDFdy:
2483 case EOpFwidth:
2484 ASSERT(getType().getBasicType() == EbtFloat);
2485 // Derivatives of constant arguments should be 0.
2486 resultArray[i].setFConst(0.0f);
2487 break;
2488
2489 default:
2490 return nullptr;
2491 }
2492 }
2493
2494 return resultArray;
2495 }
2496
foldFloatTypeUnary(const TConstantUnion & parameter,FloatTypeUnaryFunc builtinFunc,TConstantUnion * result) const2497 void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion ¶meter,
2498 FloatTypeUnaryFunc builtinFunc,
2499 TConstantUnion *result) const
2500 {
2501 ASSERT(builtinFunc);
2502
2503 ASSERT(getType().getBasicType() == EbtFloat);
2504 result->setFConst(builtinFunc(parameter.getFConst()));
2505 }
2506
2507 // static
FoldAggregateConstructor(TIntermAggregate * aggregate)2508 TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
2509 {
2510 ASSERT(aggregate->getSequence()->size() > 0u);
2511 size_t resultSize = aggregate->getType().getObjectSize();
2512 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2513 TBasicType basicType = aggregate->getBasicType();
2514
2515 size_t resultIndex = 0u;
2516
2517 if (aggregate->getSequence()->size() == 1u)
2518 {
2519 TIntermNode *argument = aggregate->getSequence()->front();
2520 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2521 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2522 // Check the special case of constructing a matrix diagonal from a single scalar,
2523 // or a vector from a single scalar.
2524 if (argumentConstant->getType().getObjectSize() == 1u)
2525 {
2526 if (aggregate->isMatrix())
2527 {
2528 int resultCols = aggregate->getType().getCols();
2529 int resultRows = aggregate->getType().getRows();
2530 for (int col = 0; col < resultCols; ++col)
2531 {
2532 for (int row = 0; row < resultRows; ++row)
2533 {
2534 if (col == row)
2535 {
2536 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2537 }
2538 else
2539 {
2540 resultArray[resultIndex].setFConst(0.0f);
2541 }
2542 ++resultIndex;
2543 }
2544 }
2545 }
2546 else
2547 {
2548 while (resultIndex < resultSize)
2549 {
2550 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2551 ++resultIndex;
2552 }
2553 }
2554 ASSERT(resultIndex == resultSize);
2555 return resultArray;
2556 }
2557 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2558 {
2559 // The special case of constructing a matrix from a matrix.
2560 int argumentCols = argumentConstant->getType().getCols();
2561 int argumentRows = argumentConstant->getType().getRows();
2562 int resultCols = aggregate->getType().getCols();
2563 int resultRows = aggregate->getType().getRows();
2564 for (int col = 0; col < resultCols; ++col)
2565 {
2566 for (int row = 0; row < resultRows; ++row)
2567 {
2568 if (col < argumentCols && row < argumentRows)
2569 {
2570 resultArray[resultIndex].cast(basicType,
2571 argumentUnionArray[col * argumentRows + row]);
2572 }
2573 else if (col == row)
2574 {
2575 resultArray[resultIndex].setFConst(1.0f);
2576 }
2577 else
2578 {
2579 resultArray[resultIndex].setFConst(0.0f);
2580 }
2581 ++resultIndex;
2582 }
2583 }
2584 ASSERT(resultIndex == resultSize);
2585 return resultArray;
2586 }
2587 }
2588
2589 for (TIntermNode *&argument : *aggregate->getSequence())
2590 {
2591 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2592 size_t argumentSize = argumentConstant->getType().getObjectSize();
2593 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2594 for (size_t i = 0u; i < argumentSize; ++i)
2595 {
2596 if (resultIndex >= resultSize)
2597 break;
2598 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2599 ++resultIndex;
2600 }
2601 }
2602 ASSERT(resultIndex == resultSize);
2603 return resultArray;
2604 }
2605
CanFoldAggregateBuiltInOp(TOperator op)2606 bool TIntermAggregate::CanFoldAggregateBuiltInOp(TOperator op)
2607 {
2608 switch (op)
2609 {
2610 case EOpAtan:
2611 case EOpPow:
2612 case EOpMod:
2613 case EOpMin:
2614 case EOpMax:
2615 case EOpClamp:
2616 case EOpMix:
2617 case EOpStep:
2618 case EOpSmoothStep:
2619 case EOpLdexp:
2620 case EOpMulMatrixComponentWise:
2621 case EOpOuterProduct:
2622 case EOpEqualComponentWise:
2623 case EOpNotEqualComponentWise:
2624 case EOpLessThanComponentWise:
2625 case EOpLessThanEqualComponentWise:
2626 case EOpGreaterThanComponentWise:
2627 case EOpGreaterThanEqualComponentWise:
2628 case EOpDistance:
2629 case EOpDot:
2630 case EOpCross:
2631 case EOpFaceforward:
2632 case EOpReflect:
2633 case EOpRefract:
2634 case EOpBitfieldExtract:
2635 case EOpBitfieldInsert:
2636 return true;
2637 default:
2638 return false;
2639 }
2640 }
2641
2642 // static
FoldAggregateBuiltIn(TIntermAggregate * aggregate,TDiagnostics * diagnostics)2643 TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2644 TDiagnostics *diagnostics)
2645 {
2646 TOperator op = aggregate->getOp();
2647 TIntermSequence *arguments = aggregate->getSequence();
2648 unsigned int argsCount = static_cast<unsigned int>(arguments->size());
2649 std::vector<const TConstantUnion *> unionArrays(argsCount);
2650 std::vector<size_t> objectSizes(argsCount);
2651 size_t maxObjectSize = 0;
2652 TBasicType basicType = EbtVoid;
2653 TSourceLoc loc;
2654 for (unsigned int i = 0; i < argsCount; i++)
2655 {
2656 TIntermConstantUnion *argConstant = (*arguments)[i]->getAsConstantUnion();
2657 ASSERT(argConstant != nullptr); // Should be checked already.
2658
2659 if (i == 0)
2660 {
2661 basicType = argConstant->getType().getBasicType();
2662 loc = argConstant->getLine();
2663 }
2664 unionArrays[i] = argConstant->getUnionArrayPointer();
2665 objectSizes[i] = argConstant->getType().getObjectSize();
2666 if (objectSizes[i] > maxObjectSize)
2667 maxObjectSize = objectSizes[i];
2668 }
2669
2670 if (!(*arguments)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
2671 {
2672 for (unsigned int i = 0; i < argsCount; i++)
2673 if (objectSizes[i] != maxObjectSize)
2674 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2675 }
2676
2677 TConstantUnion *resultArray = nullptr;
2678
2679 switch (op)
2680 {
2681 case EOpAtan:
2682 {
2683 ASSERT(basicType == EbtFloat);
2684 resultArray = new TConstantUnion[maxObjectSize];
2685 for (size_t i = 0; i < maxObjectSize; i++)
2686 {
2687 float y = unionArrays[0][i].getFConst();
2688 float x = unionArrays[1][i].getFConst();
2689 // Results are undefined if x and y are both 0.
2690 if (x == 0.0f && y == 0.0f)
2691 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2692 else
2693 resultArray[i].setFConst(atan2f(y, x));
2694 }
2695 break;
2696 }
2697
2698 case EOpPow:
2699 {
2700 ASSERT(basicType == EbtFloat);
2701 resultArray = new TConstantUnion[maxObjectSize];
2702 for (size_t i = 0; i < maxObjectSize; i++)
2703 {
2704 float x = unionArrays[0][i].getFConst();
2705 float y = unionArrays[1][i].getFConst();
2706 // Results are undefined if x < 0.
2707 // Results are undefined if x = 0 and y <= 0.
2708 if (x < 0.0f)
2709 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2710 else if (x == 0.0f && y <= 0.0f)
2711 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
2712 else
2713 resultArray[i].setFConst(powf(x, y));
2714 }
2715 break;
2716 }
2717
2718 case EOpMod:
2719 {
2720 ASSERT(basicType == EbtFloat);
2721 resultArray = new TConstantUnion[maxObjectSize];
2722 for (size_t i = 0; i < maxObjectSize; i++)
2723 {
2724 float x = unionArrays[0][i].getFConst();
2725 float y = unionArrays[1][i].getFConst();
2726 resultArray[i].setFConst(x - y * floorf(x / y));
2727 }
2728 break;
2729 }
2730
2731 case EOpMin:
2732 {
2733 resultArray = new TConstantUnion[maxObjectSize];
2734 for (size_t i = 0; i < maxObjectSize; i++)
2735 {
2736 switch (basicType)
2737 {
2738 case EbtFloat:
2739 resultArray[i].setFConst(
2740 std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2741 break;
2742 case EbtInt:
2743 resultArray[i].setIConst(
2744 std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2745 break;
2746 case EbtUInt:
2747 resultArray[i].setUConst(
2748 std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2749 break;
2750 default:
2751 UNREACHABLE();
2752 break;
2753 }
2754 }
2755 break;
2756 }
2757
2758 case EOpMax:
2759 {
2760 resultArray = new TConstantUnion[maxObjectSize];
2761 for (size_t i = 0; i < maxObjectSize; i++)
2762 {
2763 switch (basicType)
2764 {
2765 case EbtFloat:
2766 resultArray[i].setFConst(
2767 std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
2768 break;
2769 case EbtInt:
2770 resultArray[i].setIConst(
2771 std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
2772 break;
2773 case EbtUInt:
2774 resultArray[i].setUConst(
2775 std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
2776 break;
2777 default:
2778 UNREACHABLE();
2779 break;
2780 }
2781 }
2782 break;
2783 }
2784
2785 case EOpStep:
2786 {
2787 ASSERT(basicType == EbtFloat);
2788 resultArray = new TConstantUnion[maxObjectSize];
2789 for (size_t i = 0; i < maxObjectSize; i++)
2790 resultArray[i].setFConst(
2791 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
2792 break;
2793 }
2794
2795 case EOpLessThanComponentWise:
2796 {
2797 resultArray = new TConstantUnion[maxObjectSize];
2798 for (size_t i = 0; i < maxObjectSize; i++)
2799 {
2800 switch (basicType)
2801 {
2802 case EbtFloat:
2803 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2804 unionArrays[1][i].getFConst());
2805 break;
2806 case EbtInt:
2807 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2808 unionArrays[1][i].getIConst());
2809 break;
2810 case EbtUInt:
2811 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2812 unionArrays[1][i].getUConst());
2813 break;
2814 default:
2815 UNREACHABLE();
2816 break;
2817 }
2818 }
2819 break;
2820 }
2821
2822 case EOpLessThanEqualComponentWise:
2823 {
2824 resultArray = new TConstantUnion[maxObjectSize];
2825 for (size_t i = 0; i < maxObjectSize; i++)
2826 {
2827 switch (basicType)
2828 {
2829 case EbtFloat:
2830 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2831 unionArrays[1][i].getFConst());
2832 break;
2833 case EbtInt:
2834 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2835 unionArrays[1][i].getIConst());
2836 break;
2837 case EbtUInt:
2838 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2839 unionArrays[1][i].getUConst());
2840 break;
2841 default:
2842 UNREACHABLE();
2843 break;
2844 }
2845 }
2846 break;
2847 }
2848
2849 case EOpGreaterThanComponentWise:
2850 {
2851 resultArray = new TConstantUnion[maxObjectSize];
2852 for (size_t i = 0; i < maxObjectSize; i++)
2853 {
2854 switch (basicType)
2855 {
2856 case EbtFloat:
2857 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2858 unionArrays[1][i].getFConst());
2859 break;
2860 case EbtInt:
2861 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2862 unionArrays[1][i].getIConst());
2863 break;
2864 case EbtUInt:
2865 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2866 unionArrays[1][i].getUConst());
2867 break;
2868 default:
2869 UNREACHABLE();
2870 break;
2871 }
2872 }
2873 break;
2874 }
2875 case EOpGreaterThanEqualComponentWise:
2876 {
2877 resultArray = new TConstantUnion[maxObjectSize];
2878 for (size_t i = 0; i < maxObjectSize; i++)
2879 {
2880 switch (basicType)
2881 {
2882 case EbtFloat:
2883 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2884 unionArrays[1][i].getFConst());
2885 break;
2886 case EbtInt:
2887 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2888 unionArrays[1][i].getIConst());
2889 break;
2890 case EbtUInt:
2891 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2892 unionArrays[1][i].getUConst());
2893 break;
2894 default:
2895 UNREACHABLE();
2896 break;
2897 }
2898 }
2899 }
2900 break;
2901
2902 case EOpEqualComponentWise:
2903 {
2904 resultArray = new TConstantUnion[maxObjectSize];
2905 for (size_t i = 0; i < maxObjectSize; i++)
2906 {
2907 switch (basicType)
2908 {
2909 case EbtFloat:
2910 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2911 unionArrays[1][i].getFConst());
2912 break;
2913 case EbtInt:
2914 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2915 unionArrays[1][i].getIConst());
2916 break;
2917 case EbtUInt:
2918 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2919 unionArrays[1][i].getUConst());
2920 break;
2921 case EbtBool:
2922 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2923 unionArrays[1][i].getBConst());
2924 break;
2925 default:
2926 UNREACHABLE();
2927 break;
2928 }
2929 }
2930 break;
2931 }
2932
2933 case EOpNotEqualComponentWise:
2934 {
2935 resultArray = new TConstantUnion[maxObjectSize];
2936 for (size_t i = 0; i < maxObjectSize; i++)
2937 {
2938 switch (basicType)
2939 {
2940 case EbtFloat:
2941 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2942 unionArrays[1][i].getFConst());
2943 break;
2944 case EbtInt:
2945 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2946 unionArrays[1][i].getIConst());
2947 break;
2948 case EbtUInt:
2949 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2950 unionArrays[1][i].getUConst());
2951 break;
2952 case EbtBool:
2953 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2954 unionArrays[1][i].getBConst());
2955 break;
2956 default:
2957 UNREACHABLE();
2958 break;
2959 }
2960 }
2961 break;
2962 }
2963
2964 case EOpDistance:
2965 {
2966 ASSERT(basicType == EbtFloat);
2967 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
2968 resultArray = new TConstantUnion();
2969 for (size_t i = 0; i < maxObjectSize; i++)
2970 {
2971 float x = unionArrays[0][i].getFConst();
2972 float y = unionArrays[1][i].getFConst();
2973 distanceArray[i].setFConst(x - y);
2974 }
2975 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
2976 break;
2977 }
2978
2979 case EOpDot:
2980 ASSERT(basicType == EbtFloat);
2981 resultArray = new TConstantUnion();
2982 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2983 break;
2984
2985 case EOpCross:
2986 {
2987 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
2988 resultArray = new TConstantUnion[maxObjectSize];
2989 float x0 = unionArrays[0][0].getFConst();
2990 float x1 = unionArrays[0][1].getFConst();
2991 float x2 = unionArrays[0][2].getFConst();
2992 float y0 = unionArrays[1][0].getFConst();
2993 float y1 = unionArrays[1][1].getFConst();
2994 float y2 = unionArrays[1][2].getFConst();
2995 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2996 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2997 resultArray[2].setFConst(x0 * y1 - y0 * x1);
2998 break;
2999 }
3000
3001 case EOpReflect:
3002 {
3003 ASSERT(basicType == EbtFloat);
3004 // genType reflect (genType I, genType N) :
3005 // For the incident vector I and surface orientation N, returns the reflection
3006 // direction:
3007 // I - 2 * dot(N, I) * N.
3008 resultArray = new TConstantUnion[maxObjectSize];
3009 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3010 for (size_t i = 0; i < maxObjectSize; i++)
3011 {
3012 float result = unionArrays[0][i].getFConst() -
3013 2.0f * dotProduct * unionArrays[1][i].getFConst();
3014 resultArray[i].setFConst(result);
3015 }
3016 break;
3017 }
3018
3019 case EOpMulMatrixComponentWise:
3020 {
3021 ASSERT(basicType == EbtFloat && (*arguments)[0]->getAsTyped()->isMatrix() &&
3022 (*arguments)[1]->getAsTyped()->isMatrix());
3023 // Perform component-wise matrix multiplication.
3024 resultArray = new TConstantUnion[maxObjectSize];
3025 int size = (*arguments)[0]->getAsTyped()->getNominalSize();
3026 angle::Matrix<float> result =
3027 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
3028 SetUnionArrayFromMatrix(result, resultArray);
3029 break;
3030 }
3031
3032 case EOpOuterProduct:
3033 {
3034 ASSERT(basicType == EbtFloat);
3035 size_t numRows = (*arguments)[0]->getAsTyped()->getType().getObjectSize();
3036 size_t numCols = (*arguments)[1]->getAsTyped()->getType().getObjectSize();
3037 resultArray = new TConstantUnion[numRows * numCols];
3038 angle::Matrix<float> result =
3039 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
3040 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
3041 SetUnionArrayFromMatrix(result, resultArray);
3042 break;
3043 }
3044
3045 case EOpClamp:
3046 {
3047 resultArray = new TConstantUnion[maxObjectSize];
3048 for (size_t i = 0; i < maxObjectSize; i++)
3049 {
3050 switch (basicType)
3051 {
3052 case EbtFloat:
3053 {
3054 float x = unionArrays[0][i].getFConst();
3055 float min = unionArrays[1][i].getFConst();
3056 float max = unionArrays[2][i].getFConst();
3057 // Results are undefined if min > max.
3058 if (min > max)
3059 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3060 &resultArray[i]);
3061 else
3062 resultArray[i].setFConst(gl::clamp(x, min, max));
3063 break;
3064 }
3065
3066 case EbtInt:
3067 {
3068 int x = unionArrays[0][i].getIConst();
3069 int min = unionArrays[1][i].getIConst();
3070 int max = unionArrays[2][i].getIConst();
3071 // Results are undefined if min > max.
3072 if (min > max)
3073 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3074 &resultArray[i]);
3075 else
3076 resultArray[i].setIConst(gl::clamp(x, min, max));
3077 break;
3078 }
3079 case EbtUInt:
3080 {
3081 unsigned int x = unionArrays[0][i].getUConst();
3082 unsigned int min = unionArrays[1][i].getUConst();
3083 unsigned int max = unionArrays[2][i].getUConst();
3084 // Results are undefined if min > max.
3085 if (min > max)
3086 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
3087 &resultArray[i]);
3088 else
3089 resultArray[i].setUConst(gl::clamp(x, min, max));
3090 break;
3091 }
3092 default:
3093 UNREACHABLE();
3094 break;
3095 }
3096 }
3097 break;
3098 }
3099
3100 case EOpMix:
3101 {
3102 ASSERT(basicType == EbtFloat);
3103 resultArray = new TConstantUnion[maxObjectSize];
3104 for (size_t i = 0; i < maxObjectSize; i++)
3105 {
3106 float x = unionArrays[0][i].getFConst();
3107 float y = unionArrays[1][i].getFConst();
3108 TBasicType type = (*arguments)[2]->getAsTyped()->getType().getBasicType();
3109 if (type == EbtFloat)
3110 {
3111 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
3112 float a = unionArrays[2][i].getFConst();
3113 resultArray[i].setFConst(x * (1.0f - a) + y * a);
3114 }
3115 else // 3rd parameter is EbtBool
3116 {
3117 ASSERT(type == EbtBool);
3118 // Selects which vector each returned component comes from.
3119 // For a component of a that is false, the corresponding component of x is
3120 // returned.
3121 // For a component of a that is true, the corresponding component of y is
3122 // returned.
3123 bool a = unionArrays[2][i].getBConst();
3124 resultArray[i].setFConst(a ? y : x);
3125 }
3126 }
3127 break;
3128 }
3129
3130 case EOpSmoothStep:
3131 {
3132 ASSERT(basicType == EbtFloat);
3133 resultArray = new TConstantUnion[maxObjectSize];
3134 for (size_t i = 0; i < maxObjectSize; i++)
3135 {
3136 float edge0 = unionArrays[0][i].getFConst();
3137 float edge1 = unionArrays[1][i].getFConst();
3138 float x = unionArrays[2][i].getFConst();
3139 // Results are undefined if edge0 >= edge1.
3140 if (edge0 >= edge1)
3141 {
3142 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3143 }
3144 else
3145 {
3146 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
3147 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
3148 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
3149 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
3150 }
3151 }
3152 break;
3153 }
3154
3155 case EOpLdexp:
3156 {
3157 resultArray = new TConstantUnion[maxObjectSize];
3158 for (size_t i = 0; i < maxObjectSize; i++)
3159 {
3160 float x = unionArrays[0][i].getFConst();
3161 int exp = unionArrays[1][i].getIConst();
3162 if (exp > 128)
3163 {
3164 UndefinedConstantFoldingError(loc, op, basicType, diagnostics, &resultArray[i]);
3165 }
3166 else
3167 {
3168 resultArray[i].setFConst(gl::Ldexp(x, exp));
3169 }
3170 }
3171 break;
3172 }
3173
3174 case EOpFaceforward:
3175 {
3176 ASSERT(basicType == EbtFloat);
3177 // genType faceforward(genType N, genType I, genType Nref) :
3178 // If dot(Nref, I) < 0 return N, otherwise return -N.
3179 resultArray = new TConstantUnion[maxObjectSize];
3180 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
3181 for (size_t i = 0; i < maxObjectSize; i++)
3182 {
3183 if (dotProduct < 0)
3184 resultArray[i].setFConst(unionArrays[0][i].getFConst());
3185 else
3186 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
3187 }
3188 break;
3189 }
3190
3191 case EOpRefract:
3192 {
3193 ASSERT(basicType == EbtFloat);
3194 // genType refract(genType I, genType N, float eta) :
3195 // For the incident vector I and surface normal N, and the ratio of indices of
3196 // refraction eta,
3197 // return the refraction vector. The result is computed by
3198 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
3199 // if (k < 0.0)
3200 // return genType(0.0)
3201 // else
3202 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
3203 resultArray = new TConstantUnion[maxObjectSize];
3204 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
3205 for (size_t i = 0; i < maxObjectSize; i++)
3206 {
3207 float eta = unionArrays[2][i].getFConst();
3208 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
3209 if (k < 0.0f)
3210 resultArray[i].setFConst(0.0f);
3211 else
3212 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
3213 (eta * dotProduct + sqrtf(k)) *
3214 unionArrays[1][i].getFConst());
3215 }
3216 break;
3217 }
3218 case EOpBitfieldExtract:
3219 {
3220 resultArray = new TConstantUnion[maxObjectSize];
3221 for (size_t i = 0; i < maxObjectSize; ++i)
3222 {
3223 int offset = unionArrays[1][0].getIConst();
3224 int bits = unionArrays[2][0].getIConst();
3225 if (bits == 0)
3226 {
3227 if (aggregate->getBasicType() == EbtInt)
3228 {
3229 resultArray[i].setIConst(0);
3230 }
3231 else
3232 {
3233 ASSERT(aggregate->getBasicType() == EbtUInt);
3234 resultArray[i].setUConst(0);
3235 }
3236 }
3237 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3238 {
3239 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3240 &resultArray[i]);
3241 }
3242 else
3243 {
3244 // bits can be 32 here, so we need to avoid bit shift overflow.
3245 uint32_t maskMsb = 1u << (bits - 1);
3246 uint32_t mask = ((maskMsb - 1u) | maskMsb) << offset;
3247 if (aggregate->getBasicType() == EbtInt)
3248 {
3249 uint32_t value = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3250 uint32_t resultUnsigned = (value & mask) >> offset;
3251 if ((resultUnsigned & maskMsb) != 0)
3252 {
3253 // The most significant bits (from bits+1 to the most significant bit)
3254 // should be set to 1.
3255 uint32_t higherBitsMask = ((1u << (32 - bits)) - 1u) << bits;
3256 resultUnsigned |= higherBitsMask;
3257 }
3258 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3259 }
3260 else
3261 {
3262 ASSERT(aggregate->getBasicType() == EbtUInt);
3263 uint32_t value = unionArrays[0][i].getUConst();
3264 resultArray[i].setUConst((value & mask) >> offset);
3265 }
3266 }
3267 }
3268 break;
3269 }
3270 case EOpBitfieldInsert:
3271 {
3272 resultArray = new TConstantUnion[maxObjectSize];
3273 for (size_t i = 0; i < maxObjectSize; ++i)
3274 {
3275 int offset = unionArrays[2][0].getIConst();
3276 int bits = unionArrays[3][0].getIConst();
3277 if (bits == 0)
3278 {
3279 if (aggregate->getBasicType() == EbtInt)
3280 {
3281 int32_t base = unionArrays[0][i].getIConst();
3282 resultArray[i].setIConst(base);
3283 }
3284 else
3285 {
3286 ASSERT(aggregate->getBasicType() == EbtUInt);
3287 uint32_t base = unionArrays[0][i].getUConst();
3288 resultArray[i].setUConst(base);
3289 }
3290 }
3291 else if (offset < 0 || bits < 0 || offset >= 32 || bits > 32 || offset + bits > 32)
3292 {
3293 UndefinedConstantFoldingError(loc, op, aggregate->getBasicType(), diagnostics,
3294 &resultArray[i]);
3295 }
3296 else
3297 {
3298 // bits can be 32 here, so we need to avoid bit shift overflow.
3299 uint32_t maskMsb = 1u << (bits - 1);
3300 uint32_t insertMask = ((maskMsb - 1u) | maskMsb) << offset;
3301 uint32_t baseMask = ~insertMask;
3302 if (aggregate->getBasicType() == EbtInt)
3303 {
3304 uint32_t base = static_cast<uint32_t>(unionArrays[0][i].getIConst());
3305 uint32_t insert = static_cast<uint32_t>(unionArrays[1][i].getIConst());
3306 uint32_t resultUnsigned =
3307 (base & baseMask) | ((insert << offset) & insertMask);
3308 resultArray[i].setIConst(static_cast<int32_t>(resultUnsigned));
3309 }
3310 else
3311 {
3312 ASSERT(aggregate->getBasicType() == EbtUInt);
3313 uint32_t base = unionArrays[0][i].getUConst();
3314 uint32_t insert = unionArrays[1][i].getUConst();
3315 resultArray[i].setUConst((base & baseMask) |
3316 ((insert << offset) & insertMask));
3317 }
3318 }
3319 }
3320 break;
3321 }
3322
3323 default:
3324 UNREACHABLE();
3325 return nullptr;
3326 }
3327 return resultArray;
3328 }
3329
3330 } // namespace sh
3331