blob: cdc53c24dc25375cd52cd60bcabd2f587ed6a2ff [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
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>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040020#include "compiler/translator/HashNames.h"
21#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
23
24namespace
25{
26
Arun Patole9dea48f2015-04-02 11:45:09 +053027const float kPi = 3.14159265358979323846f;
28const float kDegreesToRadiansMultiplier = kPi / 180.0f;
29const float kRadiansToDegreesMultiplier = 180.0f / kPi;
30
Jamie Madillb1a85f42014-08-19 15:23:24 -040031TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
32{
33 return left > right ? left : right;
34}
35
36bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
37{
38 switch (op)
39 {
40 case EOpMul:
41 case EOpMulAssign:
42 return left.getNominalSize() == right.getNominalSize() &&
43 left.getSecondarySize() == right.getSecondarySize();
44 case EOpVectorTimesScalar:
45 case EOpVectorTimesScalarAssign:
46 return true;
47 case EOpVectorTimesMatrix:
48 return left.getNominalSize() == right.getRows();
49 case EOpVectorTimesMatrixAssign:
50 return left.getNominalSize() == right.getRows() &&
51 left.getNominalSize() == right.getCols();
52 case EOpMatrixTimesVector:
53 return left.getCols() == right.getNominalSize();
54 case EOpMatrixTimesScalar:
55 case EOpMatrixTimesScalarAssign:
56 return true;
57 case EOpMatrixTimesMatrix:
58 return left.getCols() == right.getRows();
59 case EOpMatrixTimesMatrixAssign:
60 return left.getCols() == right.getCols() &&
61 left.getRows() == right.getRows();
62
63 default:
64 UNREACHABLE();
65 return false;
66 }
67}
68
69bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040070 const TConstantUnion *rightUnionArray,
71 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040072
73bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040074 const TConstantUnion *rightUnionArray,
75 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040076{
77 const TFieldList &fields = leftNodeType.getStruct()->fields();
78
79 size_t structSize = fields.size();
80 size_t index = 0;
81
82 for (size_t j = 0; j < structSize; j++)
83 {
84 size_t size = fields[j]->type()->getObjectSize();
85 for (size_t i = 0; i < size; i++)
86 {
87 if (fields[j]->type()->getBasicType() == EbtStruct)
88 {
89 if (!CompareStructure(*fields[j]->type(),
90 &rightUnionArray[index],
91 &leftUnionArray[index]))
92 {
93 return false;
94 }
95 }
96 else
97 {
98 if (leftUnionArray[index] != rightUnionArray[index])
99 return false;
100 index++;
101 }
102 }
103 }
104 return true;
105}
106
107bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400108 const TConstantUnion *rightUnionArray,
109 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400110{
111 if (leftNodeType.isArray())
112 {
113 TType typeWithoutArrayness = leftNodeType;
114 typeWithoutArrayness.clearArrayness();
115
116 size_t arraySize = leftNodeType.getArraySize();
117
118 for (size_t i = 0; i < arraySize; ++i)
119 {
120 size_t offset = typeWithoutArrayness.getObjectSize() * i;
121 if (!CompareStruct(typeWithoutArrayness,
122 &rightUnionArray[offset],
123 &leftUnionArray[offset]))
124 {
125 return false;
126 }
127 }
128 }
129 else
130 {
131 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
132 }
133 return true;
134}
135
Arun Patole274f0702015-05-05 13:33:30 +0530136TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
137{
138 TConstantUnion *constUnion = new TConstantUnion[size];
139 for (unsigned int i = 0; i < size; ++i)
140 constUnion[i] = constant;
141
142 return constUnion;
143}
144
Arun Patolebf790422015-05-18 17:53:04 +0530145void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
146 TInfoSink &infoSink, TConstantUnion *result)
147{
148 std::stringstream constantFoldingErrorStream;
149 constantFoldingErrorStream << "'" << GetOperatorString(op)
150 << "' operation result is undefined for the values passed in";
151 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
152
153 switch (basicType)
154 {
155 case EbtFloat :
156 result->setFConst(0.0f);
157 break;
158 case EbtInt:
159 result->setIConst(0);
160 break;
161 case EbtUInt:
162 result->setUConst(0u);
163 break;
164 case EbtBool:
165 result->setBConst(false);
166 break;
167 default:
168 break;
169 }
170}
171
Arun Patole1155ddd2015-06-05 18:04:36 +0530172float VectorLength(TConstantUnion *paramArray, size_t paramArraySize)
173{
174 float result = 0.0f;
175 for (size_t i = 0; i < paramArraySize; i++)
176 {
177 float f = paramArray[i].getFConst();
178 result += f * f;
179 }
180 return sqrtf(result);
181}
182
183float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, size_t paramArraySize)
184{
185 float result = 0.0f;
186 for (size_t i = 0; i < paramArraySize; i++)
187 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
188 return result;
189}
190
Olli Etuahob43846e2015-06-02 18:18:57 +0300191TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, const TIntermTyped *originalNode)
192{
193 if (constArray == nullptr)
194 {
195 return nullptr;
196 }
197 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
198 folded->getTypePointer()->setQualifier(EvqConst);
199 folded->setLine(originalNode->getLine());
200 return folded;
201}
202
Arun Patole7fa33552015-06-10 15:15:18 +0530203angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &rows, const unsigned int &cols)
204{
205 std::vector<float> elements;
206 for (size_t i = 0; i < rows * cols; i++)
207 elements.push_back(paramArray[i].getFConst());
208 // Transpose is used since the Matrix constructor expects arguments in row-major order,
209 // whereas the paramArray is in column-major order.
210 return angle::Matrix<float>(elements, rows, cols).transpose();
211}
212
213angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &size)
214{
215 std::vector<float> elements;
216 for (size_t i = 0; i < size * size; i++)
217 elements.push_back(paramArray[i].getFConst());
218 // Transpose is used since the Matrix constructor expects arguments in row-major order,
219 // whereas the paramArray is in column-major order.
220 return angle::Matrix<float>(elements, size).transpose();
221}
222
223void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
224{
225 // Transpose is used since the input Matrix is in row-major order,
226 // whereas the actual result should be in column-major order.
227 angle::Matrix<float> result = m.transpose();
228 std::vector<float> resultElements = result.elements();
229 for (size_t i = 0; i < resultElements.size(); i++)
230 resultArray[i].setFConst(resultElements[i]);
231}
232
Jamie Madillb1a85f42014-08-19 15:23:24 -0400233} // namespace anonymous
234
235
236////////////////////////////////////////////////////////////////
237//
238// Member functions of the nodes used for building the tree.
239//
240////////////////////////////////////////////////////////////////
241
Olli Etuahod2a67b92014-10-21 16:42:57 +0300242void TIntermTyped::setTypePreservePrecision(const TType &t)
243{
244 TPrecision precision = getPrecision();
245 mType = t;
246 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
247 mType.setPrecision(precision);
248}
249
Jamie Madillb1a85f42014-08-19 15:23:24 -0400250#define REPLACE_IF_IS(node, type, original, replacement) \
251 if (node == original) { \
252 node = static_cast<type *>(replacement); \
253 return true; \
254 }
255
256bool TIntermLoop::replaceChildNode(
257 TIntermNode *original, TIntermNode *replacement)
258{
259 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
260 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
261 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
262 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
263 return false;
264}
265
Jamie Madillb1a85f42014-08-19 15:23:24 -0400266bool TIntermBranch::replaceChildNode(
267 TIntermNode *original, TIntermNode *replacement)
268{
269 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
270 return false;
271}
272
Jamie Madillb1a85f42014-08-19 15:23:24 -0400273bool TIntermBinary::replaceChildNode(
274 TIntermNode *original, TIntermNode *replacement)
275{
276 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
277 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
278 return false;
279}
280
Jamie Madillb1a85f42014-08-19 15:23:24 -0400281bool TIntermUnary::replaceChildNode(
282 TIntermNode *original, TIntermNode *replacement)
283{
284 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
285 return false;
286}
287
Jamie Madillb1a85f42014-08-19 15:23:24 -0400288bool TIntermAggregate::replaceChildNode(
289 TIntermNode *original, TIntermNode *replacement)
290{
291 for (size_t ii = 0; ii < mSequence.size(); ++ii)
292 {
293 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
294 }
295 return false;
296}
297
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300298bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
299{
300 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
301 {
302 if (*it == original)
303 {
304 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300305 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300306 return true;
307 }
308 }
309 return false;
310}
311
Olli Etuahoa6f22092015-05-08 18:31:10 +0300312bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
313{
314 TIntermSequence::size_type itPosition = 0;
315 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
316 {
317 if (itPosition == position)
318 {
319 mSequence.insert(it, insertions.begin(), insertions.end());
320 return true;
321 }
322 ++itPosition;
323 }
324 return false;
325}
326
Olli Etuahod2a67b92014-10-21 16:42:57 +0300327void TIntermAggregate::setPrecisionFromChildren()
328{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300329 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300330 if (getBasicType() == EbtBool)
331 {
332 mType.setPrecision(EbpUndefined);
333 return;
334 }
335
336 TPrecision precision = EbpUndefined;
337 TIntermSequence::iterator childIter = mSequence.begin();
338 while (childIter != mSequence.end())
339 {
340 TIntermTyped *typed = (*childIter)->getAsTyped();
341 if (typed)
342 precision = GetHigherPrecision(typed->getPrecision(), precision);
343 ++childIter;
344 }
345 mType.setPrecision(precision);
346}
347
348void TIntermAggregate::setBuiltInFunctionPrecision()
349{
350 // All built-ins returning bool should be handled as ops, not functions.
351 ASSERT(getBasicType() != EbtBool);
352
353 TPrecision precision = EbpUndefined;
354 TIntermSequence::iterator childIter = mSequence.begin();
355 while (childIter != mSequence.end())
356 {
357 TIntermTyped *typed = (*childIter)->getAsTyped();
358 // ESSL spec section 8: texture functions get their precision from the sampler.
359 if (typed && IsSampler(typed->getBasicType()))
360 {
361 precision = typed->getPrecision();
362 break;
363 }
364 ++childIter;
365 }
366 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
367 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300368 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300369 mType.setPrecision(EbpHigh);
370 else
371 mType.setPrecision(precision);
372}
373
Jamie Madillb1a85f42014-08-19 15:23:24 -0400374bool TIntermSelection::replaceChildNode(
375 TIntermNode *original, TIntermNode *replacement)
376{
377 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
378 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
379 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
380 return false;
381}
382
Olli Etuahoa3a36662015-02-17 13:46:51 +0200383bool TIntermSwitch::replaceChildNode(
384 TIntermNode *original, TIntermNode *replacement)
385{
386 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
387 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
388 return false;
389}
390
391bool TIntermCase::replaceChildNode(
392 TIntermNode *original, TIntermNode *replacement)
393{
394 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
395 return false;
396}
397
Jamie Madillb1a85f42014-08-19 15:23:24 -0400398//
399// Say whether or not an operation node changes the value of a variable.
400//
401bool TIntermOperator::isAssignment() const
402{
403 switch (mOp)
404 {
405 case EOpPostIncrement:
406 case EOpPostDecrement:
407 case EOpPreIncrement:
408 case EOpPreDecrement:
409 case EOpAssign:
410 case EOpAddAssign:
411 case EOpSubAssign:
412 case EOpMulAssign:
413 case EOpVectorTimesMatrixAssign:
414 case EOpVectorTimesScalarAssign:
415 case EOpMatrixTimesScalarAssign:
416 case EOpMatrixTimesMatrixAssign:
417 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200418 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200419 case EOpBitShiftLeftAssign:
420 case EOpBitShiftRightAssign:
421 case EOpBitwiseAndAssign:
422 case EOpBitwiseXorAssign:
423 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400424 return true;
425 default:
426 return false;
427 }
428}
429
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300430bool TIntermOperator::isMultiplication() const
431{
432 switch (mOp)
433 {
434 case EOpMul:
435 case EOpMatrixTimesMatrix:
436 case EOpMatrixTimesVector:
437 case EOpMatrixTimesScalar:
438 case EOpVectorTimesMatrix:
439 case EOpVectorTimesScalar:
440 return true;
441 default:
442 return false;
443 }
444}
445
Jamie Madillb1a85f42014-08-19 15:23:24 -0400446//
447// returns true if the operator is for one of the constructors
448//
449bool TIntermOperator::isConstructor() const
450{
451 switch (mOp)
452 {
453 case EOpConstructVec2:
454 case EOpConstructVec3:
455 case EOpConstructVec4:
456 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400457 case EOpConstructMat2x3:
458 case EOpConstructMat2x4:
459 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400460 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400461 case EOpConstructMat3x4:
462 case EOpConstructMat4x2:
463 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400464 case EOpConstructMat4:
465 case EOpConstructFloat:
466 case EOpConstructIVec2:
467 case EOpConstructIVec3:
468 case EOpConstructIVec4:
469 case EOpConstructInt:
470 case EOpConstructUVec2:
471 case EOpConstructUVec3:
472 case EOpConstructUVec4:
473 case EOpConstructUInt:
474 case EOpConstructBVec2:
475 case EOpConstructBVec3:
476 case EOpConstructBVec4:
477 case EOpConstructBool:
478 case EOpConstructStruct:
479 return true;
480 default:
481 return false;
482 }
483}
484
485//
486// Make sure the type of a unary operator is appropriate for its
487// combination of operation and operand type.
488//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200489void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400490{
491 switch (mOp)
492 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200493 case EOpFloatBitsToInt:
494 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200495 case EOpIntBitsToFloat:
496 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200497 case EOpPackSnorm2x16:
498 case EOpPackUnorm2x16:
499 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200500 case EOpUnpackSnorm2x16:
501 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200502 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530503 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200504 case EOpUnpackHalf2x16:
505 mType.setPrecision(EbpMedium);
506 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400507 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200508 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400509 }
510
Olli Etuahof6c694b2015-03-26 14:50:53 +0200511 if (funcReturnType != nullptr)
512 {
513 if (funcReturnType->getBasicType() == EbtBool)
514 {
515 // Bool types should not have precision.
516 setType(*funcReturnType);
517 }
518 else
519 {
520 // Precision of the node has been set based on the operand.
521 setTypePreservePrecision(*funcReturnType);
522 }
523 }
524
Jamie Madillb1a85f42014-08-19 15:23:24 -0400525 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400526}
527
528//
529// Establishes the type of the resultant operation, as well as
530// makes the operator the correct one for the operands.
531//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200532// For lots of operations it should already be established that the operand
533// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400534//
535bool TIntermBinary::promote(TInfoSink &infoSink)
536{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200537 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400538
Jamie Madillb1a85f42014-08-19 15:23:24 -0400539 //
540 // Base assumption: just make the type the same as the left
541 // operand. Then only deviations from this need be coded.
542 //
543 setType(mLeft->getType());
544
545 // The result gets promoted to the highest precision.
546 TPrecision higherPrecision = GetHigherPrecision(
547 mLeft->getPrecision(), mRight->getPrecision());
548 getTypePointer()->setPrecision(higherPrecision);
549
550 // Binary operations results in temporary variables unless both
551 // operands are const.
552 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
553 {
554 getTypePointer()->setQualifier(EvqTemporary);
555 }
556
557 const int nominalSize =
558 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
559
560 //
561 // All scalars or structs. Code after this test assumes this case is removed!
562 //
563 if (nominalSize == 1)
564 {
565 switch (mOp)
566 {
567 //
568 // Promote to conditional
569 //
570 case EOpEqual:
571 case EOpNotEqual:
572 case EOpLessThan:
573 case EOpGreaterThan:
574 case EOpLessThanEqual:
575 case EOpGreaterThanEqual:
576 setType(TType(EbtBool, EbpUndefined));
577 break;
578
579 //
580 // And and Or operate on conditionals
581 //
582 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200583 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400584 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200585 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400586 setType(TType(EbtBool, EbpUndefined));
587 break;
588
589 default:
590 break;
591 }
592 return true;
593 }
594
595 // If we reach here, at least one of the operands is vector or matrix.
596 // The other operand could be a scalar, vector, or matrix.
597 // Can these two operands be combined?
598 //
599 TBasicType basicType = mLeft->getBasicType();
600 switch (mOp)
601 {
602 case EOpMul:
603 if (!mLeft->isMatrix() && mRight->isMatrix())
604 {
605 if (mLeft->isVector())
606 {
607 mOp = EOpVectorTimesMatrix;
608 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700609 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400610 }
611 else
612 {
613 mOp = EOpMatrixTimesScalar;
614 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700615 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400616 }
617 }
618 else if (mLeft->isMatrix() && !mRight->isMatrix())
619 {
620 if (mRight->isVector())
621 {
622 mOp = EOpMatrixTimesVector;
623 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700624 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400625 }
626 else
627 {
628 mOp = EOpMatrixTimesScalar;
629 }
630 }
631 else if (mLeft->isMatrix() && mRight->isMatrix())
632 {
633 mOp = EOpMatrixTimesMatrix;
634 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700635 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400636 }
637 else if (!mLeft->isMatrix() && !mRight->isMatrix())
638 {
639 if (mLeft->isVector() && mRight->isVector())
640 {
641 // leave as component product
642 }
643 else if (mLeft->isVector() || mRight->isVector())
644 {
645 mOp = EOpVectorTimesScalar;
646 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700647 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400648 }
649 }
650 else
651 {
652 infoSink.info.message(EPrefixInternalError, getLine(),
653 "Missing elses");
654 return false;
655 }
656
657 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
658 {
659 return false;
660 }
661 break;
662
663 case EOpMulAssign:
664 if (!mLeft->isMatrix() && mRight->isMatrix())
665 {
666 if (mLeft->isVector())
667 {
668 mOp = EOpVectorTimesMatrixAssign;
669 }
670 else
671 {
672 return false;
673 }
674 }
675 else if (mLeft->isMatrix() && !mRight->isMatrix())
676 {
677 if (mRight->isVector())
678 {
679 return false;
680 }
681 else
682 {
683 mOp = EOpMatrixTimesScalarAssign;
684 }
685 }
686 else if (mLeft->isMatrix() && mRight->isMatrix())
687 {
688 mOp = EOpMatrixTimesMatrixAssign;
689 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700690 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400691 }
692 else if (!mLeft->isMatrix() && !mRight->isMatrix())
693 {
694 if (mLeft->isVector() && mRight->isVector())
695 {
696 // leave as component product
697 }
698 else if (mLeft->isVector() || mRight->isVector())
699 {
700 if (!mLeft->isVector())
701 return false;
702 mOp = EOpVectorTimesScalarAssign;
703 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700704 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400705 }
706 }
707 else
708 {
709 infoSink.info.message(EPrefixInternalError, getLine(),
710 "Missing elses");
711 return false;
712 }
713
714 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
715 {
716 return false;
717 }
718 break;
719
720 case EOpAssign:
721 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200722 // No more additional checks are needed.
723 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
724 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
725 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400726 case EOpAdd:
727 case EOpSub:
728 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200729 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200730 case EOpBitShiftLeft:
731 case EOpBitShiftRight:
732 case EOpBitwiseAnd:
733 case EOpBitwiseXor:
734 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400735 case EOpAddAssign:
736 case EOpSubAssign:
737 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200738 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200739 case EOpBitShiftLeftAssign:
740 case EOpBitShiftRightAssign:
741 case EOpBitwiseAndAssign:
742 case EOpBitwiseXorAssign:
743 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400744 if ((mLeft->isMatrix() && mRight->isVector()) ||
745 (mLeft->isVector() && mRight->isMatrix()))
746 {
747 return false;
748 }
749
750 // Are the sizes compatible?
751 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
752 mLeft->getSecondarySize() != mRight->getSecondarySize())
753 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200754 // If the nominal sizes of operands do not match:
755 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400756 if (!mLeft->isScalar() && !mRight->isScalar())
757 return false;
758
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200759 // In the case of compound assignment other than multiply-assign,
760 // the right side needs to be a scalar. Otherwise a vector/matrix
761 // would be assigned to a scalar. A scalar can't be shifted by a
762 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200763 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200764 (isAssignment() ||
765 mOp == EOpBitShiftLeft ||
766 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200767 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400768 }
769
770 {
771 const int secondarySize = std::max(
772 mLeft->getSecondarySize(), mRight->getSecondarySize());
773 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700774 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200775 if (mLeft->isArray())
776 {
777 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
778 mType.setArraySize(mLeft->getArraySize());
779 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400780 }
781 break;
782
783 case EOpEqual:
784 case EOpNotEqual:
785 case EOpLessThan:
786 case EOpGreaterThan:
787 case EOpLessThanEqual:
788 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200789 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
790 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400791 setType(TType(EbtBool, EbpUndefined));
792 break;
793
794 default:
795 return false;
796 }
797 return true;
798}
799
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300800TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
801{
802 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
803 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
804 if (leftConstant == nullptr || rightConstant == nullptr)
805 {
806 return nullptr;
807 }
808 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300809 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300810}
811
Olli Etuaho95310b02015-06-02 17:43:38 +0300812TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
813{
814 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
815 if (operandConstant == nullptr)
816 {
817 return nullptr;
818 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530819
820 TConstantUnion *constArray = nullptr;
821 switch (mOp)
822 {
823 case EOpAny:
824 case EOpAll:
825 case EOpLength:
826 case EOpTranspose:
827 case EOpDeterminant:
828 case EOpInverse:
829 case EOpPackSnorm2x16:
830 case EOpUnpackSnorm2x16:
831 case EOpPackUnorm2x16:
832 case EOpUnpackUnorm2x16:
833 case EOpPackHalf2x16:
834 case EOpUnpackHalf2x16:
835 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
836 break;
837 default:
838 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
839 break;
840 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300841 return CreateFoldedNode(constArray, this);
842}
843
844TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
845{
846 // Make sure that all params are constant before actual constant folding.
847 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300848 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300849 if (param->getAsConstantUnion() == nullptr)
850 {
851 return nullptr;
852 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300853 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300854 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
855 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300856}
857
Jamie Madillb1a85f42014-08-19 15:23:24 -0400858//
859// The fold functions see if an operation on a constant can be done in place,
860// without generating run-time code.
861//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300862// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400863//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300864TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
865{
866 TConstantUnion *leftArray = getUnionArrayPointer();
867 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
868
869 if (!leftArray)
870 return nullptr;
871 if (!rightArray)
872 return nullptr;
873
874 size_t objectSize = getType().getObjectSize();
875
876 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
877 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
878 {
879 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
880 }
881 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
882 {
883 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
884 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
885 objectSize = rightNode->getType().getObjectSize();
886 }
887
888 TConstantUnion *resultArray = nullptr;
889
890 switch(op)
891 {
892 case EOpAdd:
893 resultArray = new TConstantUnion[objectSize];
894 for (size_t i = 0; i < objectSize; i++)
895 resultArray[i] = leftArray[i] + rightArray[i];
896 break;
897 case EOpSub:
898 resultArray = new TConstantUnion[objectSize];
899 for (size_t i = 0; i < objectSize; i++)
900 resultArray[i] = leftArray[i] - rightArray[i];
901 break;
902
903 case EOpMul:
904 case EOpVectorTimesScalar:
905 case EOpMatrixTimesScalar:
906 resultArray = new TConstantUnion[objectSize];
907 for (size_t i = 0; i < objectSize; i++)
908 resultArray[i] = leftArray[i] * rightArray[i];
909 break;
910
911 case EOpMatrixTimesMatrix:
912 {
913 if (getType().getBasicType() != EbtFloat ||
914 rightNode->getBasicType() != EbtFloat)
915 {
916 infoSink.info.message(
917 EPrefixInternalError, getLine(),
918 "Constant Folding cannot be done for matrix multiply");
919 return nullptr;
920 }
921
922 const int leftCols = getCols();
923 const int leftRows = getRows();
924 const int rightCols = rightNode->getType().getCols();
925 const int rightRows = rightNode->getType().getRows();
926 const int resultCols = rightCols;
927 const int resultRows = leftRows;
928
929 resultArray = new TConstantUnion[resultCols * resultRows];
930 for (int row = 0; row < resultRows; row++)
931 {
932 for (int column = 0; column < resultCols; column++)
933 {
934 resultArray[resultRows * column + row].setFConst(0.0f);
935 for (int i = 0; i < leftCols; i++)
936 {
937 resultArray[resultRows * column + row].setFConst(
938 resultArray[resultRows * column + row].getFConst() +
939 leftArray[i * leftRows + row].getFConst() *
940 rightArray[column * rightRows + i].getFConst());
941 }
942 }
943 }
944 }
945 break;
946
947 case EOpDiv:
948 case EOpIMod:
949 {
950 resultArray = new TConstantUnion[objectSize];
951 for (size_t i = 0; i < objectSize; i++)
952 {
953 switch (getType().getBasicType())
954 {
955 case EbtFloat:
956 if (rightArray[i] == 0.0f)
957 {
958 infoSink.info.message(EPrefixWarning, getLine(),
959 "Divide by zero error during constant folding");
960 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
961 }
962 else
963 {
964 ASSERT(op == EOpDiv);
965 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
966 }
967 break;
968
969 case EbtInt:
970 if (rightArray[i] == 0)
971 {
972 infoSink.info.message(EPrefixWarning, getLine(),
973 "Divide by zero error during constant folding");
974 resultArray[i].setIConst(INT_MAX);
975 }
976 else
977 {
978 if (op == EOpDiv)
979 {
980 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
981 }
982 else
983 {
984 ASSERT(op == EOpIMod);
985 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
986 }
987 }
988 break;
989
990 case EbtUInt:
991 if (rightArray[i] == 0)
992 {
993 infoSink.info.message(EPrefixWarning, getLine(),
994 "Divide by zero error during constant folding");
995 resultArray[i].setUConst(UINT_MAX);
996 }
997 else
998 {
999 if (op == EOpDiv)
1000 {
1001 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1002 }
1003 else
1004 {
1005 ASSERT(op == EOpIMod);
1006 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1007 }
1008 }
1009 break;
1010
1011 default:
1012 infoSink.info.message(EPrefixInternalError, getLine(),
1013 "Constant folding cannot be done for \"/\"");
1014 return nullptr;
1015 }
1016 }
1017 }
1018 break;
1019
1020 case EOpMatrixTimesVector:
1021 {
1022 if (rightNode->getBasicType() != EbtFloat)
1023 {
1024 infoSink.info.message(EPrefixInternalError, getLine(),
1025 "Constant Folding cannot be done for matrix times vector");
1026 return nullptr;
1027 }
1028
1029 const int matrixCols = getCols();
1030 const int matrixRows = getRows();
1031
1032 resultArray = new TConstantUnion[matrixRows];
1033
1034 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1035 {
1036 resultArray[matrixRow].setFConst(0.0f);
1037 for (int col = 0; col < matrixCols; col++)
1038 {
1039 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1040 leftArray[col * matrixRows + matrixRow].getFConst() *
1041 rightArray[col].getFConst());
1042 }
1043 }
1044 }
1045 break;
1046
1047 case EOpVectorTimesMatrix:
1048 {
1049 if (getType().getBasicType() != EbtFloat)
1050 {
1051 infoSink.info.message(EPrefixInternalError, getLine(),
1052 "Constant Folding cannot be done for vector times matrix");
1053 return nullptr;
1054 }
1055
1056 const int matrixCols = rightNode->getType().getCols();
1057 const int matrixRows = rightNode->getType().getRows();
1058
1059 resultArray = new TConstantUnion[matrixCols];
1060
1061 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1062 {
1063 resultArray[matrixCol].setFConst(0.0f);
1064 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1065 {
1066 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1067 leftArray[matrixRow].getFConst() *
1068 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1069 }
1070 }
1071 }
1072 break;
1073
1074 case EOpLogicalAnd:
1075 {
1076 resultArray = new TConstantUnion[objectSize];
1077 for (size_t i = 0; i < objectSize; i++)
1078 {
1079 resultArray[i] = leftArray[i] && rightArray[i];
1080 }
1081 }
1082 break;
1083
1084 case EOpLogicalOr:
1085 {
1086 resultArray = new TConstantUnion[objectSize];
1087 for (size_t i = 0; i < objectSize; i++)
1088 {
1089 resultArray[i] = leftArray[i] || rightArray[i];
1090 }
1091 }
1092 break;
1093
1094 case EOpLogicalXor:
1095 {
1096 resultArray = new TConstantUnion[objectSize];
1097 for (size_t i = 0; i < objectSize; i++)
1098 {
1099 switch (getType().getBasicType())
1100 {
1101 case EbtBool:
1102 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1103 break;
1104 default:
1105 UNREACHABLE();
1106 break;
1107 }
1108 }
1109 }
1110 break;
1111
1112 case EOpBitwiseAnd:
1113 resultArray = new TConstantUnion[objectSize];
1114 for (size_t i = 0; i < objectSize; i++)
1115 resultArray[i] = leftArray[i] & rightArray[i];
1116 break;
1117 case EOpBitwiseXor:
1118 resultArray = new TConstantUnion[objectSize];
1119 for (size_t i = 0; i < objectSize; i++)
1120 resultArray[i] = leftArray[i] ^ rightArray[i];
1121 break;
1122 case EOpBitwiseOr:
1123 resultArray = new TConstantUnion[objectSize];
1124 for (size_t i = 0; i < objectSize; i++)
1125 resultArray[i] = leftArray[i] | rightArray[i];
1126 break;
1127 case EOpBitShiftLeft:
1128 resultArray = new TConstantUnion[objectSize];
1129 for (size_t i = 0; i < objectSize; i++)
1130 resultArray[i] = leftArray[i] << rightArray[i];
1131 break;
1132 case EOpBitShiftRight:
1133 resultArray = new TConstantUnion[objectSize];
1134 for (size_t i = 0; i < objectSize; i++)
1135 resultArray[i] = leftArray[i] >> rightArray[i];
1136 break;
1137
1138 case EOpLessThan:
1139 ASSERT(objectSize == 1);
1140 resultArray = new TConstantUnion[1];
1141 resultArray->setBConst(*leftArray < *rightArray);
1142 break;
1143
1144 case EOpGreaterThan:
1145 ASSERT(objectSize == 1);
1146 resultArray = new TConstantUnion[1];
1147 resultArray->setBConst(*leftArray > *rightArray);
1148 break;
1149
1150 case EOpLessThanEqual:
1151 ASSERT(objectSize == 1);
1152 resultArray = new TConstantUnion[1];
1153 resultArray->setBConst(!(*leftArray > *rightArray));
1154 break;
1155
1156 case EOpGreaterThanEqual:
1157 ASSERT(objectSize == 1);
1158 resultArray = new TConstantUnion[1];
1159 resultArray->setBConst(!(*leftArray < *rightArray));
1160 break;
1161
1162 case EOpEqual:
1163 case EOpNotEqual:
1164 {
1165 resultArray = new TConstantUnion[1];
1166 bool equal = true;
1167 if (getType().getBasicType() == EbtStruct)
1168 {
1169 equal = CompareStructure(getType(), rightArray, leftArray);
1170 }
1171 else
1172 {
1173 for (size_t i = 0; i < objectSize; i++)
1174 {
1175 if (leftArray[i] != rightArray[i])
1176 {
1177 equal = false;
1178 break; // break out of for loop
1179 }
1180 }
1181 }
1182 if (op == EOpEqual)
1183 {
1184 resultArray->setBConst(equal);
1185 }
1186 else
1187 {
1188 resultArray->setBConst(!equal);
1189 }
1190 }
1191 break;
1192
1193 default:
1194 infoSink.info.message(
1195 EPrefixInternalError, getLine(),
1196 "Invalid operator for constant folding");
1197 return nullptr;
1198 }
1199 return resultArray;
1200}
1201
1202//
1203// The fold functions see if an operation on a constant can be done in place,
1204// without generating run-time code.
1205//
Olli Etuaho95310b02015-06-02 17:43:38 +03001206// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001207//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301208TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001209{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301210 //
1211 // Do operations where the return type has a different number of components compared to the operand type.
1212 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001213
Arun Patoleab2b9a22015-07-06 18:27:56 +05301214 TConstantUnion *operandArray = getUnionArrayPointer();
1215 if (!operandArray)
1216 return nullptr;
1217
1218 size_t objectSize = getType().getObjectSize();
1219 TConstantUnion *resultArray = nullptr;
1220 switch (op)
1221 {
1222 case EOpAny:
1223 if (getType().getBasicType() == EbtBool)
1224 {
1225 resultArray = new TConstantUnion();
1226 resultArray->setBConst(false);
1227 for (size_t i = 0; i < objectSize; i++)
1228 {
1229 if (operandArray[i].getBConst())
1230 {
1231 resultArray->setBConst(true);
1232 break;
1233 }
1234 }
1235 break;
1236 }
1237 else
1238 {
1239 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1240 return nullptr;
1241 }
1242
1243 case EOpAll:
1244 if (getType().getBasicType() == EbtBool)
1245 {
1246 resultArray = new TConstantUnion();
1247 resultArray->setBConst(true);
1248 for (size_t i = 0; i < objectSize; i++)
1249 {
1250 if (!operandArray[i].getBConst())
1251 {
1252 resultArray->setBConst(false);
1253 break;
1254 }
1255 }
1256 break;
1257 }
1258 else
1259 {
1260 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1261 return nullptr;
1262 }
1263
1264 case EOpLength:
1265 if (getType().getBasicType() == EbtFloat)
1266 {
1267 resultArray = new TConstantUnion();
1268 resultArray->setFConst(VectorLength(operandArray, objectSize));
1269 break;
1270 }
1271 else
1272 {
1273 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1274 return nullptr;
1275 }
1276
1277 case EOpTranspose:
1278 if (getType().getBasicType() == EbtFloat)
1279 {
1280 resultArray = new TConstantUnion[objectSize];
1281 angle::Matrix<float> result =
1282 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1283 SetUnionArrayFromMatrix(result, resultArray);
1284 break;
1285 }
1286 else
1287 {
1288 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1289 return nullptr;
1290 }
1291
1292 case EOpDeterminant:
1293 if (getType().getBasicType() == EbtFloat)
1294 {
1295 unsigned int size = getType().getNominalSize();
1296 ASSERT(size >= 2 && size <= 4);
1297 resultArray = new TConstantUnion();
1298 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1299 break;
1300 }
1301 else
1302 {
1303 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1304 return nullptr;
1305 }
1306
1307 case EOpInverse:
1308 if (getType().getBasicType() == EbtFloat)
1309 {
1310 unsigned int size = getType().getNominalSize();
1311 ASSERT(size >= 2 && size <= 4);
1312 resultArray = new TConstantUnion[objectSize];
1313 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1314 SetUnionArrayFromMatrix(result, resultArray);
1315 break;
1316 }
1317 else
1318 {
1319 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1320 return nullptr;
1321 }
1322
1323 case EOpPackSnorm2x16:
1324 if (getType().getBasicType() == EbtFloat)
1325 {
1326 ASSERT(getType().getNominalSize() == 2);
1327 resultArray = new TConstantUnion();
1328 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1329 break;
1330 }
1331 else
1332 {
1333 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1334 return nullptr;
1335 }
1336
1337 case EOpUnpackSnorm2x16:
1338 if (getType().getBasicType() == EbtUInt)
1339 {
1340 resultArray = new TConstantUnion[2];
1341 float f1, f2;
1342 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1343 resultArray[0].setFConst(f1);
1344 resultArray[1].setFConst(f2);
1345 break;
1346 }
1347 else
1348 {
1349 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1350 return nullptr;
1351 }
1352
1353 case EOpPackUnorm2x16:
1354 if (getType().getBasicType() == EbtFloat)
1355 {
1356 ASSERT(getType().getNominalSize() == 2);
1357 resultArray = new TConstantUnion();
1358 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1359 break;
1360 }
1361 else
1362 {
1363 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1364 return nullptr;
1365 }
1366
1367 case EOpUnpackUnorm2x16:
1368 if (getType().getBasicType() == EbtUInt)
1369 {
1370 resultArray = new TConstantUnion[2];
1371 float f1, f2;
1372 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1373 resultArray[0].setFConst(f1);
1374 resultArray[1].setFConst(f2);
1375 break;
1376 }
1377 else
1378 {
1379 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1380 return nullptr;
1381 }
1382
1383 case EOpPackHalf2x16:
1384 if (getType().getBasicType() == EbtFloat)
1385 {
1386 ASSERT(getType().getNominalSize() == 2);
1387 resultArray = new TConstantUnion();
1388 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1389 break;
1390 }
1391 else
1392 {
1393 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1394 return nullptr;
1395 }
1396
1397 case EOpUnpackHalf2x16:
1398 if (getType().getBasicType() == EbtUInt)
1399 {
1400 resultArray = new TConstantUnion[2];
1401 float f1, f2;
1402 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1403 resultArray[0].setFConst(f1);
1404 resultArray[1].setFConst(f2);
1405 break;
1406 }
1407 else
1408 {
1409 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1410 return nullptr;
1411 }
1412 break;
1413
1414 default:
1415 break;
1416 }
1417
1418 return resultArray;
1419}
1420
1421TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1422{
1423 //
1424 // Do unary operations where the return type is the same as operand type.
1425 //
1426
1427 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001428 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301429 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001430
1431 size_t objectSize = getType().getObjectSize();
1432
Arun Patoleab2b9a22015-07-06 18:27:56 +05301433 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1434 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301435 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301436 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301437 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301438 case EOpNegative:
1439 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301440 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301441 case EbtFloat:
1442 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301443 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301444 case EbtInt:
1445 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301446 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301447 case EbtUInt:
1448 resultArray[i].setUConst(static_cast<unsigned int>(
1449 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301450 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301451 default:
1452 infoSink.info.message(
1453 EPrefixInternalError, getLine(),
1454 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301455 return nullptr;
1456 }
1457 break;
1458
Arun Patoleab2b9a22015-07-06 18:27:56 +05301459 case EOpPositive:
1460 switch (getType().getBasicType())
1461 {
1462 case EbtFloat:
1463 resultArray[i].setFConst(operandArray[i].getFConst());
1464 break;
1465 case EbtInt:
1466 resultArray[i].setIConst(operandArray[i].getIConst());
1467 break;
1468 case EbtUInt:
1469 resultArray[i].setUConst(static_cast<unsigned int>(
1470 static_cast<int>(operandArray[i].getUConst())));
1471 break;
1472 default:
1473 infoSink.info.message(
1474 EPrefixInternalError, getLine(),
1475 "Unary operation not folded into constant");
1476 return nullptr;
1477 }
1478 break;
1479
1480 case EOpLogicalNot:
1481 // this code is written for possible future use,
1482 // will not get executed currently
1483 switch (getType().getBasicType())
1484 {
1485 case EbtBool:
1486 resultArray[i].setBConst(!operandArray[i].getBConst());
1487 break;
1488 default:
1489 infoSink.info.message(
1490 EPrefixInternalError, getLine(),
1491 "Unary operation not folded into constant");
1492 return nullptr;
1493 }
1494 break;
1495
1496 case EOpBitwiseNot:
1497 switch (getType().getBasicType())
1498 {
1499 case EbtInt:
1500 resultArray[i].setIConst(~operandArray[i].getIConst());
1501 break;
1502 case EbtUInt:
1503 resultArray[i].setUConst(~operandArray[i].getUConst());
1504 break;
1505 default:
1506 infoSink.info.message(
1507 EPrefixInternalError, getLine(),
1508 "Unary operation not folded into constant");
1509 return nullptr;
1510 }
1511 break;
1512
1513 case EOpRadians:
1514 if (getType().getBasicType() == EbtFloat)
1515 {
1516 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1517 break;
1518 }
1519 infoSink.info.message(
1520 EPrefixInternalError, getLine(),
1521 "Unary operation not folded into constant");
1522 return nullptr;
1523
1524 case EOpDegrees:
1525 if (getType().getBasicType() == EbtFloat)
1526 {
1527 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1528 break;
1529 }
1530 infoSink.info.message(
1531 EPrefixInternalError, getLine(),
1532 "Unary operation not folded into constant");
1533 return nullptr;
1534
1535 case EOpSin:
1536 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1537 return nullptr;
1538 break;
1539
1540 case EOpCos:
1541 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1542 return nullptr;
1543 break;
1544
1545 case EOpTan:
1546 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1547 return nullptr;
1548 break;
1549
1550 case EOpAsin:
1551 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1552 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1553 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1554 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1555 return nullptr;
1556 break;
1557
1558 case EOpAcos:
1559 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1560 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1561 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1562 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1563 return nullptr;
1564 break;
1565
1566 case EOpAtan:
1567 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1568 return nullptr;
1569 break;
1570
1571 case EOpSinh:
1572 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1573 return nullptr;
1574 break;
1575
1576 case EOpCosh:
1577 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1578 return nullptr;
1579 break;
1580
1581 case EOpTanh:
1582 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1583 return nullptr;
1584 break;
1585
1586 case EOpAsinh:
1587 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1588 return nullptr;
1589 break;
1590
1591 case EOpAcosh:
1592 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1593 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1594 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1595 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1596 return nullptr;
1597 break;
1598
1599 case EOpAtanh:
1600 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1601 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1602 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1603 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1604 return nullptr;
1605 break;
1606
1607 case EOpAbs:
1608 switch (getType().getBasicType())
1609 {
1610 case EbtFloat:
1611 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1612 break;
1613 case EbtInt:
1614 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1615 break;
1616 default:
1617 infoSink.info.message(
1618 EPrefixInternalError, getLine(),
1619 "Unary operation not folded into constant");
1620 return nullptr;
1621 }
1622 break;
1623
1624 case EOpSign:
1625 switch (getType().getBasicType())
1626 {
1627 case EbtFloat:
1628 {
1629 float fConst = operandArray[i].getFConst();
1630 float fResult = 0.0f;
1631 if (fConst > 0.0f)
1632 fResult = 1.0f;
1633 else if (fConst < 0.0f)
1634 fResult = -1.0f;
1635 resultArray[i].setFConst(fResult);
1636 }
1637 break;
1638 case EbtInt:
1639 {
1640 int iConst = operandArray[i].getIConst();
1641 int iResult = 0;
1642 if (iConst > 0)
1643 iResult = 1;
1644 else if (iConst < 0)
1645 iResult = -1;
1646 resultArray[i].setIConst(iResult);
1647 }
1648 break;
1649 default:
1650 infoSink.info.message(
1651 EPrefixInternalError, getLine(),
1652 "Unary operation not folded into constant");
1653 return nullptr;
1654 }
1655 break;
1656
1657 case EOpFloor:
1658 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1659 return nullptr;
1660 break;
1661
1662 case EOpTrunc:
1663 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1664 return nullptr;
1665 break;
1666
1667 case EOpRound:
1668 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1669 return nullptr;
1670 break;
1671
1672 case EOpRoundEven:
1673 if (getType().getBasicType() == EbtFloat)
1674 {
1675 float x = operandArray[i].getFConst();
1676 float result;
1677 float fractPart = modff(x, &result);
1678 if (fabsf(fractPart) == 0.5f)
1679 result = 2.0f * roundf(x / 2.0f);
1680 else
1681 result = roundf(x);
1682 resultArray[i].setFConst(result);
1683 break;
1684 }
1685 infoSink.info.message(
1686 EPrefixInternalError, getLine(),
1687 "Unary operation not folded into constant");
1688 return nullptr;
1689
1690 case EOpCeil:
1691 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1692 return nullptr;
1693 break;
1694
1695 case EOpFract:
1696 if (getType().getBasicType() == EbtFloat)
1697 {
1698 float x = operandArray[i].getFConst();
1699 resultArray[i].setFConst(x - floorf(x));
1700 break;
1701 }
1702 infoSink.info.message(
1703 EPrefixInternalError, getLine(),
1704 "Unary operation not folded into constant");
1705 return nullptr;
1706
Arun Patole551279e2015-07-07 18:18:23 +05301707 case EOpIsNan:
1708 if (getType().getBasicType() == EbtFloat)
1709 {
1710 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1711 break;
1712 }
1713 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1714 return nullptr;
1715
1716 case EOpIsInf:
1717 if (getType().getBasicType() == EbtFloat)
1718 {
1719 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1720 break;
1721 }
1722 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1723 return nullptr;
1724
1725 case EOpFloatBitsToInt:
1726 if (getType().getBasicType() == EbtFloat)
1727 {
1728 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1729 break;
1730 }
1731 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1732 return nullptr;
1733
1734 case EOpFloatBitsToUint:
1735 if (getType().getBasicType() == EbtFloat)
1736 {
1737 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1738 break;
1739 }
1740 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1741 return nullptr;
1742
1743 case EOpIntBitsToFloat:
1744 if (getType().getBasicType() == EbtInt)
1745 {
1746 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1747 break;
1748 }
1749 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1750 return nullptr;
1751
1752 case EOpUintBitsToFloat:
1753 if (getType().getBasicType() == EbtUInt)
1754 {
1755 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1756 break;
1757 }
1758 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1759 return nullptr;
1760
Arun Patoleab2b9a22015-07-06 18:27:56 +05301761 case EOpExp:
1762 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1763 return nullptr;
1764 break;
1765
1766 case EOpLog:
1767 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1768 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1769 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1770 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1771 return nullptr;
1772 break;
1773
1774 case EOpExp2:
1775 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1776 return nullptr;
1777 break;
1778
1779 case EOpLog2:
1780 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1781 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1782 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1783 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1784 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1785 return nullptr;
1786 else
1787 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1788 break;
1789
1790 case EOpSqrt:
1791 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1792 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1793 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1794 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1795 return nullptr;
1796 break;
1797
1798 case EOpInverseSqrt:
1799 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1800 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1801 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1802 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1803 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1804 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1805 return nullptr;
1806 else
1807 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1808 break;
1809
1810 case EOpVectorLogicalNot:
1811 if (getType().getBasicType() == EbtBool)
1812 {
1813 resultArray[i].setBConst(!operandArray[i].getBConst());
1814 break;
1815 }
1816 infoSink.info.message(
1817 EPrefixInternalError, getLine(),
1818 "Unary operation not folded into constant");
1819 return nullptr;
1820
1821 case EOpNormalize:
1822 if (getType().getBasicType() == EbtFloat)
1823 {
1824 float x = operandArray[i].getFConst();
1825 float length = VectorLength(operandArray, objectSize);
1826 if (length)
1827 resultArray[i].setFConst(x / length);
1828 else
1829 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1830 &resultArray[i]);
1831 break;
1832 }
1833 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1834 return nullptr;
1835
Arun Patole0c5409f2015-07-08 15:17:53 +05301836 case EOpDFdx:
1837 case EOpDFdy:
1838 case EOpFwidth:
1839 if (getType().getBasicType() == EbtFloat)
1840 {
1841 // Derivatives of constant arguments should be 0.
1842 resultArray[i].setFConst(0.0f);
1843 break;
1844 }
1845 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1846 return nullptr;
1847
Arun Patole1155ddd2015-06-05 18:04:36 +05301848 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301849 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301850 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301851 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001852
Arun Patoleab2b9a22015-07-06 18:27:56 +05301853 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001854}
1855
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001856bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1857 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301858{
1859 ASSERT(builtinFunc);
1860
1861 if (getType().getBasicType() == EbtFloat)
1862 {
1863 result->setFConst(builtinFunc(parameter.getFConst()));
1864 return true;
1865 }
1866
1867 infoSink.info.message(
1868 EPrefixInternalError, getLine(),
1869 "Unary operation not folded into constant");
1870 return false;
1871}
1872
Jamie Madillb1a85f42014-08-19 15:23:24 -04001873// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001874TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301875{
Olli Etuahob43846e2015-06-02 18:18:57 +03001876 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301877 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001878 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Arun Patole274f0702015-05-05 13:33:30 +05301879 std::vector<TConstantUnion *> unionArrays(paramsCount);
1880 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001881 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301882 TBasicType basicType = EbtVoid;
1883 TSourceLoc loc;
1884 for (unsigned int i = 0; i < paramsCount; i++)
1885 {
1886 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001887 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301888
1889 if (i == 0)
1890 {
1891 basicType = paramConstant->getType().getBasicType();
1892 loc = paramConstant->getLine();
1893 }
1894 unionArrays[i] = paramConstant->getUnionArrayPointer();
1895 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001896 if (objectSizes[i] > maxObjectSize)
1897 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301898 }
1899
Arun Patole7fa33552015-06-10 15:15:18 +05301900 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1901 {
1902 for (unsigned int i = 0; i < paramsCount; i++)
1903 if (objectSizes[i] != maxObjectSize)
1904 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1905 }
Arun Patole274f0702015-05-05 13:33:30 +05301906
Olli Etuahob43846e2015-06-02 18:18:57 +03001907 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301908 if (paramsCount == 2)
1909 {
1910 //
1911 // Binary built-in
1912 //
1913 switch (op)
1914 {
Arun Patolebf790422015-05-18 17:53:04 +05301915 case EOpAtan:
1916 {
1917 if (basicType == EbtFloat)
1918 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001919 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301920 for (size_t i = 0; i < maxObjectSize; i++)
1921 {
1922 float y = unionArrays[0][i].getFConst();
1923 float x = unionArrays[1][i].getFConst();
1924 // Results are undefined if x and y are both 0.
1925 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001926 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301927 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001928 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301929 }
1930 }
1931 else
1932 UNREACHABLE();
1933 }
1934 break;
1935
1936 case EOpPow:
1937 {
1938 if (basicType == EbtFloat)
1939 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001940 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301941 for (size_t i = 0; i < maxObjectSize; i++)
1942 {
1943 float x = unionArrays[0][i].getFConst();
1944 float y = unionArrays[1][i].getFConst();
1945 // Results are undefined if x < 0.
1946 // Results are undefined if x = 0 and y <= 0.
1947 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001948 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301949 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001950 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301951 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001952 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05301953 }
1954 }
1955 else
1956 UNREACHABLE();
1957 }
1958 break;
1959
1960 case EOpMod:
1961 {
1962 if (basicType == EbtFloat)
1963 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001964 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301965 for (size_t i = 0; i < maxObjectSize; i++)
1966 {
1967 float x = unionArrays[0][i].getFConst();
1968 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001969 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05301970 }
1971 }
1972 else
1973 UNREACHABLE();
1974 }
1975 break;
1976
Arun Patole274f0702015-05-05 13:33:30 +05301977 case EOpMin:
1978 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001979 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301980 for (size_t i = 0; i < maxObjectSize; i++)
1981 {
1982 switch (basicType)
1983 {
1984 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001985 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301986 break;
1987 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001988 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301989 break;
1990 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001991 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301992 break;
1993 default:
1994 UNREACHABLE();
1995 break;
1996 }
1997 }
1998 }
1999 break;
2000
2001 case EOpMax:
2002 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002003 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302004 for (size_t i = 0; i < maxObjectSize; i++)
2005 {
2006 switch (basicType)
2007 {
2008 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002009 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302010 break;
2011 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002012 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302013 break;
2014 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002015 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302016 break;
2017 default:
2018 UNREACHABLE();
2019 break;
2020 }
2021 }
2022 }
2023 break;
2024
Arun Patolebf790422015-05-18 17:53:04 +05302025 case EOpStep:
2026 {
2027 if (basicType == EbtFloat)
2028 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002029 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302030 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002031 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302032 }
2033 else
2034 UNREACHABLE();
2035 }
2036 break;
2037
Arun Patole9d0b1f92015-05-20 14:27:17 +05302038 case EOpLessThan:
2039 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002040 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302041 for (size_t i = 0; i < maxObjectSize; i++)
2042 {
2043 switch (basicType)
2044 {
2045 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002046 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302047 break;
2048 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002049 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302050 break;
2051 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002052 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302053 break;
2054 default:
2055 UNREACHABLE();
2056 break;
2057 }
2058 }
2059 }
2060 break;
2061
2062 case EOpLessThanEqual:
2063 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002064 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302065 for (size_t i = 0; i < maxObjectSize; i++)
2066 {
2067 switch (basicType)
2068 {
2069 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002070 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302071 break;
2072 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002073 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302074 break;
2075 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002076 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302077 break;
2078 default:
2079 UNREACHABLE();
2080 break;
2081 }
2082 }
2083 }
2084 break;
2085
2086 case EOpGreaterThan:
2087 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002088 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302089 for (size_t i = 0; i < maxObjectSize; i++)
2090 {
2091 switch (basicType)
2092 {
2093 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002094 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302095 break;
2096 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002097 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302098 break;
2099 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002100 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302101 break;
2102 default:
2103 UNREACHABLE();
2104 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002105 }
2106 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302107 }
2108 break;
2109
2110 case EOpGreaterThanEqual:
2111 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002112 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302113 for (size_t i = 0; i < maxObjectSize; i++)
2114 {
2115 switch (basicType)
2116 {
2117 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002118 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302119 break;
2120 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002121 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302122 break;
2123 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002124 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302125 break;
2126 default:
2127 UNREACHABLE();
2128 break;
2129 }
2130 }
2131 }
2132 break;
2133
2134 case EOpVectorEqual:
2135 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002136 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302137 for (size_t i = 0; i < maxObjectSize; i++)
2138 {
2139 switch (basicType)
2140 {
2141 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002142 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302143 break;
2144 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002145 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302146 break;
2147 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002148 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302149 break;
2150 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002151 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302152 break;
2153 default:
2154 UNREACHABLE();
2155 break;
2156 }
2157 }
2158 }
2159 break;
2160
2161 case EOpVectorNotEqual:
2162 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002163 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302164 for (size_t i = 0; i < maxObjectSize; i++)
2165 {
2166 switch (basicType)
2167 {
2168 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002169 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302170 break;
2171 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002172 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302173 break;
2174 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002175 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302176 break;
2177 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002178 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302179 break;
2180 default:
2181 UNREACHABLE();
2182 break;
2183 }
2184 }
2185 }
2186 break;
2187
Arun Patole1155ddd2015-06-05 18:04:36 +05302188 case EOpDistance:
2189 if (basicType == EbtFloat)
2190 {
2191 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002192 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302193 for (size_t i = 0; i < maxObjectSize; i++)
2194 {
2195 float x = unionArrays[0][i].getFConst();
2196 float y = unionArrays[1][i].getFConst();
2197 distanceArray[i].setFConst(x - y);
2198 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002199 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302200 }
2201 else
2202 UNREACHABLE();
2203 break;
2204
2205 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002206
Arun Patole1155ddd2015-06-05 18:04:36 +05302207 if (basicType == EbtFloat)
2208 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002209 resultArray = new TConstantUnion();
2210 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302211 }
2212 else
2213 UNREACHABLE();
2214 break;
2215
2216 case EOpCross:
2217 if (basicType == EbtFloat && maxObjectSize == 3)
2218 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002219 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302220 float x0 = unionArrays[0][0].getFConst();
2221 float x1 = unionArrays[0][1].getFConst();
2222 float x2 = unionArrays[0][2].getFConst();
2223 float y0 = unionArrays[1][0].getFConst();
2224 float y1 = unionArrays[1][1].getFConst();
2225 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002226 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2227 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2228 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302229 }
2230 else
2231 UNREACHABLE();
2232 break;
2233
2234 case EOpReflect:
2235 if (basicType == EbtFloat)
2236 {
2237 // genType reflect (genType I, genType N) :
2238 // For the incident vector I and surface orientation N, returns the reflection direction:
2239 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002240 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302241 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2242 for (size_t i = 0; i < maxObjectSize; i++)
2243 {
2244 float result = unionArrays[0][i].getFConst() -
2245 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002246 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302247 }
2248 }
2249 else
2250 UNREACHABLE();
2251 break;
2252
Arun Patole7fa33552015-06-10 15:15:18 +05302253 case EOpMul:
2254 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2255 (*sequence)[1]->getAsTyped()->isMatrix())
2256 {
2257 // Perform component-wise matrix multiplication.
2258 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002259 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302260 angle::Matrix<float> result =
2261 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2262 SetUnionArrayFromMatrix(result, resultArray);
2263 }
2264 else
2265 UNREACHABLE();
2266 break;
2267
2268 case EOpOuterProduct:
2269 if (basicType == EbtFloat)
2270 {
2271 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2272 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2273 resultArray = new TConstantUnion[numRows * numCols];
2274 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002275 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2276 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302277 SetUnionArrayFromMatrix(result, resultArray);
2278 }
2279 else
2280 UNREACHABLE();
2281 break;
2282
Arun Patole274f0702015-05-05 13:33:30 +05302283 default:
2284 UNREACHABLE();
2285 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2286 return nullptr;
2287 }
2288 }
2289 else if (paramsCount == 3)
2290 {
2291 //
2292 // Ternary built-in
2293 //
2294 switch (op)
2295 {
2296 case EOpClamp:
2297 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002298 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302299 for (size_t i = 0; i < maxObjectSize; i++)
2300 {
2301 switch (basicType)
2302 {
2303 case EbtFloat:
2304 {
2305 float x = unionArrays[0][i].getFConst();
2306 float min = unionArrays[1][i].getFConst();
2307 float max = unionArrays[2][i].getFConst();
2308 // Results are undefined if min > max.
2309 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002310 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302311 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002312 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302313 }
2314 break;
2315 case EbtInt:
2316 {
2317 int x = unionArrays[0][i].getIConst();
2318 int min = unionArrays[1][i].getIConst();
2319 int max = unionArrays[2][i].getIConst();
2320 // Results are undefined if min > max.
2321 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002322 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302323 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002324 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302325 }
2326 break;
2327 case EbtUInt:
2328 {
2329 unsigned int x = unionArrays[0][i].getUConst();
2330 unsigned int min = unionArrays[1][i].getUConst();
2331 unsigned int max = unionArrays[2][i].getUConst();
2332 // Results are undefined if min > max.
2333 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002334 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302335 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002336 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302337 }
2338 break;
2339 default:
2340 UNREACHABLE();
2341 break;
2342 }
2343 }
2344 }
2345 break;
2346
Arun Patolebf790422015-05-18 17:53:04 +05302347 case EOpMix:
2348 {
2349 if (basicType == EbtFloat)
2350 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002351 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302352 for (size_t i = 0; i < maxObjectSize; i++)
2353 {
2354 float x = unionArrays[0][i].getFConst();
2355 float y = unionArrays[1][i].getFConst();
2356 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2357 if (type == EbtFloat)
2358 {
2359 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2360 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002361 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302362 }
2363 else // 3rd parameter is EbtBool
2364 {
2365 ASSERT(type == EbtBool);
2366 // Selects which vector each returned component comes from.
2367 // For a component of a that is false, the corresponding component of x is returned.
2368 // For a component of a that is true, the corresponding component of y is returned.
2369 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002370 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302371 }
2372 }
2373 }
2374 else
2375 UNREACHABLE();
2376 }
2377 break;
2378
2379 case EOpSmoothStep:
2380 {
2381 if (basicType == EbtFloat)
2382 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002383 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302384 for (size_t i = 0; i < maxObjectSize; i++)
2385 {
2386 float edge0 = unionArrays[0][i].getFConst();
2387 float edge1 = unionArrays[1][i].getFConst();
2388 float x = unionArrays[2][i].getFConst();
2389 // Results are undefined if edge0 >= edge1.
2390 if (edge0 >= edge1)
2391 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002392 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302393 }
2394 else
2395 {
2396 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2397 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2398 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002399 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302400 }
2401 }
2402 }
2403 else
2404 UNREACHABLE();
2405 }
2406 break;
2407
Arun Patole1155ddd2015-06-05 18:04:36 +05302408 case EOpFaceForward:
2409 if (basicType == EbtFloat)
2410 {
2411 // genType faceforward(genType N, genType I, genType Nref) :
2412 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002413 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302414 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2415 for (size_t i = 0; i < maxObjectSize; i++)
2416 {
2417 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002418 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302419 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002420 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302421 }
2422 }
2423 else
2424 UNREACHABLE();
2425 break;
2426
2427 case EOpRefract:
2428 if (basicType == EbtFloat)
2429 {
2430 // genType refract(genType I, genType N, float eta) :
2431 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2432 // return the refraction vector. The result is computed by
2433 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2434 // if (k < 0.0)
2435 // return genType(0.0)
2436 // else
2437 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002438 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302439 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2440 for (size_t i = 0; i < maxObjectSize; i++)
2441 {
2442 float eta = unionArrays[2][i].getFConst();
2443 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2444 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002445 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302446 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002447 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302448 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2449 }
2450 }
2451 else
2452 UNREACHABLE();
2453 break;
2454
Arun Patole274f0702015-05-05 13:33:30 +05302455 default:
2456 UNREACHABLE();
2457 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2458 return nullptr;
2459 }
2460 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002461 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302462}
2463
2464// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002465TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2466{
2467 if (hashFunction == NULL || name.empty())
2468 return name;
2469 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2470 TStringStream stream;
2471 stream << HASHED_NAME_PREFIX << std::hex << number;
2472 TString hashedName = stream.str();
2473 return hashedName;
2474}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002475
2476void TIntermTraverser::updateTree()
2477{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002478 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2479 {
2480 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2481 ASSERT(insertion.parent);
2482 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2483 ASSERT(inserted);
2484 UNUSED_ASSERTION_VARIABLE(inserted);
2485 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002486 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2487 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002488 const NodeUpdateEntry &replacement = mReplacements[ii];
2489 ASSERT(replacement.parent);
2490 bool replaced = replacement.parent->replaceChildNode(
2491 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002492 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002493 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002494
Olli Etuahocd94ef92015-04-16 19:18:10 +03002495 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002496 {
2497 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002498 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002499 // be replaced, we need to make sure we don't update the replaced
2500 // node; instead, we update the replacement node.
2501 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2502 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002503 NodeUpdateEntry &replacement2 = mReplacements[jj];
2504 if (replacement2.parent == replacement.original)
2505 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002506 }
2507 }
2508 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002509 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2510 {
2511 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2512 ASSERT(replacement.parent);
2513 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2514 replacement.original, replacement.replacements);
2515 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002516 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002517 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002518
2519 mInsertions.clear();
2520 mReplacements.clear();
2521 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002522}