blob: e9665f91181e260999c92c65ffa1909043e8abd7 [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 Etuaho83f34112015-06-18 15:47:46 +0300314 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300315 {
Olli Etuaho83f34112015-06-18 15:47:46 +0300316 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300317 }
Olli Etuaho83f34112015-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 Etuahod2a67b92014-10-21 16:42:57 +0300323void TIntermAggregate::setPrecisionFromChildren()
324{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300325 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300326 if (getBasicType() == EbtBool)
327 {
328 mType.setPrecision(EbpUndefined);
329 return;
330 }
331
332 TPrecision precision = EbpUndefined;
333 TIntermSequence::iterator childIter = mSequence.begin();
334 while (childIter != mSequence.end())
335 {
336 TIntermTyped *typed = (*childIter)->getAsTyped();
337 if (typed)
338 precision = GetHigherPrecision(typed->getPrecision(), precision);
339 ++childIter;
340 }
341 mType.setPrecision(precision);
342}
343
344void TIntermAggregate::setBuiltInFunctionPrecision()
345{
346 // All built-ins returning bool should be handled as ops, not functions.
347 ASSERT(getBasicType() != EbtBool);
348
349 TPrecision precision = EbpUndefined;
350 TIntermSequence::iterator childIter = mSequence.begin();
351 while (childIter != mSequence.end())
352 {
353 TIntermTyped *typed = (*childIter)->getAsTyped();
354 // ESSL spec section 8: texture functions get their precision from the sampler.
355 if (typed && IsSampler(typed->getBasicType()))
356 {
357 precision = typed->getPrecision();
358 break;
359 }
360 ++childIter;
361 }
362 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
363 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300364 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300365 mType.setPrecision(EbpHigh);
366 else
367 mType.setPrecision(precision);
368}
369
Jamie Madillb1a85f42014-08-19 15:23:24 -0400370bool TIntermSelection::replaceChildNode(
371 TIntermNode *original, TIntermNode *replacement)
372{
373 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
374 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
375 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
376 return false;
377}
378
Olli Etuahoa3a36662015-02-17 13:46:51 +0200379bool TIntermSwitch::replaceChildNode(
380 TIntermNode *original, TIntermNode *replacement)
381{
382 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
383 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
384 return false;
385}
386
387bool TIntermCase::replaceChildNode(
388 TIntermNode *original, TIntermNode *replacement)
389{
390 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
391 return false;
392}
393
Olli Etuahod7a25242015-08-18 13:49:45 +0300394TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
395{
396 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
397 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
398 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
399 mLine = node.mLine;
400}
401
402TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
403{
404 size_t arraySize = mType.getObjectSize();
405 mUnionArrayPointer = new TConstantUnion[arraySize];
406 for (size_t i = 0u; i < arraySize; ++i)
407 {
408 mUnionArrayPointer[i] = node.mUnionArrayPointer[i];
409 }
410}
411
412TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
413 : TIntermOperator(node),
414 mName(node.mName),
415 mUserDefined(node.mUserDefined),
416 mFunctionId(node.mFunctionId),
417 mOptimize(node.mOptimize),
418 mDebug(node.mDebug),
419 mUseEmulatedFunction(node.mUseEmulatedFunction),
420 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
421{
422 for (TIntermNode *child : node.mSequence)
423 {
424 TIntermTyped *typedChild = child->getAsTyped();
425 ASSERT(typedChild != nullptr);
426 TIntermTyped *childCopy = typedChild->deepCopy();
427 mSequence.push_back(childCopy);
428 }
429}
430
431TIntermBinary::TIntermBinary(const TIntermBinary &node)
432 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
433{
434 TIntermTyped *leftCopy = node.mLeft->deepCopy();
435 TIntermTyped *rightCopy = node.mRight->deepCopy();
436 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
437 mLeft = leftCopy;
438 mRight = rightCopy;
439}
440
441TIntermUnary::TIntermUnary(const TIntermUnary &node)
442 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
443{
444 TIntermTyped *operandCopy = node.mOperand->deepCopy();
445 ASSERT(operandCopy != nullptr);
446 mOperand = operandCopy;
447}
448
449TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
450{
451 // Only supported for ternary nodes, not if statements.
452 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
453 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
454 ASSERT(trueTyped != nullptr);
455 ASSERT(falseTyped != nullptr);
456 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
457 TIntermTyped *trueCopy = trueTyped->deepCopy();
458 TIntermTyped *falseCopy = falseTyped->deepCopy();
459 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
460 mCondition = conditionCopy;
461 mTrueBlock = trueCopy;
462 mFalseBlock = falseCopy;
463}
464
Jamie Madillb1a85f42014-08-19 15:23:24 -0400465//
466// Say whether or not an operation node changes the value of a variable.
467//
468bool TIntermOperator::isAssignment() const
469{
470 switch (mOp)
471 {
472 case EOpPostIncrement:
473 case EOpPostDecrement:
474 case EOpPreIncrement:
475 case EOpPreDecrement:
476 case EOpAssign:
477 case EOpAddAssign:
478 case EOpSubAssign:
479 case EOpMulAssign:
480 case EOpVectorTimesMatrixAssign:
481 case EOpVectorTimesScalarAssign:
482 case EOpMatrixTimesScalarAssign:
483 case EOpMatrixTimesMatrixAssign:
484 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200485 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200486 case EOpBitShiftLeftAssign:
487 case EOpBitShiftRightAssign:
488 case EOpBitwiseAndAssign:
489 case EOpBitwiseXorAssign:
490 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400491 return true;
492 default:
493 return false;
494 }
495}
496
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300497bool TIntermOperator::isMultiplication() const
498{
499 switch (mOp)
500 {
501 case EOpMul:
502 case EOpMatrixTimesMatrix:
503 case EOpMatrixTimesVector:
504 case EOpMatrixTimesScalar:
505 case EOpVectorTimesMatrix:
506 case EOpVectorTimesScalar:
507 return true;
508 default:
509 return false;
510 }
511}
512
Jamie Madillb1a85f42014-08-19 15:23:24 -0400513//
514// returns true if the operator is for one of the constructors
515//
516bool TIntermOperator::isConstructor() const
517{
518 switch (mOp)
519 {
520 case EOpConstructVec2:
521 case EOpConstructVec3:
522 case EOpConstructVec4:
523 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400524 case EOpConstructMat2x3:
525 case EOpConstructMat2x4:
526 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400527 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400528 case EOpConstructMat3x4:
529 case EOpConstructMat4x2:
530 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400531 case EOpConstructMat4:
532 case EOpConstructFloat:
533 case EOpConstructIVec2:
534 case EOpConstructIVec3:
535 case EOpConstructIVec4:
536 case EOpConstructInt:
537 case EOpConstructUVec2:
538 case EOpConstructUVec3:
539 case EOpConstructUVec4:
540 case EOpConstructUInt:
541 case EOpConstructBVec2:
542 case EOpConstructBVec3:
543 case EOpConstructBVec4:
544 case EOpConstructBool:
545 case EOpConstructStruct:
546 return true;
547 default:
548 return false;
549 }
550}
551
552//
553// Make sure the type of a unary operator is appropriate for its
554// combination of operation and operand type.
555//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200556void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400557{
558 switch (mOp)
559 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200560 case EOpFloatBitsToInt:
561 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200562 case EOpIntBitsToFloat:
563 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200564 case EOpPackSnorm2x16:
565 case EOpPackUnorm2x16:
566 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200567 case EOpUnpackSnorm2x16:
568 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200569 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530570 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200571 case EOpUnpackHalf2x16:
572 mType.setPrecision(EbpMedium);
573 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400574 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200575 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400576 }
577
Olli Etuahof6c694b2015-03-26 14:50:53 +0200578 if (funcReturnType != nullptr)
579 {
580 if (funcReturnType->getBasicType() == EbtBool)
581 {
582 // Bool types should not have precision.
583 setType(*funcReturnType);
584 }
585 else
586 {
587 // Precision of the node has been set based on the operand.
588 setTypePreservePrecision(*funcReturnType);
589 }
590 }
591
Jamie Madillb1a85f42014-08-19 15:23:24 -0400592 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400593}
594
595//
596// Establishes the type of the resultant operation, as well as
597// makes the operator the correct one for the operands.
598//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200599// For lots of operations it should already be established that the operand
600// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400601//
602bool TIntermBinary::promote(TInfoSink &infoSink)
603{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200604 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400605
Jamie Madillb1a85f42014-08-19 15:23:24 -0400606 //
607 // Base assumption: just make the type the same as the left
608 // operand. Then only deviations from this need be coded.
609 //
610 setType(mLeft->getType());
611
612 // The result gets promoted to the highest precision.
613 TPrecision higherPrecision = GetHigherPrecision(
614 mLeft->getPrecision(), mRight->getPrecision());
615 getTypePointer()->setPrecision(higherPrecision);
616
617 // Binary operations results in temporary variables unless both
618 // operands are const.
619 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
620 {
621 getTypePointer()->setQualifier(EvqTemporary);
622 }
623
624 const int nominalSize =
625 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
626
627 //
628 // All scalars or structs. Code after this test assumes this case is removed!
629 //
630 if (nominalSize == 1)
631 {
632 switch (mOp)
633 {
634 //
635 // Promote to conditional
636 //
637 case EOpEqual:
638 case EOpNotEqual:
639 case EOpLessThan:
640 case EOpGreaterThan:
641 case EOpLessThanEqual:
642 case EOpGreaterThanEqual:
643 setType(TType(EbtBool, EbpUndefined));
644 break;
645
646 //
647 // And and Or operate on conditionals
648 //
649 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200650 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400651 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200652 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400653 setType(TType(EbtBool, EbpUndefined));
654 break;
655
656 default:
657 break;
658 }
659 return true;
660 }
661
662 // If we reach here, at least one of the operands is vector or matrix.
663 // The other operand could be a scalar, vector, or matrix.
664 // Can these two operands be combined?
665 //
666 TBasicType basicType = mLeft->getBasicType();
667 switch (mOp)
668 {
669 case EOpMul:
670 if (!mLeft->isMatrix() && mRight->isMatrix())
671 {
672 if (mLeft->isVector())
673 {
674 mOp = EOpVectorTimesMatrix;
675 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700676 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400677 }
678 else
679 {
680 mOp = EOpMatrixTimesScalar;
681 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700682 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400683 }
684 }
685 else if (mLeft->isMatrix() && !mRight->isMatrix())
686 {
687 if (mRight->isVector())
688 {
689 mOp = EOpMatrixTimesVector;
690 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700691 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400692 }
693 else
694 {
695 mOp = EOpMatrixTimesScalar;
696 }
697 }
698 else if (mLeft->isMatrix() && mRight->isMatrix())
699 {
700 mOp = EOpMatrixTimesMatrix;
701 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700702 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400703 }
704 else if (!mLeft->isMatrix() && !mRight->isMatrix())
705 {
706 if (mLeft->isVector() && mRight->isVector())
707 {
708 // leave as component product
709 }
710 else if (mLeft->isVector() || mRight->isVector())
711 {
712 mOp = EOpVectorTimesScalar;
713 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700714 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400715 }
716 }
717 else
718 {
719 infoSink.info.message(EPrefixInternalError, getLine(),
720 "Missing elses");
721 return false;
722 }
723
724 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
725 {
726 return false;
727 }
728 break;
729
730 case EOpMulAssign:
731 if (!mLeft->isMatrix() && mRight->isMatrix())
732 {
733 if (mLeft->isVector())
734 {
735 mOp = EOpVectorTimesMatrixAssign;
736 }
737 else
738 {
739 return false;
740 }
741 }
742 else if (mLeft->isMatrix() && !mRight->isMatrix())
743 {
744 if (mRight->isVector())
745 {
746 return false;
747 }
748 else
749 {
750 mOp = EOpMatrixTimesScalarAssign;
751 }
752 }
753 else if (mLeft->isMatrix() && mRight->isMatrix())
754 {
755 mOp = EOpMatrixTimesMatrixAssign;
756 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700757 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758 }
759 else if (!mLeft->isMatrix() && !mRight->isMatrix())
760 {
761 if (mLeft->isVector() && mRight->isVector())
762 {
763 // leave as component product
764 }
765 else if (mLeft->isVector() || mRight->isVector())
766 {
767 if (!mLeft->isVector())
768 return false;
769 mOp = EOpVectorTimesScalarAssign;
770 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700771 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400772 }
773 }
774 else
775 {
776 infoSink.info.message(EPrefixInternalError, getLine(),
777 "Missing elses");
778 return false;
779 }
780
781 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
782 {
783 return false;
784 }
785 break;
786
787 case EOpAssign:
788 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200789 // No more additional checks are needed.
790 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
791 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
792 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400793 case EOpAdd:
794 case EOpSub:
795 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200796 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200797 case EOpBitShiftLeft:
798 case EOpBitShiftRight:
799 case EOpBitwiseAnd:
800 case EOpBitwiseXor:
801 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400802 case EOpAddAssign:
803 case EOpSubAssign:
804 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200805 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200806 case EOpBitShiftLeftAssign:
807 case EOpBitShiftRightAssign:
808 case EOpBitwiseAndAssign:
809 case EOpBitwiseXorAssign:
810 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400811 if ((mLeft->isMatrix() && mRight->isVector()) ||
812 (mLeft->isVector() && mRight->isMatrix()))
813 {
814 return false;
815 }
816
817 // Are the sizes compatible?
818 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
819 mLeft->getSecondarySize() != mRight->getSecondarySize())
820 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200821 // If the nominal sizes of operands do not match:
822 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400823 if (!mLeft->isScalar() && !mRight->isScalar())
824 return false;
825
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200826 // In the case of compound assignment other than multiply-assign,
827 // the right side needs to be a scalar. Otherwise a vector/matrix
828 // would be assigned to a scalar. A scalar can't be shifted by a
829 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200830 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200831 (isAssignment() ||
832 mOp == EOpBitShiftLeft ||
833 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200834 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400835 }
836
837 {
838 const int secondarySize = std::max(
839 mLeft->getSecondarySize(), mRight->getSecondarySize());
840 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700841 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200842 if (mLeft->isArray())
843 {
844 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
845 mType.setArraySize(mLeft->getArraySize());
846 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400847 }
848 break;
849
850 case EOpEqual:
851 case EOpNotEqual:
852 case EOpLessThan:
853 case EOpGreaterThan:
854 case EOpLessThanEqual:
855 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200856 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
857 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400858 setType(TType(EbtBool, EbpUndefined));
859 break;
860
861 default:
862 return false;
863 }
864 return true;
865}
866
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300867TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
868{
869 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
870 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
871 if (leftConstant == nullptr || rightConstant == nullptr)
872 {
873 return nullptr;
874 }
875 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300876 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300877}
878
Olli Etuaho95310b02015-06-02 17:43:38 +0300879TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
880{
881 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
882 if (operandConstant == nullptr)
883 {
884 return nullptr;
885 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530886
887 TConstantUnion *constArray = nullptr;
888 switch (mOp)
889 {
890 case EOpAny:
891 case EOpAll:
892 case EOpLength:
893 case EOpTranspose:
894 case EOpDeterminant:
895 case EOpInverse:
896 case EOpPackSnorm2x16:
897 case EOpUnpackSnorm2x16:
898 case EOpPackUnorm2x16:
899 case EOpUnpackUnorm2x16:
900 case EOpPackHalf2x16:
901 case EOpUnpackHalf2x16:
902 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
903 break;
904 default:
905 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
906 break;
907 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300908 return CreateFoldedNode(constArray, this);
909}
910
911TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
912{
913 // Make sure that all params are constant before actual constant folding.
914 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300915 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300916 if (param->getAsConstantUnion() == nullptr)
917 {
918 return nullptr;
919 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300920 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300921 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
922 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300923}
924
Jamie Madillb1a85f42014-08-19 15:23:24 -0400925//
926// The fold functions see if an operation on a constant can be done in place,
927// without generating run-time code.
928//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300929// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400930//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300931TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
932{
933 TConstantUnion *leftArray = getUnionArrayPointer();
934 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
935
936 if (!leftArray)
937 return nullptr;
938 if (!rightArray)
939 return nullptr;
940
941 size_t objectSize = getType().getObjectSize();
942
943 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
944 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
945 {
946 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
947 }
948 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
949 {
950 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
951 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
952 objectSize = rightNode->getType().getObjectSize();
953 }
954
955 TConstantUnion *resultArray = nullptr;
956
957 switch(op)
958 {
959 case EOpAdd:
960 resultArray = new TConstantUnion[objectSize];
961 for (size_t i = 0; i < objectSize; i++)
962 resultArray[i] = leftArray[i] + rightArray[i];
963 break;
964 case EOpSub:
965 resultArray = new TConstantUnion[objectSize];
966 for (size_t i = 0; i < objectSize; i++)
967 resultArray[i] = leftArray[i] - rightArray[i];
968 break;
969
970 case EOpMul:
971 case EOpVectorTimesScalar:
972 case EOpMatrixTimesScalar:
973 resultArray = new TConstantUnion[objectSize];
974 for (size_t i = 0; i < objectSize; i++)
975 resultArray[i] = leftArray[i] * rightArray[i];
976 break;
977
978 case EOpMatrixTimesMatrix:
979 {
980 if (getType().getBasicType() != EbtFloat ||
981 rightNode->getBasicType() != EbtFloat)
982 {
983 infoSink.info.message(
984 EPrefixInternalError, getLine(),
985 "Constant Folding cannot be done for matrix multiply");
986 return nullptr;
987 }
988
989 const int leftCols = getCols();
990 const int leftRows = getRows();
991 const int rightCols = rightNode->getType().getCols();
992 const int rightRows = rightNode->getType().getRows();
993 const int resultCols = rightCols;
994 const int resultRows = leftRows;
995
996 resultArray = new TConstantUnion[resultCols * resultRows];
997 for (int row = 0; row < resultRows; row++)
998 {
999 for (int column = 0; column < resultCols; column++)
1000 {
1001 resultArray[resultRows * column + row].setFConst(0.0f);
1002 for (int i = 0; i < leftCols; i++)
1003 {
1004 resultArray[resultRows * column + row].setFConst(
1005 resultArray[resultRows * column + row].getFConst() +
1006 leftArray[i * leftRows + row].getFConst() *
1007 rightArray[column * rightRows + i].getFConst());
1008 }
1009 }
1010 }
1011 }
1012 break;
1013
1014 case EOpDiv:
1015 case EOpIMod:
1016 {
1017 resultArray = new TConstantUnion[objectSize];
1018 for (size_t i = 0; i < objectSize; i++)
1019 {
1020 switch (getType().getBasicType())
1021 {
1022 case EbtFloat:
1023 if (rightArray[i] == 0.0f)
1024 {
1025 infoSink.info.message(EPrefixWarning, getLine(),
1026 "Divide by zero error during constant folding");
1027 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1028 }
1029 else
1030 {
1031 ASSERT(op == EOpDiv);
1032 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1033 }
1034 break;
1035
1036 case EbtInt:
1037 if (rightArray[i] == 0)
1038 {
1039 infoSink.info.message(EPrefixWarning, getLine(),
1040 "Divide by zero error during constant folding");
1041 resultArray[i].setIConst(INT_MAX);
1042 }
1043 else
1044 {
1045 if (op == EOpDiv)
1046 {
1047 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1048 }
1049 else
1050 {
1051 ASSERT(op == EOpIMod);
1052 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1053 }
1054 }
1055 break;
1056
1057 case EbtUInt:
1058 if (rightArray[i] == 0)
1059 {
1060 infoSink.info.message(EPrefixWarning, getLine(),
1061 "Divide by zero error during constant folding");
1062 resultArray[i].setUConst(UINT_MAX);
1063 }
1064 else
1065 {
1066 if (op == EOpDiv)
1067 {
1068 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1069 }
1070 else
1071 {
1072 ASSERT(op == EOpIMod);
1073 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1074 }
1075 }
1076 break;
1077
1078 default:
1079 infoSink.info.message(EPrefixInternalError, getLine(),
1080 "Constant folding cannot be done for \"/\"");
1081 return nullptr;
1082 }
1083 }
1084 }
1085 break;
1086
1087 case EOpMatrixTimesVector:
1088 {
1089 if (rightNode->getBasicType() != EbtFloat)
1090 {
1091 infoSink.info.message(EPrefixInternalError, getLine(),
1092 "Constant Folding cannot be done for matrix times vector");
1093 return nullptr;
1094 }
1095
1096 const int matrixCols = getCols();
1097 const int matrixRows = getRows();
1098
1099 resultArray = new TConstantUnion[matrixRows];
1100
1101 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1102 {
1103 resultArray[matrixRow].setFConst(0.0f);
1104 for (int col = 0; col < matrixCols; col++)
1105 {
1106 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1107 leftArray[col * matrixRows + matrixRow].getFConst() *
1108 rightArray[col].getFConst());
1109 }
1110 }
1111 }
1112 break;
1113
1114 case EOpVectorTimesMatrix:
1115 {
1116 if (getType().getBasicType() != EbtFloat)
1117 {
1118 infoSink.info.message(EPrefixInternalError, getLine(),
1119 "Constant Folding cannot be done for vector times matrix");
1120 return nullptr;
1121 }
1122
1123 const int matrixCols = rightNode->getType().getCols();
1124 const int matrixRows = rightNode->getType().getRows();
1125
1126 resultArray = new TConstantUnion[matrixCols];
1127
1128 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1129 {
1130 resultArray[matrixCol].setFConst(0.0f);
1131 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1132 {
1133 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1134 leftArray[matrixRow].getFConst() *
1135 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1136 }
1137 }
1138 }
1139 break;
1140
1141 case EOpLogicalAnd:
1142 {
1143 resultArray = new TConstantUnion[objectSize];
1144 for (size_t i = 0; i < objectSize; i++)
1145 {
1146 resultArray[i] = leftArray[i] && rightArray[i];
1147 }
1148 }
1149 break;
1150
1151 case EOpLogicalOr:
1152 {
1153 resultArray = new TConstantUnion[objectSize];
1154 for (size_t i = 0; i < objectSize; i++)
1155 {
1156 resultArray[i] = leftArray[i] || rightArray[i];
1157 }
1158 }
1159 break;
1160
1161 case EOpLogicalXor:
1162 {
1163 resultArray = new TConstantUnion[objectSize];
1164 for (size_t i = 0; i < objectSize; i++)
1165 {
1166 switch (getType().getBasicType())
1167 {
1168 case EbtBool:
1169 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1170 break;
1171 default:
1172 UNREACHABLE();
1173 break;
1174 }
1175 }
1176 }
1177 break;
1178
1179 case EOpBitwiseAnd:
1180 resultArray = new TConstantUnion[objectSize];
1181 for (size_t i = 0; i < objectSize; i++)
1182 resultArray[i] = leftArray[i] & rightArray[i];
1183 break;
1184 case EOpBitwiseXor:
1185 resultArray = new TConstantUnion[objectSize];
1186 for (size_t i = 0; i < objectSize; i++)
1187 resultArray[i] = leftArray[i] ^ rightArray[i];
1188 break;
1189 case EOpBitwiseOr:
1190 resultArray = new TConstantUnion[objectSize];
1191 for (size_t i = 0; i < objectSize; i++)
1192 resultArray[i] = leftArray[i] | rightArray[i];
1193 break;
1194 case EOpBitShiftLeft:
1195 resultArray = new TConstantUnion[objectSize];
1196 for (size_t i = 0; i < objectSize; i++)
1197 resultArray[i] = leftArray[i] << rightArray[i];
1198 break;
1199 case EOpBitShiftRight:
1200 resultArray = new TConstantUnion[objectSize];
1201 for (size_t i = 0; i < objectSize; i++)
1202 resultArray[i] = leftArray[i] >> rightArray[i];
1203 break;
1204
1205 case EOpLessThan:
1206 ASSERT(objectSize == 1);
1207 resultArray = new TConstantUnion[1];
1208 resultArray->setBConst(*leftArray < *rightArray);
1209 break;
1210
1211 case EOpGreaterThan:
1212 ASSERT(objectSize == 1);
1213 resultArray = new TConstantUnion[1];
1214 resultArray->setBConst(*leftArray > *rightArray);
1215 break;
1216
1217 case EOpLessThanEqual:
1218 ASSERT(objectSize == 1);
1219 resultArray = new TConstantUnion[1];
1220 resultArray->setBConst(!(*leftArray > *rightArray));
1221 break;
1222
1223 case EOpGreaterThanEqual:
1224 ASSERT(objectSize == 1);
1225 resultArray = new TConstantUnion[1];
1226 resultArray->setBConst(!(*leftArray < *rightArray));
1227 break;
1228
1229 case EOpEqual:
1230 case EOpNotEqual:
1231 {
1232 resultArray = new TConstantUnion[1];
1233 bool equal = true;
1234 if (getType().getBasicType() == EbtStruct)
1235 {
1236 equal = CompareStructure(getType(), rightArray, leftArray);
1237 }
1238 else
1239 {
1240 for (size_t i = 0; i < objectSize; i++)
1241 {
1242 if (leftArray[i] != rightArray[i])
1243 {
1244 equal = false;
1245 break; // break out of for loop
1246 }
1247 }
1248 }
1249 if (op == EOpEqual)
1250 {
1251 resultArray->setBConst(equal);
1252 }
1253 else
1254 {
1255 resultArray->setBConst(!equal);
1256 }
1257 }
1258 break;
1259
1260 default:
1261 infoSink.info.message(
1262 EPrefixInternalError, getLine(),
1263 "Invalid operator for constant folding");
1264 return nullptr;
1265 }
1266 return resultArray;
1267}
1268
1269//
1270// The fold functions see if an operation on a constant can be done in place,
1271// without generating run-time code.
1272//
Olli Etuaho95310b02015-06-02 17:43:38 +03001273// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001274//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301275TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001276{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301277 //
1278 // Do operations where the return type has a different number of components compared to the operand type.
1279 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001280
Arun Patoleab2b9a22015-07-06 18:27:56 +05301281 TConstantUnion *operandArray = getUnionArrayPointer();
1282 if (!operandArray)
1283 return nullptr;
1284
1285 size_t objectSize = getType().getObjectSize();
1286 TConstantUnion *resultArray = nullptr;
1287 switch (op)
1288 {
1289 case EOpAny:
1290 if (getType().getBasicType() == EbtBool)
1291 {
1292 resultArray = new TConstantUnion();
1293 resultArray->setBConst(false);
1294 for (size_t i = 0; i < objectSize; i++)
1295 {
1296 if (operandArray[i].getBConst())
1297 {
1298 resultArray->setBConst(true);
1299 break;
1300 }
1301 }
1302 break;
1303 }
1304 else
1305 {
1306 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1307 return nullptr;
1308 }
1309
1310 case EOpAll:
1311 if (getType().getBasicType() == EbtBool)
1312 {
1313 resultArray = new TConstantUnion();
1314 resultArray->setBConst(true);
1315 for (size_t i = 0; i < objectSize; i++)
1316 {
1317 if (!operandArray[i].getBConst())
1318 {
1319 resultArray->setBConst(false);
1320 break;
1321 }
1322 }
1323 break;
1324 }
1325 else
1326 {
1327 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1328 return nullptr;
1329 }
1330
1331 case EOpLength:
1332 if (getType().getBasicType() == EbtFloat)
1333 {
1334 resultArray = new TConstantUnion();
1335 resultArray->setFConst(VectorLength(operandArray, objectSize));
1336 break;
1337 }
1338 else
1339 {
1340 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1341 return nullptr;
1342 }
1343
1344 case EOpTranspose:
1345 if (getType().getBasicType() == EbtFloat)
1346 {
1347 resultArray = new TConstantUnion[objectSize];
1348 angle::Matrix<float> result =
1349 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1350 SetUnionArrayFromMatrix(result, resultArray);
1351 break;
1352 }
1353 else
1354 {
1355 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1356 return nullptr;
1357 }
1358
1359 case EOpDeterminant:
1360 if (getType().getBasicType() == EbtFloat)
1361 {
1362 unsigned int size = getType().getNominalSize();
1363 ASSERT(size >= 2 && size <= 4);
1364 resultArray = new TConstantUnion();
1365 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1366 break;
1367 }
1368 else
1369 {
1370 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1371 return nullptr;
1372 }
1373
1374 case EOpInverse:
1375 if (getType().getBasicType() == EbtFloat)
1376 {
1377 unsigned int size = getType().getNominalSize();
1378 ASSERT(size >= 2 && size <= 4);
1379 resultArray = new TConstantUnion[objectSize];
1380 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1381 SetUnionArrayFromMatrix(result, resultArray);
1382 break;
1383 }
1384 else
1385 {
1386 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1387 return nullptr;
1388 }
1389
1390 case EOpPackSnorm2x16:
1391 if (getType().getBasicType() == EbtFloat)
1392 {
1393 ASSERT(getType().getNominalSize() == 2);
1394 resultArray = new TConstantUnion();
1395 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1396 break;
1397 }
1398 else
1399 {
1400 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1401 return nullptr;
1402 }
1403
1404 case EOpUnpackSnorm2x16:
1405 if (getType().getBasicType() == EbtUInt)
1406 {
1407 resultArray = new TConstantUnion[2];
1408 float f1, f2;
1409 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1410 resultArray[0].setFConst(f1);
1411 resultArray[1].setFConst(f2);
1412 break;
1413 }
1414 else
1415 {
1416 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1417 return nullptr;
1418 }
1419
1420 case EOpPackUnorm2x16:
1421 if (getType().getBasicType() == EbtFloat)
1422 {
1423 ASSERT(getType().getNominalSize() == 2);
1424 resultArray = new TConstantUnion();
1425 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1426 break;
1427 }
1428 else
1429 {
1430 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1431 return nullptr;
1432 }
1433
1434 case EOpUnpackUnorm2x16:
1435 if (getType().getBasicType() == EbtUInt)
1436 {
1437 resultArray = new TConstantUnion[2];
1438 float f1, f2;
1439 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1440 resultArray[0].setFConst(f1);
1441 resultArray[1].setFConst(f2);
1442 break;
1443 }
1444 else
1445 {
1446 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1447 return nullptr;
1448 }
1449
1450 case EOpPackHalf2x16:
1451 if (getType().getBasicType() == EbtFloat)
1452 {
1453 ASSERT(getType().getNominalSize() == 2);
1454 resultArray = new TConstantUnion();
1455 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1456 break;
1457 }
1458 else
1459 {
1460 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1461 return nullptr;
1462 }
1463
1464 case EOpUnpackHalf2x16:
1465 if (getType().getBasicType() == EbtUInt)
1466 {
1467 resultArray = new TConstantUnion[2];
1468 float f1, f2;
1469 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1470 resultArray[0].setFConst(f1);
1471 resultArray[1].setFConst(f2);
1472 break;
1473 }
1474 else
1475 {
1476 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1477 return nullptr;
1478 }
1479 break;
1480
1481 default:
1482 break;
1483 }
1484
1485 return resultArray;
1486}
1487
1488TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1489{
1490 //
1491 // Do unary operations where the return type is the same as operand type.
1492 //
1493
1494 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001495 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301496 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001497
1498 size_t objectSize = getType().getObjectSize();
1499
Arun Patoleab2b9a22015-07-06 18:27:56 +05301500 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1501 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301502 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301503 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301504 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301505 case EOpNegative:
1506 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301507 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301508 case EbtFloat:
1509 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301510 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301511 case EbtInt:
1512 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301513 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301514 case EbtUInt:
1515 resultArray[i].setUConst(static_cast<unsigned int>(
1516 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301517 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301518 default:
1519 infoSink.info.message(
1520 EPrefixInternalError, getLine(),
1521 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301522 return nullptr;
1523 }
1524 break;
1525
Arun Patoleab2b9a22015-07-06 18:27:56 +05301526 case EOpPositive:
1527 switch (getType().getBasicType())
1528 {
1529 case EbtFloat:
1530 resultArray[i].setFConst(operandArray[i].getFConst());
1531 break;
1532 case EbtInt:
1533 resultArray[i].setIConst(operandArray[i].getIConst());
1534 break;
1535 case EbtUInt:
1536 resultArray[i].setUConst(static_cast<unsigned int>(
1537 static_cast<int>(operandArray[i].getUConst())));
1538 break;
1539 default:
1540 infoSink.info.message(
1541 EPrefixInternalError, getLine(),
1542 "Unary operation not folded into constant");
1543 return nullptr;
1544 }
1545 break;
1546
1547 case EOpLogicalNot:
1548 // this code is written for possible future use,
1549 // will not get executed currently
1550 switch (getType().getBasicType())
1551 {
1552 case EbtBool:
1553 resultArray[i].setBConst(!operandArray[i].getBConst());
1554 break;
1555 default:
1556 infoSink.info.message(
1557 EPrefixInternalError, getLine(),
1558 "Unary operation not folded into constant");
1559 return nullptr;
1560 }
1561 break;
1562
1563 case EOpBitwiseNot:
1564 switch (getType().getBasicType())
1565 {
1566 case EbtInt:
1567 resultArray[i].setIConst(~operandArray[i].getIConst());
1568 break;
1569 case EbtUInt:
1570 resultArray[i].setUConst(~operandArray[i].getUConst());
1571 break;
1572 default:
1573 infoSink.info.message(
1574 EPrefixInternalError, getLine(),
1575 "Unary operation not folded into constant");
1576 return nullptr;
1577 }
1578 break;
1579
1580 case EOpRadians:
1581 if (getType().getBasicType() == EbtFloat)
1582 {
1583 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1584 break;
1585 }
1586 infoSink.info.message(
1587 EPrefixInternalError, getLine(),
1588 "Unary operation not folded into constant");
1589 return nullptr;
1590
1591 case EOpDegrees:
1592 if (getType().getBasicType() == EbtFloat)
1593 {
1594 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1595 break;
1596 }
1597 infoSink.info.message(
1598 EPrefixInternalError, getLine(),
1599 "Unary operation not folded into constant");
1600 return nullptr;
1601
1602 case EOpSin:
1603 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1604 return nullptr;
1605 break;
1606
1607 case EOpCos:
1608 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1609 return nullptr;
1610 break;
1611
1612 case EOpTan:
1613 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1614 return nullptr;
1615 break;
1616
1617 case EOpAsin:
1618 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1619 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1620 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1621 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1622 return nullptr;
1623 break;
1624
1625 case EOpAcos:
1626 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1627 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1628 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1629 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1630 return nullptr;
1631 break;
1632
1633 case EOpAtan:
1634 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1635 return nullptr;
1636 break;
1637
1638 case EOpSinh:
1639 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1640 return nullptr;
1641 break;
1642
1643 case EOpCosh:
1644 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1645 return nullptr;
1646 break;
1647
1648 case EOpTanh:
1649 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1650 return nullptr;
1651 break;
1652
1653 case EOpAsinh:
1654 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1655 return nullptr;
1656 break;
1657
1658 case EOpAcosh:
1659 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1660 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1661 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1662 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1663 return nullptr;
1664 break;
1665
1666 case EOpAtanh:
1667 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1668 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1669 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1670 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1671 return nullptr;
1672 break;
1673
1674 case EOpAbs:
1675 switch (getType().getBasicType())
1676 {
1677 case EbtFloat:
1678 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1679 break;
1680 case EbtInt:
1681 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1682 break;
1683 default:
1684 infoSink.info.message(
1685 EPrefixInternalError, getLine(),
1686 "Unary operation not folded into constant");
1687 return nullptr;
1688 }
1689 break;
1690
1691 case EOpSign:
1692 switch (getType().getBasicType())
1693 {
1694 case EbtFloat:
1695 {
1696 float fConst = operandArray[i].getFConst();
1697 float fResult = 0.0f;
1698 if (fConst > 0.0f)
1699 fResult = 1.0f;
1700 else if (fConst < 0.0f)
1701 fResult = -1.0f;
1702 resultArray[i].setFConst(fResult);
1703 }
1704 break;
1705 case EbtInt:
1706 {
1707 int iConst = operandArray[i].getIConst();
1708 int iResult = 0;
1709 if (iConst > 0)
1710 iResult = 1;
1711 else if (iConst < 0)
1712 iResult = -1;
1713 resultArray[i].setIConst(iResult);
1714 }
1715 break;
1716 default:
1717 infoSink.info.message(
1718 EPrefixInternalError, getLine(),
1719 "Unary operation not folded into constant");
1720 return nullptr;
1721 }
1722 break;
1723
1724 case EOpFloor:
1725 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1726 return nullptr;
1727 break;
1728
1729 case EOpTrunc:
1730 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1731 return nullptr;
1732 break;
1733
1734 case EOpRound:
1735 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1736 return nullptr;
1737 break;
1738
1739 case EOpRoundEven:
1740 if (getType().getBasicType() == EbtFloat)
1741 {
1742 float x = operandArray[i].getFConst();
1743 float result;
1744 float fractPart = modff(x, &result);
1745 if (fabsf(fractPart) == 0.5f)
1746 result = 2.0f * roundf(x / 2.0f);
1747 else
1748 result = roundf(x);
1749 resultArray[i].setFConst(result);
1750 break;
1751 }
1752 infoSink.info.message(
1753 EPrefixInternalError, getLine(),
1754 "Unary operation not folded into constant");
1755 return nullptr;
1756
1757 case EOpCeil:
1758 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1759 return nullptr;
1760 break;
1761
1762 case EOpFract:
1763 if (getType().getBasicType() == EbtFloat)
1764 {
1765 float x = operandArray[i].getFConst();
1766 resultArray[i].setFConst(x - floorf(x));
1767 break;
1768 }
1769 infoSink.info.message(
1770 EPrefixInternalError, getLine(),
1771 "Unary operation not folded into constant");
1772 return nullptr;
1773
Arun Patole551279e2015-07-07 18:18:23 +05301774 case EOpIsNan:
1775 if (getType().getBasicType() == EbtFloat)
1776 {
1777 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1778 break;
1779 }
1780 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1781 return nullptr;
1782
1783 case EOpIsInf:
1784 if (getType().getBasicType() == EbtFloat)
1785 {
1786 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1787 break;
1788 }
1789 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1790 return nullptr;
1791
1792 case EOpFloatBitsToInt:
1793 if (getType().getBasicType() == EbtFloat)
1794 {
1795 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1796 break;
1797 }
1798 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1799 return nullptr;
1800
1801 case EOpFloatBitsToUint:
1802 if (getType().getBasicType() == EbtFloat)
1803 {
1804 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1805 break;
1806 }
1807 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1808 return nullptr;
1809
1810 case EOpIntBitsToFloat:
1811 if (getType().getBasicType() == EbtInt)
1812 {
1813 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1814 break;
1815 }
1816 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1817 return nullptr;
1818
1819 case EOpUintBitsToFloat:
1820 if (getType().getBasicType() == EbtUInt)
1821 {
1822 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1823 break;
1824 }
1825 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1826 return nullptr;
1827
Arun Patoleab2b9a22015-07-06 18:27:56 +05301828 case EOpExp:
1829 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1830 return nullptr;
1831 break;
1832
1833 case EOpLog:
1834 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1835 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1836 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1837 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1838 return nullptr;
1839 break;
1840
1841 case EOpExp2:
1842 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1843 return nullptr;
1844 break;
1845
1846 case EOpLog2:
1847 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1848 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1849 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1850 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1851 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1852 return nullptr;
1853 else
1854 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1855 break;
1856
1857 case EOpSqrt:
1858 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1859 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1860 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1861 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1862 return nullptr;
1863 break;
1864
1865 case EOpInverseSqrt:
1866 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1867 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1868 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
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], &sqrtf, infoSink, &resultArray[i]))
1872 return nullptr;
1873 else
1874 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1875 break;
1876
1877 case EOpVectorLogicalNot:
1878 if (getType().getBasicType() == EbtBool)
1879 {
1880 resultArray[i].setBConst(!operandArray[i].getBConst());
1881 break;
1882 }
1883 infoSink.info.message(
1884 EPrefixInternalError, getLine(),
1885 "Unary operation not folded into constant");
1886 return nullptr;
1887
1888 case EOpNormalize:
1889 if (getType().getBasicType() == EbtFloat)
1890 {
1891 float x = operandArray[i].getFConst();
1892 float length = VectorLength(operandArray, objectSize);
1893 if (length)
1894 resultArray[i].setFConst(x / length);
1895 else
1896 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1897 &resultArray[i]);
1898 break;
1899 }
1900 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1901 return nullptr;
1902
Arun Patole0c5409f2015-07-08 15:17:53 +05301903 case EOpDFdx:
1904 case EOpDFdy:
1905 case EOpFwidth:
1906 if (getType().getBasicType() == EbtFloat)
1907 {
1908 // Derivatives of constant arguments should be 0.
1909 resultArray[i].setFConst(0.0f);
1910 break;
1911 }
1912 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1913 return nullptr;
1914
Arun Patole1155ddd2015-06-05 18:04:36 +05301915 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301916 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301917 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301918 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001919
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001921}
1922
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001923bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1924 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301925{
1926 ASSERT(builtinFunc);
1927
1928 if (getType().getBasicType() == EbtFloat)
1929 {
1930 result->setFConst(builtinFunc(parameter.getFConst()));
1931 return true;
1932 }
1933
1934 infoSink.info.message(
1935 EPrefixInternalError, getLine(),
1936 "Unary operation not folded into constant");
1937 return false;
1938}
1939
Jamie Madillb1a85f42014-08-19 15:23:24 -04001940// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001941TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301942{
Olli Etuahob43846e2015-06-02 18:18:57 +03001943 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301944 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001945 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Arun Patole274f0702015-05-05 13:33:30 +05301946 std::vector<TConstantUnion *> unionArrays(paramsCount);
1947 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001948 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301949 TBasicType basicType = EbtVoid;
1950 TSourceLoc loc;
1951 for (unsigned int i = 0; i < paramsCount; i++)
1952 {
1953 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001954 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301955
1956 if (i == 0)
1957 {
1958 basicType = paramConstant->getType().getBasicType();
1959 loc = paramConstant->getLine();
1960 }
1961 unionArrays[i] = paramConstant->getUnionArrayPointer();
1962 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001963 if (objectSizes[i] > maxObjectSize)
1964 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301965 }
1966
Arun Patole7fa33552015-06-10 15:15:18 +05301967 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1968 {
1969 for (unsigned int i = 0; i < paramsCount; i++)
1970 if (objectSizes[i] != maxObjectSize)
1971 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1972 }
Arun Patole274f0702015-05-05 13:33:30 +05301973
Olli Etuahob43846e2015-06-02 18:18:57 +03001974 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301975 if (paramsCount == 2)
1976 {
1977 //
1978 // Binary built-in
1979 //
1980 switch (op)
1981 {
Arun Patolebf790422015-05-18 17:53:04 +05301982 case EOpAtan:
1983 {
1984 if (basicType == EbtFloat)
1985 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001986 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301987 for (size_t i = 0; i < maxObjectSize; i++)
1988 {
1989 float y = unionArrays[0][i].getFConst();
1990 float x = unionArrays[1][i].getFConst();
1991 // Results are undefined if x and y are both 0.
1992 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001993 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301994 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001995 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301996 }
1997 }
1998 else
1999 UNREACHABLE();
2000 }
2001 break;
2002
2003 case EOpPow:
2004 {
2005 if (basicType == EbtFloat)
2006 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002007 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302008 for (size_t i = 0; i < maxObjectSize; i++)
2009 {
2010 float x = unionArrays[0][i].getFConst();
2011 float y = unionArrays[1][i].getFConst();
2012 // Results are undefined if x < 0.
2013 // Results are undefined if x = 0 and y <= 0.
2014 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002015 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302016 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002017 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302018 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002019 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302020 }
2021 }
2022 else
2023 UNREACHABLE();
2024 }
2025 break;
2026
2027 case EOpMod:
2028 {
2029 if (basicType == EbtFloat)
2030 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002031 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302032 for (size_t i = 0; i < maxObjectSize; i++)
2033 {
2034 float x = unionArrays[0][i].getFConst();
2035 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002036 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302037 }
2038 }
2039 else
2040 UNREACHABLE();
2041 }
2042 break;
2043
Arun Patole274f0702015-05-05 13:33:30 +05302044 case EOpMin:
2045 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002046 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302047 for (size_t i = 0; i < maxObjectSize; i++)
2048 {
2049 switch (basicType)
2050 {
2051 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002052 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302053 break;
2054 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002055 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302056 break;
2057 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002058 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302059 break;
2060 default:
2061 UNREACHABLE();
2062 break;
2063 }
2064 }
2065 }
2066 break;
2067
2068 case EOpMax:
2069 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002070 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302071 for (size_t i = 0; i < maxObjectSize; i++)
2072 {
2073 switch (basicType)
2074 {
2075 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002076 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302077 break;
2078 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002079 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302080 break;
2081 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002082 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302083 break;
2084 default:
2085 UNREACHABLE();
2086 break;
2087 }
2088 }
2089 }
2090 break;
2091
Arun Patolebf790422015-05-18 17:53:04 +05302092 case EOpStep:
2093 {
2094 if (basicType == EbtFloat)
2095 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002096 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302097 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002098 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302099 }
2100 else
2101 UNREACHABLE();
2102 }
2103 break;
2104
Arun Patole9d0b1f92015-05-20 14:27:17 +05302105 case EOpLessThan:
2106 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002107 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302108 for (size_t i = 0; i < maxObjectSize; i++)
2109 {
2110 switch (basicType)
2111 {
2112 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002113 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302114 break;
2115 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002116 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302117 break;
2118 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002119 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302120 break;
2121 default:
2122 UNREACHABLE();
2123 break;
2124 }
2125 }
2126 }
2127 break;
2128
2129 case EOpLessThanEqual:
2130 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002131 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302132 for (size_t i = 0; i < maxObjectSize; i++)
2133 {
2134 switch (basicType)
2135 {
2136 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002137 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302138 break;
2139 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002140 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302141 break;
2142 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002143 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302144 break;
2145 default:
2146 UNREACHABLE();
2147 break;
2148 }
2149 }
2150 }
2151 break;
2152
2153 case EOpGreaterThan:
2154 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002155 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302156 for (size_t i = 0; i < maxObjectSize; i++)
2157 {
2158 switch (basicType)
2159 {
2160 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002161 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302162 break;
2163 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002164 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302165 break;
2166 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002167 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302168 break;
2169 default:
2170 UNREACHABLE();
2171 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002172 }
2173 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302174 }
2175 break;
2176
2177 case EOpGreaterThanEqual:
2178 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002179 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302180 for (size_t i = 0; i < maxObjectSize; i++)
2181 {
2182 switch (basicType)
2183 {
2184 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002185 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302186 break;
2187 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002188 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302189 break;
2190 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002191 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302192 break;
2193 default:
2194 UNREACHABLE();
2195 break;
2196 }
2197 }
2198 }
2199 break;
2200
2201 case EOpVectorEqual:
2202 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002203 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302204 for (size_t i = 0; i < maxObjectSize; i++)
2205 {
2206 switch (basicType)
2207 {
2208 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002209 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302210 break;
2211 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002212 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302213 break;
2214 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002215 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302216 break;
2217 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002218 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302219 break;
2220 default:
2221 UNREACHABLE();
2222 break;
2223 }
2224 }
2225 }
2226 break;
2227
2228 case EOpVectorNotEqual:
2229 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002230 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302231 for (size_t i = 0; i < maxObjectSize; i++)
2232 {
2233 switch (basicType)
2234 {
2235 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002236 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302237 break;
2238 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002239 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302240 break;
2241 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002242 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302243 break;
2244 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002245 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302246 break;
2247 default:
2248 UNREACHABLE();
2249 break;
2250 }
2251 }
2252 }
2253 break;
2254
Arun Patole1155ddd2015-06-05 18:04:36 +05302255 case EOpDistance:
2256 if (basicType == EbtFloat)
2257 {
2258 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002259 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302260 for (size_t i = 0; i < maxObjectSize; i++)
2261 {
2262 float x = unionArrays[0][i].getFConst();
2263 float y = unionArrays[1][i].getFConst();
2264 distanceArray[i].setFConst(x - y);
2265 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002266 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302267 }
2268 else
2269 UNREACHABLE();
2270 break;
2271
2272 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002273
Arun Patole1155ddd2015-06-05 18:04:36 +05302274 if (basicType == EbtFloat)
2275 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002276 resultArray = new TConstantUnion();
2277 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302278 }
2279 else
2280 UNREACHABLE();
2281 break;
2282
2283 case EOpCross:
2284 if (basicType == EbtFloat && maxObjectSize == 3)
2285 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002286 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302287 float x0 = unionArrays[0][0].getFConst();
2288 float x1 = unionArrays[0][1].getFConst();
2289 float x2 = unionArrays[0][2].getFConst();
2290 float y0 = unionArrays[1][0].getFConst();
2291 float y1 = unionArrays[1][1].getFConst();
2292 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002293 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2294 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2295 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302296 }
2297 else
2298 UNREACHABLE();
2299 break;
2300
2301 case EOpReflect:
2302 if (basicType == EbtFloat)
2303 {
2304 // genType reflect (genType I, genType N) :
2305 // For the incident vector I and surface orientation N, returns the reflection direction:
2306 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002307 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302308 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2309 for (size_t i = 0; i < maxObjectSize; i++)
2310 {
2311 float result = unionArrays[0][i].getFConst() -
2312 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002313 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302314 }
2315 }
2316 else
2317 UNREACHABLE();
2318 break;
2319
Arun Patole7fa33552015-06-10 15:15:18 +05302320 case EOpMul:
2321 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2322 (*sequence)[1]->getAsTyped()->isMatrix())
2323 {
2324 // Perform component-wise matrix multiplication.
2325 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002326 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302327 angle::Matrix<float> result =
2328 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2329 SetUnionArrayFromMatrix(result, resultArray);
2330 }
2331 else
2332 UNREACHABLE();
2333 break;
2334
2335 case EOpOuterProduct:
2336 if (basicType == EbtFloat)
2337 {
2338 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2339 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2340 resultArray = new TConstantUnion[numRows * numCols];
2341 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002342 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2343 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302344 SetUnionArrayFromMatrix(result, resultArray);
2345 }
2346 else
2347 UNREACHABLE();
2348 break;
2349
Arun Patole274f0702015-05-05 13:33:30 +05302350 default:
2351 UNREACHABLE();
2352 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2353 return nullptr;
2354 }
2355 }
2356 else if (paramsCount == 3)
2357 {
2358 //
2359 // Ternary built-in
2360 //
2361 switch (op)
2362 {
2363 case EOpClamp:
2364 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002365 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302366 for (size_t i = 0; i < maxObjectSize; i++)
2367 {
2368 switch (basicType)
2369 {
2370 case EbtFloat:
2371 {
2372 float x = unionArrays[0][i].getFConst();
2373 float min = unionArrays[1][i].getFConst();
2374 float max = unionArrays[2][i].getFConst();
2375 // Results are undefined if min > max.
2376 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002377 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302378 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002379 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302380 }
2381 break;
2382 case EbtInt:
2383 {
2384 int x = unionArrays[0][i].getIConst();
2385 int min = unionArrays[1][i].getIConst();
2386 int max = unionArrays[2][i].getIConst();
2387 // Results are undefined if min > max.
2388 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002389 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302390 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002391 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302392 }
2393 break;
2394 case EbtUInt:
2395 {
2396 unsigned int x = unionArrays[0][i].getUConst();
2397 unsigned int min = unionArrays[1][i].getUConst();
2398 unsigned int max = unionArrays[2][i].getUConst();
2399 // Results are undefined if min > max.
2400 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002401 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302402 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002403 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302404 }
2405 break;
2406 default:
2407 UNREACHABLE();
2408 break;
2409 }
2410 }
2411 }
2412 break;
2413
Arun Patolebf790422015-05-18 17:53:04 +05302414 case EOpMix:
2415 {
2416 if (basicType == EbtFloat)
2417 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002418 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302419 for (size_t i = 0; i < maxObjectSize; i++)
2420 {
2421 float x = unionArrays[0][i].getFConst();
2422 float y = unionArrays[1][i].getFConst();
2423 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2424 if (type == EbtFloat)
2425 {
2426 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2427 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002428 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302429 }
2430 else // 3rd parameter is EbtBool
2431 {
2432 ASSERT(type == EbtBool);
2433 // Selects which vector each returned component comes from.
2434 // For a component of a that is false, the corresponding component of x is returned.
2435 // For a component of a that is true, the corresponding component of y is returned.
2436 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002437 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302438 }
2439 }
2440 }
2441 else
2442 UNREACHABLE();
2443 }
2444 break;
2445
2446 case EOpSmoothStep:
2447 {
2448 if (basicType == EbtFloat)
2449 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002450 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302451 for (size_t i = 0; i < maxObjectSize; i++)
2452 {
2453 float edge0 = unionArrays[0][i].getFConst();
2454 float edge1 = unionArrays[1][i].getFConst();
2455 float x = unionArrays[2][i].getFConst();
2456 // Results are undefined if edge0 >= edge1.
2457 if (edge0 >= edge1)
2458 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002459 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302460 }
2461 else
2462 {
2463 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2464 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2465 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002466 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302467 }
2468 }
2469 }
2470 else
2471 UNREACHABLE();
2472 }
2473 break;
2474
Arun Patole1155ddd2015-06-05 18:04:36 +05302475 case EOpFaceForward:
2476 if (basicType == EbtFloat)
2477 {
2478 // genType faceforward(genType N, genType I, genType Nref) :
2479 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002480 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302481 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2482 for (size_t i = 0; i < maxObjectSize; i++)
2483 {
2484 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002485 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302486 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002487 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302488 }
2489 }
2490 else
2491 UNREACHABLE();
2492 break;
2493
2494 case EOpRefract:
2495 if (basicType == EbtFloat)
2496 {
2497 // genType refract(genType I, genType N, float eta) :
2498 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2499 // return the refraction vector. The result is computed by
2500 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2501 // if (k < 0.0)
2502 // return genType(0.0)
2503 // else
2504 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002505 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302506 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2507 for (size_t i = 0; i < maxObjectSize; i++)
2508 {
2509 float eta = unionArrays[2][i].getFConst();
2510 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2511 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002512 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302513 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002514 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302515 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2516 }
2517 }
2518 else
2519 UNREACHABLE();
2520 break;
2521
Arun Patole274f0702015-05-05 13:33:30 +05302522 default:
2523 UNREACHABLE();
2524 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2525 return nullptr;
2526 }
2527 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002528 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302529}
2530
2531// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002532TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2533{
2534 if (hashFunction == NULL || name.empty())
2535 return name;
2536 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2537 TStringStream stream;
2538 stream << HASHED_NAME_PREFIX << std::hex << number;
2539 TString hashedName = stream.str();
2540 return hashedName;
2541}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002542
2543void TIntermTraverser::updateTree()
2544{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002545 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2546 {
2547 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2548 ASSERT(insertion.parent);
Olli Etuaho83f34112015-06-18 15:47:46 +03002549 if (!insertion.insertionsAfter.empty())
2550 {
2551 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2552 insertion.insertionsAfter);
2553 ASSERT(inserted);
2554 UNUSED_ASSERTION_VARIABLE(inserted);
2555 }
2556 if (!insertion.insertionsBefore.empty())
2557 {
2558 bool inserted =
2559 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2560 ASSERT(inserted);
2561 UNUSED_ASSERTION_VARIABLE(inserted);
2562 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002563 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002564 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2565 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002566 const NodeUpdateEntry &replacement = mReplacements[ii];
2567 ASSERT(replacement.parent);
2568 bool replaced = replacement.parent->replaceChildNode(
2569 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002570 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002571 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002572
Olli Etuahocd94ef92015-04-16 19:18:10 +03002573 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002574 {
2575 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002576 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002577 // be replaced, we need to make sure we don't update the replaced
2578 // node; instead, we update the replacement node.
2579 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2580 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002581 NodeUpdateEntry &replacement2 = mReplacements[jj];
2582 if (replacement2.parent == replacement.original)
2583 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002584 }
2585 }
2586 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002587 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2588 {
2589 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2590 ASSERT(replacement.parent);
2591 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2592 replacement.original, replacement.replacements);
2593 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002594 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002595 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002596
2597 mInsertions.clear();
2598 mReplacements.clear();
2599 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002600}