blob: 49546ff40751c609a5e8a72c52fa19eab6b212e6 [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
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200172float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530173{
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
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200183float VectorDotProduct(const TConstantUnion *paramArray1,
184 const TConstantUnion *paramArray2,
185 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530186{
187 float result = 0.0f;
188 for (size_t i = 0; i < paramArraySize; i++)
189 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
190 return result;
191}
192
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200193TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
194 const TIntermTyped *originalNode,
195 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300196{
197 if (constArray == nullptr)
198 {
199 return nullptr;
200 }
201 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200202 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300203 folded->setLine(originalNode->getLine());
204 return folded;
205}
206
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200207angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
208 const unsigned int &rows,
209 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530210{
211 std::vector<float> elements;
212 for (size_t i = 0; i < rows * cols; i++)
213 elements.push_back(paramArray[i].getFConst());
214 // Transpose is used since the Matrix constructor expects arguments in row-major order,
215 // whereas the paramArray is in column-major order.
216 return angle::Matrix<float>(elements, rows, cols).transpose();
217}
218
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200219angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530220{
221 std::vector<float> elements;
222 for (size_t i = 0; i < size * size; i++)
223 elements.push_back(paramArray[i].getFConst());
224 // Transpose is used since the Matrix constructor expects arguments in row-major order,
225 // whereas the paramArray is in column-major order.
226 return angle::Matrix<float>(elements, size).transpose();
227}
228
229void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
230{
231 // Transpose is used since the input Matrix is in row-major order,
232 // whereas the actual result should be in column-major order.
233 angle::Matrix<float> result = m.transpose();
234 std::vector<float> resultElements = result.elements();
235 for (size_t i = 0; i < resultElements.size(); i++)
236 resultArray[i].setFConst(resultElements[i]);
237}
238
Jamie Madillb1a85f42014-08-19 15:23:24 -0400239} // namespace anonymous
240
241
242////////////////////////////////////////////////////////////////
243//
244// Member functions of the nodes used for building the tree.
245//
246////////////////////////////////////////////////////////////////
247
Olli Etuahod2a67b92014-10-21 16:42:57 +0300248void TIntermTyped::setTypePreservePrecision(const TType &t)
249{
250 TPrecision precision = getPrecision();
251 mType = t;
252 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
253 mType.setPrecision(precision);
254}
255
Jamie Madillb1a85f42014-08-19 15:23:24 -0400256#define REPLACE_IF_IS(node, type, original, replacement) \
257 if (node == original) { \
258 node = static_cast<type *>(replacement); \
259 return true; \
260 }
261
262bool TIntermLoop::replaceChildNode(
263 TIntermNode *original, TIntermNode *replacement)
264{
265 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
266 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
267 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200268 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400269 return false;
270}
271
Jamie Madillb1a85f42014-08-19 15:23:24 -0400272bool TIntermBranch::replaceChildNode(
273 TIntermNode *original, TIntermNode *replacement)
274{
275 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
276 return false;
277}
278
Jamie Madillb1a85f42014-08-19 15:23:24 -0400279bool TIntermBinary::replaceChildNode(
280 TIntermNode *original, TIntermNode *replacement)
281{
282 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
283 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
284 return false;
285}
286
Jamie Madillb1a85f42014-08-19 15:23:24 -0400287bool TIntermUnary::replaceChildNode(
288 TIntermNode *original, TIntermNode *replacement)
289{
290 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
291 return false;
292}
293
Jamie Madillb1a85f42014-08-19 15:23:24 -0400294bool TIntermAggregate::replaceChildNode(
295 TIntermNode *original, TIntermNode *replacement)
296{
297 for (size_t ii = 0; ii < mSequence.size(); ++ii)
298 {
299 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
300 }
301 return false;
302}
303
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300304bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
305{
306 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
307 {
308 if (*it == original)
309 {
310 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300311 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300312 return true;
313 }
314 }
315 return false;
316}
317
Olli Etuahoa6f22092015-05-08 18:31:10 +0300318bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
319{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300320 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300321 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300322 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300323 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300324 auto it = mSequence.begin() + position;
325 mSequence.insert(it, insertions.begin(), insertions.end());
326 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300327}
328
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200329bool TIntermAggregate::areChildrenConstQualified()
330{
331 for (TIntermNode *&child : mSequence)
332 {
333 TIntermTyped *typed = child->getAsTyped();
334 if (typed && typed->getQualifier() != EvqConst)
335 {
336 return false;
337 }
338 }
339 return true;
340}
341
Olli Etuahod2a67b92014-10-21 16:42:57 +0300342void TIntermAggregate::setPrecisionFromChildren()
343{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300344 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300345 if (getBasicType() == EbtBool)
346 {
347 mType.setPrecision(EbpUndefined);
348 return;
349 }
350
351 TPrecision precision = EbpUndefined;
352 TIntermSequence::iterator childIter = mSequence.begin();
353 while (childIter != mSequence.end())
354 {
355 TIntermTyped *typed = (*childIter)->getAsTyped();
356 if (typed)
357 precision = GetHigherPrecision(typed->getPrecision(), precision);
358 ++childIter;
359 }
360 mType.setPrecision(precision);
361}
362
363void TIntermAggregate::setBuiltInFunctionPrecision()
364{
365 // All built-ins returning bool should be handled as ops, not functions.
366 ASSERT(getBasicType() != EbtBool);
367
368 TPrecision precision = EbpUndefined;
369 TIntermSequence::iterator childIter = mSequence.begin();
370 while (childIter != mSequence.end())
371 {
372 TIntermTyped *typed = (*childIter)->getAsTyped();
373 // ESSL spec section 8: texture functions get their precision from the sampler.
374 if (typed && IsSampler(typed->getBasicType()))
375 {
376 precision = typed->getPrecision();
377 break;
378 }
379 ++childIter;
380 }
381 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
382 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300383 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300384 mType.setPrecision(EbpHigh);
385 else
386 mType.setPrecision(precision);
387}
388
Jamie Madillb1a85f42014-08-19 15:23:24 -0400389bool TIntermSelection::replaceChildNode(
390 TIntermNode *original, TIntermNode *replacement)
391{
392 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
393 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
394 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
395 return false;
396}
397
Olli Etuahoa3a36662015-02-17 13:46:51 +0200398bool TIntermSwitch::replaceChildNode(
399 TIntermNode *original, TIntermNode *replacement)
400{
401 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
402 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
403 return false;
404}
405
406bool TIntermCase::replaceChildNode(
407 TIntermNode *original, TIntermNode *replacement)
408{
409 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
410 return false;
411}
412
Olli Etuahod7a25242015-08-18 13:49:45 +0300413TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
414{
415 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
416 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
417 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
418 mLine = node.mLine;
419}
420
421TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
422{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200423 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300424}
425
426TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
427 : TIntermOperator(node),
428 mName(node.mName),
429 mUserDefined(node.mUserDefined),
430 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300431 mUseEmulatedFunction(node.mUseEmulatedFunction),
432 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
433{
434 for (TIntermNode *child : node.mSequence)
435 {
436 TIntermTyped *typedChild = child->getAsTyped();
437 ASSERT(typedChild != nullptr);
438 TIntermTyped *childCopy = typedChild->deepCopy();
439 mSequence.push_back(childCopy);
440 }
441}
442
443TIntermBinary::TIntermBinary(const TIntermBinary &node)
444 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
445{
446 TIntermTyped *leftCopy = node.mLeft->deepCopy();
447 TIntermTyped *rightCopy = node.mRight->deepCopy();
448 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
449 mLeft = leftCopy;
450 mRight = rightCopy;
451}
452
453TIntermUnary::TIntermUnary(const TIntermUnary &node)
454 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
455{
456 TIntermTyped *operandCopy = node.mOperand->deepCopy();
457 ASSERT(operandCopy != nullptr);
458 mOperand = operandCopy;
459}
460
461TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
462{
463 // Only supported for ternary nodes, not if statements.
464 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
465 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
466 ASSERT(trueTyped != nullptr);
467 ASSERT(falseTyped != nullptr);
468 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
469 TIntermTyped *trueCopy = trueTyped->deepCopy();
470 TIntermTyped *falseCopy = falseTyped->deepCopy();
471 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
472 mCondition = conditionCopy;
473 mTrueBlock = trueCopy;
474 mFalseBlock = falseCopy;
475}
476
Jamie Madillb1a85f42014-08-19 15:23:24 -0400477//
478// Say whether or not an operation node changes the value of a variable.
479//
480bool TIntermOperator::isAssignment() const
481{
482 switch (mOp)
483 {
484 case EOpPostIncrement:
485 case EOpPostDecrement:
486 case EOpPreIncrement:
487 case EOpPreDecrement:
488 case EOpAssign:
489 case EOpAddAssign:
490 case EOpSubAssign:
491 case EOpMulAssign:
492 case EOpVectorTimesMatrixAssign:
493 case EOpVectorTimesScalarAssign:
494 case EOpMatrixTimesScalarAssign:
495 case EOpMatrixTimesMatrixAssign:
496 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200497 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200498 case EOpBitShiftLeftAssign:
499 case EOpBitShiftRightAssign:
500 case EOpBitwiseAndAssign:
501 case EOpBitwiseXorAssign:
502 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400503 return true;
504 default:
505 return false;
506 }
507}
508
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300509bool TIntermOperator::isMultiplication() const
510{
511 switch (mOp)
512 {
513 case EOpMul:
514 case EOpMatrixTimesMatrix:
515 case EOpMatrixTimesVector:
516 case EOpMatrixTimesScalar:
517 case EOpVectorTimesMatrix:
518 case EOpVectorTimesScalar:
519 return true;
520 default:
521 return false;
522 }
523}
524
Jamie Madillb1a85f42014-08-19 15:23:24 -0400525//
526// returns true if the operator is for one of the constructors
527//
528bool TIntermOperator::isConstructor() const
529{
530 switch (mOp)
531 {
532 case EOpConstructVec2:
533 case EOpConstructVec3:
534 case EOpConstructVec4:
535 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400536 case EOpConstructMat2x3:
537 case EOpConstructMat2x4:
538 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400539 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400540 case EOpConstructMat3x4:
541 case EOpConstructMat4x2:
542 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400543 case EOpConstructMat4:
544 case EOpConstructFloat:
545 case EOpConstructIVec2:
546 case EOpConstructIVec3:
547 case EOpConstructIVec4:
548 case EOpConstructInt:
549 case EOpConstructUVec2:
550 case EOpConstructUVec3:
551 case EOpConstructUVec4:
552 case EOpConstructUInt:
553 case EOpConstructBVec2:
554 case EOpConstructBVec3:
555 case EOpConstructBVec4:
556 case EOpConstructBool:
557 case EOpConstructStruct:
558 return true;
559 default:
560 return false;
561 }
562}
563
564//
565// Make sure the type of a unary operator is appropriate for its
566// combination of operation and operand type.
567//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200568void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400569{
570 switch (mOp)
571 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200572 case EOpFloatBitsToInt:
573 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200574 case EOpIntBitsToFloat:
575 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200576 case EOpPackSnorm2x16:
577 case EOpPackUnorm2x16:
578 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200579 case EOpUnpackSnorm2x16:
580 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200581 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530582 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200583 case EOpUnpackHalf2x16:
584 mType.setPrecision(EbpMedium);
585 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400586 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200587 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400588 }
589
Olli Etuahof6c694b2015-03-26 14:50:53 +0200590 if (funcReturnType != nullptr)
591 {
592 if (funcReturnType->getBasicType() == EbtBool)
593 {
594 // Bool types should not have precision.
595 setType(*funcReturnType);
596 }
597 else
598 {
599 // Precision of the node has been set based on the operand.
600 setTypePreservePrecision(*funcReturnType);
601 }
602 }
603
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200604 if (mOperand->getQualifier() == EvqConst)
605 mType.setQualifier(EvqConst);
606 else
607 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400608}
609
610//
611// Establishes the type of the resultant operation, as well as
612// makes the operator the correct one for the operands.
613//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200614// For lots of operations it should already be established that the operand
615// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400616//
617bool TIntermBinary::promote(TInfoSink &infoSink)
618{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200619 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400620
Jamie Madillb1a85f42014-08-19 15:23:24 -0400621 //
622 // Base assumption: just make the type the same as the left
623 // operand. Then only deviations from this need be coded.
624 //
625 setType(mLeft->getType());
626
627 // The result gets promoted to the highest precision.
628 TPrecision higherPrecision = GetHigherPrecision(
629 mLeft->getPrecision(), mRight->getPrecision());
630 getTypePointer()->setPrecision(higherPrecision);
631
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200632 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400633 // Binary operations results in temporary variables unless both
634 // operands are const.
635 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
636 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200637 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400638 getTypePointer()->setQualifier(EvqTemporary);
639 }
640
641 const int nominalSize =
642 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
643
644 //
645 // All scalars or structs. Code after this test assumes this case is removed!
646 //
647 if (nominalSize == 1)
648 {
649 switch (mOp)
650 {
651 //
652 // Promote to conditional
653 //
654 case EOpEqual:
655 case EOpNotEqual:
656 case EOpLessThan:
657 case EOpGreaterThan:
658 case EOpLessThanEqual:
659 case EOpGreaterThanEqual:
660 setType(TType(EbtBool, EbpUndefined));
661 break;
662
663 //
664 // And and Or operate on conditionals
665 //
666 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200667 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400668 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200669 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400670 setType(TType(EbtBool, EbpUndefined));
671 break;
672
673 default:
674 break;
675 }
676 return true;
677 }
678
679 // If we reach here, at least one of the operands is vector or matrix.
680 // The other operand could be a scalar, vector, or matrix.
681 // Can these two operands be combined?
682 //
683 TBasicType basicType = mLeft->getBasicType();
684 switch (mOp)
685 {
686 case EOpMul:
687 if (!mLeft->isMatrix() && mRight->isMatrix())
688 {
689 if (mLeft->isVector())
690 {
691 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200692 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700693 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400694 }
695 else
696 {
697 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200698 setType(TType(basicType, higherPrecision, resultQualifier,
699 static_cast<unsigned char>(mRight->getCols()),
700 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400701 }
702 }
703 else if (mLeft->isMatrix() && !mRight->isMatrix())
704 {
705 if (mRight->isVector())
706 {
707 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200708 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700709 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400710 }
711 else
712 {
713 mOp = EOpMatrixTimesScalar;
714 }
715 }
716 else if (mLeft->isMatrix() && mRight->isMatrix())
717 {
718 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200719 setType(TType(basicType, higherPrecision, resultQualifier,
720 static_cast<unsigned char>(mRight->getCols()),
721 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400722 }
723 else if (!mLeft->isMatrix() && !mRight->isMatrix())
724 {
725 if (mLeft->isVector() && mRight->isVector())
726 {
727 // leave as component product
728 }
729 else if (mLeft->isVector() || mRight->isVector())
730 {
731 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200732 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700733 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400734 }
735 }
736 else
737 {
738 infoSink.info.message(EPrefixInternalError, getLine(),
739 "Missing elses");
740 return false;
741 }
742
743 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
744 {
745 return false;
746 }
747 break;
748
749 case EOpMulAssign:
750 if (!mLeft->isMatrix() && mRight->isMatrix())
751 {
752 if (mLeft->isVector())
753 {
754 mOp = EOpVectorTimesMatrixAssign;
755 }
756 else
757 {
758 return false;
759 }
760 }
761 else if (mLeft->isMatrix() && !mRight->isMatrix())
762 {
763 if (mRight->isVector())
764 {
765 return false;
766 }
767 else
768 {
769 mOp = EOpMatrixTimesScalarAssign;
770 }
771 }
772 else if (mLeft->isMatrix() && mRight->isMatrix())
773 {
774 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200775 setType(TType(basicType, higherPrecision, resultQualifier,
776 static_cast<unsigned char>(mRight->getCols()),
777 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400778 }
779 else if (!mLeft->isMatrix() && !mRight->isMatrix())
780 {
781 if (mLeft->isVector() && mRight->isVector())
782 {
783 // leave as component product
784 }
785 else if (mLeft->isVector() || mRight->isVector())
786 {
787 if (!mLeft->isVector())
788 return false;
789 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200790 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700791 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400792 }
793 }
794 else
795 {
796 infoSink.info.message(EPrefixInternalError, getLine(),
797 "Missing elses");
798 return false;
799 }
800
801 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
802 {
803 return false;
804 }
805 break;
806
807 case EOpAssign:
808 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200809 // No more additional checks are needed.
810 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
811 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
812 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400813 case EOpAdd:
814 case EOpSub:
815 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200816 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200817 case EOpBitShiftLeft:
818 case EOpBitShiftRight:
819 case EOpBitwiseAnd:
820 case EOpBitwiseXor:
821 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400822 case EOpAddAssign:
823 case EOpSubAssign:
824 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200825 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200826 case EOpBitShiftLeftAssign:
827 case EOpBitShiftRightAssign:
828 case EOpBitwiseAndAssign:
829 case EOpBitwiseXorAssign:
830 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400831 if ((mLeft->isMatrix() && mRight->isVector()) ||
832 (mLeft->isVector() && mRight->isMatrix()))
833 {
834 return false;
835 }
836
837 // Are the sizes compatible?
838 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
839 mLeft->getSecondarySize() != mRight->getSecondarySize())
840 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200841 // If the nominal sizes of operands do not match:
842 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400843 if (!mLeft->isScalar() && !mRight->isScalar())
844 return false;
845
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200846 // In the case of compound assignment other than multiply-assign,
847 // the right side needs to be a scalar. Otherwise a vector/matrix
848 // would be assigned to a scalar. A scalar can't be shifted by a
849 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200850 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200851 (isAssignment() ||
852 mOp == EOpBitShiftLeft ||
853 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200854 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400855 }
856
857 {
858 const int secondarySize = std::max(
859 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200860 setType(TType(basicType, higherPrecision, resultQualifier,
861 static_cast<unsigned char>(nominalSize),
862 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200863 if (mLeft->isArray())
864 {
865 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
866 mType.setArraySize(mLeft->getArraySize());
867 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400868 }
869 break;
870
871 case EOpEqual:
872 case EOpNotEqual:
873 case EOpLessThan:
874 case EOpGreaterThan:
875 case EOpLessThanEqual:
876 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200877 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
878 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400879 setType(TType(EbtBool, EbpUndefined));
880 break;
881
882 default:
883 return false;
884 }
885 return true;
886}
887
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300888TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
889{
890 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
891 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
892 if (leftConstant == nullptr || rightConstant == nullptr)
893 {
894 return nullptr;
895 }
896 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200897
898 // Nodes may be constant folded without being qualified as constant.
899 TQualifier resultQualifier = EvqConst;
900 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
901 {
902 resultQualifier = EvqTemporary;
903 }
904 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300905}
906
Olli Etuaho95310b02015-06-02 17:43:38 +0300907TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
908{
909 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
910 if (operandConstant == nullptr)
911 {
912 return nullptr;
913 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530914
915 TConstantUnion *constArray = nullptr;
916 switch (mOp)
917 {
918 case EOpAny:
919 case EOpAll:
920 case EOpLength:
921 case EOpTranspose:
922 case EOpDeterminant:
923 case EOpInverse:
924 case EOpPackSnorm2x16:
925 case EOpUnpackSnorm2x16:
926 case EOpPackUnorm2x16:
927 case EOpUnpackUnorm2x16:
928 case EOpPackHalf2x16:
929 case EOpUnpackHalf2x16:
930 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
931 break;
932 default:
933 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
934 break;
935 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200936
937 // Nodes may be constant folded without being qualified as constant.
938 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
939 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300940}
941
942TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
943{
944 // Make sure that all params are constant before actual constant folding.
945 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300946 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300947 if (param->getAsConstantUnion() == nullptr)
948 {
949 return nullptr;
950 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300951 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200952 TConstantUnion *constArray = nullptr;
953 if (isConstructor())
954 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
955 else
956 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200957
958 // Nodes may be constant folded without being qualified as constant.
959 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
960 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300961}
962
Jamie Madillb1a85f42014-08-19 15:23:24 -0400963//
964// The fold functions see if an operation on a constant can be done in place,
965// without generating run-time code.
966//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300967// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400968//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300969TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
970{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200971 const TConstantUnion *leftArray = getUnionArrayPointer();
972 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300973
974 if (!leftArray)
975 return nullptr;
976 if (!rightArray)
977 return nullptr;
978
979 size_t objectSize = getType().getObjectSize();
980
981 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
982 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
983 {
984 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
985 }
986 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
987 {
988 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
989 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
990 objectSize = rightNode->getType().getObjectSize();
991 }
992
993 TConstantUnion *resultArray = nullptr;
994
995 switch(op)
996 {
997 case EOpAdd:
998 resultArray = new TConstantUnion[objectSize];
999 for (size_t i = 0; i < objectSize; i++)
1000 resultArray[i] = leftArray[i] + rightArray[i];
1001 break;
1002 case EOpSub:
1003 resultArray = new TConstantUnion[objectSize];
1004 for (size_t i = 0; i < objectSize; i++)
1005 resultArray[i] = leftArray[i] - rightArray[i];
1006 break;
1007
1008 case EOpMul:
1009 case EOpVectorTimesScalar:
1010 case EOpMatrixTimesScalar:
1011 resultArray = new TConstantUnion[objectSize];
1012 for (size_t i = 0; i < objectSize; i++)
1013 resultArray[i] = leftArray[i] * rightArray[i];
1014 break;
1015
1016 case EOpMatrixTimesMatrix:
1017 {
1018 if (getType().getBasicType() != EbtFloat ||
1019 rightNode->getBasicType() != EbtFloat)
1020 {
1021 infoSink.info.message(
1022 EPrefixInternalError, getLine(),
1023 "Constant Folding cannot be done for matrix multiply");
1024 return nullptr;
1025 }
1026
1027 const int leftCols = getCols();
1028 const int leftRows = getRows();
1029 const int rightCols = rightNode->getType().getCols();
1030 const int rightRows = rightNode->getType().getRows();
1031 const int resultCols = rightCols;
1032 const int resultRows = leftRows;
1033
1034 resultArray = new TConstantUnion[resultCols * resultRows];
1035 for (int row = 0; row < resultRows; row++)
1036 {
1037 for (int column = 0; column < resultCols; column++)
1038 {
1039 resultArray[resultRows * column + row].setFConst(0.0f);
1040 for (int i = 0; i < leftCols; i++)
1041 {
1042 resultArray[resultRows * column + row].setFConst(
1043 resultArray[resultRows * column + row].getFConst() +
1044 leftArray[i * leftRows + row].getFConst() *
1045 rightArray[column * rightRows + i].getFConst());
1046 }
1047 }
1048 }
1049 }
1050 break;
1051
1052 case EOpDiv:
1053 case EOpIMod:
1054 {
1055 resultArray = new TConstantUnion[objectSize];
1056 for (size_t i = 0; i < objectSize; i++)
1057 {
1058 switch (getType().getBasicType())
1059 {
1060 case EbtFloat:
1061 if (rightArray[i] == 0.0f)
1062 {
1063 infoSink.info.message(EPrefixWarning, getLine(),
1064 "Divide by zero error during constant folding");
1065 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1066 }
1067 else
1068 {
1069 ASSERT(op == EOpDiv);
1070 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1071 }
1072 break;
1073
1074 case EbtInt:
1075 if (rightArray[i] == 0)
1076 {
1077 infoSink.info.message(EPrefixWarning, getLine(),
1078 "Divide by zero error during constant folding");
1079 resultArray[i].setIConst(INT_MAX);
1080 }
1081 else
1082 {
1083 if (op == EOpDiv)
1084 {
1085 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1086 }
1087 else
1088 {
1089 ASSERT(op == EOpIMod);
1090 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1091 }
1092 }
1093 break;
1094
1095 case EbtUInt:
1096 if (rightArray[i] == 0)
1097 {
1098 infoSink.info.message(EPrefixWarning, getLine(),
1099 "Divide by zero error during constant folding");
1100 resultArray[i].setUConst(UINT_MAX);
1101 }
1102 else
1103 {
1104 if (op == EOpDiv)
1105 {
1106 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1107 }
1108 else
1109 {
1110 ASSERT(op == EOpIMod);
1111 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1112 }
1113 }
1114 break;
1115
1116 default:
1117 infoSink.info.message(EPrefixInternalError, getLine(),
1118 "Constant folding cannot be done for \"/\"");
1119 return nullptr;
1120 }
1121 }
1122 }
1123 break;
1124
1125 case EOpMatrixTimesVector:
1126 {
1127 if (rightNode->getBasicType() != EbtFloat)
1128 {
1129 infoSink.info.message(EPrefixInternalError, getLine(),
1130 "Constant Folding cannot be done for matrix times vector");
1131 return nullptr;
1132 }
1133
1134 const int matrixCols = getCols();
1135 const int matrixRows = getRows();
1136
1137 resultArray = new TConstantUnion[matrixRows];
1138
1139 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1140 {
1141 resultArray[matrixRow].setFConst(0.0f);
1142 for (int col = 0; col < matrixCols; col++)
1143 {
1144 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1145 leftArray[col * matrixRows + matrixRow].getFConst() *
1146 rightArray[col].getFConst());
1147 }
1148 }
1149 }
1150 break;
1151
1152 case EOpVectorTimesMatrix:
1153 {
1154 if (getType().getBasicType() != EbtFloat)
1155 {
1156 infoSink.info.message(EPrefixInternalError, getLine(),
1157 "Constant Folding cannot be done for vector times matrix");
1158 return nullptr;
1159 }
1160
1161 const int matrixCols = rightNode->getType().getCols();
1162 const int matrixRows = rightNode->getType().getRows();
1163
1164 resultArray = new TConstantUnion[matrixCols];
1165
1166 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1167 {
1168 resultArray[matrixCol].setFConst(0.0f);
1169 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1170 {
1171 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1172 leftArray[matrixRow].getFConst() *
1173 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1174 }
1175 }
1176 }
1177 break;
1178
1179 case EOpLogicalAnd:
1180 {
1181 resultArray = new TConstantUnion[objectSize];
1182 for (size_t i = 0; i < objectSize; i++)
1183 {
1184 resultArray[i] = leftArray[i] && rightArray[i];
1185 }
1186 }
1187 break;
1188
1189 case EOpLogicalOr:
1190 {
1191 resultArray = new TConstantUnion[objectSize];
1192 for (size_t i = 0; i < objectSize; i++)
1193 {
1194 resultArray[i] = leftArray[i] || rightArray[i];
1195 }
1196 }
1197 break;
1198
1199 case EOpLogicalXor:
1200 {
1201 resultArray = new TConstantUnion[objectSize];
1202 for (size_t i = 0; i < objectSize; i++)
1203 {
1204 switch (getType().getBasicType())
1205 {
1206 case EbtBool:
1207 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1208 break;
1209 default:
1210 UNREACHABLE();
1211 break;
1212 }
1213 }
1214 }
1215 break;
1216
1217 case EOpBitwiseAnd:
1218 resultArray = new TConstantUnion[objectSize];
1219 for (size_t i = 0; i < objectSize; i++)
1220 resultArray[i] = leftArray[i] & rightArray[i];
1221 break;
1222 case EOpBitwiseXor:
1223 resultArray = new TConstantUnion[objectSize];
1224 for (size_t i = 0; i < objectSize; i++)
1225 resultArray[i] = leftArray[i] ^ rightArray[i];
1226 break;
1227 case EOpBitwiseOr:
1228 resultArray = new TConstantUnion[objectSize];
1229 for (size_t i = 0; i < objectSize; i++)
1230 resultArray[i] = leftArray[i] | rightArray[i];
1231 break;
1232 case EOpBitShiftLeft:
1233 resultArray = new TConstantUnion[objectSize];
1234 for (size_t i = 0; i < objectSize; i++)
1235 resultArray[i] = leftArray[i] << rightArray[i];
1236 break;
1237 case EOpBitShiftRight:
1238 resultArray = new TConstantUnion[objectSize];
1239 for (size_t i = 0; i < objectSize; i++)
1240 resultArray[i] = leftArray[i] >> rightArray[i];
1241 break;
1242
1243 case EOpLessThan:
1244 ASSERT(objectSize == 1);
1245 resultArray = new TConstantUnion[1];
1246 resultArray->setBConst(*leftArray < *rightArray);
1247 break;
1248
1249 case EOpGreaterThan:
1250 ASSERT(objectSize == 1);
1251 resultArray = new TConstantUnion[1];
1252 resultArray->setBConst(*leftArray > *rightArray);
1253 break;
1254
1255 case EOpLessThanEqual:
1256 ASSERT(objectSize == 1);
1257 resultArray = new TConstantUnion[1];
1258 resultArray->setBConst(!(*leftArray > *rightArray));
1259 break;
1260
1261 case EOpGreaterThanEqual:
1262 ASSERT(objectSize == 1);
1263 resultArray = new TConstantUnion[1];
1264 resultArray->setBConst(!(*leftArray < *rightArray));
1265 break;
1266
1267 case EOpEqual:
1268 case EOpNotEqual:
1269 {
1270 resultArray = new TConstantUnion[1];
1271 bool equal = true;
1272 if (getType().getBasicType() == EbtStruct)
1273 {
1274 equal = CompareStructure(getType(), rightArray, leftArray);
1275 }
1276 else
1277 {
1278 for (size_t i = 0; i < objectSize; i++)
1279 {
1280 if (leftArray[i] != rightArray[i])
1281 {
1282 equal = false;
1283 break; // break out of for loop
1284 }
1285 }
1286 }
1287 if (op == EOpEqual)
1288 {
1289 resultArray->setBConst(equal);
1290 }
1291 else
1292 {
1293 resultArray->setBConst(!equal);
1294 }
1295 }
1296 break;
1297
1298 default:
1299 infoSink.info.message(
1300 EPrefixInternalError, getLine(),
1301 "Invalid operator for constant folding");
1302 return nullptr;
1303 }
1304 return resultArray;
1305}
1306
1307//
1308// The fold functions see if an operation on a constant can be done in place,
1309// without generating run-time code.
1310//
Olli Etuaho95310b02015-06-02 17:43:38 +03001311// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001312//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301313TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001314{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301315 //
1316 // Do operations where the return type has a different number of components compared to the operand type.
1317 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001318
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001319 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301320 if (!operandArray)
1321 return nullptr;
1322
1323 size_t objectSize = getType().getObjectSize();
1324 TConstantUnion *resultArray = nullptr;
1325 switch (op)
1326 {
1327 case EOpAny:
1328 if (getType().getBasicType() == EbtBool)
1329 {
1330 resultArray = new TConstantUnion();
1331 resultArray->setBConst(false);
1332 for (size_t i = 0; i < objectSize; i++)
1333 {
1334 if (operandArray[i].getBConst())
1335 {
1336 resultArray->setBConst(true);
1337 break;
1338 }
1339 }
1340 break;
1341 }
1342 else
1343 {
1344 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1345 return nullptr;
1346 }
1347
1348 case EOpAll:
1349 if (getType().getBasicType() == EbtBool)
1350 {
1351 resultArray = new TConstantUnion();
1352 resultArray->setBConst(true);
1353 for (size_t i = 0; i < objectSize; i++)
1354 {
1355 if (!operandArray[i].getBConst())
1356 {
1357 resultArray->setBConst(false);
1358 break;
1359 }
1360 }
1361 break;
1362 }
1363 else
1364 {
1365 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1366 return nullptr;
1367 }
1368
1369 case EOpLength:
1370 if (getType().getBasicType() == EbtFloat)
1371 {
1372 resultArray = new TConstantUnion();
1373 resultArray->setFConst(VectorLength(operandArray, objectSize));
1374 break;
1375 }
1376 else
1377 {
1378 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1379 return nullptr;
1380 }
1381
1382 case EOpTranspose:
1383 if (getType().getBasicType() == EbtFloat)
1384 {
1385 resultArray = new TConstantUnion[objectSize];
1386 angle::Matrix<float> result =
1387 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1388 SetUnionArrayFromMatrix(result, resultArray);
1389 break;
1390 }
1391 else
1392 {
1393 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1394 return nullptr;
1395 }
1396
1397 case EOpDeterminant:
1398 if (getType().getBasicType() == EbtFloat)
1399 {
1400 unsigned int size = getType().getNominalSize();
1401 ASSERT(size >= 2 && size <= 4);
1402 resultArray = new TConstantUnion();
1403 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1404 break;
1405 }
1406 else
1407 {
1408 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1409 return nullptr;
1410 }
1411
1412 case EOpInverse:
1413 if (getType().getBasicType() == EbtFloat)
1414 {
1415 unsigned int size = getType().getNominalSize();
1416 ASSERT(size >= 2 && size <= 4);
1417 resultArray = new TConstantUnion[objectSize];
1418 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1419 SetUnionArrayFromMatrix(result, resultArray);
1420 break;
1421 }
1422 else
1423 {
1424 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1425 return nullptr;
1426 }
1427
1428 case EOpPackSnorm2x16:
1429 if (getType().getBasicType() == EbtFloat)
1430 {
1431 ASSERT(getType().getNominalSize() == 2);
1432 resultArray = new TConstantUnion();
1433 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1434 break;
1435 }
1436 else
1437 {
1438 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1439 return nullptr;
1440 }
1441
1442 case EOpUnpackSnorm2x16:
1443 if (getType().getBasicType() == EbtUInt)
1444 {
1445 resultArray = new TConstantUnion[2];
1446 float f1, f2;
1447 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1448 resultArray[0].setFConst(f1);
1449 resultArray[1].setFConst(f2);
1450 break;
1451 }
1452 else
1453 {
1454 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1455 return nullptr;
1456 }
1457
1458 case EOpPackUnorm2x16:
1459 if (getType().getBasicType() == EbtFloat)
1460 {
1461 ASSERT(getType().getNominalSize() == 2);
1462 resultArray = new TConstantUnion();
1463 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1464 break;
1465 }
1466 else
1467 {
1468 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1469 return nullptr;
1470 }
1471
1472 case EOpUnpackUnorm2x16:
1473 if (getType().getBasicType() == EbtUInt)
1474 {
1475 resultArray = new TConstantUnion[2];
1476 float f1, f2;
1477 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1478 resultArray[0].setFConst(f1);
1479 resultArray[1].setFConst(f2);
1480 break;
1481 }
1482 else
1483 {
1484 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1485 return nullptr;
1486 }
1487
1488 case EOpPackHalf2x16:
1489 if (getType().getBasicType() == EbtFloat)
1490 {
1491 ASSERT(getType().getNominalSize() == 2);
1492 resultArray = new TConstantUnion();
1493 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1494 break;
1495 }
1496 else
1497 {
1498 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1499 return nullptr;
1500 }
1501
1502 case EOpUnpackHalf2x16:
1503 if (getType().getBasicType() == EbtUInt)
1504 {
1505 resultArray = new TConstantUnion[2];
1506 float f1, f2;
1507 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1508 resultArray[0].setFConst(f1);
1509 resultArray[1].setFConst(f2);
1510 break;
1511 }
1512 else
1513 {
1514 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1515 return nullptr;
1516 }
1517 break;
1518
1519 default:
1520 break;
1521 }
1522
1523 return resultArray;
1524}
1525
1526TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1527{
1528 //
1529 // Do unary operations where the return type is the same as operand type.
1530 //
1531
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001532 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001533 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301534 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001535
1536 size_t objectSize = getType().getObjectSize();
1537
Arun Patoleab2b9a22015-07-06 18:27:56 +05301538 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1539 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301540 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301541 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301542 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301543 case EOpNegative:
1544 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301545 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301546 case EbtFloat:
1547 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301548 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301549 case EbtInt:
1550 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301551 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301552 case EbtUInt:
1553 resultArray[i].setUConst(static_cast<unsigned int>(
1554 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301555 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301556 default:
1557 infoSink.info.message(
1558 EPrefixInternalError, getLine(),
1559 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301560 return nullptr;
1561 }
1562 break;
1563
Arun Patoleab2b9a22015-07-06 18:27:56 +05301564 case EOpPositive:
1565 switch (getType().getBasicType())
1566 {
1567 case EbtFloat:
1568 resultArray[i].setFConst(operandArray[i].getFConst());
1569 break;
1570 case EbtInt:
1571 resultArray[i].setIConst(operandArray[i].getIConst());
1572 break;
1573 case EbtUInt:
1574 resultArray[i].setUConst(static_cast<unsigned int>(
1575 static_cast<int>(operandArray[i].getUConst())));
1576 break;
1577 default:
1578 infoSink.info.message(
1579 EPrefixInternalError, getLine(),
1580 "Unary operation not folded into constant");
1581 return nullptr;
1582 }
1583 break;
1584
1585 case EOpLogicalNot:
1586 // this code is written for possible future use,
1587 // will not get executed currently
1588 switch (getType().getBasicType())
1589 {
1590 case EbtBool:
1591 resultArray[i].setBConst(!operandArray[i].getBConst());
1592 break;
1593 default:
1594 infoSink.info.message(
1595 EPrefixInternalError, getLine(),
1596 "Unary operation not folded into constant");
1597 return nullptr;
1598 }
1599 break;
1600
1601 case EOpBitwiseNot:
1602 switch (getType().getBasicType())
1603 {
1604 case EbtInt:
1605 resultArray[i].setIConst(~operandArray[i].getIConst());
1606 break;
1607 case EbtUInt:
1608 resultArray[i].setUConst(~operandArray[i].getUConst());
1609 break;
1610 default:
1611 infoSink.info.message(
1612 EPrefixInternalError, getLine(),
1613 "Unary operation not folded into constant");
1614 return nullptr;
1615 }
1616 break;
1617
1618 case EOpRadians:
1619 if (getType().getBasicType() == EbtFloat)
1620 {
1621 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1622 break;
1623 }
1624 infoSink.info.message(
1625 EPrefixInternalError, getLine(),
1626 "Unary operation not folded into constant");
1627 return nullptr;
1628
1629 case EOpDegrees:
1630 if (getType().getBasicType() == EbtFloat)
1631 {
1632 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1633 break;
1634 }
1635 infoSink.info.message(
1636 EPrefixInternalError, getLine(),
1637 "Unary operation not folded into constant");
1638 return nullptr;
1639
1640 case EOpSin:
1641 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1642 return nullptr;
1643 break;
1644
1645 case EOpCos:
1646 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1647 return nullptr;
1648 break;
1649
1650 case EOpTan:
1651 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1652 return nullptr;
1653 break;
1654
1655 case EOpAsin:
1656 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1657 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1658 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1659 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1660 return nullptr;
1661 break;
1662
1663 case EOpAcos:
1664 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1665 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1666 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1667 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1668 return nullptr;
1669 break;
1670
1671 case EOpAtan:
1672 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1673 return nullptr;
1674 break;
1675
1676 case EOpSinh:
1677 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1678 return nullptr;
1679 break;
1680
1681 case EOpCosh:
1682 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1683 return nullptr;
1684 break;
1685
1686 case EOpTanh:
1687 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1688 return nullptr;
1689 break;
1690
1691 case EOpAsinh:
1692 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1693 return nullptr;
1694 break;
1695
1696 case EOpAcosh:
1697 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1698 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1699 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1700 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1701 return nullptr;
1702 break;
1703
1704 case EOpAtanh:
1705 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1706 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1707 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1708 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1709 return nullptr;
1710 break;
1711
1712 case EOpAbs:
1713 switch (getType().getBasicType())
1714 {
1715 case EbtFloat:
1716 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1717 break;
1718 case EbtInt:
1719 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1720 break;
1721 default:
1722 infoSink.info.message(
1723 EPrefixInternalError, getLine(),
1724 "Unary operation not folded into constant");
1725 return nullptr;
1726 }
1727 break;
1728
1729 case EOpSign:
1730 switch (getType().getBasicType())
1731 {
1732 case EbtFloat:
1733 {
1734 float fConst = operandArray[i].getFConst();
1735 float fResult = 0.0f;
1736 if (fConst > 0.0f)
1737 fResult = 1.0f;
1738 else if (fConst < 0.0f)
1739 fResult = -1.0f;
1740 resultArray[i].setFConst(fResult);
1741 }
1742 break;
1743 case EbtInt:
1744 {
1745 int iConst = operandArray[i].getIConst();
1746 int iResult = 0;
1747 if (iConst > 0)
1748 iResult = 1;
1749 else if (iConst < 0)
1750 iResult = -1;
1751 resultArray[i].setIConst(iResult);
1752 }
1753 break;
1754 default:
1755 infoSink.info.message(
1756 EPrefixInternalError, getLine(),
1757 "Unary operation not folded into constant");
1758 return nullptr;
1759 }
1760 break;
1761
1762 case EOpFloor:
1763 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1764 return nullptr;
1765 break;
1766
1767 case EOpTrunc:
1768 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1769 return nullptr;
1770 break;
1771
1772 case EOpRound:
1773 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1774 return nullptr;
1775 break;
1776
1777 case EOpRoundEven:
1778 if (getType().getBasicType() == EbtFloat)
1779 {
1780 float x = operandArray[i].getFConst();
1781 float result;
1782 float fractPart = modff(x, &result);
1783 if (fabsf(fractPart) == 0.5f)
1784 result = 2.0f * roundf(x / 2.0f);
1785 else
1786 result = roundf(x);
1787 resultArray[i].setFConst(result);
1788 break;
1789 }
1790 infoSink.info.message(
1791 EPrefixInternalError, getLine(),
1792 "Unary operation not folded into constant");
1793 return nullptr;
1794
1795 case EOpCeil:
1796 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1797 return nullptr;
1798 break;
1799
1800 case EOpFract:
1801 if (getType().getBasicType() == EbtFloat)
1802 {
1803 float x = operandArray[i].getFConst();
1804 resultArray[i].setFConst(x - floorf(x));
1805 break;
1806 }
1807 infoSink.info.message(
1808 EPrefixInternalError, getLine(),
1809 "Unary operation not folded into constant");
1810 return nullptr;
1811
Arun Patole551279e2015-07-07 18:18:23 +05301812 case EOpIsNan:
1813 if (getType().getBasicType() == EbtFloat)
1814 {
1815 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1816 break;
1817 }
1818 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1819 return nullptr;
1820
1821 case EOpIsInf:
1822 if (getType().getBasicType() == EbtFloat)
1823 {
1824 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1825 break;
1826 }
1827 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1828 return nullptr;
1829
1830 case EOpFloatBitsToInt:
1831 if (getType().getBasicType() == EbtFloat)
1832 {
1833 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1834 break;
1835 }
1836 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1837 return nullptr;
1838
1839 case EOpFloatBitsToUint:
1840 if (getType().getBasicType() == EbtFloat)
1841 {
1842 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1843 break;
1844 }
1845 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1846 return nullptr;
1847
1848 case EOpIntBitsToFloat:
1849 if (getType().getBasicType() == EbtInt)
1850 {
1851 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1852 break;
1853 }
1854 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1855 return nullptr;
1856
1857 case EOpUintBitsToFloat:
1858 if (getType().getBasicType() == EbtUInt)
1859 {
1860 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1861 break;
1862 }
1863 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1864 return nullptr;
1865
Arun Patoleab2b9a22015-07-06 18:27:56 +05301866 case EOpExp:
1867 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1868 return nullptr;
1869 break;
1870
1871 case EOpLog:
1872 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1873 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1874 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1875 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1876 return nullptr;
1877 break;
1878
1879 case EOpExp2:
1880 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1881 return nullptr;
1882 break;
1883
1884 case EOpLog2:
1885 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1886 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1887 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1888 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1889 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1890 return nullptr;
1891 else
1892 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1893 break;
1894
1895 case EOpSqrt:
1896 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1897 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1898 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1899 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1900 return nullptr;
1901 break;
1902
1903 case EOpInverseSqrt:
1904 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1905 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1906 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1907 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1908 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1909 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1910 return nullptr;
1911 else
1912 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1913 break;
1914
1915 case EOpVectorLogicalNot:
1916 if (getType().getBasicType() == EbtBool)
1917 {
1918 resultArray[i].setBConst(!operandArray[i].getBConst());
1919 break;
1920 }
1921 infoSink.info.message(
1922 EPrefixInternalError, getLine(),
1923 "Unary operation not folded into constant");
1924 return nullptr;
1925
1926 case EOpNormalize:
1927 if (getType().getBasicType() == EbtFloat)
1928 {
1929 float x = operandArray[i].getFConst();
1930 float length = VectorLength(operandArray, objectSize);
1931 if (length)
1932 resultArray[i].setFConst(x / length);
1933 else
1934 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1935 &resultArray[i]);
1936 break;
1937 }
1938 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1939 return nullptr;
1940
Arun Patole0c5409f2015-07-08 15:17:53 +05301941 case EOpDFdx:
1942 case EOpDFdy:
1943 case EOpFwidth:
1944 if (getType().getBasicType() == EbtFloat)
1945 {
1946 // Derivatives of constant arguments should be 0.
1947 resultArray[i].setFConst(0.0f);
1948 break;
1949 }
1950 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1951 return nullptr;
1952
Arun Patole1155ddd2015-06-05 18:04:36 +05301953 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301954 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301955 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301956 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001957
Arun Patoleab2b9a22015-07-06 18:27:56 +05301958 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001959}
1960
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001961bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1962 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301963{
1964 ASSERT(builtinFunc);
1965
1966 if (getType().getBasicType() == EbtFloat)
1967 {
1968 result->setFConst(builtinFunc(parameter.getFConst()));
1969 return true;
1970 }
1971
1972 infoSink.info.message(
1973 EPrefixInternalError, getLine(),
1974 "Unary operation not folded into constant");
1975 return false;
1976}
1977
Jamie Madillb1a85f42014-08-19 15:23:24 -04001978// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001979TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1980 TInfoSink &infoSink)
1981{
1982 ASSERT(aggregate->getSequence()->size() > 0u);
1983 size_t resultSize = aggregate->getType().getObjectSize();
1984 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1985 TBasicType basicType = aggregate->getBasicType();
1986
1987 size_t resultIndex = 0u;
1988
1989 if (aggregate->getSequence()->size() == 1u)
1990 {
1991 TIntermNode *argument = aggregate->getSequence()->front();
1992 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1993 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1994 // Check the special case of constructing a matrix diagonal from a single scalar,
1995 // or a vector from a single scalar.
1996 if (argumentConstant->getType().getObjectSize() == 1u)
1997 {
1998 if (aggregate->isMatrix())
1999 {
2000 int resultCols = aggregate->getType().getCols();
2001 int resultRows = aggregate->getType().getRows();
2002 for (int col = 0; col < resultCols; ++col)
2003 {
2004 for (int row = 0; row < resultRows; ++row)
2005 {
2006 if (col == row)
2007 {
2008 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2009 }
2010 else
2011 {
2012 resultArray[resultIndex].setFConst(0.0f);
2013 }
2014 ++resultIndex;
2015 }
2016 }
2017 }
2018 else
2019 {
2020 while (resultIndex < resultSize)
2021 {
2022 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2023 ++resultIndex;
2024 }
2025 }
2026 ASSERT(resultIndex == resultSize);
2027 return resultArray;
2028 }
2029 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2030 {
2031 // The special case of constructing a matrix from a matrix.
2032 int argumentCols = argumentConstant->getType().getCols();
2033 int argumentRows = argumentConstant->getType().getRows();
2034 int resultCols = aggregate->getType().getCols();
2035 int resultRows = aggregate->getType().getRows();
2036 for (int col = 0; col < resultCols; ++col)
2037 {
2038 for (int row = 0; row < resultRows; ++row)
2039 {
2040 if (col < argumentCols && row < argumentRows)
2041 {
2042 resultArray[resultIndex].cast(basicType,
2043 argumentUnionArray[col * argumentRows + row]);
2044 }
2045 else if (col == row)
2046 {
2047 resultArray[resultIndex].setFConst(1.0f);
2048 }
2049 else
2050 {
2051 resultArray[resultIndex].setFConst(0.0f);
2052 }
2053 ++resultIndex;
2054 }
2055 }
2056 ASSERT(resultIndex == resultSize);
2057 return resultArray;
2058 }
2059 }
2060
2061 for (TIntermNode *&argument : *aggregate->getSequence())
2062 {
2063 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2064 size_t argumentSize = argumentConstant->getType().getObjectSize();
2065 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2066 for (size_t i = 0u; i < argumentSize; ++i)
2067 {
2068 if (resultIndex >= resultSize)
2069 break;
2070 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2071 ++resultIndex;
2072 }
2073 }
2074 ASSERT(resultIndex == resultSize);
2075 return resultArray;
2076}
2077
2078// static
Olli Etuahob43846e2015-06-02 18:18:57 +03002079TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05302080{
Olli Etuahob43846e2015-06-02 18:18:57 +03002081 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302082 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002083 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002084 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302085 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002086 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302087 TBasicType basicType = EbtVoid;
2088 TSourceLoc loc;
2089 for (unsigned int i = 0; i < paramsCount; i++)
2090 {
2091 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002092 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302093
2094 if (i == 0)
2095 {
2096 basicType = paramConstant->getType().getBasicType();
2097 loc = paramConstant->getLine();
2098 }
2099 unionArrays[i] = paramConstant->getUnionArrayPointer();
2100 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002101 if (objectSizes[i] > maxObjectSize)
2102 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302103 }
2104
Arun Patole7fa33552015-06-10 15:15:18 +05302105 if (!(*sequence)[0]->getAsTyped()->isMatrix())
2106 {
2107 for (unsigned int i = 0; i < paramsCount; i++)
2108 if (objectSizes[i] != maxObjectSize)
2109 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2110 }
Arun Patole274f0702015-05-05 13:33:30 +05302111
Olli Etuahob43846e2015-06-02 18:18:57 +03002112 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302113 if (paramsCount == 2)
2114 {
2115 //
2116 // Binary built-in
2117 //
2118 switch (op)
2119 {
Arun Patolebf790422015-05-18 17:53:04 +05302120 case EOpAtan:
2121 {
2122 if (basicType == EbtFloat)
2123 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002124 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302125 for (size_t i = 0; i < maxObjectSize; i++)
2126 {
2127 float y = unionArrays[0][i].getFConst();
2128 float x = unionArrays[1][i].getFConst();
2129 // Results are undefined if x and y are both 0.
2130 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002131 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302132 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002133 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302134 }
2135 }
2136 else
2137 UNREACHABLE();
2138 }
2139 break;
2140
2141 case EOpPow:
2142 {
2143 if (basicType == EbtFloat)
2144 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002145 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302146 for (size_t i = 0; i < maxObjectSize; i++)
2147 {
2148 float x = unionArrays[0][i].getFConst();
2149 float y = unionArrays[1][i].getFConst();
2150 // Results are undefined if x < 0.
2151 // Results are undefined if x = 0 and y <= 0.
2152 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002153 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302154 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002155 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302156 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002157 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302158 }
2159 }
2160 else
2161 UNREACHABLE();
2162 }
2163 break;
2164
2165 case EOpMod:
2166 {
2167 if (basicType == EbtFloat)
2168 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002169 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302170 for (size_t i = 0; i < maxObjectSize; i++)
2171 {
2172 float x = unionArrays[0][i].getFConst();
2173 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002174 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302175 }
2176 }
2177 else
2178 UNREACHABLE();
2179 }
2180 break;
2181
Arun Patole274f0702015-05-05 13:33:30 +05302182 case EOpMin:
2183 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002184 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302185 for (size_t i = 0; i < maxObjectSize; i++)
2186 {
2187 switch (basicType)
2188 {
2189 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002190 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302191 break;
2192 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002193 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302194 break;
2195 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002196 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302197 break;
2198 default:
2199 UNREACHABLE();
2200 break;
2201 }
2202 }
2203 }
2204 break;
2205
2206 case EOpMax:
2207 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002208 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302209 for (size_t i = 0; i < maxObjectSize; i++)
2210 {
2211 switch (basicType)
2212 {
2213 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002214 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302215 break;
2216 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002217 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302218 break;
2219 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002220 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302221 break;
2222 default:
2223 UNREACHABLE();
2224 break;
2225 }
2226 }
2227 }
2228 break;
2229
Arun Patolebf790422015-05-18 17:53:04 +05302230 case EOpStep:
2231 {
2232 if (basicType == EbtFloat)
2233 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002234 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302235 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002236 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302237 }
2238 else
2239 UNREACHABLE();
2240 }
2241 break;
2242
Arun Patole9d0b1f92015-05-20 14:27:17 +05302243 case EOpLessThan:
2244 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002245 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302246 for (size_t i = 0; i < maxObjectSize; i++)
2247 {
2248 switch (basicType)
2249 {
2250 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002251 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302252 break;
2253 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002254 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302255 break;
2256 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002257 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302258 break;
2259 default:
2260 UNREACHABLE();
2261 break;
2262 }
2263 }
2264 }
2265 break;
2266
2267 case EOpLessThanEqual:
2268 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002269 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302270 for (size_t i = 0; i < maxObjectSize; i++)
2271 {
2272 switch (basicType)
2273 {
2274 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002275 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302276 break;
2277 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002278 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302279 break;
2280 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002281 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302282 break;
2283 default:
2284 UNREACHABLE();
2285 break;
2286 }
2287 }
2288 }
2289 break;
2290
2291 case EOpGreaterThan:
2292 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002293 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302294 for (size_t i = 0; i < maxObjectSize; i++)
2295 {
2296 switch (basicType)
2297 {
2298 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002299 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302300 break;
2301 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002302 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302303 break;
2304 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002305 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302306 break;
2307 default:
2308 UNREACHABLE();
2309 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002310 }
2311 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302312 }
2313 break;
2314
2315 case EOpGreaterThanEqual:
2316 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002317 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302318 for (size_t i = 0; i < maxObjectSize; i++)
2319 {
2320 switch (basicType)
2321 {
2322 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002323 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302324 break;
2325 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002326 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302327 break;
2328 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002329 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302330 break;
2331 default:
2332 UNREACHABLE();
2333 break;
2334 }
2335 }
2336 }
2337 break;
2338
2339 case EOpVectorEqual:
2340 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002341 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302342 for (size_t i = 0; i < maxObjectSize; i++)
2343 {
2344 switch (basicType)
2345 {
2346 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002347 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302348 break;
2349 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002350 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302351 break;
2352 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002353 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302354 break;
2355 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002356 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302357 break;
2358 default:
2359 UNREACHABLE();
2360 break;
2361 }
2362 }
2363 }
2364 break;
2365
2366 case EOpVectorNotEqual:
2367 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002368 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302369 for (size_t i = 0; i < maxObjectSize; i++)
2370 {
2371 switch (basicType)
2372 {
2373 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002374 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302375 break;
2376 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002377 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302378 break;
2379 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002380 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302381 break;
2382 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002383 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302384 break;
2385 default:
2386 UNREACHABLE();
2387 break;
2388 }
2389 }
2390 }
2391 break;
2392
Arun Patole1155ddd2015-06-05 18:04:36 +05302393 case EOpDistance:
2394 if (basicType == EbtFloat)
2395 {
2396 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002397 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302398 for (size_t i = 0; i < maxObjectSize; i++)
2399 {
2400 float x = unionArrays[0][i].getFConst();
2401 float y = unionArrays[1][i].getFConst();
2402 distanceArray[i].setFConst(x - y);
2403 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002404 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302405 }
2406 else
2407 UNREACHABLE();
2408 break;
2409
2410 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002411
Arun Patole1155ddd2015-06-05 18:04:36 +05302412 if (basicType == EbtFloat)
2413 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002414 resultArray = new TConstantUnion();
2415 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302416 }
2417 else
2418 UNREACHABLE();
2419 break;
2420
2421 case EOpCross:
2422 if (basicType == EbtFloat && maxObjectSize == 3)
2423 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002424 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302425 float x0 = unionArrays[0][0].getFConst();
2426 float x1 = unionArrays[0][1].getFConst();
2427 float x2 = unionArrays[0][2].getFConst();
2428 float y0 = unionArrays[1][0].getFConst();
2429 float y1 = unionArrays[1][1].getFConst();
2430 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002431 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2432 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2433 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302434 }
2435 else
2436 UNREACHABLE();
2437 break;
2438
2439 case EOpReflect:
2440 if (basicType == EbtFloat)
2441 {
2442 // genType reflect (genType I, genType N) :
2443 // For the incident vector I and surface orientation N, returns the reflection direction:
2444 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002445 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302446 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2447 for (size_t i = 0; i < maxObjectSize; i++)
2448 {
2449 float result = unionArrays[0][i].getFConst() -
2450 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002451 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302452 }
2453 }
2454 else
2455 UNREACHABLE();
2456 break;
2457
Arun Patole7fa33552015-06-10 15:15:18 +05302458 case EOpMul:
2459 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2460 (*sequence)[1]->getAsTyped()->isMatrix())
2461 {
2462 // Perform component-wise matrix multiplication.
2463 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002464 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302465 angle::Matrix<float> result =
2466 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2467 SetUnionArrayFromMatrix(result, resultArray);
2468 }
2469 else
2470 UNREACHABLE();
2471 break;
2472
2473 case EOpOuterProduct:
2474 if (basicType == EbtFloat)
2475 {
2476 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2477 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2478 resultArray = new TConstantUnion[numRows * numCols];
2479 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002480 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2481 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302482 SetUnionArrayFromMatrix(result, resultArray);
2483 }
2484 else
2485 UNREACHABLE();
2486 break;
2487
Arun Patole274f0702015-05-05 13:33:30 +05302488 default:
2489 UNREACHABLE();
2490 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2491 return nullptr;
2492 }
2493 }
2494 else if (paramsCount == 3)
2495 {
2496 //
2497 // Ternary built-in
2498 //
2499 switch (op)
2500 {
2501 case EOpClamp:
2502 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002503 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302504 for (size_t i = 0; i < maxObjectSize; i++)
2505 {
2506 switch (basicType)
2507 {
2508 case EbtFloat:
2509 {
2510 float x = unionArrays[0][i].getFConst();
2511 float min = unionArrays[1][i].getFConst();
2512 float max = unionArrays[2][i].getFConst();
2513 // Results are undefined if min > max.
2514 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002515 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302516 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002517 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302518 }
2519 break;
2520 case EbtInt:
2521 {
2522 int x = unionArrays[0][i].getIConst();
2523 int min = unionArrays[1][i].getIConst();
2524 int max = unionArrays[2][i].getIConst();
2525 // Results are undefined if min > max.
2526 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002527 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302528 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002529 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302530 }
2531 break;
2532 case EbtUInt:
2533 {
2534 unsigned int x = unionArrays[0][i].getUConst();
2535 unsigned int min = unionArrays[1][i].getUConst();
2536 unsigned int max = unionArrays[2][i].getUConst();
2537 // Results are undefined if min > max.
2538 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002539 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302540 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002541 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302542 }
2543 break;
2544 default:
2545 UNREACHABLE();
2546 break;
2547 }
2548 }
2549 }
2550 break;
2551
Arun Patolebf790422015-05-18 17:53:04 +05302552 case EOpMix:
2553 {
2554 if (basicType == EbtFloat)
2555 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002556 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302557 for (size_t i = 0; i < maxObjectSize; i++)
2558 {
2559 float x = unionArrays[0][i].getFConst();
2560 float y = unionArrays[1][i].getFConst();
2561 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2562 if (type == EbtFloat)
2563 {
2564 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2565 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002566 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302567 }
2568 else // 3rd parameter is EbtBool
2569 {
2570 ASSERT(type == EbtBool);
2571 // Selects which vector each returned component comes from.
2572 // For a component of a that is false, the corresponding component of x is returned.
2573 // For a component of a that is true, the corresponding component of y is returned.
2574 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002575 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302576 }
2577 }
2578 }
2579 else
2580 UNREACHABLE();
2581 }
2582 break;
2583
2584 case EOpSmoothStep:
2585 {
2586 if (basicType == EbtFloat)
2587 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002588 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302589 for (size_t i = 0; i < maxObjectSize; i++)
2590 {
2591 float edge0 = unionArrays[0][i].getFConst();
2592 float edge1 = unionArrays[1][i].getFConst();
2593 float x = unionArrays[2][i].getFConst();
2594 // Results are undefined if edge0 >= edge1.
2595 if (edge0 >= edge1)
2596 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002597 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302598 }
2599 else
2600 {
2601 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2602 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2603 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002604 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302605 }
2606 }
2607 }
2608 else
2609 UNREACHABLE();
2610 }
2611 break;
2612
Arun Patole1155ddd2015-06-05 18:04:36 +05302613 case EOpFaceForward:
2614 if (basicType == EbtFloat)
2615 {
2616 // genType faceforward(genType N, genType I, genType Nref) :
2617 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002618 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302619 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2620 for (size_t i = 0; i < maxObjectSize; i++)
2621 {
2622 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002623 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302624 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002625 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302626 }
2627 }
2628 else
2629 UNREACHABLE();
2630 break;
2631
2632 case EOpRefract:
2633 if (basicType == EbtFloat)
2634 {
2635 // genType refract(genType I, genType N, float eta) :
2636 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2637 // return the refraction vector. The result is computed by
2638 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2639 // if (k < 0.0)
2640 // return genType(0.0)
2641 // else
2642 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002643 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302644 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2645 for (size_t i = 0; i < maxObjectSize; i++)
2646 {
2647 float eta = unionArrays[2][i].getFConst();
2648 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2649 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002650 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302651 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002652 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302653 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2654 }
2655 }
2656 else
2657 UNREACHABLE();
2658 break;
2659
Arun Patole274f0702015-05-05 13:33:30 +05302660 default:
2661 UNREACHABLE();
2662 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2663 return nullptr;
2664 }
2665 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002666 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302667}
2668
2669// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002670TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2671{
2672 if (hashFunction == NULL || name.empty())
2673 return name;
2674 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2675 TStringStream stream;
2676 stream << HASHED_NAME_PREFIX << std::hex << number;
2677 TString hashedName = stream.str();
2678 return hashedName;
2679}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002680
2681void TIntermTraverser::updateTree()
2682{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002683 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2684 {
2685 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2686 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002687 if (!insertion.insertionsAfter.empty())
2688 {
2689 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2690 insertion.insertionsAfter);
2691 ASSERT(inserted);
2692 UNUSED_ASSERTION_VARIABLE(inserted);
2693 }
2694 if (!insertion.insertionsBefore.empty())
2695 {
2696 bool inserted =
2697 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2698 ASSERT(inserted);
2699 UNUSED_ASSERTION_VARIABLE(inserted);
2700 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002701 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002702 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2703 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002704 const NodeUpdateEntry &replacement = mReplacements[ii];
2705 ASSERT(replacement.parent);
2706 bool replaced = replacement.parent->replaceChildNode(
2707 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002708 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002709 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002710
Olli Etuahocd94ef92015-04-16 19:18:10 +03002711 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002712 {
2713 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002714 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002715 // be replaced, we need to make sure we don't update the replaced
2716 // node; instead, we update the replacement node.
2717 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2718 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002719 NodeUpdateEntry &replacement2 = mReplacements[jj];
2720 if (replacement2.parent == replacement.original)
2721 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002722 }
2723 }
2724 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002725 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2726 {
2727 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2728 ASSERT(replacement.parent);
2729 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2730 replacement.original, replacement.replacements);
2731 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002732 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002733 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002734
2735 mInsertions.clear();
2736 mReplacements.clear();
2737 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002738}