blob: 187ad143b1e2cd138ca7c1cf9427d16fe77094c6 [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
Olli Etuahod7a25242015-08-18 13:49:45 +0300398TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
399{
400 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
401 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
402 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
403 mLine = node.mLine;
404}
405
406TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
407{
408 size_t arraySize = mType.getObjectSize();
409 mUnionArrayPointer = new TConstantUnion[arraySize];
410 for (size_t i = 0u; i < arraySize; ++i)
411 {
412 mUnionArrayPointer[i] = node.mUnionArrayPointer[i];
413 }
414}
415
416TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
417 : TIntermOperator(node),
418 mName(node.mName),
419 mUserDefined(node.mUserDefined),
420 mFunctionId(node.mFunctionId),
421 mOptimize(node.mOptimize),
422 mDebug(node.mDebug),
423 mUseEmulatedFunction(node.mUseEmulatedFunction),
424 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
425{
426 for (TIntermNode *child : node.mSequence)
427 {
428 TIntermTyped *typedChild = child->getAsTyped();
429 ASSERT(typedChild != nullptr);
430 TIntermTyped *childCopy = typedChild->deepCopy();
431 mSequence.push_back(childCopy);
432 }
433}
434
435TIntermBinary::TIntermBinary(const TIntermBinary &node)
436 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
437{
438 TIntermTyped *leftCopy = node.mLeft->deepCopy();
439 TIntermTyped *rightCopy = node.mRight->deepCopy();
440 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
441 mLeft = leftCopy;
442 mRight = rightCopy;
443}
444
445TIntermUnary::TIntermUnary(const TIntermUnary &node)
446 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
447{
448 TIntermTyped *operandCopy = node.mOperand->deepCopy();
449 ASSERT(operandCopy != nullptr);
450 mOperand = operandCopy;
451}
452
453TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
454{
455 // Only supported for ternary nodes, not if statements.
456 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
457 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
458 ASSERT(trueTyped != nullptr);
459 ASSERT(falseTyped != nullptr);
460 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
461 TIntermTyped *trueCopy = trueTyped->deepCopy();
462 TIntermTyped *falseCopy = falseTyped->deepCopy();
463 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
464 mCondition = conditionCopy;
465 mTrueBlock = trueCopy;
466 mFalseBlock = falseCopy;
467}
468
Jamie Madillb1a85f42014-08-19 15:23:24 -0400469//
470// Say whether or not an operation node changes the value of a variable.
471//
472bool TIntermOperator::isAssignment() const
473{
474 switch (mOp)
475 {
476 case EOpPostIncrement:
477 case EOpPostDecrement:
478 case EOpPreIncrement:
479 case EOpPreDecrement:
480 case EOpAssign:
481 case EOpAddAssign:
482 case EOpSubAssign:
483 case EOpMulAssign:
484 case EOpVectorTimesMatrixAssign:
485 case EOpVectorTimesScalarAssign:
486 case EOpMatrixTimesScalarAssign:
487 case EOpMatrixTimesMatrixAssign:
488 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200489 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200490 case EOpBitShiftLeftAssign:
491 case EOpBitShiftRightAssign:
492 case EOpBitwiseAndAssign:
493 case EOpBitwiseXorAssign:
494 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400495 return true;
496 default:
497 return false;
498 }
499}
500
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300501bool TIntermOperator::isMultiplication() const
502{
503 switch (mOp)
504 {
505 case EOpMul:
506 case EOpMatrixTimesMatrix:
507 case EOpMatrixTimesVector:
508 case EOpMatrixTimesScalar:
509 case EOpVectorTimesMatrix:
510 case EOpVectorTimesScalar:
511 return true;
512 default:
513 return false;
514 }
515}
516
Jamie Madillb1a85f42014-08-19 15:23:24 -0400517//
518// returns true if the operator is for one of the constructors
519//
520bool TIntermOperator::isConstructor() const
521{
522 switch (mOp)
523 {
524 case EOpConstructVec2:
525 case EOpConstructVec3:
526 case EOpConstructVec4:
527 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400528 case EOpConstructMat2x3:
529 case EOpConstructMat2x4:
530 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400531 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400532 case EOpConstructMat3x4:
533 case EOpConstructMat4x2:
534 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400535 case EOpConstructMat4:
536 case EOpConstructFloat:
537 case EOpConstructIVec2:
538 case EOpConstructIVec3:
539 case EOpConstructIVec4:
540 case EOpConstructInt:
541 case EOpConstructUVec2:
542 case EOpConstructUVec3:
543 case EOpConstructUVec4:
544 case EOpConstructUInt:
545 case EOpConstructBVec2:
546 case EOpConstructBVec3:
547 case EOpConstructBVec4:
548 case EOpConstructBool:
549 case EOpConstructStruct:
550 return true;
551 default:
552 return false;
553 }
554}
555
556//
557// Make sure the type of a unary operator is appropriate for its
558// combination of operation and operand type.
559//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200560void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400561{
562 switch (mOp)
563 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200564 case EOpFloatBitsToInt:
565 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200566 case EOpIntBitsToFloat:
567 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200568 case EOpPackSnorm2x16:
569 case EOpPackUnorm2x16:
570 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200571 case EOpUnpackSnorm2x16:
572 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200573 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530574 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200575 case EOpUnpackHalf2x16:
576 mType.setPrecision(EbpMedium);
577 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400578 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200579 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400580 }
581
Olli Etuahof6c694b2015-03-26 14:50:53 +0200582 if (funcReturnType != nullptr)
583 {
584 if (funcReturnType->getBasicType() == EbtBool)
585 {
586 // Bool types should not have precision.
587 setType(*funcReturnType);
588 }
589 else
590 {
591 // Precision of the node has been set based on the operand.
592 setTypePreservePrecision(*funcReturnType);
593 }
594 }
595
Jamie Madillb1a85f42014-08-19 15:23:24 -0400596 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400597}
598
599//
600// Establishes the type of the resultant operation, as well as
601// makes the operator the correct one for the operands.
602//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200603// For lots of operations it should already be established that the operand
604// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400605//
606bool TIntermBinary::promote(TInfoSink &infoSink)
607{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200608 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400609
Jamie Madillb1a85f42014-08-19 15:23:24 -0400610 //
611 // Base assumption: just make the type the same as the left
612 // operand. Then only deviations from this need be coded.
613 //
614 setType(mLeft->getType());
615
616 // The result gets promoted to the highest precision.
617 TPrecision higherPrecision = GetHigherPrecision(
618 mLeft->getPrecision(), mRight->getPrecision());
619 getTypePointer()->setPrecision(higherPrecision);
620
621 // Binary operations results in temporary variables unless both
622 // operands are const.
623 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
624 {
625 getTypePointer()->setQualifier(EvqTemporary);
626 }
627
628 const int nominalSize =
629 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
630
631 //
632 // All scalars or structs. Code after this test assumes this case is removed!
633 //
634 if (nominalSize == 1)
635 {
636 switch (mOp)
637 {
638 //
639 // Promote to conditional
640 //
641 case EOpEqual:
642 case EOpNotEqual:
643 case EOpLessThan:
644 case EOpGreaterThan:
645 case EOpLessThanEqual:
646 case EOpGreaterThanEqual:
647 setType(TType(EbtBool, EbpUndefined));
648 break;
649
650 //
651 // And and Or operate on conditionals
652 //
653 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200654 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400655 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200656 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400657 setType(TType(EbtBool, EbpUndefined));
658 break;
659
660 default:
661 break;
662 }
663 return true;
664 }
665
666 // If we reach here, at least one of the operands is vector or matrix.
667 // The other operand could be a scalar, vector, or matrix.
668 // Can these two operands be combined?
669 //
670 TBasicType basicType = mLeft->getBasicType();
671 switch (mOp)
672 {
673 case EOpMul:
674 if (!mLeft->isMatrix() && mRight->isMatrix())
675 {
676 if (mLeft->isVector())
677 {
678 mOp = EOpVectorTimesMatrix;
679 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700680 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400681 }
682 else
683 {
684 mOp = EOpMatrixTimesScalar;
685 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700686 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687 }
688 }
689 else if (mLeft->isMatrix() && !mRight->isMatrix())
690 {
691 if (mRight->isVector())
692 {
693 mOp = EOpMatrixTimesVector;
694 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700695 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400696 }
697 else
698 {
699 mOp = EOpMatrixTimesScalar;
700 }
701 }
702 else if (mLeft->isMatrix() && mRight->isMatrix())
703 {
704 mOp = EOpMatrixTimesMatrix;
705 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700706 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400707 }
708 else if (!mLeft->isMatrix() && !mRight->isMatrix())
709 {
710 if (mLeft->isVector() && mRight->isVector())
711 {
712 // leave as component product
713 }
714 else if (mLeft->isVector() || mRight->isVector())
715 {
716 mOp = EOpVectorTimesScalar;
717 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700718 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400719 }
720 }
721 else
722 {
723 infoSink.info.message(EPrefixInternalError, getLine(),
724 "Missing elses");
725 return false;
726 }
727
728 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
729 {
730 return false;
731 }
732 break;
733
734 case EOpMulAssign:
735 if (!mLeft->isMatrix() && mRight->isMatrix())
736 {
737 if (mLeft->isVector())
738 {
739 mOp = EOpVectorTimesMatrixAssign;
740 }
741 else
742 {
743 return false;
744 }
745 }
746 else if (mLeft->isMatrix() && !mRight->isMatrix())
747 {
748 if (mRight->isVector())
749 {
750 return false;
751 }
752 else
753 {
754 mOp = EOpMatrixTimesScalarAssign;
755 }
756 }
757 else if (mLeft->isMatrix() && mRight->isMatrix())
758 {
759 mOp = EOpMatrixTimesMatrixAssign;
760 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700761 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400762 }
763 else if (!mLeft->isMatrix() && !mRight->isMatrix())
764 {
765 if (mLeft->isVector() && mRight->isVector())
766 {
767 // leave as component product
768 }
769 else if (mLeft->isVector() || mRight->isVector())
770 {
771 if (!mLeft->isVector())
772 return false;
773 mOp = EOpVectorTimesScalarAssign;
774 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700775 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776 }
777 }
778 else
779 {
780 infoSink.info.message(EPrefixInternalError, getLine(),
781 "Missing elses");
782 return false;
783 }
784
785 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
786 {
787 return false;
788 }
789 break;
790
791 case EOpAssign:
792 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200793 // No more additional checks are needed.
794 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
795 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
796 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797 case EOpAdd:
798 case EOpSub:
799 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200800 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200801 case EOpBitShiftLeft:
802 case EOpBitShiftRight:
803 case EOpBitwiseAnd:
804 case EOpBitwiseXor:
805 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400806 case EOpAddAssign:
807 case EOpSubAssign:
808 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200809 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200810 case EOpBitShiftLeftAssign:
811 case EOpBitShiftRightAssign:
812 case EOpBitwiseAndAssign:
813 case EOpBitwiseXorAssign:
814 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400815 if ((mLeft->isMatrix() && mRight->isVector()) ||
816 (mLeft->isVector() && mRight->isMatrix()))
817 {
818 return false;
819 }
820
821 // Are the sizes compatible?
822 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
823 mLeft->getSecondarySize() != mRight->getSecondarySize())
824 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200825 // If the nominal sizes of operands do not match:
826 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400827 if (!mLeft->isScalar() && !mRight->isScalar())
828 return false;
829
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200830 // In the case of compound assignment other than multiply-assign,
831 // the right side needs to be a scalar. Otherwise a vector/matrix
832 // would be assigned to a scalar. A scalar can't be shifted by a
833 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200834 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200835 (isAssignment() ||
836 mOp == EOpBitShiftLeft ||
837 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200838 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400839 }
840
841 {
842 const int secondarySize = std::max(
843 mLeft->getSecondarySize(), mRight->getSecondarySize());
844 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700845 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200846 if (mLeft->isArray())
847 {
848 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
849 mType.setArraySize(mLeft->getArraySize());
850 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400851 }
852 break;
853
854 case EOpEqual:
855 case EOpNotEqual:
856 case EOpLessThan:
857 case EOpGreaterThan:
858 case EOpLessThanEqual:
859 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200860 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
861 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400862 setType(TType(EbtBool, EbpUndefined));
863 break;
864
865 default:
866 return false;
867 }
868 return true;
869}
870
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300871TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
872{
873 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
874 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
875 if (leftConstant == nullptr || rightConstant == nullptr)
876 {
877 return nullptr;
878 }
879 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300880 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300881}
882
Olli Etuaho95310b02015-06-02 17:43:38 +0300883TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
884{
885 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
886 if (operandConstant == nullptr)
887 {
888 return nullptr;
889 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530890
891 TConstantUnion *constArray = nullptr;
892 switch (mOp)
893 {
894 case EOpAny:
895 case EOpAll:
896 case EOpLength:
897 case EOpTranspose:
898 case EOpDeterminant:
899 case EOpInverse:
900 case EOpPackSnorm2x16:
901 case EOpUnpackSnorm2x16:
902 case EOpPackUnorm2x16:
903 case EOpUnpackUnorm2x16:
904 case EOpPackHalf2x16:
905 case EOpUnpackHalf2x16:
906 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
907 break;
908 default:
909 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
910 break;
911 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300912 return CreateFoldedNode(constArray, this);
913}
914
915TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
916{
917 // Make sure that all params are constant before actual constant folding.
918 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300919 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300920 if (param->getAsConstantUnion() == nullptr)
921 {
922 return nullptr;
923 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300924 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300925 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
926 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300927}
928
Jamie Madillb1a85f42014-08-19 15:23:24 -0400929//
930// The fold functions see if an operation on a constant can be done in place,
931// without generating run-time code.
932//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300933// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400934//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300935TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
936{
937 TConstantUnion *leftArray = getUnionArrayPointer();
938 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
939
940 if (!leftArray)
941 return nullptr;
942 if (!rightArray)
943 return nullptr;
944
945 size_t objectSize = getType().getObjectSize();
946
947 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
948 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
949 {
950 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
951 }
952 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
953 {
954 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
955 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
956 objectSize = rightNode->getType().getObjectSize();
957 }
958
959 TConstantUnion *resultArray = nullptr;
960
961 switch(op)
962 {
963 case EOpAdd:
964 resultArray = new TConstantUnion[objectSize];
965 for (size_t i = 0; i < objectSize; i++)
966 resultArray[i] = leftArray[i] + rightArray[i];
967 break;
968 case EOpSub:
969 resultArray = new TConstantUnion[objectSize];
970 for (size_t i = 0; i < objectSize; i++)
971 resultArray[i] = leftArray[i] - rightArray[i];
972 break;
973
974 case EOpMul:
975 case EOpVectorTimesScalar:
976 case EOpMatrixTimesScalar:
977 resultArray = new TConstantUnion[objectSize];
978 for (size_t i = 0; i < objectSize; i++)
979 resultArray[i] = leftArray[i] * rightArray[i];
980 break;
981
982 case EOpMatrixTimesMatrix:
983 {
984 if (getType().getBasicType() != EbtFloat ||
985 rightNode->getBasicType() != EbtFloat)
986 {
987 infoSink.info.message(
988 EPrefixInternalError, getLine(),
989 "Constant Folding cannot be done for matrix multiply");
990 return nullptr;
991 }
992
993 const int leftCols = getCols();
994 const int leftRows = getRows();
995 const int rightCols = rightNode->getType().getCols();
996 const int rightRows = rightNode->getType().getRows();
997 const int resultCols = rightCols;
998 const int resultRows = leftRows;
999
1000 resultArray = new TConstantUnion[resultCols * resultRows];
1001 for (int row = 0; row < resultRows; row++)
1002 {
1003 for (int column = 0; column < resultCols; column++)
1004 {
1005 resultArray[resultRows * column + row].setFConst(0.0f);
1006 for (int i = 0; i < leftCols; i++)
1007 {
1008 resultArray[resultRows * column + row].setFConst(
1009 resultArray[resultRows * column + row].getFConst() +
1010 leftArray[i * leftRows + row].getFConst() *
1011 rightArray[column * rightRows + i].getFConst());
1012 }
1013 }
1014 }
1015 }
1016 break;
1017
1018 case EOpDiv:
1019 case EOpIMod:
1020 {
1021 resultArray = new TConstantUnion[objectSize];
1022 for (size_t i = 0; i < objectSize; i++)
1023 {
1024 switch (getType().getBasicType())
1025 {
1026 case EbtFloat:
1027 if (rightArray[i] == 0.0f)
1028 {
1029 infoSink.info.message(EPrefixWarning, getLine(),
1030 "Divide by zero error during constant folding");
1031 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1032 }
1033 else
1034 {
1035 ASSERT(op == EOpDiv);
1036 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1037 }
1038 break;
1039
1040 case EbtInt:
1041 if (rightArray[i] == 0)
1042 {
1043 infoSink.info.message(EPrefixWarning, getLine(),
1044 "Divide by zero error during constant folding");
1045 resultArray[i].setIConst(INT_MAX);
1046 }
1047 else
1048 {
1049 if (op == EOpDiv)
1050 {
1051 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1052 }
1053 else
1054 {
1055 ASSERT(op == EOpIMod);
1056 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1057 }
1058 }
1059 break;
1060
1061 case EbtUInt:
1062 if (rightArray[i] == 0)
1063 {
1064 infoSink.info.message(EPrefixWarning, getLine(),
1065 "Divide by zero error during constant folding");
1066 resultArray[i].setUConst(UINT_MAX);
1067 }
1068 else
1069 {
1070 if (op == EOpDiv)
1071 {
1072 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1073 }
1074 else
1075 {
1076 ASSERT(op == EOpIMod);
1077 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1078 }
1079 }
1080 break;
1081
1082 default:
1083 infoSink.info.message(EPrefixInternalError, getLine(),
1084 "Constant folding cannot be done for \"/\"");
1085 return nullptr;
1086 }
1087 }
1088 }
1089 break;
1090
1091 case EOpMatrixTimesVector:
1092 {
1093 if (rightNode->getBasicType() != EbtFloat)
1094 {
1095 infoSink.info.message(EPrefixInternalError, getLine(),
1096 "Constant Folding cannot be done for matrix times vector");
1097 return nullptr;
1098 }
1099
1100 const int matrixCols = getCols();
1101 const int matrixRows = getRows();
1102
1103 resultArray = new TConstantUnion[matrixRows];
1104
1105 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1106 {
1107 resultArray[matrixRow].setFConst(0.0f);
1108 for (int col = 0; col < matrixCols; col++)
1109 {
1110 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1111 leftArray[col * matrixRows + matrixRow].getFConst() *
1112 rightArray[col].getFConst());
1113 }
1114 }
1115 }
1116 break;
1117
1118 case EOpVectorTimesMatrix:
1119 {
1120 if (getType().getBasicType() != EbtFloat)
1121 {
1122 infoSink.info.message(EPrefixInternalError, getLine(),
1123 "Constant Folding cannot be done for vector times matrix");
1124 return nullptr;
1125 }
1126
1127 const int matrixCols = rightNode->getType().getCols();
1128 const int matrixRows = rightNode->getType().getRows();
1129
1130 resultArray = new TConstantUnion[matrixCols];
1131
1132 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1133 {
1134 resultArray[matrixCol].setFConst(0.0f);
1135 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1136 {
1137 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1138 leftArray[matrixRow].getFConst() *
1139 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1140 }
1141 }
1142 }
1143 break;
1144
1145 case EOpLogicalAnd:
1146 {
1147 resultArray = new TConstantUnion[objectSize];
1148 for (size_t i = 0; i < objectSize; i++)
1149 {
1150 resultArray[i] = leftArray[i] && rightArray[i];
1151 }
1152 }
1153 break;
1154
1155 case EOpLogicalOr:
1156 {
1157 resultArray = new TConstantUnion[objectSize];
1158 for (size_t i = 0; i < objectSize; i++)
1159 {
1160 resultArray[i] = leftArray[i] || rightArray[i];
1161 }
1162 }
1163 break;
1164
1165 case EOpLogicalXor:
1166 {
1167 resultArray = new TConstantUnion[objectSize];
1168 for (size_t i = 0; i < objectSize; i++)
1169 {
1170 switch (getType().getBasicType())
1171 {
1172 case EbtBool:
1173 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1174 break;
1175 default:
1176 UNREACHABLE();
1177 break;
1178 }
1179 }
1180 }
1181 break;
1182
1183 case EOpBitwiseAnd:
1184 resultArray = new TConstantUnion[objectSize];
1185 for (size_t i = 0; i < objectSize; i++)
1186 resultArray[i] = leftArray[i] & rightArray[i];
1187 break;
1188 case EOpBitwiseXor:
1189 resultArray = new TConstantUnion[objectSize];
1190 for (size_t i = 0; i < objectSize; i++)
1191 resultArray[i] = leftArray[i] ^ rightArray[i];
1192 break;
1193 case EOpBitwiseOr:
1194 resultArray = new TConstantUnion[objectSize];
1195 for (size_t i = 0; i < objectSize; i++)
1196 resultArray[i] = leftArray[i] | rightArray[i];
1197 break;
1198 case EOpBitShiftLeft:
1199 resultArray = new TConstantUnion[objectSize];
1200 for (size_t i = 0; i < objectSize; i++)
1201 resultArray[i] = leftArray[i] << rightArray[i];
1202 break;
1203 case EOpBitShiftRight:
1204 resultArray = new TConstantUnion[objectSize];
1205 for (size_t i = 0; i < objectSize; i++)
1206 resultArray[i] = leftArray[i] >> rightArray[i];
1207 break;
1208
1209 case EOpLessThan:
1210 ASSERT(objectSize == 1);
1211 resultArray = new TConstantUnion[1];
1212 resultArray->setBConst(*leftArray < *rightArray);
1213 break;
1214
1215 case EOpGreaterThan:
1216 ASSERT(objectSize == 1);
1217 resultArray = new TConstantUnion[1];
1218 resultArray->setBConst(*leftArray > *rightArray);
1219 break;
1220
1221 case EOpLessThanEqual:
1222 ASSERT(objectSize == 1);
1223 resultArray = new TConstantUnion[1];
1224 resultArray->setBConst(!(*leftArray > *rightArray));
1225 break;
1226
1227 case EOpGreaterThanEqual:
1228 ASSERT(objectSize == 1);
1229 resultArray = new TConstantUnion[1];
1230 resultArray->setBConst(!(*leftArray < *rightArray));
1231 break;
1232
1233 case EOpEqual:
1234 case EOpNotEqual:
1235 {
1236 resultArray = new TConstantUnion[1];
1237 bool equal = true;
1238 if (getType().getBasicType() == EbtStruct)
1239 {
1240 equal = CompareStructure(getType(), rightArray, leftArray);
1241 }
1242 else
1243 {
1244 for (size_t i = 0; i < objectSize; i++)
1245 {
1246 if (leftArray[i] != rightArray[i])
1247 {
1248 equal = false;
1249 break; // break out of for loop
1250 }
1251 }
1252 }
1253 if (op == EOpEqual)
1254 {
1255 resultArray->setBConst(equal);
1256 }
1257 else
1258 {
1259 resultArray->setBConst(!equal);
1260 }
1261 }
1262 break;
1263
1264 default:
1265 infoSink.info.message(
1266 EPrefixInternalError, getLine(),
1267 "Invalid operator for constant folding");
1268 return nullptr;
1269 }
1270 return resultArray;
1271}
1272
1273//
1274// The fold functions see if an operation on a constant can be done in place,
1275// without generating run-time code.
1276//
Olli Etuaho95310b02015-06-02 17:43:38 +03001277// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001278//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301279TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001280{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301281 //
1282 // Do operations where the return type has a different number of components compared to the operand type.
1283 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001284
Arun Patoleab2b9a22015-07-06 18:27:56 +05301285 TConstantUnion *operandArray = getUnionArrayPointer();
1286 if (!operandArray)
1287 return nullptr;
1288
1289 size_t objectSize = getType().getObjectSize();
1290 TConstantUnion *resultArray = nullptr;
1291 switch (op)
1292 {
1293 case EOpAny:
1294 if (getType().getBasicType() == EbtBool)
1295 {
1296 resultArray = new TConstantUnion();
1297 resultArray->setBConst(false);
1298 for (size_t i = 0; i < objectSize; i++)
1299 {
1300 if (operandArray[i].getBConst())
1301 {
1302 resultArray->setBConst(true);
1303 break;
1304 }
1305 }
1306 break;
1307 }
1308 else
1309 {
1310 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1311 return nullptr;
1312 }
1313
1314 case EOpAll:
1315 if (getType().getBasicType() == EbtBool)
1316 {
1317 resultArray = new TConstantUnion();
1318 resultArray->setBConst(true);
1319 for (size_t i = 0; i < objectSize; i++)
1320 {
1321 if (!operandArray[i].getBConst())
1322 {
1323 resultArray->setBConst(false);
1324 break;
1325 }
1326 }
1327 break;
1328 }
1329 else
1330 {
1331 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1332 return nullptr;
1333 }
1334
1335 case EOpLength:
1336 if (getType().getBasicType() == EbtFloat)
1337 {
1338 resultArray = new TConstantUnion();
1339 resultArray->setFConst(VectorLength(operandArray, objectSize));
1340 break;
1341 }
1342 else
1343 {
1344 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1345 return nullptr;
1346 }
1347
1348 case EOpTranspose:
1349 if (getType().getBasicType() == EbtFloat)
1350 {
1351 resultArray = new TConstantUnion[objectSize];
1352 angle::Matrix<float> result =
1353 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1354 SetUnionArrayFromMatrix(result, resultArray);
1355 break;
1356 }
1357 else
1358 {
1359 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1360 return nullptr;
1361 }
1362
1363 case EOpDeterminant:
1364 if (getType().getBasicType() == EbtFloat)
1365 {
1366 unsigned int size = getType().getNominalSize();
1367 ASSERT(size >= 2 && size <= 4);
1368 resultArray = new TConstantUnion();
1369 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1370 break;
1371 }
1372 else
1373 {
1374 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1375 return nullptr;
1376 }
1377
1378 case EOpInverse:
1379 if (getType().getBasicType() == EbtFloat)
1380 {
1381 unsigned int size = getType().getNominalSize();
1382 ASSERT(size >= 2 && size <= 4);
1383 resultArray = new TConstantUnion[objectSize];
1384 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1385 SetUnionArrayFromMatrix(result, resultArray);
1386 break;
1387 }
1388 else
1389 {
1390 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1391 return nullptr;
1392 }
1393
1394 case EOpPackSnorm2x16:
1395 if (getType().getBasicType() == EbtFloat)
1396 {
1397 ASSERT(getType().getNominalSize() == 2);
1398 resultArray = new TConstantUnion();
1399 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1400 break;
1401 }
1402 else
1403 {
1404 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1405 return nullptr;
1406 }
1407
1408 case EOpUnpackSnorm2x16:
1409 if (getType().getBasicType() == EbtUInt)
1410 {
1411 resultArray = new TConstantUnion[2];
1412 float f1, f2;
1413 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1414 resultArray[0].setFConst(f1);
1415 resultArray[1].setFConst(f2);
1416 break;
1417 }
1418 else
1419 {
1420 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1421 return nullptr;
1422 }
1423
1424 case EOpPackUnorm2x16:
1425 if (getType().getBasicType() == EbtFloat)
1426 {
1427 ASSERT(getType().getNominalSize() == 2);
1428 resultArray = new TConstantUnion();
1429 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1430 break;
1431 }
1432 else
1433 {
1434 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1435 return nullptr;
1436 }
1437
1438 case EOpUnpackUnorm2x16:
1439 if (getType().getBasicType() == EbtUInt)
1440 {
1441 resultArray = new TConstantUnion[2];
1442 float f1, f2;
1443 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1444 resultArray[0].setFConst(f1);
1445 resultArray[1].setFConst(f2);
1446 break;
1447 }
1448 else
1449 {
1450 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1451 return nullptr;
1452 }
1453
1454 case EOpPackHalf2x16:
1455 if (getType().getBasicType() == EbtFloat)
1456 {
1457 ASSERT(getType().getNominalSize() == 2);
1458 resultArray = new TConstantUnion();
1459 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1460 break;
1461 }
1462 else
1463 {
1464 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1465 return nullptr;
1466 }
1467
1468 case EOpUnpackHalf2x16:
1469 if (getType().getBasicType() == EbtUInt)
1470 {
1471 resultArray = new TConstantUnion[2];
1472 float f1, f2;
1473 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1474 resultArray[0].setFConst(f1);
1475 resultArray[1].setFConst(f2);
1476 break;
1477 }
1478 else
1479 {
1480 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1481 return nullptr;
1482 }
1483 break;
1484
1485 default:
1486 break;
1487 }
1488
1489 return resultArray;
1490}
1491
1492TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1493{
1494 //
1495 // Do unary operations where the return type is the same as operand type.
1496 //
1497
1498 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001499 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301500 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001501
1502 size_t objectSize = getType().getObjectSize();
1503
Arun Patoleab2b9a22015-07-06 18:27:56 +05301504 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1505 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301506 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301507 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301508 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301509 case EOpNegative:
1510 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301511 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301512 case EbtFloat:
1513 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301514 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301515 case EbtInt:
1516 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301517 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301518 case EbtUInt:
1519 resultArray[i].setUConst(static_cast<unsigned int>(
1520 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301521 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301522 default:
1523 infoSink.info.message(
1524 EPrefixInternalError, getLine(),
1525 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301526 return nullptr;
1527 }
1528 break;
1529
Arun Patoleab2b9a22015-07-06 18:27:56 +05301530 case EOpPositive:
1531 switch (getType().getBasicType())
1532 {
1533 case EbtFloat:
1534 resultArray[i].setFConst(operandArray[i].getFConst());
1535 break;
1536 case EbtInt:
1537 resultArray[i].setIConst(operandArray[i].getIConst());
1538 break;
1539 case EbtUInt:
1540 resultArray[i].setUConst(static_cast<unsigned int>(
1541 static_cast<int>(operandArray[i].getUConst())));
1542 break;
1543 default:
1544 infoSink.info.message(
1545 EPrefixInternalError, getLine(),
1546 "Unary operation not folded into constant");
1547 return nullptr;
1548 }
1549 break;
1550
1551 case EOpLogicalNot:
1552 // this code is written for possible future use,
1553 // will not get executed currently
1554 switch (getType().getBasicType())
1555 {
1556 case EbtBool:
1557 resultArray[i].setBConst(!operandArray[i].getBConst());
1558 break;
1559 default:
1560 infoSink.info.message(
1561 EPrefixInternalError, getLine(),
1562 "Unary operation not folded into constant");
1563 return nullptr;
1564 }
1565 break;
1566
1567 case EOpBitwiseNot:
1568 switch (getType().getBasicType())
1569 {
1570 case EbtInt:
1571 resultArray[i].setIConst(~operandArray[i].getIConst());
1572 break;
1573 case EbtUInt:
1574 resultArray[i].setUConst(~operandArray[i].getUConst());
1575 break;
1576 default:
1577 infoSink.info.message(
1578 EPrefixInternalError, getLine(),
1579 "Unary operation not folded into constant");
1580 return nullptr;
1581 }
1582 break;
1583
1584 case EOpRadians:
1585 if (getType().getBasicType() == EbtFloat)
1586 {
1587 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1588 break;
1589 }
1590 infoSink.info.message(
1591 EPrefixInternalError, getLine(),
1592 "Unary operation not folded into constant");
1593 return nullptr;
1594
1595 case EOpDegrees:
1596 if (getType().getBasicType() == EbtFloat)
1597 {
1598 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1599 break;
1600 }
1601 infoSink.info.message(
1602 EPrefixInternalError, getLine(),
1603 "Unary operation not folded into constant");
1604 return nullptr;
1605
1606 case EOpSin:
1607 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1608 return nullptr;
1609 break;
1610
1611 case EOpCos:
1612 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1613 return nullptr;
1614 break;
1615
1616 case EOpTan:
1617 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1618 return nullptr;
1619 break;
1620
1621 case EOpAsin:
1622 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1623 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1624 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1625 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1626 return nullptr;
1627 break;
1628
1629 case EOpAcos:
1630 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1631 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1632 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1633 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1634 return nullptr;
1635 break;
1636
1637 case EOpAtan:
1638 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1639 return nullptr;
1640 break;
1641
1642 case EOpSinh:
1643 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1644 return nullptr;
1645 break;
1646
1647 case EOpCosh:
1648 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1649 return nullptr;
1650 break;
1651
1652 case EOpTanh:
1653 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1654 return nullptr;
1655 break;
1656
1657 case EOpAsinh:
1658 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1659 return nullptr;
1660 break;
1661
1662 case EOpAcosh:
1663 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1664 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1665 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1666 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1667 return nullptr;
1668 break;
1669
1670 case EOpAtanh:
1671 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1672 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1673 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1674 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1675 return nullptr;
1676 break;
1677
1678 case EOpAbs:
1679 switch (getType().getBasicType())
1680 {
1681 case EbtFloat:
1682 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1683 break;
1684 case EbtInt:
1685 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1686 break;
1687 default:
1688 infoSink.info.message(
1689 EPrefixInternalError, getLine(),
1690 "Unary operation not folded into constant");
1691 return nullptr;
1692 }
1693 break;
1694
1695 case EOpSign:
1696 switch (getType().getBasicType())
1697 {
1698 case EbtFloat:
1699 {
1700 float fConst = operandArray[i].getFConst();
1701 float fResult = 0.0f;
1702 if (fConst > 0.0f)
1703 fResult = 1.0f;
1704 else if (fConst < 0.0f)
1705 fResult = -1.0f;
1706 resultArray[i].setFConst(fResult);
1707 }
1708 break;
1709 case EbtInt:
1710 {
1711 int iConst = operandArray[i].getIConst();
1712 int iResult = 0;
1713 if (iConst > 0)
1714 iResult = 1;
1715 else if (iConst < 0)
1716 iResult = -1;
1717 resultArray[i].setIConst(iResult);
1718 }
1719 break;
1720 default:
1721 infoSink.info.message(
1722 EPrefixInternalError, getLine(),
1723 "Unary operation not folded into constant");
1724 return nullptr;
1725 }
1726 break;
1727
1728 case EOpFloor:
1729 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1730 return nullptr;
1731 break;
1732
1733 case EOpTrunc:
1734 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1735 return nullptr;
1736 break;
1737
1738 case EOpRound:
1739 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1740 return nullptr;
1741 break;
1742
1743 case EOpRoundEven:
1744 if (getType().getBasicType() == EbtFloat)
1745 {
1746 float x = operandArray[i].getFConst();
1747 float result;
1748 float fractPart = modff(x, &result);
1749 if (fabsf(fractPart) == 0.5f)
1750 result = 2.0f * roundf(x / 2.0f);
1751 else
1752 result = roundf(x);
1753 resultArray[i].setFConst(result);
1754 break;
1755 }
1756 infoSink.info.message(
1757 EPrefixInternalError, getLine(),
1758 "Unary operation not folded into constant");
1759 return nullptr;
1760
1761 case EOpCeil:
1762 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1763 return nullptr;
1764 break;
1765
1766 case EOpFract:
1767 if (getType().getBasicType() == EbtFloat)
1768 {
1769 float x = operandArray[i].getFConst();
1770 resultArray[i].setFConst(x - floorf(x));
1771 break;
1772 }
1773 infoSink.info.message(
1774 EPrefixInternalError, getLine(),
1775 "Unary operation not folded into constant");
1776 return nullptr;
1777
Arun Patole551279e2015-07-07 18:18:23 +05301778 case EOpIsNan:
1779 if (getType().getBasicType() == EbtFloat)
1780 {
1781 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1782 break;
1783 }
1784 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1785 return nullptr;
1786
1787 case EOpIsInf:
1788 if (getType().getBasicType() == EbtFloat)
1789 {
1790 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1791 break;
1792 }
1793 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1794 return nullptr;
1795
1796 case EOpFloatBitsToInt:
1797 if (getType().getBasicType() == EbtFloat)
1798 {
1799 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1800 break;
1801 }
1802 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1803 return nullptr;
1804
1805 case EOpFloatBitsToUint:
1806 if (getType().getBasicType() == EbtFloat)
1807 {
1808 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1809 break;
1810 }
1811 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1812 return nullptr;
1813
1814 case EOpIntBitsToFloat:
1815 if (getType().getBasicType() == EbtInt)
1816 {
1817 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1818 break;
1819 }
1820 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1821 return nullptr;
1822
1823 case EOpUintBitsToFloat:
1824 if (getType().getBasicType() == EbtUInt)
1825 {
1826 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1827 break;
1828 }
1829 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1830 return nullptr;
1831
Arun Patoleab2b9a22015-07-06 18:27:56 +05301832 case EOpExp:
1833 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1834 return nullptr;
1835 break;
1836
1837 case EOpLog:
1838 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1839 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1840 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1841 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1842 return nullptr;
1843 break;
1844
1845 case EOpExp2:
1846 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1847 return nullptr;
1848 break;
1849
1850 case EOpLog2:
1851 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1852 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1853 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1854 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1855 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1856 return nullptr;
1857 else
1858 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1859 break;
1860
1861 case EOpSqrt:
1862 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1863 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1864 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1865 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1866 return nullptr;
1867 break;
1868
1869 case EOpInverseSqrt:
1870 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1871 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1872 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1873 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1874 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1875 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1876 return nullptr;
1877 else
1878 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1879 break;
1880
1881 case EOpVectorLogicalNot:
1882 if (getType().getBasicType() == EbtBool)
1883 {
1884 resultArray[i].setBConst(!operandArray[i].getBConst());
1885 break;
1886 }
1887 infoSink.info.message(
1888 EPrefixInternalError, getLine(),
1889 "Unary operation not folded into constant");
1890 return nullptr;
1891
1892 case EOpNormalize:
1893 if (getType().getBasicType() == EbtFloat)
1894 {
1895 float x = operandArray[i].getFConst();
1896 float length = VectorLength(operandArray, objectSize);
1897 if (length)
1898 resultArray[i].setFConst(x / length);
1899 else
1900 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1901 &resultArray[i]);
1902 break;
1903 }
1904 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1905 return nullptr;
1906
Arun Patole0c5409f2015-07-08 15:17:53 +05301907 case EOpDFdx:
1908 case EOpDFdy:
1909 case EOpFwidth:
1910 if (getType().getBasicType() == EbtFloat)
1911 {
1912 // Derivatives of constant arguments should be 0.
1913 resultArray[i].setFConst(0.0f);
1914 break;
1915 }
1916 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1917 return nullptr;
1918
Arun Patole1155ddd2015-06-05 18:04:36 +05301919 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301921 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301922 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001923
Arun Patoleab2b9a22015-07-06 18:27:56 +05301924 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001925}
1926
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001927bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1928 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301929{
1930 ASSERT(builtinFunc);
1931
1932 if (getType().getBasicType() == EbtFloat)
1933 {
1934 result->setFConst(builtinFunc(parameter.getFConst()));
1935 return true;
1936 }
1937
1938 infoSink.info.message(
1939 EPrefixInternalError, getLine(),
1940 "Unary operation not folded into constant");
1941 return false;
1942}
1943
Jamie Madillb1a85f42014-08-19 15:23:24 -04001944// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001945TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301946{
Olli Etuahob43846e2015-06-02 18:18:57 +03001947 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301948 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001949 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Arun Patole274f0702015-05-05 13:33:30 +05301950 std::vector<TConstantUnion *> unionArrays(paramsCount);
1951 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001952 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301953 TBasicType basicType = EbtVoid;
1954 TSourceLoc loc;
1955 for (unsigned int i = 0; i < paramsCount; i++)
1956 {
1957 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001958 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301959
1960 if (i == 0)
1961 {
1962 basicType = paramConstant->getType().getBasicType();
1963 loc = paramConstant->getLine();
1964 }
1965 unionArrays[i] = paramConstant->getUnionArrayPointer();
1966 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001967 if (objectSizes[i] > maxObjectSize)
1968 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301969 }
1970
Arun Patole7fa33552015-06-10 15:15:18 +05301971 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1972 {
1973 for (unsigned int i = 0; i < paramsCount; i++)
1974 if (objectSizes[i] != maxObjectSize)
1975 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1976 }
Arun Patole274f0702015-05-05 13:33:30 +05301977
Olli Etuahob43846e2015-06-02 18:18:57 +03001978 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301979 if (paramsCount == 2)
1980 {
1981 //
1982 // Binary built-in
1983 //
1984 switch (op)
1985 {
Arun Patolebf790422015-05-18 17:53:04 +05301986 case EOpAtan:
1987 {
1988 if (basicType == EbtFloat)
1989 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001990 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301991 for (size_t i = 0; i < maxObjectSize; i++)
1992 {
1993 float y = unionArrays[0][i].getFConst();
1994 float x = unionArrays[1][i].getFConst();
1995 // Results are undefined if x and y are both 0.
1996 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001997 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301998 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001999 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302000 }
2001 }
2002 else
2003 UNREACHABLE();
2004 }
2005 break;
2006
2007 case EOpPow:
2008 {
2009 if (basicType == EbtFloat)
2010 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002011 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302012 for (size_t i = 0; i < maxObjectSize; i++)
2013 {
2014 float x = unionArrays[0][i].getFConst();
2015 float y = unionArrays[1][i].getFConst();
2016 // Results are undefined if x < 0.
2017 // Results are undefined if x = 0 and y <= 0.
2018 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002019 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302020 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002021 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302022 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002023 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302024 }
2025 }
2026 else
2027 UNREACHABLE();
2028 }
2029 break;
2030
2031 case EOpMod:
2032 {
2033 if (basicType == EbtFloat)
2034 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002035 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302036 for (size_t i = 0; i < maxObjectSize; i++)
2037 {
2038 float x = unionArrays[0][i].getFConst();
2039 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002040 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302041 }
2042 }
2043 else
2044 UNREACHABLE();
2045 }
2046 break;
2047
Arun Patole274f0702015-05-05 13:33:30 +05302048 case EOpMin:
2049 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002050 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302051 for (size_t i = 0; i < maxObjectSize; i++)
2052 {
2053 switch (basicType)
2054 {
2055 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002056 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302057 break;
2058 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002059 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302060 break;
2061 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002062 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302063 break;
2064 default:
2065 UNREACHABLE();
2066 break;
2067 }
2068 }
2069 }
2070 break;
2071
2072 case EOpMax:
2073 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002074 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302075 for (size_t i = 0; i < maxObjectSize; i++)
2076 {
2077 switch (basicType)
2078 {
2079 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002080 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302081 break;
2082 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002083 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302084 break;
2085 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002086 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302087 break;
2088 default:
2089 UNREACHABLE();
2090 break;
2091 }
2092 }
2093 }
2094 break;
2095
Arun Patolebf790422015-05-18 17:53:04 +05302096 case EOpStep:
2097 {
2098 if (basicType == EbtFloat)
2099 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002100 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302101 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002102 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302103 }
2104 else
2105 UNREACHABLE();
2106 }
2107 break;
2108
Arun Patole9d0b1f92015-05-20 14:27:17 +05302109 case EOpLessThan:
2110 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002111 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302112 for (size_t i = 0; i < maxObjectSize; i++)
2113 {
2114 switch (basicType)
2115 {
2116 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002117 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302118 break;
2119 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002120 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302121 break;
2122 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002123 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302124 break;
2125 default:
2126 UNREACHABLE();
2127 break;
2128 }
2129 }
2130 }
2131 break;
2132
2133 case EOpLessThanEqual:
2134 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002135 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302136 for (size_t i = 0; i < maxObjectSize; i++)
2137 {
2138 switch (basicType)
2139 {
2140 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002141 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302142 break;
2143 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002144 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302145 break;
2146 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002147 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302148 break;
2149 default:
2150 UNREACHABLE();
2151 break;
2152 }
2153 }
2154 }
2155 break;
2156
2157 case EOpGreaterThan:
2158 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002159 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302160 for (size_t i = 0; i < maxObjectSize; i++)
2161 {
2162 switch (basicType)
2163 {
2164 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002165 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302166 break;
2167 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002168 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302169 break;
2170 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002171 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302172 break;
2173 default:
2174 UNREACHABLE();
2175 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002176 }
2177 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302178 }
2179 break;
2180
2181 case EOpGreaterThanEqual:
2182 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002183 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302184 for (size_t i = 0; i < maxObjectSize; i++)
2185 {
2186 switch (basicType)
2187 {
2188 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002189 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302190 break;
2191 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002192 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302193 break;
2194 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002195 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302196 break;
2197 default:
2198 UNREACHABLE();
2199 break;
2200 }
2201 }
2202 }
2203 break;
2204
2205 case EOpVectorEqual:
2206 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002207 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302208 for (size_t i = 0; i < maxObjectSize; i++)
2209 {
2210 switch (basicType)
2211 {
2212 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002213 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302214 break;
2215 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002216 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302217 break;
2218 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002219 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302220 break;
2221 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002222 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302223 break;
2224 default:
2225 UNREACHABLE();
2226 break;
2227 }
2228 }
2229 }
2230 break;
2231
2232 case EOpVectorNotEqual:
2233 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002234 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302235 for (size_t i = 0; i < maxObjectSize; i++)
2236 {
2237 switch (basicType)
2238 {
2239 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002240 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302241 break;
2242 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002243 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 break;
2245 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002246 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302247 break;
2248 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002249 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302250 break;
2251 default:
2252 UNREACHABLE();
2253 break;
2254 }
2255 }
2256 }
2257 break;
2258
Arun Patole1155ddd2015-06-05 18:04:36 +05302259 case EOpDistance:
2260 if (basicType == EbtFloat)
2261 {
2262 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002263 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302264 for (size_t i = 0; i < maxObjectSize; i++)
2265 {
2266 float x = unionArrays[0][i].getFConst();
2267 float y = unionArrays[1][i].getFConst();
2268 distanceArray[i].setFConst(x - y);
2269 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002270 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302271 }
2272 else
2273 UNREACHABLE();
2274 break;
2275
2276 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002277
Arun Patole1155ddd2015-06-05 18:04:36 +05302278 if (basicType == EbtFloat)
2279 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002280 resultArray = new TConstantUnion();
2281 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302282 }
2283 else
2284 UNREACHABLE();
2285 break;
2286
2287 case EOpCross:
2288 if (basicType == EbtFloat && maxObjectSize == 3)
2289 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002290 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302291 float x0 = unionArrays[0][0].getFConst();
2292 float x1 = unionArrays[0][1].getFConst();
2293 float x2 = unionArrays[0][2].getFConst();
2294 float y0 = unionArrays[1][0].getFConst();
2295 float y1 = unionArrays[1][1].getFConst();
2296 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002297 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2298 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2299 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302300 }
2301 else
2302 UNREACHABLE();
2303 break;
2304
2305 case EOpReflect:
2306 if (basicType == EbtFloat)
2307 {
2308 // genType reflect (genType I, genType N) :
2309 // For the incident vector I and surface orientation N, returns the reflection direction:
2310 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002311 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302312 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2313 for (size_t i = 0; i < maxObjectSize; i++)
2314 {
2315 float result = unionArrays[0][i].getFConst() -
2316 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002317 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302318 }
2319 }
2320 else
2321 UNREACHABLE();
2322 break;
2323
Arun Patole7fa33552015-06-10 15:15:18 +05302324 case EOpMul:
2325 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2326 (*sequence)[1]->getAsTyped()->isMatrix())
2327 {
2328 // Perform component-wise matrix multiplication.
2329 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002330 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302331 angle::Matrix<float> result =
2332 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2333 SetUnionArrayFromMatrix(result, resultArray);
2334 }
2335 else
2336 UNREACHABLE();
2337 break;
2338
2339 case EOpOuterProduct:
2340 if (basicType == EbtFloat)
2341 {
2342 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2343 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2344 resultArray = new TConstantUnion[numRows * numCols];
2345 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002346 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2347 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302348 SetUnionArrayFromMatrix(result, resultArray);
2349 }
2350 else
2351 UNREACHABLE();
2352 break;
2353
Arun Patole274f0702015-05-05 13:33:30 +05302354 default:
2355 UNREACHABLE();
2356 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2357 return nullptr;
2358 }
2359 }
2360 else if (paramsCount == 3)
2361 {
2362 //
2363 // Ternary built-in
2364 //
2365 switch (op)
2366 {
2367 case EOpClamp:
2368 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002369 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302370 for (size_t i = 0; i < maxObjectSize; i++)
2371 {
2372 switch (basicType)
2373 {
2374 case EbtFloat:
2375 {
2376 float x = unionArrays[0][i].getFConst();
2377 float min = unionArrays[1][i].getFConst();
2378 float max = unionArrays[2][i].getFConst();
2379 // Results are undefined if min > max.
2380 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002381 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302382 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002383 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302384 }
2385 break;
2386 case EbtInt:
2387 {
2388 int x = unionArrays[0][i].getIConst();
2389 int min = unionArrays[1][i].getIConst();
2390 int max = unionArrays[2][i].getIConst();
2391 // Results are undefined if min > max.
2392 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002393 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302394 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002395 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302396 }
2397 break;
2398 case EbtUInt:
2399 {
2400 unsigned int x = unionArrays[0][i].getUConst();
2401 unsigned int min = unionArrays[1][i].getUConst();
2402 unsigned int max = unionArrays[2][i].getUConst();
2403 // Results are undefined if min > max.
2404 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002405 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302406 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002407 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302408 }
2409 break;
2410 default:
2411 UNREACHABLE();
2412 break;
2413 }
2414 }
2415 }
2416 break;
2417
Arun Patolebf790422015-05-18 17:53:04 +05302418 case EOpMix:
2419 {
2420 if (basicType == EbtFloat)
2421 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002422 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302423 for (size_t i = 0; i < maxObjectSize; i++)
2424 {
2425 float x = unionArrays[0][i].getFConst();
2426 float y = unionArrays[1][i].getFConst();
2427 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2428 if (type == EbtFloat)
2429 {
2430 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2431 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002432 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302433 }
2434 else // 3rd parameter is EbtBool
2435 {
2436 ASSERT(type == EbtBool);
2437 // Selects which vector each returned component comes from.
2438 // For a component of a that is false, the corresponding component of x is returned.
2439 // For a component of a that is true, the corresponding component of y is returned.
2440 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002441 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302442 }
2443 }
2444 }
2445 else
2446 UNREACHABLE();
2447 }
2448 break;
2449
2450 case EOpSmoothStep:
2451 {
2452 if (basicType == EbtFloat)
2453 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002454 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302455 for (size_t i = 0; i < maxObjectSize; i++)
2456 {
2457 float edge0 = unionArrays[0][i].getFConst();
2458 float edge1 = unionArrays[1][i].getFConst();
2459 float x = unionArrays[2][i].getFConst();
2460 // Results are undefined if edge0 >= edge1.
2461 if (edge0 >= edge1)
2462 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002463 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302464 }
2465 else
2466 {
2467 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2468 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2469 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002470 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302471 }
2472 }
2473 }
2474 else
2475 UNREACHABLE();
2476 }
2477 break;
2478
Arun Patole1155ddd2015-06-05 18:04:36 +05302479 case EOpFaceForward:
2480 if (basicType == EbtFloat)
2481 {
2482 // genType faceforward(genType N, genType I, genType Nref) :
2483 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002484 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302485 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2486 for (size_t i = 0; i < maxObjectSize; i++)
2487 {
2488 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002489 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302490 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002491 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302492 }
2493 }
2494 else
2495 UNREACHABLE();
2496 break;
2497
2498 case EOpRefract:
2499 if (basicType == EbtFloat)
2500 {
2501 // genType refract(genType I, genType N, float eta) :
2502 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2503 // return the refraction vector. The result is computed by
2504 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2505 // if (k < 0.0)
2506 // return genType(0.0)
2507 // else
2508 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002509 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302510 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2511 for (size_t i = 0; i < maxObjectSize; i++)
2512 {
2513 float eta = unionArrays[2][i].getFConst();
2514 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2515 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002516 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302517 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002518 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302519 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2520 }
2521 }
2522 else
2523 UNREACHABLE();
2524 break;
2525
Arun Patole274f0702015-05-05 13:33:30 +05302526 default:
2527 UNREACHABLE();
2528 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2529 return nullptr;
2530 }
2531 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002532 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302533}
2534
2535// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002536TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2537{
2538 if (hashFunction == NULL || name.empty())
2539 return name;
2540 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2541 TStringStream stream;
2542 stream << HASHED_NAME_PREFIX << std::hex << number;
2543 TString hashedName = stream.str();
2544 return hashedName;
2545}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002546
2547void TIntermTraverser::updateTree()
2548{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002549 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2550 {
2551 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2552 ASSERT(insertion.parent);
2553 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2554 ASSERT(inserted);
2555 UNUSED_ASSERTION_VARIABLE(inserted);
2556 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002557 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2558 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002559 const NodeUpdateEntry &replacement = mReplacements[ii];
2560 ASSERT(replacement.parent);
2561 bool replaced = replacement.parent->replaceChildNode(
2562 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002563 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002564 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002565
Olli Etuahocd94ef92015-04-16 19:18:10 +03002566 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002567 {
2568 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002569 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002570 // be replaced, we need to make sure we don't update the replaced
2571 // node; instead, we update the replacement node.
2572 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2573 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002574 NodeUpdateEntry &replacement2 = mReplacements[jj];
2575 if (replacement2.parent == replacement.original)
2576 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002577 }
2578 }
2579 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002580 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2581 {
2582 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2583 ASSERT(replacement.parent);
2584 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2585 replacement.original, replacement.replacements);
2586 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002587 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002588 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002589
2590 mInsertions.clear();
2591 mReplacements.clear();
2592 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002593}