blob: 2cd5deef00ea4fc9fd1838a6afd90efe4a8ca16b [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,
116 // whereas the paramArray is in column-major order.
117 return angle::Matrix<float>(elements, rows, cols).transpose();
118}
119
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200120angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530121{
122 std::vector<float> elements;
123 for (size_t i = 0; i < size * size; i++)
124 elements.push_back(paramArray[i].getFConst());
125 // Transpose is used since the Matrix constructor expects arguments in row-major order,
126 // whereas the paramArray is in column-major order.
127 return angle::Matrix<float>(elements, size).transpose();
128}
129
130void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
131{
132 // Transpose is used since the input Matrix is in row-major order,
133 // whereas the actual result should be in column-major order.
134 angle::Matrix<float> result = m.transpose();
135 std::vector<float> resultElements = result.elements();
136 for (size_t i = 0; i < resultElements.size(); i++)
137 resultArray[i].setFConst(resultElements[i]);
138}
139
Jamie Madillb1a85f42014-08-19 15:23:24 -0400140} // namespace anonymous
141
142
143////////////////////////////////////////////////////////////////
144//
145// Member functions of the nodes used for building the tree.
146//
147////////////////////////////////////////////////////////////////
148
Olli Etuahod2a67b92014-10-21 16:42:57 +0300149void TIntermTyped::setTypePreservePrecision(const TType &t)
150{
151 TPrecision precision = getPrecision();
152 mType = t;
153 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
154 mType.setPrecision(precision);
155}
156
Jamie Madillb1a85f42014-08-19 15:23:24 -0400157#define REPLACE_IF_IS(node, type, original, replacement) \
158 if (node == original) { \
159 node = static_cast<type *>(replacement); \
160 return true; \
161 }
162
163bool TIntermLoop::replaceChildNode(
164 TIntermNode *original, TIntermNode *replacement)
165{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300166 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
168 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
169 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200170 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400171 return false;
172}
173
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174bool TIntermBranch::replaceChildNode(
175 TIntermNode *original, TIntermNode *replacement)
176{
177 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
178 return false;
179}
180
Jamie Madillb1a85f42014-08-19 15:23:24 -0400181bool TIntermBinary::replaceChildNode(
182 TIntermNode *original, TIntermNode *replacement)
183{
184 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
185 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
186 return false;
187}
188
Jamie Madillb1a85f42014-08-19 15:23:24 -0400189bool TIntermUnary::replaceChildNode(
190 TIntermNode *original, TIntermNode *replacement)
191{
192 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
193 return false;
194}
195
Jamie Madillb1a85f42014-08-19 15:23:24 -0400196bool TIntermAggregate::replaceChildNode(
197 TIntermNode *original, TIntermNode *replacement)
198{
199 for (size_t ii = 0; ii < mSequence.size(); ++ii)
200 {
201 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
202 }
203 return false;
204}
205
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300206bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
207{
208 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
209 {
210 if (*it == original)
211 {
212 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300213 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300214 return true;
215 }
216 }
217 return false;
218}
219
Olli Etuahoa6f22092015-05-08 18:31:10 +0300220bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
221{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300222 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300223 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300224 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300225 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300226 auto it = mSequence.begin() + position;
227 mSequence.insert(it, insertions.begin(), insertions.end());
228 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300229}
230
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200231bool TIntermAggregate::areChildrenConstQualified()
232{
233 for (TIntermNode *&child : mSequence)
234 {
235 TIntermTyped *typed = child->getAsTyped();
236 if (typed && typed->getQualifier() != EvqConst)
237 {
238 return false;
239 }
240 }
241 return true;
242}
243
Olli Etuahod2a67b92014-10-21 16:42:57 +0300244void TIntermAggregate::setPrecisionFromChildren()
245{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300246 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300247 if (getBasicType() == EbtBool)
248 {
249 mType.setPrecision(EbpUndefined);
250 return;
251 }
252
253 TPrecision precision = EbpUndefined;
254 TIntermSequence::iterator childIter = mSequence.begin();
255 while (childIter != mSequence.end())
256 {
257 TIntermTyped *typed = (*childIter)->getAsTyped();
258 if (typed)
259 precision = GetHigherPrecision(typed->getPrecision(), precision);
260 ++childIter;
261 }
262 mType.setPrecision(precision);
263}
264
265void TIntermAggregate::setBuiltInFunctionPrecision()
266{
267 // All built-ins returning bool should be handled as ops, not functions.
268 ASSERT(getBasicType() != EbtBool);
269
270 TPrecision precision = EbpUndefined;
271 TIntermSequence::iterator childIter = mSequence.begin();
272 while (childIter != mSequence.end())
273 {
274 TIntermTyped *typed = (*childIter)->getAsTyped();
275 // ESSL spec section 8: texture functions get their precision from the sampler.
276 if (typed && IsSampler(typed->getBasicType()))
277 {
278 precision = typed->getPrecision();
279 break;
280 }
281 ++childIter;
282 }
283 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
284 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300285 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300286 mType.setPrecision(EbpHigh);
287 else
288 mType.setPrecision(precision);
289}
290
Jamie Madillb1a85f42014-08-19 15:23:24 -0400291bool TIntermSelection::replaceChildNode(
292 TIntermNode *original, TIntermNode *replacement)
293{
294 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
295 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
296 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
297 return false;
298}
299
Olli Etuahoa3a36662015-02-17 13:46:51 +0200300bool TIntermSwitch::replaceChildNode(
301 TIntermNode *original, TIntermNode *replacement)
302{
303 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
304 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
305 return false;
306}
307
308bool TIntermCase::replaceChildNode(
309 TIntermNode *original, TIntermNode *replacement)
310{
311 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
312 return false;
313}
314
Olli Etuahod7a25242015-08-18 13:49:45 +0300315TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
316{
317 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
318 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
319 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
320 mLine = node.mLine;
321}
322
Olli Etuahod4f4c112016-04-15 15:11:24 +0300323bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
324{
325 TIntermAggregate *constructor = getAsAggregate();
326 if (!constructor || !constructor->isConstructor())
327 {
328 return false;
329 }
330 for (TIntermNode *&node : *constructor->getSequence())
331 {
332 if (!node->getAsConstantUnion())
333 return false;
334 }
335 return true;
336}
337
Olli Etuahod7a25242015-08-18 13:49:45 +0300338TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
339{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200340 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300341}
342
343TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
344 : TIntermOperator(node),
345 mName(node.mName),
346 mUserDefined(node.mUserDefined),
347 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300348 mUseEmulatedFunction(node.mUseEmulatedFunction),
349 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
350{
351 for (TIntermNode *child : node.mSequence)
352 {
353 TIntermTyped *typedChild = child->getAsTyped();
354 ASSERT(typedChild != nullptr);
355 TIntermTyped *childCopy = typedChild->deepCopy();
356 mSequence.push_back(childCopy);
357 }
358}
359
360TIntermBinary::TIntermBinary(const TIntermBinary &node)
361 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
362{
363 TIntermTyped *leftCopy = node.mLeft->deepCopy();
364 TIntermTyped *rightCopy = node.mRight->deepCopy();
365 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
366 mLeft = leftCopy;
367 mRight = rightCopy;
368}
369
370TIntermUnary::TIntermUnary(const TIntermUnary &node)
371 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
372{
373 TIntermTyped *operandCopy = node.mOperand->deepCopy();
374 ASSERT(operandCopy != nullptr);
375 mOperand = operandCopy;
376}
377
378TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
379{
380 // Only supported for ternary nodes, not if statements.
381 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
382 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
383 ASSERT(trueTyped != nullptr);
384 ASSERT(falseTyped != nullptr);
385 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
386 TIntermTyped *trueCopy = trueTyped->deepCopy();
387 TIntermTyped *falseCopy = falseTyped->deepCopy();
388 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
389 mCondition = conditionCopy;
390 mTrueBlock = trueCopy;
391 mFalseBlock = falseCopy;
392}
393
Jamie Madillb1a85f42014-08-19 15:23:24 -0400394//
395// Say whether or not an operation node changes the value of a variable.
396//
397bool TIntermOperator::isAssignment() const
398{
399 switch (mOp)
400 {
401 case EOpPostIncrement:
402 case EOpPostDecrement:
403 case EOpPreIncrement:
404 case EOpPreDecrement:
405 case EOpAssign:
406 case EOpAddAssign:
407 case EOpSubAssign:
408 case EOpMulAssign:
409 case EOpVectorTimesMatrixAssign:
410 case EOpVectorTimesScalarAssign:
411 case EOpMatrixTimesScalarAssign:
412 case EOpMatrixTimesMatrixAssign:
413 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200414 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200415 case EOpBitShiftLeftAssign:
416 case EOpBitShiftRightAssign:
417 case EOpBitwiseAndAssign:
418 case EOpBitwiseXorAssign:
419 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400420 return true;
421 default:
422 return false;
423 }
424}
425
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300426bool TIntermOperator::isMultiplication() const
427{
428 switch (mOp)
429 {
430 case EOpMul:
431 case EOpMatrixTimesMatrix:
432 case EOpMatrixTimesVector:
433 case EOpMatrixTimesScalar:
434 case EOpVectorTimesMatrix:
435 case EOpVectorTimesScalar:
436 return true;
437 default:
438 return false;
439 }
440}
441
Jamie Madillb1a85f42014-08-19 15:23:24 -0400442//
443// returns true if the operator is for one of the constructors
444//
445bool TIntermOperator::isConstructor() const
446{
447 switch (mOp)
448 {
449 case EOpConstructVec2:
450 case EOpConstructVec3:
451 case EOpConstructVec4:
452 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400453 case EOpConstructMat2x3:
454 case EOpConstructMat2x4:
455 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400456 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400457 case EOpConstructMat3x4:
458 case EOpConstructMat4x2:
459 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400460 case EOpConstructMat4:
461 case EOpConstructFloat:
462 case EOpConstructIVec2:
463 case EOpConstructIVec3:
464 case EOpConstructIVec4:
465 case EOpConstructInt:
466 case EOpConstructUVec2:
467 case EOpConstructUVec3:
468 case EOpConstructUVec4:
469 case EOpConstructUInt:
470 case EOpConstructBVec2:
471 case EOpConstructBVec3:
472 case EOpConstructBVec4:
473 case EOpConstructBool:
474 case EOpConstructStruct:
475 return true;
476 default:
477 return false;
478 }
479}
480
Olli Etuaho1dded802016-08-18 18:13:13 +0300481TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
482{
483 if (left.isMatrix())
484 {
485 if (right.isMatrix())
486 {
487 return EOpMatrixTimesMatrix;
488 }
489 else
490 {
491 if (right.isVector())
492 {
493 return EOpMatrixTimesVector;
494 }
495 else
496 {
497 return EOpMatrixTimesScalar;
498 }
499 }
500 }
501 else
502 {
503 if (right.isMatrix())
504 {
505 if (left.isVector())
506 {
507 return EOpVectorTimesMatrix;
508 }
509 else
510 {
511 return EOpMatrixTimesScalar;
512 }
513 }
514 else
515 {
516 // Neither operand is a matrix.
517 if (left.isVector() == right.isVector())
518 {
519 // Leave as component product.
520 return EOpMul;
521 }
522 else
523 {
524 return EOpVectorTimesScalar;
525 }
526 }
527 }
528}
529
530TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
531{
532 if (left.isMatrix())
533 {
534 if (right.isMatrix())
535 {
536 return EOpMatrixTimesMatrixAssign;
537 }
538 else
539 {
540 // right should be scalar, but this may not be validated yet.
541 return EOpMatrixTimesScalarAssign;
542 }
543 }
544 else
545 {
546 if (right.isMatrix())
547 {
548 // Left should be a vector, but this may not be validated yet.
549 return EOpVectorTimesMatrixAssign;
550 }
551 else
552 {
553 // Neither operand is a matrix.
554 if (left.isVector() == right.isVector())
555 {
556 // Leave as component product.
557 return EOpMulAssign;
558 }
559 else
560 {
561 // left should be vector and right should be scalar, but this may not be validated
562 // yet.
563 return EOpVectorTimesScalarAssign;
564 }
565 }
566 }
567}
568
Jamie Madillb1a85f42014-08-19 15:23:24 -0400569//
570// Make sure the type of a unary operator is appropriate for its
571// combination of operation and operand type.
572//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200573void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400574{
575 switch (mOp)
576 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200577 case EOpFloatBitsToInt:
578 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200579 case EOpIntBitsToFloat:
580 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200581 case EOpPackSnorm2x16:
582 case EOpPackUnorm2x16:
583 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200584 case EOpUnpackSnorm2x16:
585 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200586 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530587 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200588 case EOpUnpackHalf2x16:
589 mType.setPrecision(EbpMedium);
590 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400591 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200592 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400593 }
594
Olli Etuahof6c694b2015-03-26 14:50:53 +0200595 if (funcReturnType != nullptr)
596 {
597 if (funcReturnType->getBasicType() == EbtBool)
598 {
599 // Bool types should not have precision.
600 setType(*funcReturnType);
601 }
602 else
603 {
604 // Precision of the node has been set based on the operand.
605 setTypePreservePrecision(*funcReturnType);
606 }
607 }
608
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200609 if (mOperand->getQualifier() == EvqConst)
610 mType.setQualifier(EvqConst);
611 else
612 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400613}
614
615//
616// Establishes the type of the resultant operation, as well as
617// makes the operator the correct one for the operands.
618//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200619// For lots of operations it should already be established that the operand
620// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400621//
Olli Etuaho3fdec912016-08-18 15:08:06 +0300622bool TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400623{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200624 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400625
Olli Etuaho1dded802016-08-18 18:13:13 +0300626 ASSERT(!isMultiplication() ||
627 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
628
Jamie Madillb1a85f42014-08-19 15:23:24 -0400629 //
630 // Base assumption: just make the type the same as the left
631 // operand. Then only deviations from this need be coded.
632 //
633 setType(mLeft->getType());
634
635 // The result gets promoted to the highest precision.
636 TPrecision higherPrecision = GetHigherPrecision(
637 mLeft->getPrecision(), mRight->getPrecision());
638 getTypePointer()->setPrecision(higherPrecision);
639
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200640 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400641 // Binary operations results in temporary variables unless both
642 // operands are const.
643 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
644 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200645 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400646 getTypePointer()->setQualifier(EvqTemporary);
647 }
648
649 const int nominalSize =
650 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
651
652 //
653 // All scalars or structs. Code after this test assumes this case is removed!
654 //
655 if (nominalSize == 1)
656 {
657 switch (mOp)
658 {
659 //
660 // Promote to conditional
661 //
662 case EOpEqual:
663 case EOpNotEqual:
664 case EOpLessThan:
665 case EOpGreaterThan:
666 case EOpLessThanEqual:
667 case EOpGreaterThanEqual:
668 setType(TType(EbtBool, EbpUndefined));
669 break;
670
671 //
672 // And and Or operate on conditionals
673 //
674 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200675 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400676 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200677 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400678 setType(TType(EbtBool, EbpUndefined));
679 break;
680
681 default:
682 break;
683 }
684 return true;
685 }
686
687 // If we reach here, at least one of the operands is vector or matrix.
688 // The other operand could be a scalar, vector, or matrix.
689 // Can these two operands be combined?
690 //
691 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300692
Jamie Madillb1a85f42014-08-19 15:23:24 -0400693 switch (mOp)
694 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300695 case EOpMul:
696 break;
697 case EOpMatrixTimesScalar:
698 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400699 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200700 setType(TType(basicType, higherPrecision, resultQualifier,
701 static_cast<unsigned char>(mRight->getCols()),
702 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400703 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300704 break;
705 case EOpMatrixTimesVector:
706 setType(TType(basicType, higherPrecision, resultQualifier,
707 static_cast<unsigned char>(mLeft->getRows()), 1));
708 break;
709 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200710 setType(TType(basicType, higherPrecision, resultQualifier,
711 static_cast<unsigned char>(mRight->getCols()),
712 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300713 break;
714 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200715 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300716 static_cast<unsigned char>(nominalSize), 1));
717 break;
718 case EOpVectorTimesMatrix:
719 setType(TType(basicType, higherPrecision, resultQualifier,
720 static_cast<unsigned char>(mRight->getCols()), 1));
721 break;
722 case EOpMulAssign:
723 case EOpVectorTimesScalarAssign:
724 case EOpVectorTimesMatrixAssign:
725 case EOpMatrixTimesScalarAssign:
726 case EOpMatrixTimesMatrixAssign:
727 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
728 break;
729 case EOpAssign:
730 case EOpInitialize:
731 // No more additional checks are needed.
732 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
733 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
734 break;
735 case EOpAdd:
736 case EOpSub:
737 case EOpDiv:
738 case EOpIMod:
739 case EOpBitShiftLeft:
740 case EOpBitShiftRight:
741 case EOpBitwiseAnd:
742 case EOpBitwiseXor:
743 case EOpBitwiseOr:
744 case EOpAddAssign:
745 case EOpSubAssign:
746 case EOpDivAssign:
747 case EOpIModAssign:
748 case EOpBitShiftLeftAssign:
749 case EOpBitShiftRightAssign:
750 case EOpBitwiseAndAssign:
751 case EOpBitwiseXorAssign:
752 case EOpBitwiseOrAssign:
753 if ((mLeft->isMatrix() && mRight->isVector()) ||
754 (mLeft->isVector() && mRight->isMatrix()))
Jamie Madillb1a85f42014-08-19 15:23:24 -0400755 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300756 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400757 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300758
759 // Are the sizes compatible?
760 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
761 mLeft->getSecondarySize() != mRight->getSecondarySize())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400762 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300763 // If the nominal sizes of operands do not match:
764 // One of them must be a scalar.
765 if (!mLeft->isScalar() && !mRight->isScalar())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400766 return false;
Olli Etuaho1dded802016-08-18 18:13:13 +0300767
768 // In the case of compound assignment other than multiply-assign,
769 // the right side needs to be a scalar. Otherwise a vector/matrix
770 // would be assigned to a scalar. A scalar can't be shifted by a
771 // vector either.
772 if (!mRight->isScalar() &&
773 (isAssignment() || mOp == EOpBitShiftLeft || mOp == EOpBitShiftRight))
774 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400775 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776
Olli Etuahoe79904c2015-03-18 16:56:42 +0200777 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300778 const int secondarySize =
779 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
780 setType(TType(basicType, higherPrecision, resultQualifier,
781 static_cast<unsigned char>(nominalSize),
782 static_cast<unsigned char>(secondarySize)));
783 if (mLeft->isArray())
784 {
785 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
786 mType.setArraySize(mLeft->getArraySize());
787 }
Olli Etuahoe79904c2015-03-18 16:56:42 +0200788 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300789 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400790
Olli Etuaho1dded802016-08-18 18:13:13 +0300791 case EOpEqual:
792 case EOpNotEqual:
793 case EOpLessThan:
794 case EOpGreaterThan:
795 case EOpLessThanEqual:
796 case EOpGreaterThanEqual:
797 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
798 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
799 setType(TType(EbtBool, EbpUndefined));
800 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400801
Olli Etuaho1dded802016-08-18 18:13:13 +0300802 default:
803 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400804 }
805 return true;
806}
807
Olli Etuaho3fdec912016-08-18 15:08:06 +0300808TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300809{
810 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
811 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
812 if (leftConstant == nullptr || rightConstant == nullptr)
813 {
814 return nullptr;
815 }
Olli Etuaho3fdec912016-08-18 15:08:06 +0300816 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200817
818 // Nodes may be constant folded without being qualified as constant.
819 TQualifier resultQualifier = EvqConst;
820 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
821 {
822 resultQualifier = EvqTemporary;
823 }
824 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300825}
826
Olli Etuaho95310b02015-06-02 17:43:38 +0300827TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
828{
829 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
830 if (operandConstant == nullptr)
831 {
832 return nullptr;
833 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530834
835 TConstantUnion *constArray = nullptr;
836 switch (mOp)
837 {
838 case EOpAny:
839 case EOpAll:
840 case EOpLength:
841 case EOpTranspose:
842 case EOpDeterminant:
843 case EOpInverse:
844 case EOpPackSnorm2x16:
845 case EOpUnpackSnorm2x16:
846 case EOpPackUnorm2x16:
847 case EOpUnpackUnorm2x16:
848 case EOpPackHalf2x16:
849 case EOpUnpackHalf2x16:
850 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
851 break;
852 default:
853 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
854 break;
855 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200856
857 // Nodes may be constant folded without being qualified as constant.
858 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
859 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300860}
861
862TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
863{
864 // Make sure that all params are constant before actual constant folding.
865 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300866 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300867 if (param->getAsConstantUnion() == nullptr)
868 {
869 return nullptr;
870 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300871 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200872 TConstantUnion *constArray = nullptr;
873 if (isConstructor())
874 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
875 else
876 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200877
878 // Nodes may be constant folded without being qualified as constant.
879 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
880 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300881}
882
Jamie Madillb1a85f42014-08-19 15:23:24 -0400883//
884// The fold functions see if an operation on a constant can be done in place,
885// without generating run-time code.
886//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300887// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400888//
Olli Etuaho3fdec912016-08-18 15:08:06 +0300889TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
890 TIntermConstantUnion *rightNode,
891 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300892{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200893 const TConstantUnion *leftArray = getUnionArrayPointer();
894 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300895
896 if (!leftArray)
897 return nullptr;
898 if (!rightArray)
899 return nullptr;
900
901 size_t objectSize = getType().getObjectSize();
902
903 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
904 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
905 {
906 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
907 }
908 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
909 {
910 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
911 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
912 objectSize = rightNode->getType().getObjectSize();
913 }
914
915 TConstantUnion *resultArray = nullptr;
916
917 switch(op)
918 {
919 case EOpAdd:
920 resultArray = new TConstantUnion[objectSize];
921 for (size_t i = 0; i < objectSize; i++)
922 resultArray[i] = leftArray[i] + rightArray[i];
923 break;
924 case EOpSub:
925 resultArray = new TConstantUnion[objectSize];
926 for (size_t i = 0; i < objectSize; i++)
927 resultArray[i] = leftArray[i] - rightArray[i];
928 break;
929
930 case EOpMul:
931 case EOpVectorTimesScalar:
932 case EOpMatrixTimesScalar:
933 resultArray = new TConstantUnion[objectSize];
934 for (size_t i = 0; i < objectSize; i++)
935 resultArray[i] = leftArray[i] * rightArray[i];
936 break;
937
938 case EOpMatrixTimesMatrix:
939 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300940 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300941
942 const int leftCols = getCols();
943 const int leftRows = getRows();
944 const int rightCols = rightNode->getType().getCols();
945 const int rightRows = rightNode->getType().getRows();
946 const int resultCols = rightCols;
947 const int resultRows = leftRows;
948
949 resultArray = new TConstantUnion[resultCols * resultRows];
950 for (int row = 0; row < resultRows; row++)
951 {
952 for (int column = 0; column < resultCols; column++)
953 {
954 resultArray[resultRows * column + row].setFConst(0.0f);
955 for (int i = 0; i < leftCols; i++)
956 {
957 resultArray[resultRows * column + row].setFConst(
958 resultArray[resultRows * column + row].getFConst() +
959 leftArray[i * leftRows + row].getFConst() *
960 rightArray[column * rightRows + i].getFConst());
961 }
962 }
963 }
964 }
965 break;
966
967 case EOpDiv:
968 case EOpIMod:
969 {
970 resultArray = new TConstantUnion[objectSize];
971 for (size_t i = 0; i < objectSize; i++)
972 {
973 switch (getType().getBasicType())
974 {
975 case EbtFloat:
976 if (rightArray[i] == 0.0f)
977 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300978 diagnostics->warning(
979 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300980 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
981 }
982 else
983 {
984 ASSERT(op == EOpDiv);
985 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
986 }
987 break;
988
989 case EbtInt:
990 if (rightArray[i] == 0)
991 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300992 diagnostics->warning(
993 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300994 resultArray[i].setIConst(INT_MAX);
995 }
996 else
997 {
998 if (op == EOpDiv)
999 {
1000 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1001 }
1002 else
1003 {
1004 ASSERT(op == EOpIMod);
1005 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1006 }
1007 }
1008 break;
1009
1010 case EbtUInt:
1011 if (rightArray[i] == 0)
1012 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001013 diagnostics->warning(
1014 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001015 resultArray[i].setUConst(UINT_MAX);
1016 }
1017 else
1018 {
1019 if (op == EOpDiv)
1020 {
1021 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1022 }
1023 else
1024 {
1025 ASSERT(op == EOpIMod);
1026 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1027 }
1028 }
1029 break;
1030
1031 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001032 UNREACHABLE();
1033 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001034 }
1035 }
1036 }
1037 break;
1038
1039 case EOpMatrixTimesVector:
1040 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001041 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001042
1043 const int matrixCols = getCols();
1044 const int matrixRows = getRows();
1045
1046 resultArray = new TConstantUnion[matrixRows];
1047
1048 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1049 {
1050 resultArray[matrixRow].setFConst(0.0f);
1051 for (int col = 0; col < matrixCols; col++)
1052 {
1053 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1054 leftArray[col * matrixRows + matrixRow].getFConst() *
1055 rightArray[col].getFConst());
1056 }
1057 }
1058 }
1059 break;
1060
1061 case EOpVectorTimesMatrix:
1062 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001063 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001064
1065 const int matrixCols = rightNode->getType().getCols();
1066 const int matrixRows = rightNode->getType().getRows();
1067
1068 resultArray = new TConstantUnion[matrixCols];
1069
1070 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1071 {
1072 resultArray[matrixCol].setFConst(0.0f);
1073 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1074 {
1075 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1076 leftArray[matrixRow].getFConst() *
1077 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1078 }
1079 }
1080 }
1081 break;
1082
1083 case EOpLogicalAnd:
1084 {
1085 resultArray = new TConstantUnion[objectSize];
1086 for (size_t i = 0; i < objectSize; i++)
1087 {
1088 resultArray[i] = leftArray[i] && rightArray[i];
1089 }
1090 }
1091 break;
1092
1093 case EOpLogicalOr:
1094 {
1095 resultArray = new TConstantUnion[objectSize];
1096 for (size_t i = 0; i < objectSize; i++)
1097 {
1098 resultArray[i] = leftArray[i] || rightArray[i];
1099 }
1100 }
1101 break;
1102
1103 case EOpLogicalXor:
1104 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001105 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001106 resultArray = new TConstantUnion[objectSize];
1107 for (size_t i = 0; i < objectSize; i++)
1108 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001109 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001110 }
1111 }
1112 break;
1113
1114 case EOpBitwiseAnd:
1115 resultArray = new TConstantUnion[objectSize];
1116 for (size_t i = 0; i < objectSize; i++)
1117 resultArray[i] = leftArray[i] & rightArray[i];
1118 break;
1119 case EOpBitwiseXor:
1120 resultArray = new TConstantUnion[objectSize];
1121 for (size_t i = 0; i < objectSize; i++)
1122 resultArray[i] = leftArray[i] ^ rightArray[i];
1123 break;
1124 case EOpBitwiseOr:
1125 resultArray = new TConstantUnion[objectSize];
1126 for (size_t i = 0; i < objectSize; i++)
1127 resultArray[i] = leftArray[i] | rightArray[i];
1128 break;
1129 case EOpBitShiftLeft:
1130 resultArray = new TConstantUnion[objectSize];
1131 for (size_t i = 0; i < objectSize; i++)
1132 resultArray[i] = leftArray[i] << rightArray[i];
1133 break;
1134 case EOpBitShiftRight:
1135 resultArray = new TConstantUnion[objectSize];
1136 for (size_t i = 0; i < objectSize; i++)
1137 resultArray[i] = leftArray[i] >> rightArray[i];
1138 break;
1139
1140 case EOpLessThan:
1141 ASSERT(objectSize == 1);
1142 resultArray = new TConstantUnion[1];
1143 resultArray->setBConst(*leftArray < *rightArray);
1144 break;
1145
1146 case EOpGreaterThan:
1147 ASSERT(objectSize == 1);
1148 resultArray = new TConstantUnion[1];
1149 resultArray->setBConst(*leftArray > *rightArray);
1150 break;
1151
1152 case EOpLessThanEqual:
1153 ASSERT(objectSize == 1);
1154 resultArray = new TConstantUnion[1];
1155 resultArray->setBConst(!(*leftArray > *rightArray));
1156 break;
1157
1158 case EOpGreaterThanEqual:
1159 ASSERT(objectSize == 1);
1160 resultArray = new TConstantUnion[1];
1161 resultArray->setBConst(!(*leftArray < *rightArray));
1162 break;
1163
1164 case EOpEqual:
1165 case EOpNotEqual:
1166 {
1167 resultArray = new TConstantUnion[1];
1168 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001169 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001170 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001171 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001172 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001173 equal = false;
1174 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001175 }
1176 }
1177 if (op == EOpEqual)
1178 {
1179 resultArray->setBConst(equal);
1180 }
1181 else
1182 {
1183 resultArray->setBConst(!equal);
1184 }
1185 }
1186 break;
1187
1188 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001189 UNREACHABLE();
1190 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001191 }
1192 return resultArray;
1193}
1194
1195//
1196// The fold functions see if an operation on a constant can be done in place,
1197// without generating run-time code.
1198//
Olli Etuaho95310b02015-06-02 17:43:38 +03001199// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001200//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301201TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001202{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301203 //
1204 // Do operations where the return type has a different number of components compared to the operand type.
1205 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001206
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001207 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301208 if (!operandArray)
1209 return nullptr;
1210
1211 size_t objectSize = getType().getObjectSize();
1212 TConstantUnion *resultArray = nullptr;
1213 switch (op)
1214 {
1215 case EOpAny:
1216 if (getType().getBasicType() == EbtBool)
1217 {
1218 resultArray = new TConstantUnion();
1219 resultArray->setBConst(false);
1220 for (size_t i = 0; i < objectSize; i++)
1221 {
1222 if (operandArray[i].getBConst())
1223 {
1224 resultArray->setBConst(true);
1225 break;
1226 }
1227 }
1228 break;
1229 }
1230 else
1231 {
1232 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1233 return nullptr;
1234 }
1235
1236 case EOpAll:
1237 if (getType().getBasicType() == EbtBool)
1238 {
1239 resultArray = new TConstantUnion();
1240 resultArray->setBConst(true);
1241 for (size_t i = 0; i < objectSize; i++)
1242 {
1243 if (!operandArray[i].getBConst())
1244 {
1245 resultArray->setBConst(false);
1246 break;
1247 }
1248 }
1249 break;
1250 }
1251 else
1252 {
1253 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1254 return nullptr;
1255 }
1256
1257 case EOpLength:
1258 if (getType().getBasicType() == EbtFloat)
1259 {
1260 resultArray = new TConstantUnion();
1261 resultArray->setFConst(VectorLength(operandArray, objectSize));
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 EOpTranspose:
1271 if (getType().getBasicType() == EbtFloat)
1272 {
1273 resultArray = new TConstantUnion[objectSize];
1274 angle::Matrix<float> result =
1275 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1276 SetUnionArrayFromMatrix(result, resultArray);
1277 break;
1278 }
1279 else
1280 {
1281 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1282 return nullptr;
1283 }
1284
1285 case EOpDeterminant:
1286 if (getType().getBasicType() == EbtFloat)
1287 {
1288 unsigned int size = getType().getNominalSize();
1289 ASSERT(size >= 2 && size <= 4);
1290 resultArray = new TConstantUnion();
1291 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
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 EOpInverse:
1301 if (getType().getBasicType() == EbtFloat)
1302 {
1303 unsigned int size = getType().getNominalSize();
1304 ASSERT(size >= 2 && size <= 4);
1305 resultArray = new TConstantUnion[objectSize];
1306 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1307 SetUnionArrayFromMatrix(result, resultArray);
1308 break;
1309 }
1310 else
1311 {
1312 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1313 return nullptr;
1314 }
1315
1316 case EOpPackSnorm2x16:
1317 if (getType().getBasicType() == EbtFloat)
1318 {
1319 ASSERT(getType().getNominalSize() == 2);
1320 resultArray = new TConstantUnion();
1321 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
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 EOpUnpackSnorm2x16:
1331 if (getType().getBasicType() == EbtUInt)
1332 {
1333 resultArray = new TConstantUnion[2];
1334 float f1, f2;
1335 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1336 resultArray[0].setFConst(f1);
1337 resultArray[1].setFConst(f2);
1338 break;
1339 }
1340 else
1341 {
1342 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1343 return nullptr;
1344 }
1345
1346 case EOpPackUnorm2x16:
1347 if (getType().getBasicType() == EbtFloat)
1348 {
1349 ASSERT(getType().getNominalSize() == 2);
1350 resultArray = new TConstantUnion();
1351 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1352 break;
1353 }
1354 else
1355 {
1356 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1357 return nullptr;
1358 }
1359
1360 case EOpUnpackUnorm2x16:
1361 if (getType().getBasicType() == EbtUInt)
1362 {
1363 resultArray = new TConstantUnion[2];
1364 float f1, f2;
1365 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1366 resultArray[0].setFConst(f1);
1367 resultArray[1].setFConst(f2);
1368 break;
1369 }
1370 else
1371 {
1372 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1373 return nullptr;
1374 }
1375
1376 case EOpPackHalf2x16:
1377 if (getType().getBasicType() == EbtFloat)
1378 {
1379 ASSERT(getType().getNominalSize() == 2);
1380 resultArray = new TConstantUnion();
1381 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1382 break;
1383 }
1384 else
1385 {
1386 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1387 return nullptr;
1388 }
1389
1390 case EOpUnpackHalf2x16:
1391 if (getType().getBasicType() == EbtUInt)
1392 {
1393 resultArray = new TConstantUnion[2];
1394 float f1, f2;
1395 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1396 resultArray[0].setFConst(f1);
1397 resultArray[1].setFConst(f2);
1398 break;
1399 }
1400 else
1401 {
1402 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1403 return nullptr;
1404 }
1405 break;
1406
1407 default:
1408 break;
1409 }
1410
1411 return resultArray;
1412}
1413
1414TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1415{
1416 //
1417 // Do unary operations where the return type is the same as operand type.
1418 //
1419
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001420 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001421 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301422 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001423
1424 size_t objectSize = getType().getObjectSize();
1425
Arun Patoleab2b9a22015-07-06 18:27:56 +05301426 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1427 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301428 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301429 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301430 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301431 case EOpNegative:
1432 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301433 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301434 case EbtFloat:
1435 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301436 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301437 case EbtInt:
1438 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301439 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301440 case EbtUInt:
1441 resultArray[i].setUConst(static_cast<unsigned int>(
1442 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301443 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301444 default:
1445 infoSink.info.message(
1446 EPrefixInternalError, getLine(),
1447 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301448 return nullptr;
1449 }
1450 break;
1451
Arun Patoleab2b9a22015-07-06 18:27:56 +05301452 case EOpPositive:
1453 switch (getType().getBasicType())
1454 {
1455 case EbtFloat:
1456 resultArray[i].setFConst(operandArray[i].getFConst());
1457 break;
1458 case EbtInt:
1459 resultArray[i].setIConst(operandArray[i].getIConst());
1460 break;
1461 case EbtUInt:
1462 resultArray[i].setUConst(static_cast<unsigned int>(
1463 static_cast<int>(operandArray[i].getUConst())));
1464 break;
1465 default:
1466 infoSink.info.message(
1467 EPrefixInternalError, getLine(),
1468 "Unary operation not folded into constant");
1469 return nullptr;
1470 }
1471 break;
1472
1473 case EOpLogicalNot:
1474 // this code is written for possible future use,
1475 // will not get executed currently
1476 switch (getType().getBasicType())
1477 {
1478 case EbtBool:
1479 resultArray[i].setBConst(!operandArray[i].getBConst());
1480 break;
1481 default:
1482 infoSink.info.message(
1483 EPrefixInternalError, getLine(),
1484 "Unary operation not folded into constant");
1485 return nullptr;
1486 }
1487 break;
1488
1489 case EOpBitwiseNot:
1490 switch (getType().getBasicType())
1491 {
1492 case EbtInt:
1493 resultArray[i].setIConst(~operandArray[i].getIConst());
1494 break;
1495 case EbtUInt:
1496 resultArray[i].setUConst(~operandArray[i].getUConst());
1497 break;
1498 default:
1499 infoSink.info.message(
1500 EPrefixInternalError, getLine(),
1501 "Unary operation not folded into constant");
1502 return nullptr;
1503 }
1504 break;
1505
1506 case EOpRadians:
1507 if (getType().getBasicType() == EbtFloat)
1508 {
1509 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1510 break;
1511 }
1512 infoSink.info.message(
1513 EPrefixInternalError, getLine(),
1514 "Unary operation not folded into constant");
1515 return nullptr;
1516
1517 case EOpDegrees:
1518 if (getType().getBasicType() == EbtFloat)
1519 {
1520 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1521 break;
1522 }
1523 infoSink.info.message(
1524 EPrefixInternalError, getLine(),
1525 "Unary operation not folded into constant");
1526 return nullptr;
1527
1528 case EOpSin:
1529 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1530 return nullptr;
1531 break;
1532
1533 case EOpCos:
1534 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1535 return nullptr;
1536 break;
1537
1538 case EOpTan:
1539 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1540 return nullptr;
1541 break;
1542
1543 case EOpAsin:
1544 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1545 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1546 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1547 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1548 return nullptr;
1549 break;
1550
1551 case EOpAcos:
1552 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1553 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1554 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1555 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1556 return nullptr;
1557 break;
1558
1559 case EOpAtan:
1560 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1561 return nullptr;
1562 break;
1563
1564 case EOpSinh:
1565 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1566 return nullptr;
1567 break;
1568
1569 case EOpCosh:
1570 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1571 return nullptr;
1572 break;
1573
1574 case EOpTanh:
1575 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1576 return nullptr;
1577 break;
1578
1579 case EOpAsinh:
1580 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1581 return nullptr;
1582 break;
1583
1584 case EOpAcosh:
1585 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1586 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1587 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1588 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1589 return nullptr;
1590 break;
1591
1592 case EOpAtanh:
1593 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1594 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1595 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1596 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1597 return nullptr;
1598 break;
1599
1600 case EOpAbs:
1601 switch (getType().getBasicType())
1602 {
1603 case EbtFloat:
1604 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1605 break;
1606 case EbtInt:
1607 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1608 break;
1609 default:
1610 infoSink.info.message(
1611 EPrefixInternalError, getLine(),
1612 "Unary operation not folded into constant");
1613 return nullptr;
1614 }
1615 break;
1616
1617 case EOpSign:
1618 switch (getType().getBasicType())
1619 {
1620 case EbtFloat:
1621 {
1622 float fConst = operandArray[i].getFConst();
1623 float fResult = 0.0f;
1624 if (fConst > 0.0f)
1625 fResult = 1.0f;
1626 else if (fConst < 0.0f)
1627 fResult = -1.0f;
1628 resultArray[i].setFConst(fResult);
1629 }
1630 break;
1631 case EbtInt:
1632 {
1633 int iConst = operandArray[i].getIConst();
1634 int iResult = 0;
1635 if (iConst > 0)
1636 iResult = 1;
1637 else if (iConst < 0)
1638 iResult = -1;
1639 resultArray[i].setIConst(iResult);
1640 }
1641 break;
1642 default:
1643 infoSink.info.message(
1644 EPrefixInternalError, getLine(),
1645 "Unary operation not folded into constant");
1646 return nullptr;
1647 }
1648 break;
1649
1650 case EOpFloor:
1651 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1652 return nullptr;
1653 break;
1654
1655 case EOpTrunc:
1656 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1657 return nullptr;
1658 break;
1659
1660 case EOpRound:
1661 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1662 return nullptr;
1663 break;
1664
1665 case EOpRoundEven:
1666 if (getType().getBasicType() == EbtFloat)
1667 {
1668 float x = operandArray[i].getFConst();
1669 float result;
1670 float fractPart = modff(x, &result);
1671 if (fabsf(fractPart) == 0.5f)
1672 result = 2.0f * roundf(x / 2.0f);
1673 else
1674 result = roundf(x);
1675 resultArray[i].setFConst(result);
1676 break;
1677 }
1678 infoSink.info.message(
1679 EPrefixInternalError, getLine(),
1680 "Unary operation not folded into constant");
1681 return nullptr;
1682
1683 case EOpCeil:
1684 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1685 return nullptr;
1686 break;
1687
1688 case EOpFract:
1689 if (getType().getBasicType() == EbtFloat)
1690 {
1691 float x = operandArray[i].getFConst();
1692 resultArray[i].setFConst(x - floorf(x));
1693 break;
1694 }
1695 infoSink.info.message(
1696 EPrefixInternalError, getLine(),
1697 "Unary operation not folded into constant");
1698 return nullptr;
1699
Arun Patole551279e2015-07-07 18:18:23 +05301700 case EOpIsNan:
1701 if (getType().getBasicType() == EbtFloat)
1702 {
1703 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1704 break;
1705 }
1706 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1707 return nullptr;
1708
1709 case EOpIsInf:
1710 if (getType().getBasicType() == EbtFloat)
1711 {
1712 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1713 break;
1714 }
1715 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1716 return nullptr;
1717
1718 case EOpFloatBitsToInt:
1719 if (getType().getBasicType() == EbtFloat)
1720 {
1721 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1722 break;
1723 }
1724 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1725 return nullptr;
1726
1727 case EOpFloatBitsToUint:
1728 if (getType().getBasicType() == EbtFloat)
1729 {
1730 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1731 break;
1732 }
1733 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1734 return nullptr;
1735
1736 case EOpIntBitsToFloat:
1737 if (getType().getBasicType() == EbtInt)
1738 {
1739 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1740 break;
1741 }
1742 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1743 return nullptr;
1744
1745 case EOpUintBitsToFloat:
1746 if (getType().getBasicType() == EbtUInt)
1747 {
1748 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1749 break;
1750 }
1751 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1752 return nullptr;
1753
Arun Patoleab2b9a22015-07-06 18:27:56 +05301754 case EOpExp:
1755 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1756 return nullptr;
1757 break;
1758
1759 case EOpLog:
1760 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1761 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1762 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1763 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1764 return nullptr;
1765 break;
1766
1767 case EOpExp2:
1768 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1769 return nullptr;
1770 break;
1771
1772 case EOpLog2:
1773 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1774 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1775 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1776 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1777 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1778 return nullptr;
1779 else
1780 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1781 break;
1782
1783 case EOpSqrt:
1784 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1785 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1786 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1787 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1788 return nullptr;
1789 break;
1790
1791 case EOpInverseSqrt:
1792 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1793 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1794 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1795 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1796 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1797 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1798 return nullptr;
1799 else
1800 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1801 break;
1802
1803 case EOpVectorLogicalNot:
1804 if (getType().getBasicType() == EbtBool)
1805 {
1806 resultArray[i].setBConst(!operandArray[i].getBConst());
1807 break;
1808 }
1809 infoSink.info.message(
1810 EPrefixInternalError, getLine(),
1811 "Unary operation not folded into constant");
1812 return nullptr;
1813
1814 case EOpNormalize:
1815 if (getType().getBasicType() == EbtFloat)
1816 {
1817 float x = operandArray[i].getFConst();
1818 float length = VectorLength(operandArray, objectSize);
1819 if (length)
1820 resultArray[i].setFConst(x / length);
1821 else
1822 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1823 &resultArray[i]);
1824 break;
1825 }
1826 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1827 return nullptr;
1828
Arun Patole0c5409f2015-07-08 15:17:53 +05301829 case EOpDFdx:
1830 case EOpDFdy:
1831 case EOpFwidth:
1832 if (getType().getBasicType() == EbtFloat)
1833 {
1834 // Derivatives of constant arguments should be 0.
1835 resultArray[i].setFConst(0.0f);
1836 break;
1837 }
1838 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1839 return nullptr;
1840
Arun Patole1155ddd2015-06-05 18:04:36 +05301841 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301842 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301843 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301844 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001845
Arun Patoleab2b9a22015-07-06 18:27:56 +05301846 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001847}
1848
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001849bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1850 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301851{
1852 ASSERT(builtinFunc);
1853
1854 if (getType().getBasicType() == EbtFloat)
1855 {
1856 result->setFConst(builtinFunc(parameter.getFConst()));
1857 return true;
1858 }
1859
1860 infoSink.info.message(
1861 EPrefixInternalError, getLine(),
1862 "Unary operation not folded into constant");
1863 return false;
1864}
1865
Jamie Madillb1a85f42014-08-19 15:23:24 -04001866// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001867TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1868 TInfoSink &infoSink)
1869{
1870 ASSERT(aggregate->getSequence()->size() > 0u);
1871 size_t resultSize = aggregate->getType().getObjectSize();
1872 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1873 TBasicType basicType = aggregate->getBasicType();
1874
1875 size_t resultIndex = 0u;
1876
1877 if (aggregate->getSequence()->size() == 1u)
1878 {
1879 TIntermNode *argument = aggregate->getSequence()->front();
1880 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1881 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1882 // Check the special case of constructing a matrix diagonal from a single scalar,
1883 // or a vector from a single scalar.
1884 if (argumentConstant->getType().getObjectSize() == 1u)
1885 {
1886 if (aggregate->isMatrix())
1887 {
1888 int resultCols = aggregate->getType().getCols();
1889 int resultRows = aggregate->getType().getRows();
1890 for (int col = 0; col < resultCols; ++col)
1891 {
1892 for (int row = 0; row < resultRows; ++row)
1893 {
1894 if (col == row)
1895 {
1896 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1897 }
1898 else
1899 {
1900 resultArray[resultIndex].setFConst(0.0f);
1901 }
1902 ++resultIndex;
1903 }
1904 }
1905 }
1906 else
1907 {
1908 while (resultIndex < resultSize)
1909 {
1910 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1911 ++resultIndex;
1912 }
1913 }
1914 ASSERT(resultIndex == resultSize);
1915 return resultArray;
1916 }
1917 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1918 {
1919 // The special case of constructing a matrix from a matrix.
1920 int argumentCols = argumentConstant->getType().getCols();
1921 int argumentRows = argumentConstant->getType().getRows();
1922 int resultCols = aggregate->getType().getCols();
1923 int resultRows = aggregate->getType().getRows();
1924 for (int col = 0; col < resultCols; ++col)
1925 {
1926 for (int row = 0; row < resultRows; ++row)
1927 {
1928 if (col < argumentCols && row < argumentRows)
1929 {
1930 resultArray[resultIndex].cast(basicType,
1931 argumentUnionArray[col * argumentRows + row]);
1932 }
1933 else if (col == row)
1934 {
1935 resultArray[resultIndex].setFConst(1.0f);
1936 }
1937 else
1938 {
1939 resultArray[resultIndex].setFConst(0.0f);
1940 }
1941 ++resultIndex;
1942 }
1943 }
1944 ASSERT(resultIndex == resultSize);
1945 return resultArray;
1946 }
1947 }
1948
1949 for (TIntermNode *&argument : *aggregate->getSequence())
1950 {
1951 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1952 size_t argumentSize = argumentConstant->getType().getObjectSize();
1953 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1954 for (size_t i = 0u; i < argumentSize; ++i)
1955 {
1956 if (resultIndex >= resultSize)
1957 break;
1958 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1959 ++resultIndex;
1960 }
1961 }
1962 ASSERT(resultIndex == resultSize);
1963 return resultArray;
1964}
1965
1966// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001967TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301968{
Olli Etuahob43846e2015-06-02 18:18:57 +03001969 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301970 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001971 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001972 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05301973 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001974 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301975 TBasicType basicType = EbtVoid;
1976 TSourceLoc loc;
1977 for (unsigned int i = 0; i < paramsCount; i++)
1978 {
1979 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001980 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301981
1982 if (i == 0)
1983 {
1984 basicType = paramConstant->getType().getBasicType();
1985 loc = paramConstant->getLine();
1986 }
1987 unionArrays[i] = paramConstant->getUnionArrayPointer();
1988 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001989 if (objectSizes[i] > maxObjectSize)
1990 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301991 }
1992
Arun Patole7fa33552015-06-10 15:15:18 +05301993 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1994 {
1995 for (unsigned int i = 0; i < paramsCount; i++)
1996 if (objectSizes[i] != maxObjectSize)
1997 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1998 }
Arun Patole274f0702015-05-05 13:33:30 +05301999
Olli Etuahob43846e2015-06-02 18:18:57 +03002000 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302001 if (paramsCount == 2)
2002 {
2003 //
2004 // Binary built-in
2005 //
2006 switch (op)
2007 {
Arun Patolebf790422015-05-18 17:53:04 +05302008 case EOpAtan:
2009 {
2010 if (basicType == EbtFloat)
2011 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002012 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302013 for (size_t i = 0; i < maxObjectSize; i++)
2014 {
2015 float y = unionArrays[0][i].getFConst();
2016 float x = unionArrays[1][i].getFConst();
2017 // Results are undefined if x and y are both 0.
2018 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002019 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302020 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002021 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302022 }
2023 }
2024 else
2025 UNREACHABLE();
2026 }
2027 break;
2028
2029 case EOpPow:
2030 {
2031 if (basicType == EbtFloat)
2032 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002033 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302034 for (size_t i = 0; i < maxObjectSize; i++)
2035 {
2036 float x = unionArrays[0][i].getFConst();
2037 float y = unionArrays[1][i].getFConst();
2038 // Results are undefined if x < 0.
2039 // Results are undefined if x = 0 and y <= 0.
2040 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002041 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302042 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002043 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302044 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002045 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302046 }
2047 }
2048 else
2049 UNREACHABLE();
2050 }
2051 break;
2052
2053 case EOpMod:
2054 {
2055 if (basicType == EbtFloat)
2056 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002057 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302058 for (size_t i = 0; i < maxObjectSize; i++)
2059 {
2060 float x = unionArrays[0][i].getFConst();
2061 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002062 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302063 }
2064 }
2065 else
2066 UNREACHABLE();
2067 }
2068 break;
2069
Arun Patole274f0702015-05-05 13:33:30 +05302070 case EOpMin:
2071 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002072 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302073 for (size_t i = 0; i < maxObjectSize; i++)
2074 {
2075 switch (basicType)
2076 {
2077 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002078 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302079 break;
2080 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002081 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302082 break;
2083 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002084 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302085 break;
2086 default:
2087 UNREACHABLE();
2088 break;
2089 }
2090 }
2091 }
2092 break;
2093
2094 case EOpMax:
2095 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002096 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302097 for (size_t i = 0; i < maxObjectSize; i++)
2098 {
2099 switch (basicType)
2100 {
2101 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002102 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302103 break;
2104 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002105 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302106 break;
2107 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002108 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302109 break;
2110 default:
2111 UNREACHABLE();
2112 break;
2113 }
2114 }
2115 }
2116 break;
2117
Arun Patolebf790422015-05-18 17:53:04 +05302118 case EOpStep:
2119 {
2120 if (basicType == EbtFloat)
2121 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002122 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302123 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002124 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302125 }
2126 else
2127 UNREACHABLE();
2128 }
2129 break;
2130
Arun Patole9d0b1f92015-05-20 14:27:17 +05302131 case EOpLessThan:
2132 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002133 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302134 for (size_t i = 0; i < maxObjectSize; i++)
2135 {
2136 switch (basicType)
2137 {
2138 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002139 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302140 break;
2141 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002142 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302143 break;
2144 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002145 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302146 break;
2147 default:
2148 UNREACHABLE();
2149 break;
2150 }
2151 }
2152 }
2153 break;
2154
2155 case EOpLessThanEqual:
2156 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002157 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302158 for (size_t i = 0; i < maxObjectSize; i++)
2159 {
2160 switch (basicType)
2161 {
2162 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002163 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302164 break;
2165 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002166 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302167 break;
2168 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002169 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302170 break;
2171 default:
2172 UNREACHABLE();
2173 break;
2174 }
2175 }
2176 }
2177 break;
2178
2179 case EOpGreaterThan:
2180 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002181 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302182 for (size_t i = 0; i < maxObjectSize; i++)
2183 {
2184 switch (basicType)
2185 {
2186 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002187 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302188 break;
2189 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002190 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302191 break;
2192 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002193 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302194 break;
2195 default:
2196 UNREACHABLE();
2197 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002198 }
2199 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302200 }
2201 break;
2202
2203 case EOpGreaterThanEqual:
2204 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002205 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302206 for (size_t i = 0; i < maxObjectSize; i++)
2207 {
2208 switch (basicType)
2209 {
2210 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002211 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302212 break;
2213 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002214 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302215 break;
2216 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002217 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302218 break;
2219 default:
2220 UNREACHABLE();
2221 break;
2222 }
2223 }
2224 }
2225 break;
2226
2227 case EOpVectorEqual:
2228 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002229 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302230 for (size_t i = 0; i < maxObjectSize; i++)
2231 {
2232 switch (basicType)
2233 {
2234 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002235 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302236 break;
2237 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002238 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302239 break;
2240 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002241 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302242 break;
2243 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002244 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302245 break;
2246 default:
2247 UNREACHABLE();
2248 break;
2249 }
2250 }
2251 }
2252 break;
2253
2254 case EOpVectorNotEqual:
2255 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002256 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302257 for (size_t i = 0; i < maxObjectSize; i++)
2258 {
2259 switch (basicType)
2260 {
2261 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002262 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302263 break;
2264 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002265 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302266 break;
2267 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002268 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302269 break;
2270 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002271 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302272 break;
2273 default:
2274 UNREACHABLE();
2275 break;
2276 }
2277 }
2278 }
2279 break;
2280
Arun Patole1155ddd2015-06-05 18:04:36 +05302281 case EOpDistance:
2282 if (basicType == EbtFloat)
2283 {
2284 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002285 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302286 for (size_t i = 0; i < maxObjectSize; i++)
2287 {
2288 float x = unionArrays[0][i].getFConst();
2289 float y = unionArrays[1][i].getFConst();
2290 distanceArray[i].setFConst(x - y);
2291 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002292 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302293 }
2294 else
2295 UNREACHABLE();
2296 break;
2297
2298 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002299
Arun Patole1155ddd2015-06-05 18:04:36 +05302300 if (basicType == EbtFloat)
2301 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002302 resultArray = new TConstantUnion();
2303 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302304 }
2305 else
2306 UNREACHABLE();
2307 break;
2308
2309 case EOpCross:
2310 if (basicType == EbtFloat && maxObjectSize == 3)
2311 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002312 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302313 float x0 = unionArrays[0][0].getFConst();
2314 float x1 = unionArrays[0][1].getFConst();
2315 float x2 = unionArrays[0][2].getFConst();
2316 float y0 = unionArrays[1][0].getFConst();
2317 float y1 = unionArrays[1][1].getFConst();
2318 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002319 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2320 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2321 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302322 }
2323 else
2324 UNREACHABLE();
2325 break;
2326
2327 case EOpReflect:
2328 if (basicType == EbtFloat)
2329 {
2330 // genType reflect (genType I, genType N) :
2331 // For the incident vector I and surface orientation N, returns the reflection direction:
2332 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002333 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302334 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2335 for (size_t i = 0; i < maxObjectSize; i++)
2336 {
2337 float result = unionArrays[0][i].getFConst() -
2338 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002339 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302340 }
2341 }
2342 else
2343 UNREACHABLE();
2344 break;
2345
Arun Patole7fa33552015-06-10 15:15:18 +05302346 case EOpMul:
2347 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2348 (*sequence)[1]->getAsTyped()->isMatrix())
2349 {
2350 // Perform component-wise matrix multiplication.
2351 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002352 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302353 angle::Matrix<float> result =
2354 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2355 SetUnionArrayFromMatrix(result, resultArray);
2356 }
2357 else
2358 UNREACHABLE();
2359 break;
2360
2361 case EOpOuterProduct:
2362 if (basicType == EbtFloat)
2363 {
2364 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2365 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2366 resultArray = new TConstantUnion[numRows * numCols];
2367 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002368 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2369 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302370 SetUnionArrayFromMatrix(result, resultArray);
2371 }
2372 else
2373 UNREACHABLE();
2374 break;
2375
Arun Patole274f0702015-05-05 13:33:30 +05302376 default:
2377 UNREACHABLE();
2378 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2379 return nullptr;
2380 }
2381 }
2382 else if (paramsCount == 3)
2383 {
2384 //
2385 // Ternary built-in
2386 //
2387 switch (op)
2388 {
2389 case EOpClamp:
2390 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002391 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302392 for (size_t i = 0; i < maxObjectSize; i++)
2393 {
2394 switch (basicType)
2395 {
2396 case EbtFloat:
2397 {
2398 float x = unionArrays[0][i].getFConst();
2399 float min = unionArrays[1][i].getFConst();
2400 float max = unionArrays[2][i].getFConst();
2401 // Results are undefined if min > max.
2402 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002403 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302404 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002405 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302406 }
2407 break;
2408 case EbtInt:
2409 {
2410 int x = unionArrays[0][i].getIConst();
2411 int min = unionArrays[1][i].getIConst();
2412 int max = unionArrays[2][i].getIConst();
2413 // Results are undefined if min > max.
2414 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002415 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302416 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002417 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302418 }
2419 break;
2420 case EbtUInt:
2421 {
2422 unsigned int x = unionArrays[0][i].getUConst();
2423 unsigned int min = unionArrays[1][i].getUConst();
2424 unsigned int max = unionArrays[2][i].getUConst();
2425 // Results are undefined if min > max.
2426 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002427 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302428 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002429 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302430 }
2431 break;
2432 default:
2433 UNREACHABLE();
2434 break;
2435 }
2436 }
2437 }
2438 break;
2439
Arun Patolebf790422015-05-18 17:53:04 +05302440 case EOpMix:
2441 {
2442 if (basicType == EbtFloat)
2443 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002444 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302445 for (size_t i = 0; i < maxObjectSize; i++)
2446 {
2447 float x = unionArrays[0][i].getFConst();
2448 float y = unionArrays[1][i].getFConst();
2449 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2450 if (type == EbtFloat)
2451 {
2452 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2453 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002454 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302455 }
2456 else // 3rd parameter is EbtBool
2457 {
2458 ASSERT(type == EbtBool);
2459 // Selects which vector each returned component comes from.
2460 // For a component of a that is false, the corresponding component of x is returned.
2461 // For a component of a that is true, the corresponding component of y is returned.
2462 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002463 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302464 }
2465 }
2466 }
2467 else
2468 UNREACHABLE();
2469 }
2470 break;
2471
2472 case EOpSmoothStep:
2473 {
2474 if (basicType == EbtFloat)
2475 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002476 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302477 for (size_t i = 0; i < maxObjectSize; i++)
2478 {
2479 float edge0 = unionArrays[0][i].getFConst();
2480 float edge1 = unionArrays[1][i].getFConst();
2481 float x = unionArrays[2][i].getFConst();
2482 // Results are undefined if edge0 >= edge1.
2483 if (edge0 >= edge1)
2484 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002485 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302486 }
2487 else
2488 {
2489 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2490 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2491 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002492 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302493 }
2494 }
2495 }
2496 else
2497 UNREACHABLE();
2498 }
2499 break;
2500
Arun Patole1155ddd2015-06-05 18:04:36 +05302501 case EOpFaceForward:
2502 if (basicType == EbtFloat)
2503 {
2504 // genType faceforward(genType N, genType I, genType Nref) :
2505 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002506 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302507 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2508 for (size_t i = 0; i < maxObjectSize; i++)
2509 {
2510 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002511 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302512 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002513 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302514 }
2515 }
2516 else
2517 UNREACHABLE();
2518 break;
2519
2520 case EOpRefract:
2521 if (basicType == EbtFloat)
2522 {
2523 // genType refract(genType I, genType N, float eta) :
2524 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2525 // return the refraction vector. The result is computed by
2526 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2527 // if (k < 0.0)
2528 // return genType(0.0)
2529 // else
2530 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002531 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302532 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2533 for (size_t i = 0; i < maxObjectSize; i++)
2534 {
2535 float eta = unionArrays[2][i].getFConst();
2536 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2537 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002538 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302539 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002540 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302541 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2542 }
2543 }
2544 else
2545 UNREACHABLE();
2546 break;
2547
Arun Patole274f0702015-05-05 13:33:30 +05302548 default:
2549 UNREACHABLE();
2550 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2551 return nullptr;
2552 }
2553 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002554 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302555}
2556
2557// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002558TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2559{
2560 if (hashFunction == NULL || name.empty())
2561 return name;
2562 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2563 TStringStream stream;
2564 stream << HASHED_NAME_PREFIX << std::hex << number;
2565 TString hashedName = stream.str();
2566 return hashedName;
2567}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002568
2569void TIntermTraverser::updateTree()
2570{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002571 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2572 {
2573 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2574 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002575 if (!insertion.insertionsAfter.empty())
2576 {
2577 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2578 insertion.insertionsAfter);
2579 ASSERT(inserted);
2580 UNUSED_ASSERTION_VARIABLE(inserted);
2581 }
2582 if (!insertion.insertionsBefore.empty())
2583 {
2584 bool inserted =
2585 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2586 ASSERT(inserted);
2587 UNUSED_ASSERTION_VARIABLE(inserted);
2588 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002589 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002590 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2591 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002592 const NodeUpdateEntry &replacement = mReplacements[ii];
2593 ASSERT(replacement.parent);
2594 bool replaced = replacement.parent->replaceChildNode(
2595 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002596 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002597 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002598
Olli Etuahocd94ef92015-04-16 19:18:10 +03002599 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002600 {
2601 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002602 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002603 // be replaced, we need to make sure we don't update the replaced
2604 // node; instead, we update the replacement node.
2605 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2606 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002607 NodeUpdateEntry &replacement2 = mReplacements[jj];
2608 if (replacement2.parent == replacement.original)
2609 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002610 }
2611 }
2612 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002613 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2614 {
2615 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2616 ASSERT(replacement.parent);
2617 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2618 replacement.original, replacement.replacements);
2619 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002620 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002621 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002622
Jamie Madill03d863c2016-07-27 18:15:53 -04002623 clearReplacementQueue();
2624}
2625
2626void TIntermTraverser::clearReplacementQueue()
2627{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002628 mReplacements.clear();
2629 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002630 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002631}
Jamie Madill1048e432016-07-23 18:51:28 -04002632
Jamie Madill03d863c2016-07-27 18:15:53 -04002633void TIntermTraverser::queueReplacement(TIntermNode *original,
2634 TIntermNode *replacement,
2635 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002636{
Jamie Madill03d863c2016-07-27 18:15:53 -04002637 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002638}
2639
Jamie Madill03d863c2016-07-27 18:15:53 -04002640void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2641 TIntermNode *original,
2642 TIntermNode *replacement,
2643 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002644{
Jamie Madill03d863c2016-07-27 18:15:53 -04002645 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2646 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002647}