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