blob: 0a089c66769be2753d4f6fbae45a322895153130 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040020#include "compiler/translator/HashNames.h"
21#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
23
24namespace
25{
26
Arun Patole9dea48f2015-04-02 11:45:09 +053027const float kPi = 3.14159265358979323846f;
28const float kDegreesToRadiansMultiplier = kPi / 180.0f;
29const float kRadiansToDegreesMultiplier = 180.0f / kPi;
30
Jamie Madillb1a85f42014-08-19 15:23:24 -040031TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
32{
33 return left > right ? left : right;
34}
35
36bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
37{
38 switch (op)
39 {
40 case EOpMul:
41 case EOpMulAssign:
42 return left.getNominalSize() == right.getNominalSize() &&
43 left.getSecondarySize() == right.getSecondarySize();
44 case EOpVectorTimesScalar:
45 case EOpVectorTimesScalarAssign:
46 return true;
47 case EOpVectorTimesMatrix:
48 return left.getNominalSize() == right.getRows();
49 case EOpVectorTimesMatrixAssign:
50 return left.getNominalSize() == right.getRows() &&
51 left.getNominalSize() == right.getCols();
52 case EOpMatrixTimesVector:
53 return left.getCols() == right.getNominalSize();
54 case EOpMatrixTimesScalar:
55 case EOpMatrixTimesScalarAssign:
56 return true;
57 case EOpMatrixTimesMatrix:
58 return left.getCols() == right.getRows();
59 case EOpMatrixTimesMatrixAssign:
60 return left.getCols() == right.getCols() &&
61 left.getRows() == right.getRows();
62
63 default:
64 UNREACHABLE();
65 return false;
66 }
67}
68
69bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040070 const TConstantUnion *rightUnionArray,
71 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040072
73bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040074 const TConstantUnion *rightUnionArray,
75 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040076{
77 const TFieldList &fields = leftNodeType.getStruct()->fields();
78
79 size_t structSize = fields.size();
80 size_t index = 0;
81
82 for (size_t j = 0; j < structSize; j++)
83 {
84 size_t size = fields[j]->type()->getObjectSize();
85 for (size_t i = 0; i < size; i++)
86 {
87 if (fields[j]->type()->getBasicType() == EbtStruct)
88 {
89 if (!CompareStructure(*fields[j]->type(),
90 &rightUnionArray[index],
91 &leftUnionArray[index]))
92 {
93 return false;
94 }
95 }
96 else
97 {
98 if (leftUnionArray[index] != rightUnionArray[index])
99 return false;
100 index++;
101 }
102 }
103 }
104 return true;
105}
106
107bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400108 const TConstantUnion *rightUnionArray,
109 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400110{
111 if (leftNodeType.isArray())
112 {
113 TType typeWithoutArrayness = leftNodeType;
114 typeWithoutArrayness.clearArrayness();
115
116 size_t arraySize = leftNodeType.getArraySize();
117
118 for (size_t i = 0; i < arraySize; ++i)
119 {
120 size_t offset = typeWithoutArrayness.getObjectSize() * i;
121 if (!CompareStruct(typeWithoutArrayness,
122 &rightUnionArray[offset],
123 &leftUnionArray[offset]))
124 {
125 return false;
126 }
127 }
128 }
129 else
130 {
131 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
132 }
133 return true;
134}
135
Arun Patole274f0702015-05-05 13:33:30 +0530136TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
137{
138 TConstantUnion *constUnion = new TConstantUnion[size];
139 for (unsigned int i = 0; i < size; ++i)
140 constUnion[i] = constant;
141
142 return constUnion;
143}
144
Arun Patolebf790422015-05-18 17:53:04 +0530145void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
146 TInfoSink &infoSink, TConstantUnion *result)
147{
148 std::stringstream constantFoldingErrorStream;
149 constantFoldingErrorStream << "'" << GetOperatorString(op)
150 << "' operation result is undefined for the values passed in";
151 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
152
153 switch (basicType)
154 {
155 case EbtFloat :
156 result->setFConst(0.0f);
157 break;
158 case EbtInt:
159 result->setIConst(0);
160 break;
161 case EbtUInt:
162 result->setUConst(0u);
163 break;
164 case EbtBool:
165 result->setBConst(false);
166 break;
167 default:
168 break;
169 }
170}
171
Arun Patole1155ddd2015-06-05 18:04:36 +0530172float VectorLength(TConstantUnion *paramArray, size_t paramArraySize)
173{
174 float result = 0.0f;
175 for (size_t i = 0; i < paramArraySize; i++)
176 {
177 float f = paramArray[i].getFConst();
178 result += f * f;
179 }
180 return sqrtf(result);
181}
182
183float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, size_t paramArraySize)
184{
185 float result = 0.0f;
186 for (size_t i = 0; i < paramArraySize; i++)
187 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
188 return result;
189}
190
Olli Etuahob43846e2015-06-02 18:18:57 +0300191TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, const TIntermTyped *originalNode)
192{
193 if (constArray == nullptr)
194 {
195 return nullptr;
196 }
197 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
198 folded->getTypePointer()->setQualifier(EvqConst);
199 folded->setLine(originalNode->getLine());
200 return folded;
201}
202
Arun Patole7fa33552015-06-10 15:15:18 +0530203angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &rows, const unsigned int &cols)
204{
205 std::vector<float> elements;
206 for (size_t i = 0; i < rows * cols; i++)
207 elements.push_back(paramArray[i].getFConst());
208 // Transpose is used since the Matrix constructor expects arguments in row-major order,
209 // whereas the paramArray is in column-major order.
210 return angle::Matrix<float>(elements, rows, cols).transpose();
211}
212
213angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &size)
214{
215 std::vector<float> elements;
216 for (size_t i = 0; i < size * size; i++)
217 elements.push_back(paramArray[i].getFConst());
218 // Transpose is used since the Matrix constructor expects arguments in row-major order,
219 // whereas the paramArray is in column-major order.
220 return angle::Matrix<float>(elements, size).transpose();
221}
222
223void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
224{
225 // Transpose is used since the input Matrix is in row-major order,
226 // whereas the actual result should be in column-major order.
227 angle::Matrix<float> result = m.transpose();
228 std::vector<float> resultElements = result.elements();
229 for (size_t i = 0; i < resultElements.size(); i++)
230 resultArray[i].setFConst(resultElements[i]);
231}
232
Jamie Madillb1a85f42014-08-19 15:23:24 -0400233} // namespace anonymous
234
235
236////////////////////////////////////////////////////////////////
237//
238// Member functions of the nodes used for building the tree.
239//
240////////////////////////////////////////////////////////////////
241
Olli Etuahod2a67b92014-10-21 16:42:57 +0300242void TIntermTyped::setTypePreservePrecision(const TType &t)
243{
244 TPrecision precision = getPrecision();
245 mType = t;
246 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
247 mType.setPrecision(precision);
248}
249
Jamie Madillb1a85f42014-08-19 15:23:24 -0400250#define REPLACE_IF_IS(node, type, original, replacement) \
251 if (node == original) { \
252 node = static_cast<type *>(replacement); \
253 return true; \
254 }
255
256bool TIntermLoop::replaceChildNode(
257 TIntermNode *original, TIntermNode *replacement)
258{
259 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
260 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
261 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
262 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
263 return false;
264}
265
Jamie Madillb1a85f42014-08-19 15:23:24 -0400266bool TIntermBranch::replaceChildNode(
267 TIntermNode *original, TIntermNode *replacement)
268{
269 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
270 return false;
271}
272
Jamie Madillb1a85f42014-08-19 15:23:24 -0400273bool TIntermBinary::replaceChildNode(
274 TIntermNode *original, TIntermNode *replacement)
275{
276 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
277 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
278 return false;
279}
280
Jamie Madillb1a85f42014-08-19 15:23:24 -0400281bool TIntermUnary::replaceChildNode(
282 TIntermNode *original, TIntermNode *replacement)
283{
284 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
285 return false;
286}
287
Jamie Madillb1a85f42014-08-19 15:23:24 -0400288bool TIntermAggregate::replaceChildNode(
289 TIntermNode *original, TIntermNode *replacement)
290{
291 for (size_t ii = 0; ii < mSequence.size(); ++ii)
292 {
293 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
294 }
295 return false;
296}
297
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300298bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
299{
300 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
301 {
302 if (*it == original)
303 {
304 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300305 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300306 return true;
307 }
308 }
309 return false;
310}
311
Olli Etuahoa6f22092015-05-08 18:31:10 +0300312bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
313{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300314 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300315 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300316 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300317 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300318 auto it = mSequence.begin() + position;
319 mSequence.insert(it, insertions.begin(), insertions.end());
320 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300321}
322
Olli 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),
Olli Etuahod7a25242015-08-18 13:49:45 +0300417 mUseEmulatedFunction(node.mUseEmulatedFunction),
418 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
419{
420 for (TIntermNode *child : node.mSequence)
421 {
422 TIntermTyped *typedChild = child->getAsTyped();
423 ASSERT(typedChild != nullptr);
424 TIntermTyped *childCopy = typedChild->deepCopy();
425 mSequence.push_back(childCopy);
426 }
427}
428
429TIntermBinary::TIntermBinary(const TIntermBinary &node)
430 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
431{
432 TIntermTyped *leftCopy = node.mLeft->deepCopy();
433 TIntermTyped *rightCopy = node.mRight->deepCopy();
434 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
435 mLeft = leftCopy;
436 mRight = rightCopy;
437}
438
439TIntermUnary::TIntermUnary(const TIntermUnary &node)
440 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
441{
442 TIntermTyped *operandCopy = node.mOperand->deepCopy();
443 ASSERT(operandCopy != nullptr);
444 mOperand = operandCopy;
445}
446
447TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
448{
449 // Only supported for ternary nodes, not if statements.
450 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
451 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
452 ASSERT(trueTyped != nullptr);
453 ASSERT(falseTyped != nullptr);
454 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
455 TIntermTyped *trueCopy = trueTyped->deepCopy();
456 TIntermTyped *falseCopy = falseTyped->deepCopy();
457 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
458 mCondition = conditionCopy;
459 mTrueBlock = trueCopy;
460 mFalseBlock = falseCopy;
461}
462
Jamie Madillb1a85f42014-08-19 15:23:24 -0400463//
464// Say whether or not an operation node changes the value of a variable.
465//
466bool TIntermOperator::isAssignment() const
467{
468 switch (mOp)
469 {
470 case EOpPostIncrement:
471 case EOpPostDecrement:
472 case EOpPreIncrement:
473 case EOpPreDecrement:
474 case EOpAssign:
475 case EOpAddAssign:
476 case EOpSubAssign:
477 case EOpMulAssign:
478 case EOpVectorTimesMatrixAssign:
479 case EOpVectorTimesScalarAssign:
480 case EOpMatrixTimesScalarAssign:
481 case EOpMatrixTimesMatrixAssign:
482 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200483 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200484 case EOpBitShiftLeftAssign:
485 case EOpBitShiftRightAssign:
486 case EOpBitwiseAndAssign:
487 case EOpBitwiseXorAssign:
488 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400489 return true;
490 default:
491 return false;
492 }
493}
494
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300495bool TIntermOperator::isMultiplication() const
496{
497 switch (mOp)
498 {
499 case EOpMul:
500 case EOpMatrixTimesMatrix:
501 case EOpMatrixTimesVector:
502 case EOpMatrixTimesScalar:
503 case EOpVectorTimesMatrix:
504 case EOpVectorTimesScalar:
505 return true;
506 default:
507 return false;
508 }
509}
510
Jamie Madillb1a85f42014-08-19 15:23:24 -0400511//
512// returns true if the operator is for one of the constructors
513//
514bool TIntermOperator::isConstructor() const
515{
516 switch (mOp)
517 {
518 case EOpConstructVec2:
519 case EOpConstructVec3:
520 case EOpConstructVec4:
521 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400522 case EOpConstructMat2x3:
523 case EOpConstructMat2x4:
524 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400525 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400526 case EOpConstructMat3x4:
527 case EOpConstructMat4x2:
528 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400529 case EOpConstructMat4:
530 case EOpConstructFloat:
531 case EOpConstructIVec2:
532 case EOpConstructIVec3:
533 case EOpConstructIVec4:
534 case EOpConstructInt:
535 case EOpConstructUVec2:
536 case EOpConstructUVec3:
537 case EOpConstructUVec4:
538 case EOpConstructUInt:
539 case EOpConstructBVec2:
540 case EOpConstructBVec3:
541 case EOpConstructBVec4:
542 case EOpConstructBool:
543 case EOpConstructStruct:
544 return true;
545 default:
546 return false;
547 }
548}
549
550//
551// Make sure the type of a unary operator is appropriate for its
552// combination of operation and operand type.
553//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200554void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400555{
556 switch (mOp)
557 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200558 case EOpFloatBitsToInt:
559 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200560 case EOpIntBitsToFloat:
561 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200562 case EOpPackSnorm2x16:
563 case EOpPackUnorm2x16:
564 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200565 case EOpUnpackSnorm2x16:
566 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200567 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530568 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200569 case EOpUnpackHalf2x16:
570 mType.setPrecision(EbpMedium);
571 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400572 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200573 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400574 }
575
Olli Etuahof6c694b2015-03-26 14:50:53 +0200576 if (funcReturnType != nullptr)
577 {
578 if (funcReturnType->getBasicType() == EbtBool)
579 {
580 // Bool types should not have precision.
581 setType(*funcReturnType);
582 }
583 else
584 {
585 // Precision of the node has been set based on the operand.
586 setTypePreservePrecision(*funcReturnType);
587 }
588 }
589
Jamie Madillb1a85f42014-08-19 15:23:24 -0400590 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400591}
592
593//
594// Establishes the type of the resultant operation, as well as
595// makes the operator the correct one for the operands.
596//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200597// For lots of operations it should already be established that the operand
598// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400599//
600bool TIntermBinary::promote(TInfoSink &infoSink)
601{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200602 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400603
Jamie Madillb1a85f42014-08-19 15:23:24 -0400604 //
605 // Base assumption: just make the type the same as the left
606 // operand. Then only deviations from this need be coded.
607 //
608 setType(mLeft->getType());
609
610 // The result gets promoted to the highest precision.
611 TPrecision higherPrecision = GetHigherPrecision(
612 mLeft->getPrecision(), mRight->getPrecision());
613 getTypePointer()->setPrecision(higherPrecision);
614
615 // Binary operations results in temporary variables unless both
616 // operands are const.
617 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
618 {
619 getTypePointer()->setQualifier(EvqTemporary);
620 }
621
622 const int nominalSize =
623 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
624
625 //
626 // All scalars or structs. Code after this test assumes this case is removed!
627 //
628 if (nominalSize == 1)
629 {
630 switch (mOp)
631 {
632 //
633 // Promote to conditional
634 //
635 case EOpEqual:
636 case EOpNotEqual:
637 case EOpLessThan:
638 case EOpGreaterThan:
639 case EOpLessThanEqual:
640 case EOpGreaterThanEqual:
641 setType(TType(EbtBool, EbpUndefined));
642 break;
643
644 //
645 // And and Or operate on conditionals
646 //
647 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200648 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400649 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200650 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400651 setType(TType(EbtBool, EbpUndefined));
652 break;
653
654 default:
655 break;
656 }
657 return true;
658 }
659
660 // If we reach here, at least one of the operands is vector or matrix.
661 // The other operand could be a scalar, vector, or matrix.
662 // Can these two operands be combined?
663 //
664 TBasicType basicType = mLeft->getBasicType();
665 switch (mOp)
666 {
667 case EOpMul:
668 if (!mLeft->isMatrix() && mRight->isMatrix())
669 {
670 if (mLeft->isVector())
671 {
672 mOp = EOpVectorTimesMatrix;
673 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700674 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400675 }
676 else
677 {
678 mOp = EOpMatrixTimesScalar;
679 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700680 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400681 }
682 }
683 else if (mLeft->isMatrix() && !mRight->isMatrix())
684 {
685 if (mRight->isVector())
686 {
687 mOp = EOpMatrixTimesVector;
688 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700689 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400690 }
691 else
692 {
693 mOp = EOpMatrixTimesScalar;
694 }
695 }
696 else if (mLeft->isMatrix() && mRight->isMatrix())
697 {
698 mOp = EOpMatrixTimesMatrix;
699 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700700 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400701 }
702 else if (!mLeft->isMatrix() && !mRight->isMatrix())
703 {
704 if (mLeft->isVector() && mRight->isVector())
705 {
706 // leave as component product
707 }
708 else if (mLeft->isVector() || mRight->isVector())
709 {
710 mOp = EOpVectorTimesScalar;
711 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700712 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400713 }
714 }
715 else
716 {
717 infoSink.info.message(EPrefixInternalError, getLine(),
718 "Missing elses");
719 return false;
720 }
721
722 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
723 {
724 return false;
725 }
726 break;
727
728 case EOpMulAssign:
729 if (!mLeft->isMatrix() && mRight->isMatrix())
730 {
731 if (mLeft->isVector())
732 {
733 mOp = EOpVectorTimesMatrixAssign;
734 }
735 else
736 {
737 return false;
738 }
739 }
740 else if (mLeft->isMatrix() && !mRight->isMatrix())
741 {
742 if (mRight->isVector())
743 {
744 return false;
745 }
746 else
747 {
748 mOp = EOpMatrixTimesScalarAssign;
749 }
750 }
751 else if (mLeft->isMatrix() && mRight->isMatrix())
752 {
753 mOp = EOpMatrixTimesMatrixAssign;
754 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700755 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400756 }
757 else if (!mLeft->isMatrix() && !mRight->isMatrix())
758 {
759 if (mLeft->isVector() && mRight->isVector())
760 {
761 // leave as component product
762 }
763 else if (mLeft->isVector() || mRight->isVector())
764 {
765 if (!mLeft->isVector())
766 return false;
767 mOp = EOpVectorTimesScalarAssign;
768 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700769 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400770 }
771 }
772 else
773 {
774 infoSink.info.message(EPrefixInternalError, getLine(),
775 "Missing elses");
776 return false;
777 }
778
779 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
780 {
781 return false;
782 }
783 break;
784
785 case EOpAssign:
786 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200787 // No more additional checks are needed.
788 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
789 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
790 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400791 case EOpAdd:
792 case EOpSub:
793 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200794 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200795 case EOpBitShiftLeft:
796 case EOpBitShiftRight:
797 case EOpBitwiseAnd:
798 case EOpBitwiseXor:
799 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400800 case EOpAddAssign:
801 case EOpSubAssign:
802 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200803 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200804 case EOpBitShiftLeftAssign:
805 case EOpBitShiftRightAssign:
806 case EOpBitwiseAndAssign:
807 case EOpBitwiseXorAssign:
808 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400809 if ((mLeft->isMatrix() && mRight->isVector()) ||
810 (mLeft->isVector() && mRight->isMatrix()))
811 {
812 return false;
813 }
814
815 // Are the sizes compatible?
816 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
817 mLeft->getSecondarySize() != mRight->getSecondarySize())
818 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200819 // If the nominal sizes of operands do not match:
820 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400821 if (!mLeft->isScalar() && !mRight->isScalar())
822 return false;
823
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200824 // In the case of compound assignment other than multiply-assign,
825 // the right side needs to be a scalar. Otherwise a vector/matrix
826 // would be assigned to a scalar. A scalar can't be shifted by a
827 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200828 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200829 (isAssignment() ||
830 mOp == EOpBitShiftLeft ||
831 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200832 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400833 }
834
835 {
836 const int secondarySize = std::max(
837 mLeft->getSecondarySize(), mRight->getSecondarySize());
838 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700839 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200840 if (mLeft->isArray())
841 {
842 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
843 mType.setArraySize(mLeft->getArraySize());
844 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400845 }
846 break;
847
848 case EOpEqual:
849 case EOpNotEqual:
850 case EOpLessThan:
851 case EOpGreaterThan:
852 case EOpLessThanEqual:
853 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200854 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
855 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400856 setType(TType(EbtBool, EbpUndefined));
857 break;
858
859 default:
860 return false;
861 }
862 return true;
863}
864
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300865TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
866{
867 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
868 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
869 if (leftConstant == nullptr || rightConstant == nullptr)
870 {
871 return nullptr;
872 }
873 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300874 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300875}
876
Olli Etuaho95310b02015-06-02 17:43:38 +0300877TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
878{
879 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
880 if (operandConstant == nullptr)
881 {
882 return nullptr;
883 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530884
885 TConstantUnion *constArray = nullptr;
886 switch (mOp)
887 {
888 case EOpAny:
889 case EOpAll:
890 case EOpLength:
891 case EOpTranspose:
892 case EOpDeterminant:
893 case EOpInverse:
894 case EOpPackSnorm2x16:
895 case EOpUnpackSnorm2x16:
896 case EOpPackUnorm2x16:
897 case EOpUnpackUnorm2x16:
898 case EOpPackHalf2x16:
899 case EOpUnpackHalf2x16:
900 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
901 break;
902 default:
903 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
904 break;
905 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300906 return CreateFoldedNode(constArray, this);
907}
908
909TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
910{
911 // Make sure that all params are constant before actual constant folding.
912 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300913 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300914 if (param->getAsConstantUnion() == nullptr)
915 {
916 return nullptr;
917 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300918 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300919 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
920 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300921}
922
Jamie Madillb1a85f42014-08-19 15:23:24 -0400923//
924// The fold functions see if an operation on a constant can be done in place,
925// without generating run-time code.
926//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300927// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400928//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300929TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
930{
931 TConstantUnion *leftArray = getUnionArrayPointer();
932 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
933
934 if (!leftArray)
935 return nullptr;
936 if (!rightArray)
937 return nullptr;
938
939 size_t objectSize = getType().getObjectSize();
940
941 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
942 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
943 {
944 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
945 }
946 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
947 {
948 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
949 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
950 objectSize = rightNode->getType().getObjectSize();
951 }
952
953 TConstantUnion *resultArray = nullptr;
954
955 switch(op)
956 {
957 case EOpAdd:
958 resultArray = new TConstantUnion[objectSize];
959 for (size_t i = 0; i < objectSize; i++)
960 resultArray[i] = leftArray[i] + rightArray[i];
961 break;
962 case EOpSub:
963 resultArray = new TConstantUnion[objectSize];
964 for (size_t i = 0; i < objectSize; i++)
965 resultArray[i] = leftArray[i] - rightArray[i];
966 break;
967
968 case EOpMul:
969 case EOpVectorTimesScalar:
970 case EOpMatrixTimesScalar:
971 resultArray = new TConstantUnion[objectSize];
972 for (size_t i = 0; i < objectSize; i++)
973 resultArray[i] = leftArray[i] * rightArray[i];
974 break;
975
976 case EOpMatrixTimesMatrix:
977 {
978 if (getType().getBasicType() != EbtFloat ||
979 rightNode->getBasicType() != EbtFloat)
980 {
981 infoSink.info.message(
982 EPrefixInternalError, getLine(),
983 "Constant Folding cannot be done for matrix multiply");
984 return nullptr;
985 }
986
987 const int leftCols = getCols();
988 const int leftRows = getRows();
989 const int rightCols = rightNode->getType().getCols();
990 const int rightRows = rightNode->getType().getRows();
991 const int resultCols = rightCols;
992 const int resultRows = leftRows;
993
994 resultArray = new TConstantUnion[resultCols * resultRows];
995 for (int row = 0; row < resultRows; row++)
996 {
997 for (int column = 0; column < resultCols; column++)
998 {
999 resultArray[resultRows * column + row].setFConst(0.0f);
1000 for (int i = 0; i < leftCols; i++)
1001 {
1002 resultArray[resultRows * column + row].setFConst(
1003 resultArray[resultRows * column + row].getFConst() +
1004 leftArray[i * leftRows + row].getFConst() *
1005 rightArray[column * rightRows + i].getFConst());
1006 }
1007 }
1008 }
1009 }
1010 break;
1011
1012 case EOpDiv:
1013 case EOpIMod:
1014 {
1015 resultArray = new TConstantUnion[objectSize];
1016 for (size_t i = 0; i < objectSize; i++)
1017 {
1018 switch (getType().getBasicType())
1019 {
1020 case EbtFloat:
1021 if (rightArray[i] == 0.0f)
1022 {
1023 infoSink.info.message(EPrefixWarning, getLine(),
1024 "Divide by zero error during constant folding");
1025 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1026 }
1027 else
1028 {
1029 ASSERT(op == EOpDiv);
1030 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1031 }
1032 break;
1033
1034 case EbtInt:
1035 if (rightArray[i] == 0)
1036 {
1037 infoSink.info.message(EPrefixWarning, getLine(),
1038 "Divide by zero error during constant folding");
1039 resultArray[i].setIConst(INT_MAX);
1040 }
1041 else
1042 {
1043 if (op == EOpDiv)
1044 {
1045 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1046 }
1047 else
1048 {
1049 ASSERT(op == EOpIMod);
1050 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1051 }
1052 }
1053 break;
1054
1055 case EbtUInt:
1056 if (rightArray[i] == 0)
1057 {
1058 infoSink.info.message(EPrefixWarning, getLine(),
1059 "Divide by zero error during constant folding");
1060 resultArray[i].setUConst(UINT_MAX);
1061 }
1062 else
1063 {
1064 if (op == EOpDiv)
1065 {
1066 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1067 }
1068 else
1069 {
1070 ASSERT(op == EOpIMod);
1071 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1072 }
1073 }
1074 break;
1075
1076 default:
1077 infoSink.info.message(EPrefixInternalError, getLine(),
1078 "Constant folding cannot be done for \"/\"");
1079 return nullptr;
1080 }
1081 }
1082 }
1083 break;
1084
1085 case EOpMatrixTimesVector:
1086 {
1087 if (rightNode->getBasicType() != EbtFloat)
1088 {
1089 infoSink.info.message(EPrefixInternalError, getLine(),
1090 "Constant Folding cannot be done for matrix times vector");
1091 return nullptr;
1092 }
1093
1094 const int matrixCols = getCols();
1095 const int matrixRows = getRows();
1096
1097 resultArray = new TConstantUnion[matrixRows];
1098
1099 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1100 {
1101 resultArray[matrixRow].setFConst(0.0f);
1102 for (int col = 0; col < matrixCols; col++)
1103 {
1104 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1105 leftArray[col * matrixRows + matrixRow].getFConst() *
1106 rightArray[col].getFConst());
1107 }
1108 }
1109 }
1110 break;
1111
1112 case EOpVectorTimesMatrix:
1113 {
1114 if (getType().getBasicType() != EbtFloat)
1115 {
1116 infoSink.info.message(EPrefixInternalError, getLine(),
1117 "Constant Folding cannot be done for vector times matrix");
1118 return nullptr;
1119 }
1120
1121 const int matrixCols = rightNode->getType().getCols();
1122 const int matrixRows = rightNode->getType().getRows();
1123
1124 resultArray = new TConstantUnion[matrixCols];
1125
1126 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1127 {
1128 resultArray[matrixCol].setFConst(0.0f);
1129 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1130 {
1131 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1132 leftArray[matrixRow].getFConst() *
1133 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1134 }
1135 }
1136 }
1137 break;
1138
1139 case EOpLogicalAnd:
1140 {
1141 resultArray = new TConstantUnion[objectSize];
1142 for (size_t i = 0; i < objectSize; i++)
1143 {
1144 resultArray[i] = leftArray[i] && rightArray[i];
1145 }
1146 }
1147 break;
1148
1149 case EOpLogicalOr:
1150 {
1151 resultArray = new TConstantUnion[objectSize];
1152 for (size_t i = 0; i < objectSize; i++)
1153 {
1154 resultArray[i] = leftArray[i] || rightArray[i];
1155 }
1156 }
1157 break;
1158
1159 case EOpLogicalXor:
1160 {
1161 resultArray = new TConstantUnion[objectSize];
1162 for (size_t i = 0; i < objectSize; i++)
1163 {
1164 switch (getType().getBasicType())
1165 {
1166 case EbtBool:
1167 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1168 break;
1169 default:
1170 UNREACHABLE();
1171 break;
1172 }
1173 }
1174 }
1175 break;
1176
1177 case EOpBitwiseAnd:
1178 resultArray = new TConstantUnion[objectSize];
1179 for (size_t i = 0; i < objectSize; i++)
1180 resultArray[i] = leftArray[i] & rightArray[i];
1181 break;
1182 case EOpBitwiseXor:
1183 resultArray = new TConstantUnion[objectSize];
1184 for (size_t i = 0; i < objectSize; i++)
1185 resultArray[i] = leftArray[i] ^ rightArray[i];
1186 break;
1187 case EOpBitwiseOr:
1188 resultArray = new TConstantUnion[objectSize];
1189 for (size_t i = 0; i < objectSize; i++)
1190 resultArray[i] = leftArray[i] | rightArray[i];
1191 break;
1192 case EOpBitShiftLeft:
1193 resultArray = new TConstantUnion[objectSize];
1194 for (size_t i = 0; i < objectSize; i++)
1195 resultArray[i] = leftArray[i] << rightArray[i];
1196 break;
1197 case EOpBitShiftRight:
1198 resultArray = new TConstantUnion[objectSize];
1199 for (size_t i = 0; i < objectSize; i++)
1200 resultArray[i] = leftArray[i] >> rightArray[i];
1201 break;
1202
1203 case EOpLessThan:
1204 ASSERT(objectSize == 1);
1205 resultArray = new TConstantUnion[1];
1206 resultArray->setBConst(*leftArray < *rightArray);
1207 break;
1208
1209 case EOpGreaterThan:
1210 ASSERT(objectSize == 1);
1211 resultArray = new TConstantUnion[1];
1212 resultArray->setBConst(*leftArray > *rightArray);
1213 break;
1214
1215 case EOpLessThanEqual:
1216 ASSERT(objectSize == 1);
1217 resultArray = new TConstantUnion[1];
1218 resultArray->setBConst(!(*leftArray > *rightArray));
1219 break;
1220
1221 case EOpGreaterThanEqual:
1222 ASSERT(objectSize == 1);
1223 resultArray = new TConstantUnion[1];
1224 resultArray->setBConst(!(*leftArray < *rightArray));
1225 break;
1226
1227 case EOpEqual:
1228 case EOpNotEqual:
1229 {
1230 resultArray = new TConstantUnion[1];
1231 bool equal = true;
1232 if (getType().getBasicType() == EbtStruct)
1233 {
1234 equal = CompareStructure(getType(), rightArray, leftArray);
1235 }
1236 else
1237 {
1238 for (size_t i = 0; i < objectSize; i++)
1239 {
1240 if (leftArray[i] != rightArray[i])
1241 {
1242 equal = false;
1243 break; // break out of for loop
1244 }
1245 }
1246 }
1247 if (op == EOpEqual)
1248 {
1249 resultArray->setBConst(equal);
1250 }
1251 else
1252 {
1253 resultArray->setBConst(!equal);
1254 }
1255 }
1256 break;
1257
1258 default:
1259 infoSink.info.message(
1260 EPrefixInternalError, getLine(),
1261 "Invalid operator for constant folding");
1262 return nullptr;
1263 }
1264 return resultArray;
1265}
1266
1267//
1268// The fold functions see if an operation on a constant can be done in place,
1269// without generating run-time code.
1270//
Olli Etuaho95310b02015-06-02 17:43:38 +03001271// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001272//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301273TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001274{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301275 //
1276 // Do operations where the return type has a different number of components compared to the operand type.
1277 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001278
Arun Patoleab2b9a22015-07-06 18:27:56 +05301279 TConstantUnion *operandArray = getUnionArrayPointer();
1280 if (!operandArray)
1281 return nullptr;
1282
1283 size_t objectSize = getType().getObjectSize();
1284 TConstantUnion *resultArray = nullptr;
1285 switch (op)
1286 {
1287 case EOpAny:
1288 if (getType().getBasicType() == EbtBool)
1289 {
1290 resultArray = new TConstantUnion();
1291 resultArray->setBConst(false);
1292 for (size_t i = 0; i < objectSize; i++)
1293 {
1294 if (operandArray[i].getBConst())
1295 {
1296 resultArray->setBConst(true);
1297 break;
1298 }
1299 }
1300 break;
1301 }
1302 else
1303 {
1304 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1305 return nullptr;
1306 }
1307
1308 case EOpAll:
1309 if (getType().getBasicType() == EbtBool)
1310 {
1311 resultArray = new TConstantUnion();
1312 resultArray->setBConst(true);
1313 for (size_t i = 0; i < objectSize; i++)
1314 {
1315 if (!operandArray[i].getBConst())
1316 {
1317 resultArray->setBConst(false);
1318 break;
1319 }
1320 }
1321 break;
1322 }
1323 else
1324 {
1325 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1326 return nullptr;
1327 }
1328
1329 case EOpLength:
1330 if (getType().getBasicType() == EbtFloat)
1331 {
1332 resultArray = new TConstantUnion();
1333 resultArray->setFConst(VectorLength(operandArray, objectSize));
1334 break;
1335 }
1336 else
1337 {
1338 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1339 return nullptr;
1340 }
1341
1342 case EOpTranspose:
1343 if (getType().getBasicType() == EbtFloat)
1344 {
1345 resultArray = new TConstantUnion[objectSize];
1346 angle::Matrix<float> result =
1347 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1348 SetUnionArrayFromMatrix(result, resultArray);
1349 break;
1350 }
1351 else
1352 {
1353 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1354 return nullptr;
1355 }
1356
1357 case EOpDeterminant:
1358 if (getType().getBasicType() == EbtFloat)
1359 {
1360 unsigned int size = getType().getNominalSize();
1361 ASSERT(size >= 2 && size <= 4);
1362 resultArray = new TConstantUnion();
1363 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1364 break;
1365 }
1366 else
1367 {
1368 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1369 return nullptr;
1370 }
1371
1372 case EOpInverse:
1373 if (getType().getBasicType() == EbtFloat)
1374 {
1375 unsigned int size = getType().getNominalSize();
1376 ASSERT(size >= 2 && size <= 4);
1377 resultArray = new TConstantUnion[objectSize];
1378 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1379 SetUnionArrayFromMatrix(result, resultArray);
1380 break;
1381 }
1382 else
1383 {
1384 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1385 return nullptr;
1386 }
1387
1388 case EOpPackSnorm2x16:
1389 if (getType().getBasicType() == EbtFloat)
1390 {
1391 ASSERT(getType().getNominalSize() == 2);
1392 resultArray = new TConstantUnion();
1393 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1394 break;
1395 }
1396 else
1397 {
1398 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1399 return nullptr;
1400 }
1401
1402 case EOpUnpackSnorm2x16:
1403 if (getType().getBasicType() == EbtUInt)
1404 {
1405 resultArray = new TConstantUnion[2];
1406 float f1, f2;
1407 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1408 resultArray[0].setFConst(f1);
1409 resultArray[1].setFConst(f2);
1410 break;
1411 }
1412 else
1413 {
1414 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1415 return nullptr;
1416 }
1417
1418 case EOpPackUnorm2x16:
1419 if (getType().getBasicType() == EbtFloat)
1420 {
1421 ASSERT(getType().getNominalSize() == 2);
1422 resultArray = new TConstantUnion();
1423 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1424 break;
1425 }
1426 else
1427 {
1428 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1429 return nullptr;
1430 }
1431
1432 case EOpUnpackUnorm2x16:
1433 if (getType().getBasicType() == EbtUInt)
1434 {
1435 resultArray = new TConstantUnion[2];
1436 float f1, f2;
1437 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1438 resultArray[0].setFConst(f1);
1439 resultArray[1].setFConst(f2);
1440 break;
1441 }
1442 else
1443 {
1444 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1445 return nullptr;
1446 }
1447
1448 case EOpPackHalf2x16:
1449 if (getType().getBasicType() == EbtFloat)
1450 {
1451 ASSERT(getType().getNominalSize() == 2);
1452 resultArray = new TConstantUnion();
1453 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1454 break;
1455 }
1456 else
1457 {
1458 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1459 return nullptr;
1460 }
1461
1462 case EOpUnpackHalf2x16:
1463 if (getType().getBasicType() == EbtUInt)
1464 {
1465 resultArray = new TConstantUnion[2];
1466 float f1, f2;
1467 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1468 resultArray[0].setFConst(f1);
1469 resultArray[1].setFConst(f2);
1470 break;
1471 }
1472 else
1473 {
1474 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1475 return nullptr;
1476 }
1477 break;
1478
1479 default:
1480 break;
1481 }
1482
1483 return resultArray;
1484}
1485
1486TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1487{
1488 //
1489 // Do unary operations where the return type is the same as operand type.
1490 //
1491
1492 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001493 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301494 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001495
1496 size_t objectSize = getType().getObjectSize();
1497
Arun Patoleab2b9a22015-07-06 18:27:56 +05301498 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1499 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301500 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301501 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301502 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301503 case EOpNegative:
1504 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301505 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301506 case EbtFloat:
1507 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301508 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301509 case EbtInt:
1510 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301511 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301512 case EbtUInt:
1513 resultArray[i].setUConst(static_cast<unsigned int>(
1514 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301515 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301516 default:
1517 infoSink.info.message(
1518 EPrefixInternalError, getLine(),
1519 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301520 return nullptr;
1521 }
1522 break;
1523
Arun Patoleab2b9a22015-07-06 18:27:56 +05301524 case EOpPositive:
1525 switch (getType().getBasicType())
1526 {
1527 case EbtFloat:
1528 resultArray[i].setFConst(operandArray[i].getFConst());
1529 break;
1530 case EbtInt:
1531 resultArray[i].setIConst(operandArray[i].getIConst());
1532 break;
1533 case EbtUInt:
1534 resultArray[i].setUConst(static_cast<unsigned int>(
1535 static_cast<int>(operandArray[i].getUConst())));
1536 break;
1537 default:
1538 infoSink.info.message(
1539 EPrefixInternalError, getLine(),
1540 "Unary operation not folded into constant");
1541 return nullptr;
1542 }
1543 break;
1544
1545 case EOpLogicalNot:
1546 // this code is written for possible future use,
1547 // will not get executed currently
1548 switch (getType().getBasicType())
1549 {
1550 case EbtBool:
1551 resultArray[i].setBConst(!operandArray[i].getBConst());
1552 break;
1553 default:
1554 infoSink.info.message(
1555 EPrefixInternalError, getLine(),
1556 "Unary operation not folded into constant");
1557 return nullptr;
1558 }
1559 break;
1560
1561 case EOpBitwiseNot:
1562 switch (getType().getBasicType())
1563 {
1564 case EbtInt:
1565 resultArray[i].setIConst(~operandArray[i].getIConst());
1566 break;
1567 case EbtUInt:
1568 resultArray[i].setUConst(~operandArray[i].getUConst());
1569 break;
1570 default:
1571 infoSink.info.message(
1572 EPrefixInternalError, getLine(),
1573 "Unary operation not folded into constant");
1574 return nullptr;
1575 }
1576 break;
1577
1578 case EOpRadians:
1579 if (getType().getBasicType() == EbtFloat)
1580 {
1581 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1582 break;
1583 }
1584 infoSink.info.message(
1585 EPrefixInternalError, getLine(),
1586 "Unary operation not folded into constant");
1587 return nullptr;
1588
1589 case EOpDegrees:
1590 if (getType().getBasicType() == EbtFloat)
1591 {
1592 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1593 break;
1594 }
1595 infoSink.info.message(
1596 EPrefixInternalError, getLine(),
1597 "Unary operation not folded into constant");
1598 return nullptr;
1599
1600 case EOpSin:
1601 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1602 return nullptr;
1603 break;
1604
1605 case EOpCos:
1606 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1607 return nullptr;
1608 break;
1609
1610 case EOpTan:
1611 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1612 return nullptr;
1613 break;
1614
1615 case EOpAsin:
1616 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1617 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1618 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1619 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1620 return nullptr;
1621 break;
1622
1623 case EOpAcos:
1624 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1625 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1626 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1627 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1628 return nullptr;
1629 break;
1630
1631 case EOpAtan:
1632 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1633 return nullptr;
1634 break;
1635
1636 case EOpSinh:
1637 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1638 return nullptr;
1639 break;
1640
1641 case EOpCosh:
1642 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1643 return nullptr;
1644 break;
1645
1646 case EOpTanh:
1647 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1648 return nullptr;
1649 break;
1650
1651 case EOpAsinh:
1652 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1653 return nullptr;
1654 break;
1655
1656 case EOpAcosh:
1657 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1658 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1659 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1660 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1661 return nullptr;
1662 break;
1663
1664 case EOpAtanh:
1665 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1666 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1667 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1668 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1669 return nullptr;
1670 break;
1671
1672 case EOpAbs:
1673 switch (getType().getBasicType())
1674 {
1675 case EbtFloat:
1676 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1677 break;
1678 case EbtInt:
1679 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1680 break;
1681 default:
1682 infoSink.info.message(
1683 EPrefixInternalError, getLine(),
1684 "Unary operation not folded into constant");
1685 return nullptr;
1686 }
1687 break;
1688
1689 case EOpSign:
1690 switch (getType().getBasicType())
1691 {
1692 case EbtFloat:
1693 {
1694 float fConst = operandArray[i].getFConst();
1695 float fResult = 0.0f;
1696 if (fConst > 0.0f)
1697 fResult = 1.0f;
1698 else if (fConst < 0.0f)
1699 fResult = -1.0f;
1700 resultArray[i].setFConst(fResult);
1701 }
1702 break;
1703 case EbtInt:
1704 {
1705 int iConst = operandArray[i].getIConst();
1706 int iResult = 0;
1707 if (iConst > 0)
1708 iResult = 1;
1709 else if (iConst < 0)
1710 iResult = -1;
1711 resultArray[i].setIConst(iResult);
1712 }
1713 break;
1714 default:
1715 infoSink.info.message(
1716 EPrefixInternalError, getLine(),
1717 "Unary operation not folded into constant");
1718 return nullptr;
1719 }
1720 break;
1721
1722 case EOpFloor:
1723 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1724 return nullptr;
1725 break;
1726
1727 case EOpTrunc:
1728 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1729 return nullptr;
1730 break;
1731
1732 case EOpRound:
1733 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1734 return nullptr;
1735 break;
1736
1737 case EOpRoundEven:
1738 if (getType().getBasicType() == EbtFloat)
1739 {
1740 float x = operandArray[i].getFConst();
1741 float result;
1742 float fractPart = modff(x, &result);
1743 if (fabsf(fractPart) == 0.5f)
1744 result = 2.0f * roundf(x / 2.0f);
1745 else
1746 result = roundf(x);
1747 resultArray[i].setFConst(result);
1748 break;
1749 }
1750 infoSink.info.message(
1751 EPrefixInternalError, getLine(),
1752 "Unary operation not folded into constant");
1753 return nullptr;
1754
1755 case EOpCeil:
1756 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1757 return nullptr;
1758 break;
1759
1760 case EOpFract:
1761 if (getType().getBasicType() == EbtFloat)
1762 {
1763 float x = operandArray[i].getFConst();
1764 resultArray[i].setFConst(x - floorf(x));
1765 break;
1766 }
1767 infoSink.info.message(
1768 EPrefixInternalError, getLine(),
1769 "Unary operation not folded into constant");
1770 return nullptr;
1771
Arun Patole551279e2015-07-07 18:18:23 +05301772 case EOpIsNan:
1773 if (getType().getBasicType() == EbtFloat)
1774 {
1775 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1776 break;
1777 }
1778 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1779 return nullptr;
1780
1781 case EOpIsInf:
1782 if (getType().getBasicType() == EbtFloat)
1783 {
1784 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1785 break;
1786 }
1787 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1788 return nullptr;
1789
1790 case EOpFloatBitsToInt:
1791 if (getType().getBasicType() == EbtFloat)
1792 {
1793 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1794 break;
1795 }
1796 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1797 return nullptr;
1798
1799 case EOpFloatBitsToUint:
1800 if (getType().getBasicType() == EbtFloat)
1801 {
1802 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1803 break;
1804 }
1805 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1806 return nullptr;
1807
1808 case EOpIntBitsToFloat:
1809 if (getType().getBasicType() == EbtInt)
1810 {
1811 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1812 break;
1813 }
1814 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1815 return nullptr;
1816
1817 case EOpUintBitsToFloat:
1818 if (getType().getBasicType() == EbtUInt)
1819 {
1820 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1821 break;
1822 }
1823 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1824 return nullptr;
1825
Arun Patoleab2b9a22015-07-06 18:27:56 +05301826 case EOpExp:
1827 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1828 return nullptr;
1829 break;
1830
1831 case EOpLog:
1832 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1833 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1834 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1835 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1836 return nullptr;
1837 break;
1838
1839 case EOpExp2:
1840 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1841 return nullptr;
1842 break;
1843
1844 case EOpLog2:
1845 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1846 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1847 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1848 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1849 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1850 return nullptr;
1851 else
1852 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1853 break;
1854
1855 case EOpSqrt:
1856 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1857 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1858 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1859 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1860 return nullptr;
1861 break;
1862
1863 case EOpInverseSqrt:
1864 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1865 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1866 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1867 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1868 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1869 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1870 return nullptr;
1871 else
1872 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1873 break;
1874
1875 case EOpVectorLogicalNot:
1876 if (getType().getBasicType() == EbtBool)
1877 {
1878 resultArray[i].setBConst(!operandArray[i].getBConst());
1879 break;
1880 }
1881 infoSink.info.message(
1882 EPrefixInternalError, getLine(),
1883 "Unary operation not folded into constant");
1884 return nullptr;
1885
1886 case EOpNormalize:
1887 if (getType().getBasicType() == EbtFloat)
1888 {
1889 float x = operandArray[i].getFConst();
1890 float length = VectorLength(operandArray, objectSize);
1891 if (length)
1892 resultArray[i].setFConst(x / length);
1893 else
1894 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1895 &resultArray[i]);
1896 break;
1897 }
1898 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1899 return nullptr;
1900
Arun Patole0c5409f2015-07-08 15:17:53 +05301901 case EOpDFdx:
1902 case EOpDFdy:
1903 case EOpFwidth:
1904 if (getType().getBasicType() == EbtFloat)
1905 {
1906 // Derivatives of constant arguments should be 0.
1907 resultArray[i].setFConst(0.0f);
1908 break;
1909 }
1910 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1911 return nullptr;
1912
Arun Patole1155ddd2015-06-05 18:04:36 +05301913 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301914 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301915 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301916 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001917
Arun Patoleab2b9a22015-07-06 18:27:56 +05301918 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001919}
1920
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001921bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1922 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301923{
1924 ASSERT(builtinFunc);
1925
1926 if (getType().getBasicType() == EbtFloat)
1927 {
1928 result->setFConst(builtinFunc(parameter.getFConst()));
1929 return true;
1930 }
1931
1932 infoSink.info.message(
1933 EPrefixInternalError, getLine(),
1934 "Unary operation not folded into constant");
1935 return false;
1936}
1937
Jamie Madillb1a85f42014-08-19 15:23:24 -04001938// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001939TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301940{
Olli Etuahob43846e2015-06-02 18:18:57 +03001941 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301942 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001943 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Arun Patole274f0702015-05-05 13:33:30 +05301944 std::vector<TConstantUnion *> unionArrays(paramsCount);
1945 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001946 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301947 TBasicType basicType = EbtVoid;
1948 TSourceLoc loc;
1949 for (unsigned int i = 0; i < paramsCount; i++)
1950 {
1951 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001952 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301953
1954 if (i == 0)
1955 {
1956 basicType = paramConstant->getType().getBasicType();
1957 loc = paramConstant->getLine();
1958 }
1959 unionArrays[i] = paramConstant->getUnionArrayPointer();
1960 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001961 if (objectSizes[i] > maxObjectSize)
1962 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301963 }
1964
Arun Patole7fa33552015-06-10 15:15:18 +05301965 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1966 {
1967 for (unsigned int i = 0; i < paramsCount; i++)
1968 if (objectSizes[i] != maxObjectSize)
1969 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1970 }
Arun Patole274f0702015-05-05 13:33:30 +05301971
Olli Etuahob43846e2015-06-02 18:18:57 +03001972 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301973 if (paramsCount == 2)
1974 {
1975 //
1976 // Binary built-in
1977 //
1978 switch (op)
1979 {
Arun Patolebf790422015-05-18 17:53:04 +05301980 case EOpAtan:
1981 {
1982 if (basicType == EbtFloat)
1983 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001984 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301985 for (size_t i = 0; i < maxObjectSize; i++)
1986 {
1987 float y = unionArrays[0][i].getFConst();
1988 float x = unionArrays[1][i].getFConst();
1989 // Results are undefined if x and y are both 0.
1990 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001991 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301992 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001993 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301994 }
1995 }
1996 else
1997 UNREACHABLE();
1998 }
1999 break;
2000
2001 case EOpPow:
2002 {
2003 if (basicType == EbtFloat)
2004 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002005 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302006 for (size_t i = 0; i < maxObjectSize; i++)
2007 {
2008 float x = unionArrays[0][i].getFConst();
2009 float y = unionArrays[1][i].getFConst();
2010 // Results are undefined if x < 0.
2011 // Results are undefined if x = 0 and y <= 0.
2012 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002013 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302014 else if (x == 0.0f && y <= 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
Olli Etuahob43846e2015-06-02 18:18:57 +03002017 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302018 }
2019 }
2020 else
2021 UNREACHABLE();
2022 }
2023 break;
2024
2025 case EOpMod:
2026 {
2027 if (basicType == EbtFloat)
2028 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002029 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302030 for (size_t i = 0; i < maxObjectSize; i++)
2031 {
2032 float x = unionArrays[0][i].getFConst();
2033 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002034 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302035 }
2036 }
2037 else
2038 UNREACHABLE();
2039 }
2040 break;
2041
Arun Patole274f0702015-05-05 13:33:30 +05302042 case EOpMin:
2043 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002044 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302045 for (size_t i = 0; i < maxObjectSize; i++)
2046 {
2047 switch (basicType)
2048 {
2049 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002050 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302051 break;
2052 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002053 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302054 break;
2055 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002056 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302057 break;
2058 default:
2059 UNREACHABLE();
2060 break;
2061 }
2062 }
2063 }
2064 break;
2065
2066 case EOpMax:
2067 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002068 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302069 for (size_t i = 0; i < maxObjectSize; i++)
2070 {
2071 switch (basicType)
2072 {
2073 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002074 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302075 break;
2076 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002077 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302078 break;
2079 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002080 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302081 break;
2082 default:
2083 UNREACHABLE();
2084 break;
2085 }
2086 }
2087 }
2088 break;
2089
Arun Patolebf790422015-05-18 17:53:04 +05302090 case EOpStep:
2091 {
2092 if (basicType == EbtFloat)
2093 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002094 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302095 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002096 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302097 }
2098 else
2099 UNREACHABLE();
2100 }
2101 break;
2102
Arun Patole9d0b1f92015-05-20 14:27:17 +05302103 case EOpLessThan:
2104 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002105 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302106 for (size_t i = 0; i < maxObjectSize; i++)
2107 {
2108 switch (basicType)
2109 {
2110 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002111 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302112 break;
2113 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002114 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302115 break;
2116 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002117 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302118 break;
2119 default:
2120 UNREACHABLE();
2121 break;
2122 }
2123 }
2124 }
2125 break;
2126
2127 case EOpLessThanEqual:
2128 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002129 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302130 for (size_t i = 0; i < maxObjectSize; i++)
2131 {
2132 switch (basicType)
2133 {
2134 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002135 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302136 break;
2137 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002138 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302139 break;
2140 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002141 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302142 break;
2143 default:
2144 UNREACHABLE();
2145 break;
2146 }
2147 }
2148 }
2149 break;
2150
2151 case EOpGreaterThan:
2152 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002153 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302154 for (size_t i = 0; i < maxObjectSize; i++)
2155 {
2156 switch (basicType)
2157 {
2158 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002159 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302160 break;
2161 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002162 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302163 break;
2164 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002165 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302166 break;
2167 default:
2168 UNREACHABLE();
2169 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002170 }
2171 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302172 }
2173 break;
2174
2175 case EOpGreaterThanEqual:
2176 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002177 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302178 for (size_t i = 0; i < maxObjectSize; i++)
2179 {
2180 switch (basicType)
2181 {
2182 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002183 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302184 break;
2185 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002186 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302187 break;
2188 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002189 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302190 break;
2191 default:
2192 UNREACHABLE();
2193 break;
2194 }
2195 }
2196 }
2197 break;
2198
2199 case EOpVectorEqual:
2200 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002201 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302202 for (size_t i = 0; i < maxObjectSize; i++)
2203 {
2204 switch (basicType)
2205 {
2206 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002207 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302208 break;
2209 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002210 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302211 break;
2212 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002213 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302214 break;
2215 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002216 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302217 break;
2218 default:
2219 UNREACHABLE();
2220 break;
2221 }
2222 }
2223 }
2224 break;
2225
2226 case EOpVectorNotEqual:
2227 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002228 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302229 for (size_t i = 0; i < maxObjectSize; i++)
2230 {
2231 switch (basicType)
2232 {
2233 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002234 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302235 break;
2236 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002237 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302238 break;
2239 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002240 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302241 break;
2242 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002243 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 break;
2245 default:
2246 UNREACHABLE();
2247 break;
2248 }
2249 }
2250 }
2251 break;
2252
Arun Patole1155ddd2015-06-05 18:04:36 +05302253 case EOpDistance:
2254 if (basicType == EbtFloat)
2255 {
2256 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002257 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302258 for (size_t i = 0; i < maxObjectSize; i++)
2259 {
2260 float x = unionArrays[0][i].getFConst();
2261 float y = unionArrays[1][i].getFConst();
2262 distanceArray[i].setFConst(x - y);
2263 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002264 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302265 }
2266 else
2267 UNREACHABLE();
2268 break;
2269
2270 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002271
Arun Patole1155ddd2015-06-05 18:04:36 +05302272 if (basicType == EbtFloat)
2273 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002274 resultArray = new TConstantUnion();
2275 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302276 }
2277 else
2278 UNREACHABLE();
2279 break;
2280
2281 case EOpCross:
2282 if (basicType == EbtFloat && maxObjectSize == 3)
2283 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002284 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302285 float x0 = unionArrays[0][0].getFConst();
2286 float x1 = unionArrays[0][1].getFConst();
2287 float x2 = unionArrays[0][2].getFConst();
2288 float y0 = unionArrays[1][0].getFConst();
2289 float y1 = unionArrays[1][1].getFConst();
2290 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002291 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2292 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2293 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302294 }
2295 else
2296 UNREACHABLE();
2297 break;
2298
2299 case EOpReflect:
2300 if (basicType == EbtFloat)
2301 {
2302 // genType reflect (genType I, genType N) :
2303 // For the incident vector I and surface orientation N, returns the reflection direction:
2304 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002305 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302306 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2307 for (size_t i = 0; i < maxObjectSize; i++)
2308 {
2309 float result = unionArrays[0][i].getFConst() -
2310 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002311 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302312 }
2313 }
2314 else
2315 UNREACHABLE();
2316 break;
2317
Arun Patole7fa33552015-06-10 15:15:18 +05302318 case EOpMul:
2319 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2320 (*sequence)[1]->getAsTyped()->isMatrix())
2321 {
2322 // Perform component-wise matrix multiplication.
2323 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002324 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302325 angle::Matrix<float> result =
2326 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2327 SetUnionArrayFromMatrix(result, resultArray);
2328 }
2329 else
2330 UNREACHABLE();
2331 break;
2332
2333 case EOpOuterProduct:
2334 if (basicType == EbtFloat)
2335 {
2336 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2337 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2338 resultArray = new TConstantUnion[numRows * numCols];
2339 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002340 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2341 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302342 SetUnionArrayFromMatrix(result, resultArray);
2343 }
2344 else
2345 UNREACHABLE();
2346 break;
2347
Arun Patole274f0702015-05-05 13:33:30 +05302348 default:
2349 UNREACHABLE();
2350 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2351 return nullptr;
2352 }
2353 }
2354 else if (paramsCount == 3)
2355 {
2356 //
2357 // Ternary built-in
2358 //
2359 switch (op)
2360 {
2361 case EOpClamp:
2362 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002363 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302364 for (size_t i = 0; i < maxObjectSize; i++)
2365 {
2366 switch (basicType)
2367 {
2368 case EbtFloat:
2369 {
2370 float x = unionArrays[0][i].getFConst();
2371 float min = unionArrays[1][i].getFConst();
2372 float max = unionArrays[2][i].getFConst();
2373 // Results are undefined if min > max.
2374 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002375 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302376 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002377 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302378 }
2379 break;
2380 case EbtInt:
2381 {
2382 int x = unionArrays[0][i].getIConst();
2383 int min = unionArrays[1][i].getIConst();
2384 int max = unionArrays[2][i].getIConst();
2385 // Results are undefined if min > max.
2386 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002387 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302388 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002389 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302390 }
2391 break;
2392 case EbtUInt:
2393 {
2394 unsigned int x = unionArrays[0][i].getUConst();
2395 unsigned int min = unionArrays[1][i].getUConst();
2396 unsigned int max = unionArrays[2][i].getUConst();
2397 // Results are undefined if min > max.
2398 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002399 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302400 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002401 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302402 }
2403 break;
2404 default:
2405 UNREACHABLE();
2406 break;
2407 }
2408 }
2409 }
2410 break;
2411
Arun Patolebf790422015-05-18 17:53:04 +05302412 case EOpMix:
2413 {
2414 if (basicType == EbtFloat)
2415 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002416 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302417 for (size_t i = 0; i < maxObjectSize; i++)
2418 {
2419 float x = unionArrays[0][i].getFConst();
2420 float y = unionArrays[1][i].getFConst();
2421 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2422 if (type == EbtFloat)
2423 {
2424 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2425 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002426 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302427 }
2428 else // 3rd parameter is EbtBool
2429 {
2430 ASSERT(type == EbtBool);
2431 // Selects which vector each returned component comes from.
2432 // For a component of a that is false, the corresponding component of x is returned.
2433 // For a component of a that is true, the corresponding component of y is returned.
2434 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002435 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302436 }
2437 }
2438 }
2439 else
2440 UNREACHABLE();
2441 }
2442 break;
2443
2444 case EOpSmoothStep:
2445 {
2446 if (basicType == EbtFloat)
2447 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002448 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302449 for (size_t i = 0; i < maxObjectSize; i++)
2450 {
2451 float edge0 = unionArrays[0][i].getFConst();
2452 float edge1 = unionArrays[1][i].getFConst();
2453 float x = unionArrays[2][i].getFConst();
2454 // Results are undefined if edge0 >= edge1.
2455 if (edge0 >= edge1)
2456 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002457 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302458 }
2459 else
2460 {
2461 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2462 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2463 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002464 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302465 }
2466 }
2467 }
2468 else
2469 UNREACHABLE();
2470 }
2471 break;
2472
Arun Patole1155ddd2015-06-05 18:04:36 +05302473 case EOpFaceForward:
2474 if (basicType == EbtFloat)
2475 {
2476 // genType faceforward(genType N, genType I, genType Nref) :
2477 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002478 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302479 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2480 for (size_t i = 0; i < maxObjectSize; i++)
2481 {
2482 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002483 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302484 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002485 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302486 }
2487 }
2488 else
2489 UNREACHABLE();
2490 break;
2491
2492 case EOpRefract:
2493 if (basicType == EbtFloat)
2494 {
2495 // genType refract(genType I, genType N, float eta) :
2496 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2497 // return the refraction vector. The result is computed by
2498 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2499 // if (k < 0.0)
2500 // return genType(0.0)
2501 // else
2502 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002503 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302504 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2505 for (size_t i = 0; i < maxObjectSize; i++)
2506 {
2507 float eta = unionArrays[2][i].getFConst();
2508 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2509 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002510 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302511 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002512 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302513 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2514 }
2515 }
2516 else
2517 UNREACHABLE();
2518 break;
2519
Arun Patole274f0702015-05-05 13:33:30 +05302520 default:
2521 UNREACHABLE();
2522 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2523 return nullptr;
2524 }
2525 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002526 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302527}
2528
2529// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002530TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2531{
2532 if (hashFunction == NULL || name.empty())
2533 return name;
2534 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2535 TStringStream stream;
2536 stream << HASHED_NAME_PREFIX << std::hex << number;
2537 TString hashedName = stream.str();
2538 return hashedName;
2539}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002540
2541void TIntermTraverser::updateTree()
2542{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002543 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2544 {
2545 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2546 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002547 if (!insertion.insertionsAfter.empty())
2548 {
2549 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2550 insertion.insertionsAfter);
2551 ASSERT(inserted);
2552 UNUSED_ASSERTION_VARIABLE(inserted);
2553 }
2554 if (!insertion.insertionsBefore.empty())
2555 {
2556 bool inserted =
2557 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2558 ASSERT(inserted);
2559 UNUSED_ASSERTION_VARIABLE(inserted);
2560 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002561 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002562 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2563 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002564 const NodeUpdateEntry &replacement = mReplacements[ii];
2565 ASSERT(replacement.parent);
2566 bool replaced = replacement.parent->replaceChildNode(
2567 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002568 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002569 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002570
Olli Etuahocd94ef92015-04-16 19:18:10 +03002571 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002572 {
2573 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002574 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002575 // be replaced, we need to make sure we don't update the replaced
2576 // node; instead, we update the replacement node.
2577 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2578 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002579 NodeUpdateEntry &replacement2 = mReplacements[jj];
2580 if (replacement2.parent == replacement.original)
2581 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002582 }
2583 }
2584 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002585 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2586 {
2587 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2588 ASSERT(replacement.parent);
2589 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2590 replacement.original, replacement.replacements);
2591 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002592 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002593 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002594
2595 mInsertions.clear();
2596 mReplacements.clear();
2597 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002598}