blob: d35e88e4fe98707d8a85d0da0f85a35a88e5cffe [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{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300314 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300315 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300316 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300317 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300318 auto it = mSequence.begin() + position;
319 mSequence.insert(it, insertions.begin(), insertions.end());
320 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300321}
322
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200323bool TIntermAggregate::areChildrenConstQualified()
324{
325 for (TIntermNode *&child : mSequence)
326 {
327 TIntermTyped *typed = child->getAsTyped();
328 if (typed && typed->getQualifier() != EvqConst)
329 {
330 return false;
331 }
332 }
333 return true;
334}
335
Olli Etuahod2a67b92014-10-21 16:42:57 +0300336void TIntermAggregate::setPrecisionFromChildren()
337{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300338 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300339 if (getBasicType() == EbtBool)
340 {
341 mType.setPrecision(EbpUndefined);
342 return;
343 }
344
345 TPrecision precision = EbpUndefined;
346 TIntermSequence::iterator childIter = mSequence.begin();
347 while (childIter != mSequence.end())
348 {
349 TIntermTyped *typed = (*childIter)->getAsTyped();
350 if (typed)
351 precision = GetHigherPrecision(typed->getPrecision(), precision);
352 ++childIter;
353 }
354 mType.setPrecision(precision);
355}
356
357void TIntermAggregate::setBuiltInFunctionPrecision()
358{
359 // All built-ins returning bool should be handled as ops, not functions.
360 ASSERT(getBasicType() != EbtBool);
361
362 TPrecision precision = EbpUndefined;
363 TIntermSequence::iterator childIter = mSequence.begin();
364 while (childIter != mSequence.end())
365 {
366 TIntermTyped *typed = (*childIter)->getAsTyped();
367 // ESSL spec section 8: texture functions get their precision from the sampler.
368 if (typed && IsSampler(typed->getBasicType()))
369 {
370 precision = typed->getPrecision();
371 break;
372 }
373 ++childIter;
374 }
375 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
376 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300377 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300378 mType.setPrecision(EbpHigh);
379 else
380 mType.setPrecision(precision);
381}
382
Jamie Madillb1a85f42014-08-19 15:23:24 -0400383bool TIntermSelection::replaceChildNode(
384 TIntermNode *original, TIntermNode *replacement)
385{
386 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
387 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
388 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
389 return false;
390}
391
Olli Etuahoa3a36662015-02-17 13:46:51 +0200392bool TIntermSwitch::replaceChildNode(
393 TIntermNode *original, TIntermNode *replacement)
394{
395 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
396 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
397 return false;
398}
399
400bool TIntermCase::replaceChildNode(
401 TIntermNode *original, TIntermNode *replacement)
402{
403 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
404 return false;
405}
406
Olli Etuahod7a25242015-08-18 13:49:45 +0300407TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
408{
409 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
410 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
411 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
412 mLine = node.mLine;
413}
414
415TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
416{
417 size_t arraySize = mType.getObjectSize();
418 mUnionArrayPointer = new TConstantUnion[arraySize];
419 for (size_t i = 0u; i < arraySize; ++i)
420 {
421 mUnionArrayPointer[i] = node.mUnionArrayPointer[i];
422 }
423}
424
425TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
426 : TIntermOperator(node),
427 mName(node.mName),
428 mUserDefined(node.mUserDefined),
429 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300430 mUseEmulatedFunction(node.mUseEmulatedFunction),
431 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
432{
433 for (TIntermNode *child : node.mSequence)
434 {
435 TIntermTyped *typedChild = child->getAsTyped();
436 ASSERT(typedChild != nullptr);
437 TIntermTyped *childCopy = typedChild->deepCopy();
438 mSequence.push_back(childCopy);
439 }
440}
441
442TIntermBinary::TIntermBinary(const TIntermBinary &node)
443 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
444{
445 TIntermTyped *leftCopy = node.mLeft->deepCopy();
446 TIntermTyped *rightCopy = node.mRight->deepCopy();
447 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
448 mLeft = leftCopy;
449 mRight = rightCopy;
450}
451
452TIntermUnary::TIntermUnary(const TIntermUnary &node)
453 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
454{
455 TIntermTyped *operandCopy = node.mOperand->deepCopy();
456 ASSERT(operandCopy != nullptr);
457 mOperand = operandCopy;
458}
459
460TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
461{
462 // Only supported for ternary nodes, not if statements.
463 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
464 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
465 ASSERT(trueTyped != nullptr);
466 ASSERT(falseTyped != nullptr);
467 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
468 TIntermTyped *trueCopy = trueTyped->deepCopy();
469 TIntermTyped *falseCopy = falseTyped->deepCopy();
470 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
471 mCondition = conditionCopy;
472 mTrueBlock = trueCopy;
473 mFalseBlock = falseCopy;
474}
475
Jamie Madillb1a85f42014-08-19 15:23:24 -0400476//
477// Say whether or not an operation node changes the value of a variable.
478//
479bool TIntermOperator::isAssignment() const
480{
481 switch (mOp)
482 {
483 case EOpPostIncrement:
484 case EOpPostDecrement:
485 case EOpPreIncrement:
486 case EOpPreDecrement:
487 case EOpAssign:
488 case EOpAddAssign:
489 case EOpSubAssign:
490 case EOpMulAssign:
491 case EOpVectorTimesMatrixAssign:
492 case EOpVectorTimesScalarAssign:
493 case EOpMatrixTimesScalarAssign:
494 case EOpMatrixTimesMatrixAssign:
495 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200496 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200497 case EOpBitShiftLeftAssign:
498 case EOpBitShiftRightAssign:
499 case EOpBitwiseAndAssign:
500 case EOpBitwiseXorAssign:
501 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400502 return true;
503 default:
504 return false;
505 }
506}
507
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300508bool TIntermOperator::isMultiplication() const
509{
510 switch (mOp)
511 {
512 case EOpMul:
513 case EOpMatrixTimesMatrix:
514 case EOpMatrixTimesVector:
515 case EOpMatrixTimesScalar:
516 case EOpVectorTimesMatrix:
517 case EOpVectorTimesScalar:
518 return true;
519 default:
520 return false;
521 }
522}
523
Jamie Madillb1a85f42014-08-19 15:23:24 -0400524//
525// returns true if the operator is for one of the constructors
526//
527bool TIntermOperator::isConstructor() const
528{
529 switch (mOp)
530 {
531 case EOpConstructVec2:
532 case EOpConstructVec3:
533 case EOpConstructVec4:
534 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400535 case EOpConstructMat2x3:
536 case EOpConstructMat2x4:
537 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400538 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400539 case EOpConstructMat3x4:
540 case EOpConstructMat4x2:
541 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400542 case EOpConstructMat4:
543 case EOpConstructFloat:
544 case EOpConstructIVec2:
545 case EOpConstructIVec3:
546 case EOpConstructIVec4:
547 case EOpConstructInt:
548 case EOpConstructUVec2:
549 case EOpConstructUVec3:
550 case EOpConstructUVec4:
551 case EOpConstructUInt:
552 case EOpConstructBVec2:
553 case EOpConstructBVec3:
554 case EOpConstructBVec4:
555 case EOpConstructBool:
556 case EOpConstructStruct:
557 return true;
558 default:
559 return false;
560 }
561}
562
563//
564// Make sure the type of a unary operator is appropriate for its
565// combination of operation and operand type.
566//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200567void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400568{
569 switch (mOp)
570 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200571 case EOpFloatBitsToInt:
572 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200573 case EOpIntBitsToFloat:
574 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200575 case EOpPackSnorm2x16:
576 case EOpPackUnorm2x16:
577 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200578 case EOpUnpackSnorm2x16:
579 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200580 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530581 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200582 case EOpUnpackHalf2x16:
583 mType.setPrecision(EbpMedium);
584 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400585 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200586 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400587 }
588
Olli Etuahof6c694b2015-03-26 14:50:53 +0200589 if (funcReturnType != nullptr)
590 {
591 if (funcReturnType->getBasicType() == EbtBool)
592 {
593 // Bool types should not have precision.
594 setType(*funcReturnType);
595 }
596 else
597 {
598 // Precision of the node has been set based on the operand.
599 setTypePreservePrecision(*funcReturnType);
600 }
601 }
602
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200603 if (mOperand->getQualifier() == EvqConst)
604 mType.setQualifier(EvqConst);
605 else
606 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400607}
608
609//
610// Establishes the type of the resultant operation, as well as
611// makes the operator the correct one for the operands.
612//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200613// For lots of operations it should already be established that the operand
614// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400615//
616bool TIntermBinary::promote(TInfoSink &infoSink)
617{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200618 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400619
Jamie Madillb1a85f42014-08-19 15:23:24 -0400620 //
621 // Base assumption: just make the type the same as the left
622 // operand. Then only deviations from this need be coded.
623 //
624 setType(mLeft->getType());
625
626 // The result gets promoted to the highest precision.
627 TPrecision higherPrecision = GetHigherPrecision(
628 mLeft->getPrecision(), mRight->getPrecision());
629 getTypePointer()->setPrecision(higherPrecision);
630
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200631 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400632 // Binary operations results in temporary variables unless both
633 // operands are const.
634 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
635 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200636 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400637 getTypePointer()->setQualifier(EvqTemporary);
638 }
639
640 const int nominalSize =
641 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
642
643 //
644 // All scalars or structs. Code after this test assumes this case is removed!
645 //
646 if (nominalSize == 1)
647 {
648 switch (mOp)
649 {
650 //
651 // Promote to conditional
652 //
653 case EOpEqual:
654 case EOpNotEqual:
655 case EOpLessThan:
656 case EOpGreaterThan:
657 case EOpLessThanEqual:
658 case EOpGreaterThanEqual:
659 setType(TType(EbtBool, EbpUndefined));
660 break;
661
662 //
663 // And and Or operate on conditionals
664 //
665 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200666 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400667 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200668 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400669 setType(TType(EbtBool, EbpUndefined));
670 break;
671
672 default:
673 break;
674 }
675 return true;
676 }
677
678 // If we reach here, at least one of the operands is vector or matrix.
679 // The other operand could be a scalar, vector, or matrix.
680 // Can these two operands be combined?
681 //
682 TBasicType basicType = mLeft->getBasicType();
683 switch (mOp)
684 {
685 case EOpMul:
686 if (!mLeft->isMatrix() && mRight->isMatrix())
687 {
688 if (mLeft->isVector())
689 {
690 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200691 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700692 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400693 }
694 else
695 {
696 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200697 setType(TType(basicType, higherPrecision, resultQualifier,
698 static_cast<unsigned char>(mRight->getCols()),
699 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400700 }
701 }
702 else if (mLeft->isMatrix() && !mRight->isMatrix())
703 {
704 if (mRight->isVector())
705 {
706 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200707 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700708 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400709 }
710 else
711 {
712 mOp = EOpMatrixTimesScalar;
713 }
714 }
715 else if (mLeft->isMatrix() && mRight->isMatrix())
716 {
717 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200718 setType(TType(basicType, higherPrecision, resultQualifier,
719 static_cast<unsigned char>(mRight->getCols()),
720 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400721 }
722 else if (!mLeft->isMatrix() && !mRight->isMatrix())
723 {
724 if (mLeft->isVector() && mRight->isVector())
725 {
726 // leave as component product
727 }
728 else if (mLeft->isVector() || mRight->isVector())
729 {
730 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200731 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700732 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400733 }
734 }
735 else
736 {
737 infoSink.info.message(EPrefixInternalError, getLine(),
738 "Missing elses");
739 return false;
740 }
741
742 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
743 {
744 return false;
745 }
746 break;
747
748 case EOpMulAssign:
749 if (!mLeft->isMatrix() && mRight->isMatrix())
750 {
751 if (mLeft->isVector())
752 {
753 mOp = EOpVectorTimesMatrixAssign;
754 }
755 else
756 {
757 return false;
758 }
759 }
760 else if (mLeft->isMatrix() && !mRight->isMatrix())
761 {
762 if (mRight->isVector())
763 {
764 return false;
765 }
766 else
767 {
768 mOp = EOpMatrixTimesScalarAssign;
769 }
770 }
771 else if (mLeft->isMatrix() && mRight->isMatrix())
772 {
773 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200774 setType(TType(basicType, higherPrecision, resultQualifier,
775 static_cast<unsigned char>(mRight->getCols()),
776 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400777 }
778 else if (!mLeft->isMatrix() && !mRight->isMatrix())
779 {
780 if (mLeft->isVector() && mRight->isVector())
781 {
782 // leave as component product
783 }
784 else if (mLeft->isVector() || mRight->isVector())
785 {
786 if (!mLeft->isVector())
787 return false;
788 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200789 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700790 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400791 }
792 }
793 else
794 {
795 infoSink.info.message(EPrefixInternalError, getLine(),
796 "Missing elses");
797 return false;
798 }
799
800 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
801 {
802 return false;
803 }
804 break;
805
806 case EOpAssign:
807 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200808 // No more additional checks are needed.
809 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
810 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
811 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400812 case EOpAdd:
813 case EOpSub:
814 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200815 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200816 case EOpBitShiftLeft:
817 case EOpBitShiftRight:
818 case EOpBitwiseAnd:
819 case EOpBitwiseXor:
820 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400821 case EOpAddAssign:
822 case EOpSubAssign:
823 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200824 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200825 case EOpBitShiftLeftAssign:
826 case EOpBitShiftRightAssign:
827 case EOpBitwiseAndAssign:
828 case EOpBitwiseXorAssign:
829 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400830 if ((mLeft->isMatrix() && mRight->isVector()) ||
831 (mLeft->isVector() && mRight->isMatrix()))
832 {
833 return false;
834 }
835
836 // Are the sizes compatible?
837 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
838 mLeft->getSecondarySize() != mRight->getSecondarySize())
839 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200840 // If the nominal sizes of operands do not match:
841 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400842 if (!mLeft->isScalar() && !mRight->isScalar())
843 return false;
844
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200845 // In the case of compound assignment other than multiply-assign,
846 // the right side needs to be a scalar. Otherwise a vector/matrix
847 // would be assigned to a scalar. A scalar can't be shifted by a
848 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200849 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200850 (isAssignment() ||
851 mOp == EOpBitShiftLeft ||
852 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200853 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400854 }
855
856 {
857 const int secondarySize = std::max(
858 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200859 setType(TType(basicType, higherPrecision, resultQualifier,
860 static_cast<unsigned char>(nominalSize),
861 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200862 if (mLeft->isArray())
863 {
864 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
865 mType.setArraySize(mLeft->getArraySize());
866 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400867 }
868 break;
869
870 case EOpEqual:
871 case EOpNotEqual:
872 case EOpLessThan:
873 case EOpGreaterThan:
874 case EOpLessThanEqual:
875 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200876 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
877 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400878 setType(TType(EbtBool, EbpUndefined));
879 break;
880
881 default:
882 return false;
883 }
884 return true;
885}
886
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300887TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
888{
889 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
890 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
891 if (leftConstant == nullptr || rightConstant == nullptr)
892 {
893 return nullptr;
894 }
895 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300896 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300897}
898
Olli Etuaho95310b02015-06-02 17:43:38 +0300899TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
900{
901 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
902 if (operandConstant == nullptr)
903 {
904 return nullptr;
905 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530906
907 TConstantUnion *constArray = nullptr;
908 switch (mOp)
909 {
910 case EOpAny:
911 case EOpAll:
912 case EOpLength:
913 case EOpTranspose:
914 case EOpDeterminant:
915 case EOpInverse:
916 case EOpPackSnorm2x16:
917 case EOpUnpackSnorm2x16:
918 case EOpPackUnorm2x16:
919 case EOpUnpackUnorm2x16:
920 case EOpPackHalf2x16:
921 case EOpUnpackHalf2x16:
922 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
923 break;
924 default:
925 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
926 break;
927 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300928 return CreateFoldedNode(constArray, this);
929}
930
931TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
932{
933 // Make sure that all params are constant before actual constant folding.
934 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300935 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300936 if (param->getAsConstantUnion() == nullptr)
937 {
938 return nullptr;
939 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300940 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300941 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
942 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300943}
944
Jamie Madillb1a85f42014-08-19 15:23:24 -0400945//
946// The fold functions see if an operation on a constant can be done in place,
947// without generating run-time code.
948//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300949// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400950//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300951TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
952{
953 TConstantUnion *leftArray = getUnionArrayPointer();
954 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
955
956 if (!leftArray)
957 return nullptr;
958 if (!rightArray)
959 return nullptr;
960
961 size_t objectSize = getType().getObjectSize();
962
963 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
964 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
965 {
966 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
967 }
968 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
969 {
970 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
971 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
972 objectSize = rightNode->getType().getObjectSize();
973 }
974
975 TConstantUnion *resultArray = nullptr;
976
977 switch(op)
978 {
979 case EOpAdd:
980 resultArray = new TConstantUnion[objectSize];
981 for (size_t i = 0; i < objectSize; i++)
982 resultArray[i] = leftArray[i] + rightArray[i];
983 break;
984 case EOpSub:
985 resultArray = new TConstantUnion[objectSize];
986 for (size_t i = 0; i < objectSize; i++)
987 resultArray[i] = leftArray[i] - rightArray[i];
988 break;
989
990 case EOpMul:
991 case EOpVectorTimesScalar:
992 case EOpMatrixTimesScalar:
993 resultArray = new TConstantUnion[objectSize];
994 for (size_t i = 0; i < objectSize; i++)
995 resultArray[i] = leftArray[i] * rightArray[i];
996 break;
997
998 case EOpMatrixTimesMatrix:
999 {
1000 if (getType().getBasicType() != EbtFloat ||
1001 rightNode->getBasicType() != EbtFloat)
1002 {
1003 infoSink.info.message(
1004 EPrefixInternalError, getLine(),
1005 "Constant Folding cannot be done for matrix multiply");
1006 return nullptr;
1007 }
1008
1009 const int leftCols = getCols();
1010 const int leftRows = getRows();
1011 const int rightCols = rightNode->getType().getCols();
1012 const int rightRows = rightNode->getType().getRows();
1013 const int resultCols = rightCols;
1014 const int resultRows = leftRows;
1015
1016 resultArray = new TConstantUnion[resultCols * resultRows];
1017 for (int row = 0; row < resultRows; row++)
1018 {
1019 for (int column = 0; column < resultCols; column++)
1020 {
1021 resultArray[resultRows * column + row].setFConst(0.0f);
1022 for (int i = 0; i < leftCols; i++)
1023 {
1024 resultArray[resultRows * column + row].setFConst(
1025 resultArray[resultRows * column + row].getFConst() +
1026 leftArray[i * leftRows + row].getFConst() *
1027 rightArray[column * rightRows + i].getFConst());
1028 }
1029 }
1030 }
1031 }
1032 break;
1033
1034 case EOpDiv:
1035 case EOpIMod:
1036 {
1037 resultArray = new TConstantUnion[objectSize];
1038 for (size_t i = 0; i < objectSize; i++)
1039 {
1040 switch (getType().getBasicType())
1041 {
1042 case EbtFloat:
1043 if (rightArray[i] == 0.0f)
1044 {
1045 infoSink.info.message(EPrefixWarning, getLine(),
1046 "Divide by zero error during constant folding");
1047 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1048 }
1049 else
1050 {
1051 ASSERT(op == EOpDiv);
1052 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1053 }
1054 break;
1055
1056 case EbtInt:
1057 if (rightArray[i] == 0)
1058 {
1059 infoSink.info.message(EPrefixWarning, getLine(),
1060 "Divide by zero error during constant folding");
1061 resultArray[i].setIConst(INT_MAX);
1062 }
1063 else
1064 {
1065 if (op == EOpDiv)
1066 {
1067 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1068 }
1069 else
1070 {
1071 ASSERT(op == EOpIMod);
1072 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1073 }
1074 }
1075 break;
1076
1077 case EbtUInt:
1078 if (rightArray[i] == 0)
1079 {
1080 infoSink.info.message(EPrefixWarning, getLine(),
1081 "Divide by zero error during constant folding");
1082 resultArray[i].setUConst(UINT_MAX);
1083 }
1084 else
1085 {
1086 if (op == EOpDiv)
1087 {
1088 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1089 }
1090 else
1091 {
1092 ASSERT(op == EOpIMod);
1093 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1094 }
1095 }
1096 break;
1097
1098 default:
1099 infoSink.info.message(EPrefixInternalError, getLine(),
1100 "Constant folding cannot be done for \"/\"");
1101 return nullptr;
1102 }
1103 }
1104 }
1105 break;
1106
1107 case EOpMatrixTimesVector:
1108 {
1109 if (rightNode->getBasicType() != EbtFloat)
1110 {
1111 infoSink.info.message(EPrefixInternalError, getLine(),
1112 "Constant Folding cannot be done for matrix times vector");
1113 return nullptr;
1114 }
1115
1116 const int matrixCols = getCols();
1117 const int matrixRows = getRows();
1118
1119 resultArray = new TConstantUnion[matrixRows];
1120
1121 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1122 {
1123 resultArray[matrixRow].setFConst(0.0f);
1124 for (int col = 0; col < matrixCols; col++)
1125 {
1126 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1127 leftArray[col * matrixRows + matrixRow].getFConst() *
1128 rightArray[col].getFConst());
1129 }
1130 }
1131 }
1132 break;
1133
1134 case EOpVectorTimesMatrix:
1135 {
1136 if (getType().getBasicType() != EbtFloat)
1137 {
1138 infoSink.info.message(EPrefixInternalError, getLine(),
1139 "Constant Folding cannot be done for vector times matrix");
1140 return nullptr;
1141 }
1142
1143 const int matrixCols = rightNode->getType().getCols();
1144 const int matrixRows = rightNode->getType().getRows();
1145
1146 resultArray = new TConstantUnion[matrixCols];
1147
1148 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1149 {
1150 resultArray[matrixCol].setFConst(0.0f);
1151 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1152 {
1153 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1154 leftArray[matrixRow].getFConst() *
1155 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1156 }
1157 }
1158 }
1159 break;
1160
1161 case EOpLogicalAnd:
1162 {
1163 resultArray = new TConstantUnion[objectSize];
1164 for (size_t i = 0; i < objectSize; i++)
1165 {
1166 resultArray[i] = leftArray[i] && rightArray[i];
1167 }
1168 }
1169 break;
1170
1171 case EOpLogicalOr:
1172 {
1173 resultArray = new TConstantUnion[objectSize];
1174 for (size_t i = 0; i < objectSize; i++)
1175 {
1176 resultArray[i] = leftArray[i] || rightArray[i];
1177 }
1178 }
1179 break;
1180
1181 case EOpLogicalXor:
1182 {
1183 resultArray = new TConstantUnion[objectSize];
1184 for (size_t i = 0; i < objectSize; i++)
1185 {
1186 switch (getType().getBasicType())
1187 {
1188 case EbtBool:
1189 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1190 break;
1191 default:
1192 UNREACHABLE();
1193 break;
1194 }
1195 }
1196 }
1197 break;
1198
1199 case EOpBitwiseAnd:
1200 resultArray = new TConstantUnion[objectSize];
1201 for (size_t i = 0; i < objectSize; i++)
1202 resultArray[i] = leftArray[i] & rightArray[i];
1203 break;
1204 case EOpBitwiseXor:
1205 resultArray = new TConstantUnion[objectSize];
1206 for (size_t i = 0; i < objectSize; i++)
1207 resultArray[i] = leftArray[i] ^ rightArray[i];
1208 break;
1209 case EOpBitwiseOr:
1210 resultArray = new TConstantUnion[objectSize];
1211 for (size_t i = 0; i < objectSize; i++)
1212 resultArray[i] = leftArray[i] | rightArray[i];
1213 break;
1214 case EOpBitShiftLeft:
1215 resultArray = new TConstantUnion[objectSize];
1216 for (size_t i = 0; i < objectSize; i++)
1217 resultArray[i] = leftArray[i] << rightArray[i];
1218 break;
1219 case EOpBitShiftRight:
1220 resultArray = new TConstantUnion[objectSize];
1221 for (size_t i = 0; i < objectSize; i++)
1222 resultArray[i] = leftArray[i] >> rightArray[i];
1223 break;
1224
1225 case EOpLessThan:
1226 ASSERT(objectSize == 1);
1227 resultArray = new TConstantUnion[1];
1228 resultArray->setBConst(*leftArray < *rightArray);
1229 break;
1230
1231 case EOpGreaterThan:
1232 ASSERT(objectSize == 1);
1233 resultArray = new TConstantUnion[1];
1234 resultArray->setBConst(*leftArray > *rightArray);
1235 break;
1236
1237 case EOpLessThanEqual:
1238 ASSERT(objectSize == 1);
1239 resultArray = new TConstantUnion[1];
1240 resultArray->setBConst(!(*leftArray > *rightArray));
1241 break;
1242
1243 case EOpGreaterThanEqual:
1244 ASSERT(objectSize == 1);
1245 resultArray = new TConstantUnion[1];
1246 resultArray->setBConst(!(*leftArray < *rightArray));
1247 break;
1248
1249 case EOpEqual:
1250 case EOpNotEqual:
1251 {
1252 resultArray = new TConstantUnion[1];
1253 bool equal = true;
1254 if (getType().getBasicType() == EbtStruct)
1255 {
1256 equal = CompareStructure(getType(), rightArray, leftArray);
1257 }
1258 else
1259 {
1260 for (size_t i = 0; i < objectSize; i++)
1261 {
1262 if (leftArray[i] != rightArray[i])
1263 {
1264 equal = false;
1265 break; // break out of for loop
1266 }
1267 }
1268 }
1269 if (op == EOpEqual)
1270 {
1271 resultArray->setBConst(equal);
1272 }
1273 else
1274 {
1275 resultArray->setBConst(!equal);
1276 }
1277 }
1278 break;
1279
1280 default:
1281 infoSink.info.message(
1282 EPrefixInternalError, getLine(),
1283 "Invalid operator for constant folding");
1284 return nullptr;
1285 }
1286 return resultArray;
1287}
1288
1289//
1290// The fold functions see if an operation on a constant can be done in place,
1291// without generating run-time code.
1292//
Olli Etuaho95310b02015-06-02 17:43:38 +03001293// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001294//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301295TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001296{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301297 //
1298 // Do operations where the return type has a different number of components compared to the operand type.
1299 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001300
Arun Patoleab2b9a22015-07-06 18:27:56 +05301301 TConstantUnion *operandArray = getUnionArrayPointer();
1302 if (!operandArray)
1303 return nullptr;
1304
1305 size_t objectSize = getType().getObjectSize();
1306 TConstantUnion *resultArray = nullptr;
1307 switch (op)
1308 {
1309 case EOpAny:
1310 if (getType().getBasicType() == EbtBool)
1311 {
1312 resultArray = new TConstantUnion();
1313 resultArray->setBConst(false);
1314 for (size_t i = 0; i < objectSize; i++)
1315 {
1316 if (operandArray[i].getBConst())
1317 {
1318 resultArray->setBConst(true);
1319 break;
1320 }
1321 }
1322 break;
1323 }
1324 else
1325 {
1326 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1327 return nullptr;
1328 }
1329
1330 case EOpAll:
1331 if (getType().getBasicType() == EbtBool)
1332 {
1333 resultArray = new TConstantUnion();
1334 resultArray->setBConst(true);
1335 for (size_t i = 0; i < objectSize; i++)
1336 {
1337 if (!operandArray[i].getBConst())
1338 {
1339 resultArray->setBConst(false);
1340 break;
1341 }
1342 }
1343 break;
1344 }
1345 else
1346 {
1347 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1348 return nullptr;
1349 }
1350
1351 case EOpLength:
1352 if (getType().getBasicType() == EbtFloat)
1353 {
1354 resultArray = new TConstantUnion();
1355 resultArray->setFConst(VectorLength(operandArray, objectSize));
1356 break;
1357 }
1358 else
1359 {
1360 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1361 return nullptr;
1362 }
1363
1364 case EOpTranspose:
1365 if (getType().getBasicType() == EbtFloat)
1366 {
1367 resultArray = new TConstantUnion[objectSize];
1368 angle::Matrix<float> result =
1369 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1370 SetUnionArrayFromMatrix(result, resultArray);
1371 break;
1372 }
1373 else
1374 {
1375 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1376 return nullptr;
1377 }
1378
1379 case EOpDeterminant:
1380 if (getType().getBasicType() == EbtFloat)
1381 {
1382 unsigned int size = getType().getNominalSize();
1383 ASSERT(size >= 2 && size <= 4);
1384 resultArray = new TConstantUnion();
1385 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
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 EOpInverse:
1395 if (getType().getBasicType() == EbtFloat)
1396 {
1397 unsigned int size = getType().getNominalSize();
1398 ASSERT(size >= 2 && size <= 4);
1399 resultArray = new TConstantUnion[objectSize];
1400 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1401 SetUnionArrayFromMatrix(result, resultArray);
1402 break;
1403 }
1404 else
1405 {
1406 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1407 return nullptr;
1408 }
1409
1410 case EOpPackSnorm2x16:
1411 if (getType().getBasicType() == EbtFloat)
1412 {
1413 ASSERT(getType().getNominalSize() == 2);
1414 resultArray = new TConstantUnion();
1415 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
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 EOpUnpackSnorm2x16:
1425 if (getType().getBasicType() == EbtUInt)
1426 {
1427 resultArray = new TConstantUnion[2];
1428 float f1, f2;
1429 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1430 resultArray[0].setFConst(f1);
1431 resultArray[1].setFConst(f2);
1432 break;
1433 }
1434 else
1435 {
1436 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1437 return nullptr;
1438 }
1439
1440 case EOpPackUnorm2x16:
1441 if (getType().getBasicType() == EbtFloat)
1442 {
1443 ASSERT(getType().getNominalSize() == 2);
1444 resultArray = new TConstantUnion();
1445 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
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 EOpUnpackUnorm2x16:
1455 if (getType().getBasicType() == EbtUInt)
1456 {
1457 resultArray = new TConstantUnion[2];
1458 float f1, f2;
1459 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1460 resultArray[0].setFConst(f1);
1461 resultArray[1].setFConst(f2);
1462 break;
1463 }
1464 else
1465 {
1466 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1467 return nullptr;
1468 }
1469
1470 case EOpPackHalf2x16:
1471 if (getType().getBasicType() == EbtFloat)
1472 {
1473 ASSERT(getType().getNominalSize() == 2);
1474 resultArray = new TConstantUnion();
1475 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1476 break;
1477 }
1478 else
1479 {
1480 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1481 return nullptr;
1482 }
1483
1484 case EOpUnpackHalf2x16:
1485 if (getType().getBasicType() == EbtUInt)
1486 {
1487 resultArray = new TConstantUnion[2];
1488 float f1, f2;
1489 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1490 resultArray[0].setFConst(f1);
1491 resultArray[1].setFConst(f2);
1492 break;
1493 }
1494 else
1495 {
1496 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1497 return nullptr;
1498 }
1499 break;
1500
1501 default:
1502 break;
1503 }
1504
1505 return resultArray;
1506}
1507
1508TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1509{
1510 //
1511 // Do unary operations where the return type is the same as operand type.
1512 //
1513
1514 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001515 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301516 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001517
1518 size_t objectSize = getType().getObjectSize();
1519
Arun Patoleab2b9a22015-07-06 18:27:56 +05301520 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1521 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301522 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301523 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301524 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301525 case EOpNegative:
1526 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301527 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301528 case EbtFloat:
1529 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301530 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301531 case EbtInt:
1532 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301533 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301534 case EbtUInt:
1535 resultArray[i].setUConst(static_cast<unsigned int>(
1536 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301537 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301538 default:
1539 infoSink.info.message(
1540 EPrefixInternalError, getLine(),
1541 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301542 return nullptr;
1543 }
1544 break;
1545
Arun Patoleab2b9a22015-07-06 18:27:56 +05301546 case EOpPositive:
1547 switch (getType().getBasicType())
1548 {
1549 case EbtFloat:
1550 resultArray[i].setFConst(operandArray[i].getFConst());
1551 break;
1552 case EbtInt:
1553 resultArray[i].setIConst(operandArray[i].getIConst());
1554 break;
1555 case EbtUInt:
1556 resultArray[i].setUConst(static_cast<unsigned int>(
1557 static_cast<int>(operandArray[i].getUConst())));
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 EOpLogicalNot:
1568 // this code is written for possible future use,
1569 // will not get executed currently
1570 switch (getType().getBasicType())
1571 {
1572 case EbtBool:
1573 resultArray[i].setBConst(!operandArray[i].getBConst());
1574 break;
1575 default:
1576 infoSink.info.message(
1577 EPrefixInternalError, getLine(),
1578 "Unary operation not folded into constant");
1579 return nullptr;
1580 }
1581 break;
1582
1583 case EOpBitwiseNot:
1584 switch (getType().getBasicType())
1585 {
1586 case EbtInt:
1587 resultArray[i].setIConst(~operandArray[i].getIConst());
1588 break;
1589 case EbtUInt:
1590 resultArray[i].setUConst(~operandArray[i].getUConst());
1591 break;
1592 default:
1593 infoSink.info.message(
1594 EPrefixInternalError, getLine(),
1595 "Unary operation not folded into constant");
1596 return nullptr;
1597 }
1598 break;
1599
1600 case EOpRadians:
1601 if (getType().getBasicType() == EbtFloat)
1602 {
1603 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1604 break;
1605 }
1606 infoSink.info.message(
1607 EPrefixInternalError, getLine(),
1608 "Unary operation not folded into constant");
1609 return nullptr;
1610
1611 case EOpDegrees:
1612 if (getType().getBasicType() == EbtFloat)
1613 {
1614 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1615 break;
1616 }
1617 infoSink.info.message(
1618 EPrefixInternalError, getLine(),
1619 "Unary operation not folded into constant");
1620 return nullptr;
1621
1622 case EOpSin:
1623 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1624 return nullptr;
1625 break;
1626
1627 case EOpCos:
1628 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1629 return nullptr;
1630 break;
1631
1632 case EOpTan:
1633 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1634 return nullptr;
1635 break;
1636
1637 case EOpAsin:
1638 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1639 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1640 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1641 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1642 return nullptr;
1643 break;
1644
1645 case EOpAcos:
1646 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1647 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1648 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1649 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1650 return nullptr;
1651 break;
1652
1653 case EOpAtan:
1654 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1655 return nullptr;
1656 break;
1657
1658 case EOpSinh:
1659 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1660 return nullptr;
1661 break;
1662
1663 case EOpCosh:
1664 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1665 return nullptr;
1666 break;
1667
1668 case EOpTanh:
1669 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1670 return nullptr;
1671 break;
1672
1673 case EOpAsinh:
1674 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1675 return nullptr;
1676 break;
1677
1678 case EOpAcosh:
1679 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1680 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1681 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1682 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1683 return nullptr;
1684 break;
1685
1686 case EOpAtanh:
1687 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1688 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1689 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1690 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1691 return nullptr;
1692 break;
1693
1694 case EOpAbs:
1695 switch (getType().getBasicType())
1696 {
1697 case EbtFloat:
1698 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1699 break;
1700 case EbtInt:
1701 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1702 break;
1703 default:
1704 infoSink.info.message(
1705 EPrefixInternalError, getLine(),
1706 "Unary operation not folded into constant");
1707 return nullptr;
1708 }
1709 break;
1710
1711 case EOpSign:
1712 switch (getType().getBasicType())
1713 {
1714 case EbtFloat:
1715 {
1716 float fConst = operandArray[i].getFConst();
1717 float fResult = 0.0f;
1718 if (fConst > 0.0f)
1719 fResult = 1.0f;
1720 else if (fConst < 0.0f)
1721 fResult = -1.0f;
1722 resultArray[i].setFConst(fResult);
1723 }
1724 break;
1725 case EbtInt:
1726 {
1727 int iConst = operandArray[i].getIConst();
1728 int iResult = 0;
1729 if (iConst > 0)
1730 iResult = 1;
1731 else if (iConst < 0)
1732 iResult = -1;
1733 resultArray[i].setIConst(iResult);
1734 }
1735 break;
1736 default:
1737 infoSink.info.message(
1738 EPrefixInternalError, getLine(),
1739 "Unary operation not folded into constant");
1740 return nullptr;
1741 }
1742 break;
1743
1744 case EOpFloor:
1745 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1746 return nullptr;
1747 break;
1748
1749 case EOpTrunc:
1750 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1751 return nullptr;
1752 break;
1753
1754 case EOpRound:
1755 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1756 return nullptr;
1757 break;
1758
1759 case EOpRoundEven:
1760 if (getType().getBasicType() == EbtFloat)
1761 {
1762 float x = operandArray[i].getFConst();
1763 float result;
1764 float fractPart = modff(x, &result);
1765 if (fabsf(fractPart) == 0.5f)
1766 result = 2.0f * roundf(x / 2.0f);
1767 else
1768 result = roundf(x);
1769 resultArray[i].setFConst(result);
1770 break;
1771 }
1772 infoSink.info.message(
1773 EPrefixInternalError, getLine(),
1774 "Unary operation not folded into constant");
1775 return nullptr;
1776
1777 case EOpCeil:
1778 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1779 return nullptr;
1780 break;
1781
1782 case EOpFract:
1783 if (getType().getBasicType() == EbtFloat)
1784 {
1785 float x = operandArray[i].getFConst();
1786 resultArray[i].setFConst(x - floorf(x));
1787 break;
1788 }
1789 infoSink.info.message(
1790 EPrefixInternalError, getLine(),
1791 "Unary operation not folded into constant");
1792 return nullptr;
1793
Arun Patole551279e2015-07-07 18:18:23 +05301794 case EOpIsNan:
1795 if (getType().getBasicType() == EbtFloat)
1796 {
1797 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1798 break;
1799 }
1800 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1801 return nullptr;
1802
1803 case EOpIsInf:
1804 if (getType().getBasicType() == EbtFloat)
1805 {
1806 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1807 break;
1808 }
1809 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1810 return nullptr;
1811
1812 case EOpFloatBitsToInt:
1813 if (getType().getBasicType() == EbtFloat)
1814 {
1815 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1816 break;
1817 }
1818 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1819 return nullptr;
1820
1821 case EOpFloatBitsToUint:
1822 if (getType().getBasicType() == EbtFloat)
1823 {
1824 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1825 break;
1826 }
1827 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1828 return nullptr;
1829
1830 case EOpIntBitsToFloat:
1831 if (getType().getBasicType() == EbtInt)
1832 {
1833 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1834 break;
1835 }
1836 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1837 return nullptr;
1838
1839 case EOpUintBitsToFloat:
1840 if (getType().getBasicType() == EbtUInt)
1841 {
1842 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1843 break;
1844 }
1845 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1846 return nullptr;
1847
Arun Patoleab2b9a22015-07-06 18:27:56 +05301848 case EOpExp:
1849 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1850 return nullptr;
1851 break;
1852
1853 case EOpLog:
1854 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1855 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1856 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1857 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1858 return nullptr;
1859 break;
1860
1861 case EOpExp2:
1862 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1863 return nullptr;
1864 break;
1865
1866 case EOpLog2:
1867 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1868 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1869 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1870 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1871 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1872 return nullptr;
1873 else
1874 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1875 break;
1876
1877 case EOpSqrt:
1878 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1879 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1880 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1881 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1882 return nullptr;
1883 break;
1884
1885 case EOpInverseSqrt:
1886 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1887 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1888 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1889 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1890 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1891 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1892 return nullptr;
1893 else
1894 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1895 break;
1896
1897 case EOpVectorLogicalNot:
1898 if (getType().getBasicType() == EbtBool)
1899 {
1900 resultArray[i].setBConst(!operandArray[i].getBConst());
1901 break;
1902 }
1903 infoSink.info.message(
1904 EPrefixInternalError, getLine(),
1905 "Unary operation not folded into constant");
1906 return nullptr;
1907
1908 case EOpNormalize:
1909 if (getType().getBasicType() == EbtFloat)
1910 {
1911 float x = operandArray[i].getFConst();
1912 float length = VectorLength(operandArray, objectSize);
1913 if (length)
1914 resultArray[i].setFConst(x / length);
1915 else
1916 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1917 &resultArray[i]);
1918 break;
1919 }
1920 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1921 return nullptr;
1922
Arun Patole0c5409f2015-07-08 15:17:53 +05301923 case EOpDFdx:
1924 case EOpDFdy:
1925 case EOpFwidth:
1926 if (getType().getBasicType() == EbtFloat)
1927 {
1928 // Derivatives of constant arguments should be 0.
1929 resultArray[i].setFConst(0.0f);
1930 break;
1931 }
1932 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1933 return nullptr;
1934
Arun Patole1155ddd2015-06-05 18:04:36 +05301935 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301937 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301938 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001939
Arun Patoleab2b9a22015-07-06 18:27:56 +05301940 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001941}
1942
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001943bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1944 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301945{
1946 ASSERT(builtinFunc);
1947
1948 if (getType().getBasicType() == EbtFloat)
1949 {
1950 result->setFConst(builtinFunc(parameter.getFConst()));
1951 return true;
1952 }
1953
1954 infoSink.info.message(
1955 EPrefixInternalError, getLine(),
1956 "Unary operation not folded into constant");
1957 return false;
1958}
1959
Jamie Madillb1a85f42014-08-19 15:23:24 -04001960// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001961TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301962{
Olli Etuahob43846e2015-06-02 18:18:57 +03001963 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301964 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001965 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Arun Patole274f0702015-05-05 13:33:30 +05301966 std::vector<TConstantUnion *> unionArrays(paramsCount);
1967 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001968 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301969 TBasicType basicType = EbtVoid;
1970 TSourceLoc loc;
1971 for (unsigned int i = 0; i < paramsCount; i++)
1972 {
1973 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001974 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301975
1976 if (i == 0)
1977 {
1978 basicType = paramConstant->getType().getBasicType();
1979 loc = paramConstant->getLine();
1980 }
1981 unionArrays[i] = paramConstant->getUnionArrayPointer();
1982 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001983 if (objectSizes[i] > maxObjectSize)
1984 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301985 }
1986
Arun Patole7fa33552015-06-10 15:15:18 +05301987 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1988 {
1989 for (unsigned int i = 0; i < paramsCount; i++)
1990 if (objectSizes[i] != maxObjectSize)
1991 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1992 }
Arun Patole274f0702015-05-05 13:33:30 +05301993
Olli Etuahob43846e2015-06-02 18:18:57 +03001994 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301995 if (paramsCount == 2)
1996 {
1997 //
1998 // Binary built-in
1999 //
2000 switch (op)
2001 {
Arun Patolebf790422015-05-18 17:53:04 +05302002 case EOpAtan:
2003 {
2004 if (basicType == EbtFloat)
2005 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002006 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302007 for (size_t i = 0; i < maxObjectSize; i++)
2008 {
2009 float y = unionArrays[0][i].getFConst();
2010 float x = unionArrays[1][i].getFConst();
2011 // Results are undefined if x and y are both 0.
2012 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002013 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302014 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002015 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302016 }
2017 }
2018 else
2019 UNREACHABLE();
2020 }
2021 break;
2022
2023 case EOpPow:
2024 {
2025 if (basicType == EbtFloat)
2026 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002027 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302028 for (size_t i = 0; i < maxObjectSize; i++)
2029 {
2030 float x = unionArrays[0][i].getFConst();
2031 float y = unionArrays[1][i].getFConst();
2032 // Results are undefined if x < 0.
2033 // Results are undefined if x = 0 and y <= 0.
2034 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002035 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302036 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002037 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302038 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002039 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302040 }
2041 }
2042 else
2043 UNREACHABLE();
2044 }
2045 break;
2046
2047 case EOpMod:
2048 {
2049 if (basicType == EbtFloat)
2050 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002051 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302052 for (size_t i = 0; i < maxObjectSize; i++)
2053 {
2054 float x = unionArrays[0][i].getFConst();
2055 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002056 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302057 }
2058 }
2059 else
2060 UNREACHABLE();
2061 }
2062 break;
2063
Arun Patole274f0702015-05-05 13:33:30 +05302064 case EOpMin:
2065 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002066 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302067 for (size_t i = 0; i < maxObjectSize; i++)
2068 {
2069 switch (basicType)
2070 {
2071 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002072 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302073 break;
2074 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002075 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302076 break;
2077 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002078 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302079 break;
2080 default:
2081 UNREACHABLE();
2082 break;
2083 }
2084 }
2085 }
2086 break;
2087
2088 case EOpMax:
2089 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002090 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302091 for (size_t i = 0; i < maxObjectSize; i++)
2092 {
2093 switch (basicType)
2094 {
2095 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002096 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302097 break;
2098 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002099 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302100 break;
2101 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002102 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302103 break;
2104 default:
2105 UNREACHABLE();
2106 break;
2107 }
2108 }
2109 }
2110 break;
2111
Arun Patolebf790422015-05-18 17:53:04 +05302112 case EOpStep:
2113 {
2114 if (basicType == EbtFloat)
2115 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002116 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302117 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002118 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302119 }
2120 else
2121 UNREACHABLE();
2122 }
2123 break;
2124
Arun Patole9d0b1f92015-05-20 14:27:17 +05302125 case EOpLessThan:
2126 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002127 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302128 for (size_t i = 0; i < maxObjectSize; i++)
2129 {
2130 switch (basicType)
2131 {
2132 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002133 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302134 break;
2135 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002136 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302137 break;
2138 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002139 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302140 break;
2141 default:
2142 UNREACHABLE();
2143 break;
2144 }
2145 }
2146 }
2147 break;
2148
2149 case EOpLessThanEqual:
2150 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002151 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302152 for (size_t i = 0; i < maxObjectSize; i++)
2153 {
2154 switch (basicType)
2155 {
2156 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002157 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302158 break;
2159 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002160 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302161 break;
2162 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002163 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302164 break;
2165 default:
2166 UNREACHABLE();
2167 break;
2168 }
2169 }
2170 }
2171 break;
2172
2173 case EOpGreaterThan:
2174 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002175 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302176 for (size_t i = 0; i < maxObjectSize; i++)
2177 {
2178 switch (basicType)
2179 {
2180 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002181 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302182 break;
2183 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002184 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302185 break;
2186 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002187 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302188 break;
2189 default:
2190 UNREACHABLE();
2191 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002192 }
2193 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302194 }
2195 break;
2196
2197 case EOpGreaterThanEqual:
2198 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002199 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302200 for (size_t i = 0; i < maxObjectSize; i++)
2201 {
2202 switch (basicType)
2203 {
2204 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002205 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302206 break;
2207 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002208 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302209 break;
2210 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002211 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302212 break;
2213 default:
2214 UNREACHABLE();
2215 break;
2216 }
2217 }
2218 }
2219 break;
2220
2221 case EOpVectorEqual:
2222 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002223 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302224 for (size_t i = 0; i < maxObjectSize; i++)
2225 {
2226 switch (basicType)
2227 {
2228 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002229 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302230 break;
2231 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002232 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302233 break;
2234 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002235 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302236 break;
2237 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002238 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302239 break;
2240 default:
2241 UNREACHABLE();
2242 break;
2243 }
2244 }
2245 }
2246 break;
2247
2248 case EOpVectorNotEqual:
2249 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002250 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302251 for (size_t i = 0; i < maxObjectSize; i++)
2252 {
2253 switch (basicType)
2254 {
2255 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002256 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302257 break;
2258 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002259 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302260 break;
2261 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002262 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302263 break;
2264 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002265 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302266 break;
2267 default:
2268 UNREACHABLE();
2269 break;
2270 }
2271 }
2272 }
2273 break;
2274
Arun Patole1155ddd2015-06-05 18:04:36 +05302275 case EOpDistance:
2276 if (basicType == EbtFloat)
2277 {
2278 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002279 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302280 for (size_t i = 0; i < maxObjectSize; i++)
2281 {
2282 float x = unionArrays[0][i].getFConst();
2283 float y = unionArrays[1][i].getFConst();
2284 distanceArray[i].setFConst(x - y);
2285 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002286 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302287 }
2288 else
2289 UNREACHABLE();
2290 break;
2291
2292 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002293
Arun Patole1155ddd2015-06-05 18:04:36 +05302294 if (basicType == EbtFloat)
2295 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002296 resultArray = new TConstantUnion();
2297 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302298 }
2299 else
2300 UNREACHABLE();
2301 break;
2302
2303 case EOpCross:
2304 if (basicType == EbtFloat && maxObjectSize == 3)
2305 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002306 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302307 float x0 = unionArrays[0][0].getFConst();
2308 float x1 = unionArrays[0][1].getFConst();
2309 float x2 = unionArrays[0][2].getFConst();
2310 float y0 = unionArrays[1][0].getFConst();
2311 float y1 = unionArrays[1][1].getFConst();
2312 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002313 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2314 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2315 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302316 }
2317 else
2318 UNREACHABLE();
2319 break;
2320
2321 case EOpReflect:
2322 if (basicType == EbtFloat)
2323 {
2324 // genType reflect (genType I, genType N) :
2325 // For the incident vector I and surface orientation N, returns the reflection direction:
2326 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002327 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302328 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2329 for (size_t i = 0; i < maxObjectSize; i++)
2330 {
2331 float result = unionArrays[0][i].getFConst() -
2332 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002333 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302334 }
2335 }
2336 else
2337 UNREACHABLE();
2338 break;
2339
Arun Patole7fa33552015-06-10 15:15:18 +05302340 case EOpMul:
2341 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2342 (*sequence)[1]->getAsTyped()->isMatrix())
2343 {
2344 // Perform component-wise matrix multiplication.
2345 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002346 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302347 angle::Matrix<float> result =
2348 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2349 SetUnionArrayFromMatrix(result, resultArray);
2350 }
2351 else
2352 UNREACHABLE();
2353 break;
2354
2355 case EOpOuterProduct:
2356 if (basicType == EbtFloat)
2357 {
2358 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2359 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2360 resultArray = new TConstantUnion[numRows * numCols];
2361 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002362 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2363 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302364 SetUnionArrayFromMatrix(result, resultArray);
2365 }
2366 else
2367 UNREACHABLE();
2368 break;
2369
Arun Patole274f0702015-05-05 13:33:30 +05302370 default:
2371 UNREACHABLE();
2372 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2373 return nullptr;
2374 }
2375 }
2376 else if (paramsCount == 3)
2377 {
2378 //
2379 // Ternary built-in
2380 //
2381 switch (op)
2382 {
2383 case EOpClamp:
2384 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002385 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302386 for (size_t i = 0; i < maxObjectSize; i++)
2387 {
2388 switch (basicType)
2389 {
2390 case EbtFloat:
2391 {
2392 float x = unionArrays[0][i].getFConst();
2393 float min = unionArrays[1][i].getFConst();
2394 float max = unionArrays[2][i].getFConst();
2395 // Results are undefined if min > max.
2396 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002397 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302398 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002399 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302400 }
2401 break;
2402 case EbtInt:
2403 {
2404 int x = unionArrays[0][i].getIConst();
2405 int min = unionArrays[1][i].getIConst();
2406 int max = unionArrays[2][i].getIConst();
2407 // Results are undefined if min > max.
2408 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002409 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302410 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002411 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302412 }
2413 break;
2414 case EbtUInt:
2415 {
2416 unsigned int x = unionArrays[0][i].getUConst();
2417 unsigned int min = unionArrays[1][i].getUConst();
2418 unsigned int max = unionArrays[2][i].getUConst();
2419 // Results are undefined if min > max.
2420 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002421 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302422 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002423 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302424 }
2425 break;
2426 default:
2427 UNREACHABLE();
2428 break;
2429 }
2430 }
2431 }
2432 break;
2433
Arun Patolebf790422015-05-18 17:53:04 +05302434 case EOpMix:
2435 {
2436 if (basicType == EbtFloat)
2437 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002438 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302439 for (size_t i = 0; i < maxObjectSize; i++)
2440 {
2441 float x = unionArrays[0][i].getFConst();
2442 float y = unionArrays[1][i].getFConst();
2443 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2444 if (type == EbtFloat)
2445 {
2446 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2447 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002448 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302449 }
2450 else // 3rd parameter is EbtBool
2451 {
2452 ASSERT(type == EbtBool);
2453 // Selects which vector each returned component comes from.
2454 // For a component of a that is false, the corresponding component of x is returned.
2455 // For a component of a that is true, the corresponding component of y is returned.
2456 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002457 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302458 }
2459 }
2460 }
2461 else
2462 UNREACHABLE();
2463 }
2464 break;
2465
2466 case EOpSmoothStep:
2467 {
2468 if (basicType == EbtFloat)
2469 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002470 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302471 for (size_t i = 0; i < maxObjectSize; i++)
2472 {
2473 float edge0 = unionArrays[0][i].getFConst();
2474 float edge1 = unionArrays[1][i].getFConst();
2475 float x = unionArrays[2][i].getFConst();
2476 // Results are undefined if edge0 >= edge1.
2477 if (edge0 >= edge1)
2478 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002479 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302480 }
2481 else
2482 {
2483 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2484 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2485 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002486 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302487 }
2488 }
2489 }
2490 else
2491 UNREACHABLE();
2492 }
2493 break;
2494
Arun Patole1155ddd2015-06-05 18:04:36 +05302495 case EOpFaceForward:
2496 if (basicType == EbtFloat)
2497 {
2498 // genType faceforward(genType N, genType I, genType Nref) :
2499 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002500 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302501 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2502 for (size_t i = 0; i < maxObjectSize; i++)
2503 {
2504 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002505 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302506 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002507 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302508 }
2509 }
2510 else
2511 UNREACHABLE();
2512 break;
2513
2514 case EOpRefract:
2515 if (basicType == EbtFloat)
2516 {
2517 // genType refract(genType I, genType N, float eta) :
2518 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2519 // return the refraction vector. The result is computed by
2520 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2521 // if (k < 0.0)
2522 // return genType(0.0)
2523 // else
2524 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002525 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302526 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2527 for (size_t i = 0; i < maxObjectSize; i++)
2528 {
2529 float eta = unionArrays[2][i].getFConst();
2530 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2531 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002532 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302533 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002534 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302535 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2536 }
2537 }
2538 else
2539 UNREACHABLE();
2540 break;
2541
Arun Patole274f0702015-05-05 13:33:30 +05302542 default:
2543 UNREACHABLE();
2544 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2545 return nullptr;
2546 }
2547 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002548 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302549}
2550
2551// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002552TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2553{
2554 if (hashFunction == NULL || name.empty())
2555 return name;
2556 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2557 TStringStream stream;
2558 stream << HASHED_NAME_PREFIX << std::hex << number;
2559 TString hashedName = stream.str();
2560 return hashedName;
2561}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002562
2563void TIntermTraverser::updateTree()
2564{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002565 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2566 {
2567 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2568 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002569 if (!insertion.insertionsAfter.empty())
2570 {
2571 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2572 insertion.insertionsAfter);
2573 ASSERT(inserted);
2574 UNUSED_ASSERTION_VARIABLE(inserted);
2575 }
2576 if (!insertion.insertionsBefore.empty())
2577 {
2578 bool inserted =
2579 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2580 ASSERT(inserted);
2581 UNUSED_ASSERTION_VARIABLE(inserted);
2582 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002583 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002584 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2585 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002586 const NodeUpdateEntry &replacement = mReplacements[ii];
2587 ASSERT(replacement.parent);
2588 bool replaced = replacement.parent->replaceChildNode(
2589 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002590 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002591 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002592
Olli Etuahocd94ef92015-04-16 19:18:10 +03002593 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002594 {
2595 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002596 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002597 // be replaced, we need to make sure we don't update the replaced
2598 // node; instead, we update the replacement node.
2599 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2600 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002601 NodeUpdateEntry &replacement2 = mReplacements[jj];
2602 if (replacement2.parent == replacement.original)
2603 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002604 }
2605 }
2606 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002607 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2608 {
2609 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2610 ASSERT(replacement.parent);
2611 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2612 replacement.original, replacement.replacements);
2613 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002614 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002615 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002616
2617 mInsertions.clear();
2618 mReplacements.clear();
2619 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002620}