blob: dcf47879ae3ec9b4aed7921f26d90a66870afd09 [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"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/HashNames.h"
22#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
24
25namespace
26{
27
Arun Patole9dea48f2015-04-02 11:45:09 +053028const float kPi = 3.14159265358979323846f;
29const float kDegreesToRadiansMultiplier = kPi / 180.0f;
30const float kRadiansToDegreesMultiplier = 180.0f / kPi;
31
Jamie Madillb1a85f42014-08-19 15:23:24 -040032TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
33{
34 return left > right ? left : right;
35}
36
Arun Patole274f0702015-05-05 13:33:30 +053037TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
38{
39 TConstantUnion *constUnion = new TConstantUnion[size];
40 for (unsigned int i = 0; i < size; ++i)
41 constUnion[i] = constant;
42
43 return constUnion;
44}
45
Arun Patolebf790422015-05-18 17:53:04 +053046void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
47 TInfoSink &infoSink, TConstantUnion *result)
48{
49 std::stringstream constantFoldingErrorStream;
50 constantFoldingErrorStream << "'" << GetOperatorString(op)
51 << "' operation result is undefined for the values passed in";
52 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
53
54 switch (basicType)
55 {
56 case EbtFloat :
57 result->setFConst(0.0f);
58 break;
59 case EbtInt:
60 result->setIConst(0);
61 break;
62 case EbtUInt:
63 result->setUConst(0u);
64 break;
65 case EbtBool:
66 result->setBConst(false);
67 break;
68 default:
69 break;
70 }
71}
72
Olli Etuaho5c0e0232015-11-11 15:55:59 +020073float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053074{
75 float result = 0.0f;
76 for (size_t i = 0; i < paramArraySize; i++)
77 {
78 float f = paramArray[i].getFConst();
79 result += f * f;
80 }
81 return sqrtf(result);
82}
83
Olli Etuaho5c0e0232015-11-11 15:55:59 +020084float VectorDotProduct(const TConstantUnion *paramArray1,
85 const TConstantUnion *paramArray2,
86 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053087{
88 float result = 0.0f;
89 for (size_t i = 0; i < paramArraySize; i++)
90 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
91 return result;
92}
93
Olli Etuaho7c3848e2015-11-04 13:19:17 +020094TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
95 const TIntermTyped *originalNode,
96 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +030097{
98 if (constArray == nullptr)
99 {
100 return nullptr;
101 }
102 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200103 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 folded->setLine(originalNode->getLine());
105 return folded;
106}
107
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200108angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
109 const unsigned int &rows,
110 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530111{
112 std::vector<float> elements;
113 for (size_t i = 0; i < rows * cols; i++)
114 elements.push_back(paramArray[i].getFConst());
115 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300116 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
117 // so that the created matrix will have the expected dimensions after the transpose.
118 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530119}
120
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200121angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530122{
123 std::vector<float> elements;
124 for (size_t i = 0; i < size * size; i++)
125 elements.push_back(paramArray[i].getFConst());
126 // Transpose is used since the Matrix constructor expects arguments in row-major order,
127 // whereas the paramArray is in column-major order.
128 return angle::Matrix<float>(elements, size).transpose();
129}
130
131void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
132{
133 // Transpose is used since the input Matrix is in row-major order,
134 // whereas the actual result should be in column-major order.
135 angle::Matrix<float> result = m.transpose();
136 std::vector<float> resultElements = result.elements();
137 for (size_t i = 0; i < resultElements.size(); i++)
138 resultArray[i].setFConst(resultElements[i]);
139}
140
Jamie Madillb1a85f42014-08-19 15:23:24 -0400141} // namespace anonymous
142
143
144////////////////////////////////////////////////////////////////
145//
146// Member functions of the nodes used for building the tree.
147//
148////////////////////////////////////////////////////////////////
149
Olli Etuahod2a67b92014-10-21 16:42:57 +0300150void TIntermTyped::setTypePreservePrecision(const TType &t)
151{
152 TPrecision precision = getPrecision();
153 mType = t;
154 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
155 mType.setPrecision(precision);
156}
157
Jamie Madillb1a85f42014-08-19 15:23:24 -0400158#define REPLACE_IF_IS(node, type, original, replacement) \
159 if (node == original) { \
160 node = static_cast<type *>(replacement); \
161 return true; \
162 }
163
164bool TIntermLoop::replaceChildNode(
165 TIntermNode *original, TIntermNode *replacement)
166{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300167 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400168 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
169 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
170 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200171 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400172 return false;
173}
174
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175bool TIntermBranch::replaceChildNode(
176 TIntermNode *original, TIntermNode *replacement)
177{
178 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
179 return false;
180}
181
Jamie Madillb1a85f42014-08-19 15:23:24 -0400182bool TIntermBinary::replaceChildNode(
183 TIntermNode *original, TIntermNode *replacement)
184{
185 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
186 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
187 return false;
188}
189
Jamie Madillb1a85f42014-08-19 15:23:24 -0400190bool TIntermUnary::replaceChildNode(
191 TIntermNode *original, TIntermNode *replacement)
192{
193 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
194 return false;
195}
196
Jamie Madillb1a85f42014-08-19 15:23:24 -0400197bool TIntermAggregate::replaceChildNode(
198 TIntermNode *original, TIntermNode *replacement)
199{
200 for (size_t ii = 0; ii < mSequence.size(); ++ii)
201 {
202 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
203 }
204 return false;
205}
206
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300207bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
208{
209 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
210 {
211 if (*it == original)
212 {
213 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300214 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300215 return true;
216 }
217 }
218 return false;
219}
220
Olli Etuahoa6f22092015-05-08 18:31:10 +0300221bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
222{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300223 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300224 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300225 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300226 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300227 auto it = mSequence.begin() + position;
228 mSequence.insert(it, insertions.begin(), insertions.end());
229 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300230}
231
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200232bool TIntermAggregate::areChildrenConstQualified()
233{
234 for (TIntermNode *&child : mSequence)
235 {
236 TIntermTyped *typed = child->getAsTyped();
237 if (typed && typed->getQualifier() != EvqConst)
238 {
239 return false;
240 }
241 }
242 return true;
243}
244
Olli Etuahod2a67b92014-10-21 16:42:57 +0300245void TIntermAggregate::setPrecisionFromChildren()
246{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300247 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300248 if (getBasicType() == EbtBool)
249 {
250 mType.setPrecision(EbpUndefined);
251 return;
252 }
253
254 TPrecision precision = EbpUndefined;
255 TIntermSequence::iterator childIter = mSequence.begin();
256 while (childIter != mSequence.end())
257 {
258 TIntermTyped *typed = (*childIter)->getAsTyped();
259 if (typed)
260 precision = GetHigherPrecision(typed->getPrecision(), precision);
261 ++childIter;
262 }
263 mType.setPrecision(precision);
264}
265
266void TIntermAggregate::setBuiltInFunctionPrecision()
267{
268 // All built-ins returning bool should be handled as ops, not functions.
269 ASSERT(getBasicType() != EbtBool);
270
271 TPrecision precision = EbpUndefined;
272 TIntermSequence::iterator childIter = mSequence.begin();
273 while (childIter != mSequence.end())
274 {
275 TIntermTyped *typed = (*childIter)->getAsTyped();
276 // ESSL spec section 8: texture functions get their precision from the sampler.
277 if (typed && IsSampler(typed->getBasicType()))
278 {
279 precision = typed->getPrecision();
280 break;
281 }
282 ++childIter;
283 }
284 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
285 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300286 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300287 mType.setPrecision(EbpHigh);
288 else
289 mType.setPrecision(precision);
290}
291
Jamie Madillb1a85f42014-08-19 15:23:24 -0400292bool TIntermSelection::replaceChildNode(
293 TIntermNode *original, TIntermNode *replacement)
294{
295 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
296 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
297 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
298 return false;
299}
300
Olli Etuahoa3a36662015-02-17 13:46:51 +0200301bool TIntermSwitch::replaceChildNode(
302 TIntermNode *original, TIntermNode *replacement)
303{
304 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
305 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
306 return false;
307}
308
309bool TIntermCase::replaceChildNode(
310 TIntermNode *original, TIntermNode *replacement)
311{
312 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
313 return false;
314}
315
Olli Etuahod7a25242015-08-18 13:49:45 +0300316TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
317{
318 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
319 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
320 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
321 mLine = node.mLine;
322}
323
Olli Etuahod4f4c112016-04-15 15:11:24 +0300324bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
325{
326 TIntermAggregate *constructor = getAsAggregate();
327 if (!constructor || !constructor->isConstructor())
328 {
329 return false;
330 }
331 for (TIntermNode *&node : *constructor->getSequence())
332 {
333 if (!node->getAsConstantUnion())
334 return false;
335 }
336 return true;
337}
338
Olli Etuahod7a25242015-08-18 13:49:45 +0300339TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
340{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200341 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300342}
343
344TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
345 : TIntermOperator(node),
346 mName(node.mName),
347 mUserDefined(node.mUserDefined),
348 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300349 mUseEmulatedFunction(node.mUseEmulatedFunction),
350 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
351{
352 for (TIntermNode *child : node.mSequence)
353 {
354 TIntermTyped *typedChild = child->getAsTyped();
355 ASSERT(typedChild != nullptr);
356 TIntermTyped *childCopy = typedChild->deepCopy();
357 mSequence.push_back(childCopy);
358 }
359}
360
361TIntermBinary::TIntermBinary(const TIntermBinary &node)
362 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
363{
364 TIntermTyped *leftCopy = node.mLeft->deepCopy();
365 TIntermTyped *rightCopy = node.mRight->deepCopy();
366 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
367 mLeft = leftCopy;
368 mRight = rightCopy;
369}
370
371TIntermUnary::TIntermUnary(const TIntermUnary &node)
372 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
373{
374 TIntermTyped *operandCopy = node.mOperand->deepCopy();
375 ASSERT(operandCopy != nullptr);
376 mOperand = operandCopy;
377}
378
379TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
380{
381 // Only supported for ternary nodes, not if statements.
382 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
383 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
384 ASSERT(trueTyped != nullptr);
385 ASSERT(falseTyped != nullptr);
386 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
387 TIntermTyped *trueCopy = trueTyped->deepCopy();
388 TIntermTyped *falseCopy = falseTyped->deepCopy();
389 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
390 mCondition = conditionCopy;
391 mTrueBlock = trueCopy;
392 mFalseBlock = falseCopy;
393}
394
Jamie Madillb1a85f42014-08-19 15:23:24 -0400395bool TIntermOperator::isAssignment() const
396{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300397 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400398}
399
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300400bool TIntermOperator::isMultiplication() const
401{
402 switch (mOp)
403 {
404 case EOpMul:
405 case EOpMatrixTimesMatrix:
406 case EOpMatrixTimesVector:
407 case EOpMatrixTimesScalar:
408 case EOpVectorTimesMatrix:
409 case EOpVectorTimesScalar:
410 return true;
411 default:
412 return false;
413 }
414}
415
Jamie Madillb1a85f42014-08-19 15:23:24 -0400416//
417// returns true if the operator is for one of the constructors
418//
419bool TIntermOperator::isConstructor() const
420{
421 switch (mOp)
422 {
423 case EOpConstructVec2:
424 case EOpConstructVec3:
425 case EOpConstructVec4:
426 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400427 case EOpConstructMat2x3:
428 case EOpConstructMat2x4:
429 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400430 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400431 case EOpConstructMat3x4:
432 case EOpConstructMat4x2:
433 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400434 case EOpConstructMat4:
435 case EOpConstructFloat:
436 case EOpConstructIVec2:
437 case EOpConstructIVec3:
438 case EOpConstructIVec4:
439 case EOpConstructInt:
440 case EOpConstructUVec2:
441 case EOpConstructUVec3:
442 case EOpConstructUVec4:
443 case EOpConstructUInt:
444 case EOpConstructBVec2:
445 case EOpConstructBVec3:
446 case EOpConstructBVec4:
447 case EOpConstructBool:
448 case EOpConstructStruct:
449 return true;
450 default:
451 return false;
452 }
453}
454
Olli Etuaho1dded802016-08-18 18:13:13 +0300455TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
456{
457 if (left.isMatrix())
458 {
459 if (right.isMatrix())
460 {
461 return EOpMatrixTimesMatrix;
462 }
463 else
464 {
465 if (right.isVector())
466 {
467 return EOpMatrixTimesVector;
468 }
469 else
470 {
471 return EOpMatrixTimesScalar;
472 }
473 }
474 }
475 else
476 {
477 if (right.isMatrix())
478 {
479 if (left.isVector())
480 {
481 return EOpVectorTimesMatrix;
482 }
483 else
484 {
485 return EOpMatrixTimesScalar;
486 }
487 }
488 else
489 {
490 // Neither operand is a matrix.
491 if (left.isVector() == right.isVector())
492 {
493 // Leave as component product.
494 return EOpMul;
495 }
496 else
497 {
498 return EOpVectorTimesScalar;
499 }
500 }
501 }
502}
503
504TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
505{
506 if (left.isMatrix())
507 {
508 if (right.isMatrix())
509 {
510 return EOpMatrixTimesMatrixAssign;
511 }
512 else
513 {
514 // right should be scalar, but this may not be validated yet.
515 return EOpMatrixTimesScalarAssign;
516 }
517 }
518 else
519 {
520 if (right.isMatrix())
521 {
522 // Left should be a vector, but this may not be validated yet.
523 return EOpVectorTimesMatrixAssign;
524 }
525 else
526 {
527 // Neither operand is a matrix.
528 if (left.isVector() == right.isVector())
529 {
530 // Leave as component product.
531 return EOpMulAssign;
532 }
533 else
534 {
535 // left should be vector and right should be scalar, but this may not be validated
536 // yet.
537 return EOpVectorTimesScalarAssign;
538 }
539 }
540 }
541}
542
Jamie Madillb1a85f42014-08-19 15:23:24 -0400543//
544// Make sure the type of a unary operator is appropriate for its
545// combination of operation and operand type.
546//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200547void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400548{
549 switch (mOp)
550 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200551 case EOpFloatBitsToInt:
552 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200553 case EOpIntBitsToFloat:
554 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200555 case EOpPackSnorm2x16:
556 case EOpPackUnorm2x16:
557 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200558 case EOpUnpackSnorm2x16:
559 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200560 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530561 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200562 case EOpUnpackHalf2x16:
563 mType.setPrecision(EbpMedium);
564 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400565 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200566 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400567 }
568
Olli Etuahof6c694b2015-03-26 14:50:53 +0200569 if (funcReturnType != nullptr)
570 {
571 if (funcReturnType->getBasicType() == EbtBool)
572 {
573 // Bool types should not have precision.
574 setType(*funcReturnType);
575 }
576 else
577 {
578 // Precision of the node has been set based on the operand.
579 setTypePreservePrecision(*funcReturnType);
580 }
581 }
582
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200583 if (mOperand->getQualifier() == EvqConst)
584 mType.setQualifier(EvqConst);
585 else
586 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400587}
588
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300589TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
590 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
591{
592 promote();
593}
594
Jamie Madillb1a85f42014-08-19 15:23:24 -0400595//
596// Establishes the type of the resultant operation, as well as
597// makes the operator the correct one for the operands.
598//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200599// For lots of operations it should already be established that the operand
600// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400601//
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300602void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400603{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200604 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400605
Olli Etuaho1dded802016-08-18 18:13:13 +0300606 ASSERT(!isMultiplication() ||
607 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
608
Jamie Madillb1a85f42014-08-19 15:23:24 -0400609 // Base assumption: just make the type the same as the left
610 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400611 setType(mLeft->getType());
612
613 // The result gets promoted to the highest precision.
614 TPrecision higherPrecision = GetHigherPrecision(
615 mLeft->getPrecision(), mRight->getPrecision());
616 getTypePointer()->setPrecision(higherPrecision);
617
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200618 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400619 // Binary operations results in temporary variables unless both
620 // operands are const.
621 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
622 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200623 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400624 getTypePointer()->setQualifier(EvqTemporary);
625 }
626
627 const int nominalSize =
628 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
629
630 //
631 // All scalars or structs. Code after this test assumes this case is removed!
632 //
633 if (nominalSize == 1)
634 {
635 switch (mOp)
636 {
637 //
638 // Promote to conditional
639 //
640 case EOpEqual:
641 case EOpNotEqual:
642 case EOpLessThan:
643 case EOpGreaterThan:
644 case EOpLessThanEqual:
645 case EOpGreaterThanEqual:
646 setType(TType(EbtBool, EbpUndefined));
647 break;
648
649 //
650 // And and Or operate on conditionals
651 //
652 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200653 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400654 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200655 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400656 setType(TType(EbtBool, EbpUndefined));
657 break;
658
659 default:
660 break;
661 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300662 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400663 }
664
665 // If we reach here, at least one of the operands is vector or matrix.
666 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400667 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300668
Jamie Madillb1a85f42014-08-19 15:23:24 -0400669 switch (mOp)
670 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300671 case EOpMul:
672 break;
673 case EOpMatrixTimesScalar:
674 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400675 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200676 setType(TType(basicType, higherPrecision, resultQualifier,
677 static_cast<unsigned char>(mRight->getCols()),
678 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400679 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300680 break;
681 case EOpMatrixTimesVector:
682 setType(TType(basicType, higherPrecision, resultQualifier,
683 static_cast<unsigned char>(mLeft->getRows()), 1));
684 break;
685 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200686 setType(TType(basicType, higherPrecision, resultQualifier,
687 static_cast<unsigned char>(mRight->getCols()),
688 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300689 break;
690 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200691 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300692 static_cast<unsigned char>(nominalSize), 1));
693 break;
694 case EOpVectorTimesMatrix:
695 setType(TType(basicType, higherPrecision, resultQualifier,
696 static_cast<unsigned char>(mRight->getCols()), 1));
697 break;
698 case EOpMulAssign:
699 case EOpVectorTimesScalarAssign:
700 case EOpVectorTimesMatrixAssign:
701 case EOpMatrixTimesScalarAssign:
702 case EOpMatrixTimesMatrixAssign:
703 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
704 break;
705 case EOpAssign:
706 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300707 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
708 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
709 break;
710 case EOpAdd:
711 case EOpSub:
712 case EOpDiv:
713 case EOpIMod:
714 case EOpBitShiftLeft:
715 case EOpBitShiftRight:
716 case EOpBitwiseAnd:
717 case EOpBitwiseXor:
718 case EOpBitwiseOr:
719 case EOpAddAssign:
720 case EOpSubAssign:
721 case EOpDivAssign:
722 case EOpIModAssign:
723 case EOpBitShiftLeftAssign:
724 case EOpBitShiftRightAssign:
725 case EOpBitwiseAndAssign:
726 case EOpBitwiseXorAssign:
727 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300728 {
729 const int secondarySize =
730 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
731 setType(TType(basicType, higherPrecision, resultQualifier,
732 static_cast<unsigned char>(nominalSize),
733 static_cast<unsigned char>(secondarySize)));
734 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300735 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300736 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300737 case EOpEqual:
738 case EOpNotEqual:
739 case EOpLessThan:
740 case EOpGreaterThan:
741 case EOpLessThanEqual:
742 case EOpGreaterThanEqual:
743 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
744 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300745 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300746 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400747
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300748 case EOpIndexDirect:
749 case EOpIndexIndirect:
750 case EOpIndexDirectInterfaceBlock:
751 case EOpIndexDirectStruct:
752 // TODO (oetuaho): These ops could be handled here as well (should be done closer to the
753 // top of the function).
754 UNREACHABLE();
755 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300756 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300757 UNREACHABLE();
758 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400759 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400760}
761
Olli Etuaho3fdec912016-08-18 15:08:06 +0300762TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300763{
764 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
765 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
766 if (leftConstant == nullptr || rightConstant == nullptr)
767 {
768 return nullptr;
769 }
Olli Etuaho3fdec912016-08-18 15:08:06 +0300770 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200771
772 // Nodes may be constant folded without being qualified as constant.
773 TQualifier resultQualifier = EvqConst;
774 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
775 {
776 resultQualifier = EvqTemporary;
777 }
778 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300779}
780
Olli Etuaho95310b02015-06-02 17:43:38 +0300781TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
782{
783 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
784 if (operandConstant == nullptr)
785 {
786 return nullptr;
787 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530788
789 TConstantUnion *constArray = nullptr;
790 switch (mOp)
791 {
792 case EOpAny:
793 case EOpAll:
794 case EOpLength:
795 case EOpTranspose:
796 case EOpDeterminant:
797 case EOpInverse:
798 case EOpPackSnorm2x16:
799 case EOpUnpackSnorm2x16:
800 case EOpPackUnorm2x16:
801 case EOpUnpackUnorm2x16:
802 case EOpPackHalf2x16:
803 case EOpUnpackHalf2x16:
804 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
805 break;
806 default:
807 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
808 break;
809 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200810
811 // Nodes may be constant folded without being qualified as constant.
812 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
813 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300814}
815
816TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
817{
818 // Make sure that all params are constant before actual constant folding.
819 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300820 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300821 if (param->getAsConstantUnion() == nullptr)
822 {
823 return nullptr;
824 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300825 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200826 TConstantUnion *constArray = nullptr;
827 if (isConstructor())
828 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
829 else
830 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200831
832 // Nodes may be constant folded without being qualified as constant.
833 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
834 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300835}
836
Jamie Madillb1a85f42014-08-19 15:23:24 -0400837//
838// The fold functions see if an operation on a constant can be done in place,
839// without generating run-time code.
840//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300841// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400842//
Olli Etuaho3fdec912016-08-18 15:08:06 +0300843TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
844 TIntermConstantUnion *rightNode,
845 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300846{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200847 const TConstantUnion *leftArray = getUnionArrayPointer();
848 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300849
850 if (!leftArray)
851 return nullptr;
852 if (!rightArray)
853 return nullptr;
854
855 size_t objectSize = getType().getObjectSize();
856
857 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
858 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
859 {
860 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
861 }
862 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
863 {
864 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
865 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
866 objectSize = rightNode->getType().getObjectSize();
867 }
868
869 TConstantUnion *resultArray = nullptr;
870
871 switch(op)
872 {
873 case EOpAdd:
874 resultArray = new TConstantUnion[objectSize];
875 for (size_t i = 0; i < objectSize; i++)
876 resultArray[i] = leftArray[i] + rightArray[i];
877 break;
878 case EOpSub:
879 resultArray = new TConstantUnion[objectSize];
880 for (size_t i = 0; i < objectSize; i++)
881 resultArray[i] = leftArray[i] - rightArray[i];
882 break;
883
884 case EOpMul:
885 case EOpVectorTimesScalar:
886 case EOpMatrixTimesScalar:
887 resultArray = new TConstantUnion[objectSize];
888 for (size_t i = 0; i < objectSize; i++)
889 resultArray[i] = leftArray[i] * rightArray[i];
890 break;
891
892 case EOpMatrixTimesMatrix:
893 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300894 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300895
896 const int leftCols = getCols();
897 const int leftRows = getRows();
898 const int rightCols = rightNode->getType().getCols();
899 const int rightRows = rightNode->getType().getRows();
900 const int resultCols = rightCols;
901 const int resultRows = leftRows;
902
903 resultArray = new TConstantUnion[resultCols * resultRows];
904 for (int row = 0; row < resultRows; row++)
905 {
906 for (int column = 0; column < resultCols; column++)
907 {
908 resultArray[resultRows * column + row].setFConst(0.0f);
909 for (int i = 0; i < leftCols; i++)
910 {
911 resultArray[resultRows * column + row].setFConst(
912 resultArray[resultRows * column + row].getFConst() +
913 leftArray[i * leftRows + row].getFConst() *
914 rightArray[column * rightRows + i].getFConst());
915 }
916 }
917 }
918 }
919 break;
920
921 case EOpDiv:
922 case EOpIMod:
923 {
924 resultArray = new TConstantUnion[objectSize];
925 for (size_t i = 0; i < objectSize; i++)
926 {
927 switch (getType().getBasicType())
928 {
929 case EbtFloat:
930 if (rightArray[i] == 0.0f)
931 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300932 diagnostics->warning(
933 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300934 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
935 }
936 else
937 {
938 ASSERT(op == EOpDiv);
939 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
940 }
941 break;
942
943 case EbtInt:
944 if (rightArray[i] == 0)
945 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300946 diagnostics->warning(
947 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300948 resultArray[i].setIConst(INT_MAX);
949 }
950 else
951 {
952 if (op == EOpDiv)
953 {
954 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
955 }
956 else
957 {
958 ASSERT(op == EOpIMod);
959 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
960 }
961 }
962 break;
963
964 case EbtUInt:
965 if (rightArray[i] == 0)
966 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300967 diagnostics->warning(
968 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300969 resultArray[i].setUConst(UINT_MAX);
970 }
971 else
972 {
973 if (op == EOpDiv)
974 {
975 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
976 }
977 else
978 {
979 ASSERT(op == EOpIMod);
980 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
981 }
982 }
983 break;
984
985 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +0300986 UNREACHABLE();
987 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300988 }
989 }
990 }
991 break;
992
993 case EOpMatrixTimesVector:
994 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300995 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300996
997 const int matrixCols = getCols();
998 const int matrixRows = getRows();
999
1000 resultArray = new TConstantUnion[matrixRows];
1001
1002 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1003 {
1004 resultArray[matrixRow].setFConst(0.0f);
1005 for (int col = 0; col < matrixCols; col++)
1006 {
1007 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1008 leftArray[col * matrixRows + matrixRow].getFConst() *
1009 rightArray[col].getFConst());
1010 }
1011 }
1012 }
1013 break;
1014
1015 case EOpVectorTimesMatrix:
1016 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001017 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001018
1019 const int matrixCols = rightNode->getType().getCols();
1020 const int matrixRows = rightNode->getType().getRows();
1021
1022 resultArray = new TConstantUnion[matrixCols];
1023
1024 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1025 {
1026 resultArray[matrixCol].setFConst(0.0f);
1027 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1028 {
1029 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1030 leftArray[matrixRow].getFConst() *
1031 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1032 }
1033 }
1034 }
1035 break;
1036
1037 case EOpLogicalAnd:
1038 {
1039 resultArray = new TConstantUnion[objectSize];
1040 for (size_t i = 0; i < objectSize; i++)
1041 {
1042 resultArray[i] = leftArray[i] && rightArray[i];
1043 }
1044 }
1045 break;
1046
1047 case EOpLogicalOr:
1048 {
1049 resultArray = new TConstantUnion[objectSize];
1050 for (size_t i = 0; i < objectSize; i++)
1051 {
1052 resultArray[i] = leftArray[i] || rightArray[i];
1053 }
1054 }
1055 break;
1056
1057 case EOpLogicalXor:
1058 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001059 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001060 resultArray = new TConstantUnion[objectSize];
1061 for (size_t i = 0; i < objectSize; i++)
1062 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001063 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001064 }
1065 }
1066 break;
1067
1068 case EOpBitwiseAnd:
1069 resultArray = new TConstantUnion[objectSize];
1070 for (size_t i = 0; i < objectSize; i++)
1071 resultArray[i] = leftArray[i] & rightArray[i];
1072 break;
1073 case EOpBitwiseXor:
1074 resultArray = new TConstantUnion[objectSize];
1075 for (size_t i = 0; i < objectSize; i++)
1076 resultArray[i] = leftArray[i] ^ rightArray[i];
1077 break;
1078 case EOpBitwiseOr:
1079 resultArray = new TConstantUnion[objectSize];
1080 for (size_t i = 0; i < objectSize; i++)
1081 resultArray[i] = leftArray[i] | rightArray[i];
1082 break;
1083 case EOpBitShiftLeft:
1084 resultArray = new TConstantUnion[objectSize];
1085 for (size_t i = 0; i < objectSize; i++)
1086 resultArray[i] = leftArray[i] << rightArray[i];
1087 break;
1088 case EOpBitShiftRight:
1089 resultArray = new TConstantUnion[objectSize];
1090 for (size_t i = 0; i < objectSize; i++)
1091 resultArray[i] = leftArray[i] >> rightArray[i];
1092 break;
1093
1094 case EOpLessThan:
1095 ASSERT(objectSize == 1);
1096 resultArray = new TConstantUnion[1];
1097 resultArray->setBConst(*leftArray < *rightArray);
1098 break;
1099
1100 case EOpGreaterThan:
1101 ASSERT(objectSize == 1);
1102 resultArray = new TConstantUnion[1];
1103 resultArray->setBConst(*leftArray > *rightArray);
1104 break;
1105
1106 case EOpLessThanEqual:
1107 ASSERT(objectSize == 1);
1108 resultArray = new TConstantUnion[1];
1109 resultArray->setBConst(!(*leftArray > *rightArray));
1110 break;
1111
1112 case EOpGreaterThanEqual:
1113 ASSERT(objectSize == 1);
1114 resultArray = new TConstantUnion[1];
1115 resultArray->setBConst(!(*leftArray < *rightArray));
1116 break;
1117
1118 case EOpEqual:
1119 case EOpNotEqual:
1120 {
1121 resultArray = new TConstantUnion[1];
1122 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001123 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001124 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001125 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001126 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001127 equal = false;
1128 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001129 }
1130 }
1131 if (op == EOpEqual)
1132 {
1133 resultArray->setBConst(equal);
1134 }
1135 else
1136 {
1137 resultArray->setBConst(!equal);
1138 }
1139 }
1140 break;
1141
1142 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001143 UNREACHABLE();
1144 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001145 }
1146 return resultArray;
1147}
1148
1149//
1150// The fold functions see if an operation on a constant can be done in place,
1151// without generating run-time code.
1152//
Olli Etuaho95310b02015-06-02 17:43:38 +03001153// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001154//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301155TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001156{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301157 //
1158 // Do operations where the return type has a different number of components compared to the operand type.
1159 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001160
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001161 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301162 if (!operandArray)
1163 return nullptr;
1164
1165 size_t objectSize = getType().getObjectSize();
1166 TConstantUnion *resultArray = nullptr;
1167 switch (op)
1168 {
1169 case EOpAny:
1170 if (getType().getBasicType() == EbtBool)
1171 {
1172 resultArray = new TConstantUnion();
1173 resultArray->setBConst(false);
1174 for (size_t i = 0; i < objectSize; i++)
1175 {
1176 if (operandArray[i].getBConst())
1177 {
1178 resultArray->setBConst(true);
1179 break;
1180 }
1181 }
1182 break;
1183 }
1184 else
1185 {
1186 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1187 return nullptr;
1188 }
1189
1190 case EOpAll:
1191 if (getType().getBasicType() == EbtBool)
1192 {
1193 resultArray = new TConstantUnion();
1194 resultArray->setBConst(true);
1195 for (size_t i = 0; i < objectSize; i++)
1196 {
1197 if (!operandArray[i].getBConst())
1198 {
1199 resultArray->setBConst(false);
1200 break;
1201 }
1202 }
1203 break;
1204 }
1205 else
1206 {
1207 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1208 return nullptr;
1209 }
1210
1211 case EOpLength:
1212 if (getType().getBasicType() == EbtFloat)
1213 {
1214 resultArray = new TConstantUnion();
1215 resultArray->setFConst(VectorLength(operandArray, objectSize));
1216 break;
1217 }
1218 else
1219 {
1220 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1221 return nullptr;
1222 }
1223
1224 case EOpTranspose:
1225 if (getType().getBasicType() == EbtFloat)
1226 {
1227 resultArray = new TConstantUnion[objectSize];
1228 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001229 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301230 SetUnionArrayFromMatrix(result, resultArray);
1231 break;
1232 }
1233 else
1234 {
1235 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1236 return nullptr;
1237 }
1238
1239 case EOpDeterminant:
1240 if (getType().getBasicType() == EbtFloat)
1241 {
1242 unsigned int size = getType().getNominalSize();
1243 ASSERT(size >= 2 && size <= 4);
1244 resultArray = new TConstantUnion();
1245 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1246 break;
1247 }
1248 else
1249 {
1250 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1251 return nullptr;
1252 }
1253
1254 case EOpInverse:
1255 if (getType().getBasicType() == EbtFloat)
1256 {
1257 unsigned int size = getType().getNominalSize();
1258 ASSERT(size >= 2 && size <= 4);
1259 resultArray = new TConstantUnion[objectSize];
1260 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1261 SetUnionArrayFromMatrix(result, resultArray);
1262 break;
1263 }
1264 else
1265 {
1266 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1267 return nullptr;
1268 }
1269
1270 case EOpPackSnorm2x16:
1271 if (getType().getBasicType() == EbtFloat)
1272 {
1273 ASSERT(getType().getNominalSize() == 2);
1274 resultArray = new TConstantUnion();
1275 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1276 break;
1277 }
1278 else
1279 {
1280 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1281 return nullptr;
1282 }
1283
1284 case EOpUnpackSnorm2x16:
1285 if (getType().getBasicType() == EbtUInt)
1286 {
1287 resultArray = new TConstantUnion[2];
1288 float f1, f2;
1289 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1290 resultArray[0].setFConst(f1);
1291 resultArray[1].setFConst(f2);
1292 break;
1293 }
1294 else
1295 {
1296 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1297 return nullptr;
1298 }
1299
1300 case EOpPackUnorm2x16:
1301 if (getType().getBasicType() == EbtFloat)
1302 {
1303 ASSERT(getType().getNominalSize() == 2);
1304 resultArray = new TConstantUnion();
1305 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1306 break;
1307 }
1308 else
1309 {
1310 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1311 return nullptr;
1312 }
1313
1314 case EOpUnpackUnorm2x16:
1315 if (getType().getBasicType() == EbtUInt)
1316 {
1317 resultArray = new TConstantUnion[2];
1318 float f1, f2;
1319 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1320 resultArray[0].setFConst(f1);
1321 resultArray[1].setFConst(f2);
1322 break;
1323 }
1324 else
1325 {
1326 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1327 return nullptr;
1328 }
1329
1330 case EOpPackHalf2x16:
1331 if (getType().getBasicType() == EbtFloat)
1332 {
1333 ASSERT(getType().getNominalSize() == 2);
1334 resultArray = new TConstantUnion();
1335 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1336 break;
1337 }
1338 else
1339 {
1340 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1341 return nullptr;
1342 }
1343
1344 case EOpUnpackHalf2x16:
1345 if (getType().getBasicType() == EbtUInt)
1346 {
1347 resultArray = new TConstantUnion[2];
1348 float f1, f2;
1349 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1350 resultArray[0].setFConst(f1);
1351 resultArray[1].setFConst(f2);
1352 break;
1353 }
1354 else
1355 {
1356 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1357 return nullptr;
1358 }
1359 break;
1360
1361 default:
1362 break;
1363 }
1364
1365 return resultArray;
1366}
1367
1368TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1369{
1370 //
1371 // Do unary operations where the return type is the same as operand type.
1372 //
1373
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001374 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001375 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301376 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001377
1378 size_t objectSize = getType().getObjectSize();
1379
Arun Patoleab2b9a22015-07-06 18:27:56 +05301380 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1381 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301382 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301383 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301384 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301385 case EOpNegative:
1386 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301387 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301388 case EbtFloat:
1389 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301390 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301391 case EbtInt:
1392 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301393 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301394 case EbtUInt:
1395 resultArray[i].setUConst(static_cast<unsigned int>(
1396 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301397 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301398 default:
1399 infoSink.info.message(
1400 EPrefixInternalError, getLine(),
1401 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301402 return nullptr;
1403 }
1404 break;
1405
Arun Patoleab2b9a22015-07-06 18:27:56 +05301406 case EOpPositive:
1407 switch (getType().getBasicType())
1408 {
1409 case EbtFloat:
1410 resultArray[i].setFConst(operandArray[i].getFConst());
1411 break;
1412 case EbtInt:
1413 resultArray[i].setIConst(operandArray[i].getIConst());
1414 break;
1415 case EbtUInt:
1416 resultArray[i].setUConst(static_cast<unsigned int>(
1417 static_cast<int>(operandArray[i].getUConst())));
1418 break;
1419 default:
1420 infoSink.info.message(
1421 EPrefixInternalError, getLine(),
1422 "Unary operation not folded into constant");
1423 return nullptr;
1424 }
1425 break;
1426
1427 case EOpLogicalNot:
1428 // this code is written for possible future use,
1429 // will not get executed currently
1430 switch (getType().getBasicType())
1431 {
1432 case EbtBool:
1433 resultArray[i].setBConst(!operandArray[i].getBConst());
1434 break;
1435 default:
1436 infoSink.info.message(
1437 EPrefixInternalError, getLine(),
1438 "Unary operation not folded into constant");
1439 return nullptr;
1440 }
1441 break;
1442
1443 case EOpBitwiseNot:
1444 switch (getType().getBasicType())
1445 {
1446 case EbtInt:
1447 resultArray[i].setIConst(~operandArray[i].getIConst());
1448 break;
1449 case EbtUInt:
1450 resultArray[i].setUConst(~operandArray[i].getUConst());
1451 break;
1452 default:
1453 infoSink.info.message(
1454 EPrefixInternalError, getLine(),
1455 "Unary operation not folded into constant");
1456 return nullptr;
1457 }
1458 break;
1459
1460 case EOpRadians:
1461 if (getType().getBasicType() == EbtFloat)
1462 {
1463 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1464 break;
1465 }
1466 infoSink.info.message(
1467 EPrefixInternalError, getLine(),
1468 "Unary operation not folded into constant");
1469 return nullptr;
1470
1471 case EOpDegrees:
1472 if (getType().getBasicType() == EbtFloat)
1473 {
1474 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1475 break;
1476 }
1477 infoSink.info.message(
1478 EPrefixInternalError, getLine(),
1479 "Unary operation not folded into constant");
1480 return nullptr;
1481
1482 case EOpSin:
1483 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1484 return nullptr;
1485 break;
1486
1487 case EOpCos:
1488 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1489 return nullptr;
1490 break;
1491
1492 case EOpTan:
1493 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1494 return nullptr;
1495 break;
1496
1497 case EOpAsin:
1498 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1499 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1500 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1501 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1502 return nullptr;
1503 break;
1504
1505 case EOpAcos:
1506 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1507 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1508 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1509 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1510 return nullptr;
1511 break;
1512
1513 case EOpAtan:
1514 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1515 return nullptr;
1516 break;
1517
1518 case EOpSinh:
1519 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1520 return nullptr;
1521 break;
1522
1523 case EOpCosh:
1524 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1525 return nullptr;
1526 break;
1527
1528 case EOpTanh:
1529 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1530 return nullptr;
1531 break;
1532
1533 case EOpAsinh:
1534 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1535 return nullptr;
1536 break;
1537
1538 case EOpAcosh:
1539 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1540 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1541 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1542 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1543 return nullptr;
1544 break;
1545
1546 case EOpAtanh:
1547 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1548 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1549 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1550 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1551 return nullptr;
1552 break;
1553
1554 case EOpAbs:
1555 switch (getType().getBasicType())
1556 {
1557 case EbtFloat:
1558 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1559 break;
1560 case EbtInt:
1561 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1562 break;
1563 default:
1564 infoSink.info.message(
1565 EPrefixInternalError, getLine(),
1566 "Unary operation not folded into constant");
1567 return nullptr;
1568 }
1569 break;
1570
1571 case EOpSign:
1572 switch (getType().getBasicType())
1573 {
1574 case EbtFloat:
1575 {
1576 float fConst = operandArray[i].getFConst();
1577 float fResult = 0.0f;
1578 if (fConst > 0.0f)
1579 fResult = 1.0f;
1580 else if (fConst < 0.0f)
1581 fResult = -1.0f;
1582 resultArray[i].setFConst(fResult);
1583 }
1584 break;
1585 case EbtInt:
1586 {
1587 int iConst = operandArray[i].getIConst();
1588 int iResult = 0;
1589 if (iConst > 0)
1590 iResult = 1;
1591 else if (iConst < 0)
1592 iResult = -1;
1593 resultArray[i].setIConst(iResult);
1594 }
1595 break;
1596 default:
1597 infoSink.info.message(
1598 EPrefixInternalError, getLine(),
1599 "Unary operation not folded into constant");
1600 return nullptr;
1601 }
1602 break;
1603
1604 case EOpFloor:
1605 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1606 return nullptr;
1607 break;
1608
1609 case EOpTrunc:
1610 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1611 return nullptr;
1612 break;
1613
1614 case EOpRound:
1615 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1616 return nullptr;
1617 break;
1618
1619 case EOpRoundEven:
1620 if (getType().getBasicType() == EbtFloat)
1621 {
1622 float x = operandArray[i].getFConst();
1623 float result;
1624 float fractPart = modff(x, &result);
1625 if (fabsf(fractPart) == 0.5f)
1626 result = 2.0f * roundf(x / 2.0f);
1627 else
1628 result = roundf(x);
1629 resultArray[i].setFConst(result);
1630 break;
1631 }
1632 infoSink.info.message(
1633 EPrefixInternalError, getLine(),
1634 "Unary operation not folded into constant");
1635 return nullptr;
1636
1637 case EOpCeil:
1638 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1639 return nullptr;
1640 break;
1641
1642 case EOpFract:
1643 if (getType().getBasicType() == EbtFloat)
1644 {
1645 float x = operandArray[i].getFConst();
1646 resultArray[i].setFConst(x - floorf(x));
1647 break;
1648 }
1649 infoSink.info.message(
1650 EPrefixInternalError, getLine(),
1651 "Unary operation not folded into constant");
1652 return nullptr;
1653
Arun Patole551279e2015-07-07 18:18:23 +05301654 case EOpIsNan:
1655 if (getType().getBasicType() == EbtFloat)
1656 {
1657 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1658 break;
1659 }
1660 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1661 return nullptr;
1662
1663 case EOpIsInf:
1664 if (getType().getBasicType() == EbtFloat)
1665 {
1666 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1667 break;
1668 }
1669 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1670 return nullptr;
1671
1672 case EOpFloatBitsToInt:
1673 if (getType().getBasicType() == EbtFloat)
1674 {
1675 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1676 break;
1677 }
1678 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1679 return nullptr;
1680
1681 case EOpFloatBitsToUint:
1682 if (getType().getBasicType() == EbtFloat)
1683 {
1684 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1685 break;
1686 }
1687 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1688 return nullptr;
1689
1690 case EOpIntBitsToFloat:
1691 if (getType().getBasicType() == EbtInt)
1692 {
1693 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1694 break;
1695 }
1696 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1697 return nullptr;
1698
1699 case EOpUintBitsToFloat:
1700 if (getType().getBasicType() == EbtUInt)
1701 {
1702 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1703 break;
1704 }
1705 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1706 return nullptr;
1707
Arun Patoleab2b9a22015-07-06 18:27:56 +05301708 case EOpExp:
1709 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1710 return nullptr;
1711 break;
1712
1713 case EOpLog:
1714 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1715 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1716 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1717 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1718 return nullptr;
1719 break;
1720
1721 case EOpExp2:
1722 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1723 return nullptr;
1724 break;
1725
1726 case EOpLog2:
1727 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1728 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1729 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1730 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1731 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1732 return nullptr;
1733 else
1734 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1735 break;
1736
1737 case EOpSqrt:
1738 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1739 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1740 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1741 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1742 return nullptr;
1743 break;
1744
1745 case EOpInverseSqrt:
1746 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1747 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1748 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1749 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1750 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1751 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1752 return nullptr;
1753 else
1754 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1755 break;
1756
1757 case EOpVectorLogicalNot:
1758 if (getType().getBasicType() == EbtBool)
1759 {
1760 resultArray[i].setBConst(!operandArray[i].getBConst());
1761 break;
1762 }
1763 infoSink.info.message(
1764 EPrefixInternalError, getLine(),
1765 "Unary operation not folded into constant");
1766 return nullptr;
1767
1768 case EOpNormalize:
1769 if (getType().getBasicType() == EbtFloat)
1770 {
1771 float x = operandArray[i].getFConst();
1772 float length = VectorLength(operandArray, objectSize);
1773 if (length)
1774 resultArray[i].setFConst(x / length);
1775 else
1776 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1777 &resultArray[i]);
1778 break;
1779 }
1780 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1781 return nullptr;
1782
Arun Patole0c5409f2015-07-08 15:17:53 +05301783 case EOpDFdx:
1784 case EOpDFdy:
1785 case EOpFwidth:
1786 if (getType().getBasicType() == EbtFloat)
1787 {
1788 // Derivatives of constant arguments should be 0.
1789 resultArray[i].setFConst(0.0f);
1790 break;
1791 }
1792 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1793 return nullptr;
1794
Arun Patole1155ddd2015-06-05 18:04:36 +05301795 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301796 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301797 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301798 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001799
Arun Patoleab2b9a22015-07-06 18:27:56 +05301800 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001801}
1802
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001803bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1804 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301805{
1806 ASSERT(builtinFunc);
1807
1808 if (getType().getBasicType() == EbtFloat)
1809 {
1810 result->setFConst(builtinFunc(parameter.getFConst()));
1811 return true;
1812 }
1813
1814 infoSink.info.message(
1815 EPrefixInternalError, getLine(),
1816 "Unary operation not folded into constant");
1817 return false;
1818}
1819
Jamie Madillb1a85f42014-08-19 15:23:24 -04001820// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001821TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1822 TInfoSink &infoSink)
1823{
1824 ASSERT(aggregate->getSequence()->size() > 0u);
1825 size_t resultSize = aggregate->getType().getObjectSize();
1826 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1827 TBasicType basicType = aggregate->getBasicType();
1828
1829 size_t resultIndex = 0u;
1830
1831 if (aggregate->getSequence()->size() == 1u)
1832 {
1833 TIntermNode *argument = aggregate->getSequence()->front();
1834 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1835 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1836 // Check the special case of constructing a matrix diagonal from a single scalar,
1837 // or a vector from a single scalar.
1838 if (argumentConstant->getType().getObjectSize() == 1u)
1839 {
1840 if (aggregate->isMatrix())
1841 {
1842 int resultCols = aggregate->getType().getCols();
1843 int resultRows = aggregate->getType().getRows();
1844 for (int col = 0; col < resultCols; ++col)
1845 {
1846 for (int row = 0; row < resultRows; ++row)
1847 {
1848 if (col == row)
1849 {
1850 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1851 }
1852 else
1853 {
1854 resultArray[resultIndex].setFConst(0.0f);
1855 }
1856 ++resultIndex;
1857 }
1858 }
1859 }
1860 else
1861 {
1862 while (resultIndex < resultSize)
1863 {
1864 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1865 ++resultIndex;
1866 }
1867 }
1868 ASSERT(resultIndex == resultSize);
1869 return resultArray;
1870 }
1871 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1872 {
1873 // The special case of constructing a matrix from a matrix.
1874 int argumentCols = argumentConstant->getType().getCols();
1875 int argumentRows = argumentConstant->getType().getRows();
1876 int resultCols = aggregate->getType().getCols();
1877 int resultRows = aggregate->getType().getRows();
1878 for (int col = 0; col < resultCols; ++col)
1879 {
1880 for (int row = 0; row < resultRows; ++row)
1881 {
1882 if (col < argumentCols && row < argumentRows)
1883 {
1884 resultArray[resultIndex].cast(basicType,
1885 argumentUnionArray[col * argumentRows + row]);
1886 }
1887 else if (col == row)
1888 {
1889 resultArray[resultIndex].setFConst(1.0f);
1890 }
1891 else
1892 {
1893 resultArray[resultIndex].setFConst(0.0f);
1894 }
1895 ++resultIndex;
1896 }
1897 }
1898 ASSERT(resultIndex == resultSize);
1899 return resultArray;
1900 }
1901 }
1902
1903 for (TIntermNode *&argument : *aggregate->getSequence())
1904 {
1905 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1906 size_t argumentSize = argumentConstant->getType().getObjectSize();
1907 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1908 for (size_t i = 0u; i < argumentSize; ++i)
1909 {
1910 if (resultIndex >= resultSize)
1911 break;
1912 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1913 ++resultIndex;
1914 }
1915 }
1916 ASSERT(resultIndex == resultSize);
1917 return resultArray;
1918}
1919
1920// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001921TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301922{
Olli Etuahob43846e2015-06-02 18:18:57 +03001923 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301924 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001925 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001926 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05301927 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001928 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301929 TBasicType basicType = EbtVoid;
1930 TSourceLoc loc;
1931 for (unsigned int i = 0; i < paramsCount; i++)
1932 {
1933 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001934 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301935
1936 if (i == 0)
1937 {
1938 basicType = paramConstant->getType().getBasicType();
1939 loc = paramConstant->getLine();
1940 }
1941 unionArrays[i] = paramConstant->getUnionArrayPointer();
1942 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001943 if (objectSizes[i] > maxObjectSize)
1944 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301945 }
1946
Olli Etuahod5da5052016-08-29 13:16:55 +03001947 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05301948 {
1949 for (unsigned int i = 0; i < paramsCount; i++)
1950 if (objectSizes[i] != maxObjectSize)
1951 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1952 }
Arun Patole274f0702015-05-05 13:33:30 +05301953
Olli Etuahob43846e2015-06-02 18:18:57 +03001954 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301955 if (paramsCount == 2)
1956 {
1957 //
1958 // Binary built-in
1959 //
1960 switch (op)
1961 {
Arun Patolebf790422015-05-18 17:53:04 +05301962 case EOpAtan:
1963 {
1964 if (basicType == EbtFloat)
1965 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001966 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301967 for (size_t i = 0; i < maxObjectSize; i++)
1968 {
1969 float y = unionArrays[0][i].getFConst();
1970 float x = unionArrays[1][i].getFConst();
1971 // Results are undefined if x and y are both 0.
1972 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001973 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301974 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001975 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301976 }
1977 }
1978 else
1979 UNREACHABLE();
1980 }
1981 break;
1982
1983 case EOpPow:
1984 {
1985 if (basicType == EbtFloat)
1986 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001987 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301988 for (size_t i = 0; i < maxObjectSize; i++)
1989 {
1990 float x = unionArrays[0][i].getFConst();
1991 float y = unionArrays[1][i].getFConst();
1992 // Results are undefined if x < 0.
1993 // Results are undefined if x = 0 and y <= 0.
1994 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001995 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301996 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001997 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301998 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001999 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302000 }
2001 }
2002 else
2003 UNREACHABLE();
2004 }
2005 break;
2006
2007 case EOpMod:
2008 {
2009 if (basicType == EbtFloat)
2010 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002011 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302012 for (size_t i = 0; i < maxObjectSize; i++)
2013 {
2014 float x = unionArrays[0][i].getFConst();
2015 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002016 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302017 }
2018 }
2019 else
2020 UNREACHABLE();
2021 }
2022 break;
2023
Arun Patole274f0702015-05-05 13:33:30 +05302024 case EOpMin:
2025 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002026 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302027 for (size_t i = 0; i < maxObjectSize; i++)
2028 {
2029 switch (basicType)
2030 {
2031 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002032 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302033 break;
2034 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002035 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302036 break;
2037 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002038 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302039 break;
2040 default:
2041 UNREACHABLE();
2042 break;
2043 }
2044 }
2045 }
2046 break;
2047
2048 case EOpMax:
2049 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002050 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302051 for (size_t i = 0; i < maxObjectSize; i++)
2052 {
2053 switch (basicType)
2054 {
2055 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002056 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302057 break;
2058 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002059 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302060 break;
2061 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002062 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302063 break;
2064 default:
2065 UNREACHABLE();
2066 break;
2067 }
2068 }
2069 }
2070 break;
2071
Arun Patolebf790422015-05-18 17:53:04 +05302072 case EOpStep:
2073 {
2074 if (basicType == EbtFloat)
2075 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002076 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302077 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002078 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302079 }
2080 else
2081 UNREACHABLE();
2082 }
2083 break;
2084
Arun Patole9d0b1f92015-05-20 14:27:17 +05302085 case EOpLessThan:
2086 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002087 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302088 for (size_t i = 0; i < maxObjectSize; i++)
2089 {
2090 switch (basicType)
2091 {
2092 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002093 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302094 break;
2095 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002096 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302097 break;
2098 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002099 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302100 break;
2101 default:
2102 UNREACHABLE();
2103 break;
2104 }
2105 }
2106 }
2107 break;
2108
2109 case EOpLessThanEqual:
2110 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002111 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302112 for (size_t i = 0; i < maxObjectSize; i++)
2113 {
2114 switch (basicType)
2115 {
2116 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002117 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302118 break;
2119 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002120 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302121 break;
2122 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002123 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302124 break;
2125 default:
2126 UNREACHABLE();
2127 break;
2128 }
2129 }
2130 }
2131 break;
2132
2133 case EOpGreaterThan:
2134 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002135 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302136 for (size_t i = 0; i < maxObjectSize; i++)
2137 {
2138 switch (basicType)
2139 {
2140 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002141 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302142 break;
2143 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002144 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302145 break;
2146 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002147 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302148 break;
2149 default:
2150 UNREACHABLE();
2151 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002152 }
2153 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302154 }
2155 break;
2156
2157 case EOpGreaterThanEqual:
2158 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002159 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302160 for (size_t i = 0; i < maxObjectSize; i++)
2161 {
2162 switch (basicType)
2163 {
2164 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002165 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302166 break;
2167 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002168 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302169 break;
2170 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002171 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302172 break;
2173 default:
2174 UNREACHABLE();
2175 break;
2176 }
2177 }
2178 }
2179 break;
2180
2181 case EOpVectorEqual:
2182 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002183 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302184 for (size_t i = 0; i < maxObjectSize; i++)
2185 {
2186 switch (basicType)
2187 {
2188 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002189 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302190 break;
2191 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002192 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302193 break;
2194 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002195 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302196 break;
2197 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002198 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302199 break;
2200 default:
2201 UNREACHABLE();
2202 break;
2203 }
2204 }
2205 }
2206 break;
2207
2208 case EOpVectorNotEqual:
2209 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002210 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302211 for (size_t i = 0; i < maxObjectSize; i++)
2212 {
2213 switch (basicType)
2214 {
2215 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002216 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302217 break;
2218 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002219 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302220 break;
2221 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002222 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302223 break;
2224 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002225 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302226 break;
2227 default:
2228 UNREACHABLE();
2229 break;
2230 }
2231 }
2232 }
2233 break;
2234
Arun Patole1155ddd2015-06-05 18:04:36 +05302235 case EOpDistance:
2236 if (basicType == EbtFloat)
2237 {
2238 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002239 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302240 for (size_t i = 0; i < maxObjectSize; i++)
2241 {
2242 float x = unionArrays[0][i].getFConst();
2243 float y = unionArrays[1][i].getFConst();
2244 distanceArray[i].setFConst(x - y);
2245 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002246 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302247 }
2248 else
2249 UNREACHABLE();
2250 break;
2251
2252 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002253
Arun Patole1155ddd2015-06-05 18:04:36 +05302254 if (basicType == EbtFloat)
2255 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002256 resultArray = new TConstantUnion();
2257 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302258 }
2259 else
2260 UNREACHABLE();
2261 break;
2262
2263 case EOpCross:
2264 if (basicType == EbtFloat && maxObjectSize == 3)
2265 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002266 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302267 float x0 = unionArrays[0][0].getFConst();
2268 float x1 = unionArrays[0][1].getFConst();
2269 float x2 = unionArrays[0][2].getFConst();
2270 float y0 = unionArrays[1][0].getFConst();
2271 float y1 = unionArrays[1][1].getFConst();
2272 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002273 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2274 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2275 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302276 }
2277 else
2278 UNREACHABLE();
2279 break;
2280
2281 case EOpReflect:
2282 if (basicType == EbtFloat)
2283 {
2284 // genType reflect (genType I, genType N) :
2285 // For the incident vector I and surface orientation N, returns the reflection direction:
2286 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002287 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302288 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2289 for (size_t i = 0; i < maxObjectSize; i++)
2290 {
2291 float result = unionArrays[0][i].getFConst() -
2292 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002293 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302294 }
2295 }
2296 else
2297 UNREACHABLE();
2298 break;
2299
Arun Patole7fa33552015-06-10 15:15:18 +05302300 case EOpMul:
2301 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2302 (*sequence)[1]->getAsTyped()->isMatrix())
2303 {
2304 // Perform component-wise matrix multiplication.
2305 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002306 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302307 angle::Matrix<float> result =
2308 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2309 SetUnionArrayFromMatrix(result, resultArray);
2310 }
2311 else
2312 UNREACHABLE();
2313 break;
2314
2315 case EOpOuterProduct:
2316 if (basicType == EbtFloat)
2317 {
2318 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2319 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2320 resultArray = new TConstantUnion[numRows * numCols];
2321 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002322 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2323 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302324 SetUnionArrayFromMatrix(result, resultArray);
2325 }
2326 else
2327 UNREACHABLE();
2328 break;
2329
Arun Patole274f0702015-05-05 13:33:30 +05302330 default:
2331 UNREACHABLE();
2332 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2333 return nullptr;
2334 }
2335 }
2336 else if (paramsCount == 3)
2337 {
2338 //
2339 // Ternary built-in
2340 //
2341 switch (op)
2342 {
2343 case EOpClamp:
2344 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002345 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302346 for (size_t i = 0; i < maxObjectSize; i++)
2347 {
2348 switch (basicType)
2349 {
2350 case EbtFloat:
2351 {
2352 float x = unionArrays[0][i].getFConst();
2353 float min = unionArrays[1][i].getFConst();
2354 float max = unionArrays[2][i].getFConst();
2355 // Results are undefined if min > max.
2356 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002357 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302358 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002359 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302360 }
2361 break;
2362 case EbtInt:
2363 {
2364 int x = unionArrays[0][i].getIConst();
2365 int min = unionArrays[1][i].getIConst();
2366 int max = unionArrays[2][i].getIConst();
2367 // Results are undefined if min > max.
2368 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002369 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302370 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002371 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302372 }
2373 break;
2374 case EbtUInt:
2375 {
2376 unsigned int x = unionArrays[0][i].getUConst();
2377 unsigned int min = unionArrays[1][i].getUConst();
2378 unsigned int max = unionArrays[2][i].getUConst();
2379 // Results are undefined if min > max.
2380 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002381 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302382 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002383 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302384 }
2385 break;
2386 default:
2387 UNREACHABLE();
2388 break;
2389 }
2390 }
2391 }
2392 break;
2393
Arun Patolebf790422015-05-18 17:53:04 +05302394 case EOpMix:
2395 {
2396 if (basicType == EbtFloat)
2397 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002398 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302399 for (size_t i = 0; i < maxObjectSize; i++)
2400 {
2401 float x = unionArrays[0][i].getFConst();
2402 float y = unionArrays[1][i].getFConst();
2403 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2404 if (type == EbtFloat)
2405 {
2406 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2407 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002408 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302409 }
2410 else // 3rd parameter is EbtBool
2411 {
2412 ASSERT(type == EbtBool);
2413 // Selects which vector each returned component comes from.
2414 // For a component of a that is false, the corresponding component of x is returned.
2415 // For a component of a that is true, the corresponding component of y is returned.
2416 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002417 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302418 }
2419 }
2420 }
2421 else
2422 UNREACHABLE();
2423 }
2424 break;
2425
2426 case EOpSmoothStep:
2427 {
2428 if (basicType == EbtFloat)
2429 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002430 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302431 for (size_t i = 0; i < maxObjectSize; i++)
2432 {
2433 float edge0 = unionArrays[0][i].getFConst();
2434 float edge1 = unionArrays[1][i].getFConst();
2435 float x = unionArrays[2][i].getFConst();
2436 // Results are undefined if edge0 >= edge1.
2437 if (edge0 >= edge1)
2438 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002439 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302440 }
2441 else
2442 {
2443 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2444 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2445 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002446 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302447 }
2448 }
2449 }
2450 else
2451 UNREACHABLE();
2452 }
2453 break;
2454
Arun Patole1155ddd2015-06-05 18:04:36 +05302455 case EOpFaceForward:
2456 if (basicType == EbtFloat)
2457 {
2458 // genType faceforward(genType N, genType I, genType Nref) :
2459 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002460 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302461 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2462 for (size_t i = 0; i < maxObjectSize; i++)
2463 {
2464 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002465 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302466 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002467 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302468 }
2469 }
2470 else
2471 UNREACHABLE();
2472 break;
2473
2474 case EOpRefract:
2475 if (basicType == EbtFloat)
2476 {
2477 // genType refract(genType I, genType N, float eta) :
2478 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2479 // return the refraction vector. The result is computed by
2480 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2481 // if (k < 0.0)
2482 // return genType(0.0)
2483 // else
2484 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002485 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302486 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2487 for (size_t i = 0; i < maxObjectSize; i++)
2488 {
2489 float eta = unionArrays[2][i].getFConst();
2490 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2491 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002492 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302493 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002494 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302495 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2496 }
2497 }
2498 else
2499 UNREACHABLE();
2500 break;
2501
Arun Patole274f0702015-05-05 13:33:30 +05302502 default:
2503 UNREACHABLE();
2504 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2505 return nullptr;
2506 }
2507 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002508 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302509}
2510
2511// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002512TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2513{
2514 if (hashFunction == NULL || name.empty())
2515 return name;
2516 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2517 TStringStream stream;
2518 stream << HASHED_NAME_PREFIX << std::hex << number;
2519 TString hashedName = stream.str();
2520 return hashedName;
2521}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002522
2523void TIntermTraverser::updateTree()
2524{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002525 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2526 {
2527 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2528 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002529 if (!insertion.insertionsAfter.empty())
2530 {
2531 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2532 insertion.insertionsAfter);
2533 ASSERT(inserted);
2534 UNUSED_ASSERTION_VARIABLE(inserted);
2535 }
2536 if (!insertion.insertionsBefore.empty())
2537 {
2538 bool inserted =
2539 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2540 ASSERT(inserted);
2541 UNUSED_ASSERTION_VARIABLE(inserted);
2542 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002543 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002544 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2545 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002546 const NodeUpdateEntry &replacement = mReplacements[ii];
2547 ASSERT(replacement.parent);
2548 bool replaced = replacement.parent->replaceChildNode(
2549 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002550 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002551 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002552
Olli Etuahocd94ef92015-04-16 19:18:10 +03002553 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002554 {
2555 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002556 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002557 // be replaced, we need to make sure we don't update the replaced
2558 // node; instead, we update the replacement node.
2559 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2560 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002561 NodeUpdateEntry &replacement2 = mReplacements[jj];
2562 if (replacement2.parent == replacement.original)
2563 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002564 }
2565 }
2566 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002567 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2568 {
2569 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2570 ASSERT(replacement.parent);
2571 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2572 replacement.original, replacement.replacements);
2573 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002574 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002575 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002576
Jamie Madill03d863c2016-07-27 18:15:53 -04002577 clearReplacementQueue();
2578}
2579
2580void TIntermTraverser::clearReplacementQueue()
2581{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002582 mReplacements.clear();
2583 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002584 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002585}
Jamie Madill1048e432016-07-23 18:51:28 -04002586
Jamie Madill03d863c2016-07-27 18:15:53 -04002587void TIntermTraverser::queueReplacement(TIntermNode *original,
2588 TIntermNode *replacement,
2589 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002590{
Jamie Madill03d863c2016-07-27 18:15:53 -04002591 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002592}
2593
Jamie Madill03d863c2016-07-27 18:15:53 -04002594void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2595 TIntermNode *original,
2596 TIntermNode *replacement,
2597 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002598{
Jamie Madill03d863c2016-07-27 18:15:53 -04002599 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2600 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002601}