blob: ccbd80f47664b71395c8f4e52e3e98454b2dce2b [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040020#include "compiler/translator/HashNames.h"
21#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
23
24namespace
25{
26
Arun Patole9dea48f2015-04-02 11:45:09 +053027const float kPi = 3.14159265358979323846f;
28const float kDegreesToRadiansMultiplier = kPi / 180.0f;
29const float kRadiansToDegreesMultiplier = 180.0f / kPi;
30
Jamie Madillb1a85f42014-08-19 15:23:24 -040031TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
32{
33 return left > right ? left : right;
34}
35
36bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
37{
38 switch (op)
39 {
40 case EOpMul:
41 case EOpMulAssign:
42 return left.getNominalSize() == right.getNominalSize() &&
43 left.getSecondarySize() == right.getSecondarySize();
44 case EOpVectorTimesScalar:
45 case EOpVectorTimesScalarAssign:
46 return true;
47 case EOpVectorTimesMatrix:
48 return left.getNominalSize() == right.getRows();
49 case EOpVectorTimesMatrixAssign:
50 return left.getNominalSize() == right.getRows() &&
51 left.getNominalSize() == right.getCols();
52 case EOpMatrixTimesVector:
53 return left.getCols() == right.getNominalSize();
54 case EOpMatrixTimesScalar:
55 case EOpMatrixTimesScalarAssign:
56 return true;
57 case EOpMatrixTimesMatrix:
58 return left.getCols() == right.getRows();
59 case EOpMatrixTimesMatrixAssign:
Olli Etuahodcf12c72016-06-28 15:03:06 +030060 // We need to check two things:
61 // 1. The matrix multiplication step is valid.
62 // 2. The result will have the same number of columns as the lvalue.
63 return left.getCols() == right.getRows() && left.getCols() == right.getCols();
Jamie Madillb1a85f42014-08-19 15:23:24 -040064
65 default:
66 UNREACHABLE();
67 return false;
68 }
69}
70
Arun Patole274f0702015-05-05 13:33:30 +053071TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
72{
73 TConstantUnion *constUnion = new TConstantUnion[size];
74 for (unsigned int i = 0; i < size; ++i)
75 constUnion[i] = constant;
76
77 return constUnion;
78}
79
Arun Patolebf790422015-05-18 17:53:04 +053080void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
81 TInfoSink &infoSink, TConstantUnion *result)
82{
83 std::stringstream constantFoldingErrorStream;
84 constantFoldingErrorStream << "'" << GetOperatorString(op)
85 << "' operation result is undefined for the values passed in";
86 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
87
88 switch (basicType)
89 {
90 case EbtFloat :
91 result->setFConst(0.0f);
92 break;
93 case EbtInt:
94 result->setIConst(0);
95 break;
96 case EbtUInt:
97 result->setUConst(0u);
98 break;
99 case EbtBool:
100 result->setBConst(false);
101 break;
102 default:
103 break;
104 }
105}
106
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200107float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530108{
109 float result = 0.0f;
110 for (size_t i = 0; i < paramArraySize; i++)
111 {
112 float f = paramArray[i].getFConst();
113 result += f * f;
114 }
115 return sqrtf(result);
116}
117
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200118float VectorDotProduct(const TConstantUnion *paramArray1,
119 const TConstantUnion *paramArray2,
120 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530121{
122 float result = 0.0f;
123 for (size_t i = 0; i < paramArraySize; i++)
124 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
125 return result;
126}
127
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200128TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
129 const TIntermTyped *originalNode,
130 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300131{
132 if (constArray == nullptr)
133 {
134 return nullptr;
135 }
136 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200137 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300138 folded->setLine(originalNode->getLine());
139 return folded;
140}
141
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200142angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
143 const unsigned int &rows,
144 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530145{
146 std::vector<float> elements;
147 for (size_t i = 0; i < rows * cols; i++)
148 elements.push_back(paramArray[i].getFConst());
149 // Transpose is used since the Matrix constructor expects arguments in row-major order,
150 // whereas the paramArray is in column-major order.
151 return angle::Matrix<float>(elements, rows, cols).transpose();
152}
153
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200154angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530155{
156 std::vector<float> elements;
157 for (size_t i = 0; i < size * size; i++)
158 elements.push_back(paramArray[i].getFConst());
159 // Transpose is used since the Matrix constructor expects arguments in row-major order,
160 // whereas the paramArray is in column-major order.
161 return angle::Matrix<float>(elements, size).transpose();
162}
163
164void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
165{
166 // Transpose is used since the input Matrix is in row-major order,
167 // whereas the actual result should be in column-major order.
168 angle::Matrix<float> result = m.transpose();
169 std::vector<float> resultElements = result.elements();
170 for (size_t i = 0; i < resultElements.size(); i++)
171 resultArray[i].setFConst(resultElements[i]);
172}
173
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174} // namespace anonymous
175
176
177////////////////////////////////////////////////////////////////
178//
179// Member functions of the nodes used for building the tree.
180//
181////////////////////////////////////////////////////////////////
182
Olli Etuahod2a67b92014-10-21 16:42:57 +0300183void TIntermTyped::setTypePreservePrecision(const TType &t)
184{
185 TPrecision precision = getPrecision();
186 mType = t;
187 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
188 mType.setPrecision(precision);
189}
190
Jamie Madillb1a85f42014-08-19 15:23:24 -0400191#define REPLACE_IF_IS(node, type, original, replacement) \
192 if (node == original) { \
193 node = static_cast<type *>(replacement); \
194 return true; \
195 }
196
197bool TIntermLoop::replaceChildNode(
198 TIntermNode *original, TIntermNode *replacement)
199{
200 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
201 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
202 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200203 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400204 return false;
205}
206
Jamie Madillb1a85f42014-08-19 15:23:24 -0400207bool TIntermBranch::replaceChildNode(
208 TIntermNode *original, TIntermNode *replacement)
209{
210 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
211 return false;
212}
213
Jamie Madillb1a85f42014-08-19 15:23:24 -0400214bool TIntermBinary::replaceChildNode(
215 TIntermNode *original, TIntermNode *replacement)
216{
217 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
218 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
219 return false;
220}
221
Jamie Madillb1a85f42014-08-19 15:23:24 -0400222bool TIntermUnary::replaceChildNode(
223 TIntermNode *original, TIntermNode *replacement)
224{
225 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
226 return false;
227}
228
Jamie Madillb1a85f42014-08-19 15:23:24 -0400229bool TIntermAggregate::replaceChildNode(
230 TIntermNode *original, TIntermNode *replacement)
231{
232 for (size_t ii = 0; ii < mSequence.size(); ++ii)
233 {
234 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
235 }
236 return false;
237}
238
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300239bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
240{
241 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
242 {
243 if (*it == original)
244 {
245 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300246 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300247 return true;
248 }
249 }
250 return false;
251}
252
Olli Etuahoa6f22092015-05-08 18:31:10 +0300253bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
254{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300255 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300256 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300257 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300258 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300259 auto it = mSequence.begin() + position;
260 mSequence.insert(it, insertions.begin(), insertions.end());
261 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300262}
263
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200264bool TIntermAggregate::areChildrenConstQualified()
265{
266 for (TIntermNode *&child : mSequence)
267 {
268 TIntermTyped *typed = child->getAsTyped();
269 if (typed && typed->getQualifier() != EvqConst)
270 {
271 return false;
272 }
273 }
274 return true;
275}
276
Olli Etuahod2a67b92014-10-21 16:42:57 +0300277void TIntermAggregate::setPrecisionFromChildren()
278{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300279 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300280 if (getBasicType() == EbtBool)
281 {
282 mType.setPrecision(EbpUndefined);
283 return;
284 }
285
286 TPrecision precision = EbpUndefined;
287 TIntermSequence::iterator childIter = mSequence.begin();
288 while (childIter != mSequence.end())
289 {
290 TIntermTyped *typed = (*childIter)->getAsTyped();
291 if (typed)
292 precision = GetHigherPrecision(typed->getPrecision(), precision);
293 ++childIter;
294 }
295 mType.setPrecision(precision);
296}
297
298void TIntermAggregate::setBuiltInFunctionPrecision()
299{
300 // All built-ins returning bool should be handled as ops, not functions.
301 ASSERT(getBasicType() != EbtBool);
302
303 TPrecision precision = EbpUndefined;
304 TIntermSequence::iterator childIter = mSequence.begin();
305 while (childIter != mSequence.end())
306 {
307 TIntermTyped *typed = (*childIter)->getAsTyped();
308 // ESSL spec section 8: texture functions get their precision from the sampler.
309 if (typed && IsSampler(typed->getBasicType()))
310 {
311 precision = typed->getPrecision();
312 break;
313 }
314 ++childIter;
315 }
316 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
317 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300318 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300319 mType.setPrecision(EbpHigh);
320 else
321 mType.setPrecision(precision);
322}
323
Jamie Madillb1a85f42014-08-19 15:23:24 -0400324bool TIntermSelection::replaceChildNode(
325 TIntermNode *original, TIntermNode *replacement)
326{
327 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
328 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
329 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
330 return false;
331}
332
Olli Etuahoa3a36662015-02-17 13:46:51 +0200333bool TIntermSwitch::replaceChildNode(
334 TIntermNode *original, TIntermNode *replacement)
335{
336 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
337 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
338 return false;
339}
340
341bool TIntermCase::replaceChildNode(
342 TIntermNode *original, TIntermNode *replacement)
343{
344 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
345 return false;
346}
347
Olli Etuahod7a25242015-08-18 13:49:45 +0300348TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
349{
350 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
351 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
352 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
353 mLine = node.mLine;
354}
355
Olli Etuahod4f4c112016-04-15 15:11:24 +0300356bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
357{
358 TIntermAggregate *constructor = getAsAggregate();
359 if (!constructor || !constructor->isConstructor())
360 {
361 return false;
362 }
363 for (TIntermNode *&node : *constructor->getSequence())
364 {
365 if (!node->getAsConstantUnion())
366 return false;
367 }
368 return true;
369}
370
Olli Etuahod7a25242015-08-18 13:49:45 +0300371TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
372{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200373 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300374}
375
376TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
377 : TIntermOperator(node),
378 mName(node.mName),
379 mUserDefined(node.mUserDefined),
380 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300381 mUseEmulatedFunction(node.mUseEmulatedFunction),
382 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
383{
384 for (TIntermNode *child : node.mSequence)
385 {
386 TIntermTyped *typedChild = child->getAsTyped();
387 ASSERT(typedChild != nullptr);
388 TIntermTyped *childCopy = typedChild->deepCopy();
389 mSequence.push_back(childCopy);
390 }
391}
392
393TIntermBinary::TIntermBinary(const TIntermBinary &node)
394 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
395{
396 TIntermTyped *leftCopy = node.mLeft->deepCopy();
397 TIntermTyped *rightCopy = node.mRight->deepCopy();
398 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
399 mLeft = leftCopy;
400 mRight = rightCopy;
401}
402
403TIntermUnary::TIntermUnary(const TIntermUnary &node)
404 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
405{
406 TIntermTyped *operandCopy = node.mOperand->deepCopy();
407 ASSERT(operandCopy != nullptr);
408 mOperand = operandCopy;
409}
410
411TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
412{
413 // Only supported for ternary nodes, not if statements.
414 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
415 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
416 ASSERT(trueTyped != nullptr);
417 ASSERT(falseTyped != nullptr);
418 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
419 TIntermTyped *trueCopy = trueTyped->deepCopy();
420 TIntermTyped *falseCopy = falseTyped->deepCopy();
421 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
422 mCondition = conditionCopy;
423 mTrueBlock = trueCopy;
424 mFalseBlock = falseCopy;
425}
426
Jamie Madillb1a85f42014-08-19 15:23:24 -0400427//
428// Say whether or not an operation node changes the value of a variable.
429//
430bool TIntermOperator::isAssignment() const
431{
432 switch (mOp)
433 {
434 case EOpPostIncrement:
435 case EOpPostDecrement:
436 case EOpPreIncrement:
437 case EOpPreDecrement:
438 case EOpAssign:
439 case EOpAddAssign:
440 case EOpSubAssign:
441 case EOpMulAssign:
442 case EOpVectorTimesMatrixAssign:
443 case EOpVectorTimesScalarAssign:
444 case EOpMatrixTimesScalarAssign:
445 case EOpMatrixTimesMatrixAssign:
446 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200447 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200448 case EOpBitShiftLeftAssign:
449 case EOpBitShiftRightAssign:
450 case EOpBitwiseAndAssign:
451 case EOpBitwiseXorAssign:
452 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400453 return true;
454 default:
455 return false;
456 }
457}
458
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300459bool TIntermOperator::isMultiplication() const
460{
461 switch (mOp)
462 {
463 case EOpMul:
464 case EOpMatrixTimesMatrix:
465 case EOpMatrixTimesVector:
466 case EOpMatrixTimesScalar:
467 case EOpVectorTimesMatrix:
468 case EOpVectorTimesScalar:
469 return true;
470 default:
471 return false;
472 }
473}
474
Jamie Madillb1a85f42014-08-19 15:23:24 -0400475//
476// returns true if the operator is for one of the constructors
477//
478bool TIntermOperator::isConstructor() const
479{
480 switch (mOp)
481 {
482 case EOpConstructVec2:
483 case EOpConstructVec3:
484 case EOpConstructVec4:
485 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400486 case EOpConstructMat2x3:
487 case EOpConstructMat2x4:
488 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400489 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400490 case EOpConstructMat3x4:
491 case EOpConstructMat4x2:
492 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400493 case EOpConstructMat4:
494 case EOpConstructFloat:
495 case EOpConstructIVec2:
496 case EOpConstructIVec3:
497 case EOpConstructIVec4:
498 case EOpConstructInt:
499 case EOpConstructUVec2:
500 case EOpConstructUVec3:
501 case EOpConstructUVec4:
502 case EOpConstructUInt:
503 case EOpConstructBVec2:
504 case EOpConstructBVec3:
505 case EOpConstructBVec4:
506 case EOpConstructBool:
507 case EOpConstructStruct:
508 return true;
509 default:
510 return false;
511 }
512}
513
514//
515// Make sure the type of a unary operator is appropriate for its
516// combination of operation and operand type.
517//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200518void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400519{
520 switch (mOp)
521 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200522 case EOpFloatBitsToInt:
523 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200524 case EOpIntBitsToFloat:
525 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200526 case EOpPackSnorm2x16:
527 case EOpPackUnorm2x16:
528 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200529 case EOpUnpackSnorm2x16:
530 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200531 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530532 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200533 case EOpUnpackHalf2x16:
534 mType.setPrecision(EbpMedium);
535 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400536 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200537 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400538 }
539
Olli Etuahof6c694b2015-03-26 14:50:53 +0200540 if (funcReturnType != nullptr)
541 {
542 if (funcReturnType->getBasicType() == EbtBool)
543 {
544 // Bool types should not have precision.
545 setType(*funcReturnType);
546 }
547 else
548 {
549 // Precision of the node has been set based on the operand.
550 setTypePreservePrecision(*funcReturnType);
551 }
552 }
553
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200554 if (mOperand->getQualifier() == EvqConst)
555 mType.setQualifier(EvqConst);
556 else
557 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400558}
559
560//
561// Establishes the type of the resultant operation, as well as
562// makes the operator the correct one for the operands.
563//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200564// For lots of operations it should already be established that the operand
565// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400566//
567bool TIntermBinary::promote(TInfoSink &infoSink)
568{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200569 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400570
Jamie Madillb1a85f42014-08-19 15:23:24 -0400571 //
572 // Base assumption: just make the type the same as the left
573 // operand. Then only deviations from this need be coded.
574 //
575 setType(mLeft->getType());
576
577 // The result gets promoted to the highest precision.
578 TPrecision higherPrecision = GetHigherPrecision(
579 mLeft->getPrecision(), mRight->getPrecision());
580 getTypePointer()->setPrecision(higherPrecision);
581
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200582 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400583 // Binary operations results in temporary variables unless both
584 // operands are const.
585 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
586 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200587 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400588 getTypePointer()->setQualifier(EvqTemporary);
589 }
590
591 const int nominalSize =
592 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
593
594 //
595 // All scalars or structs. Code after this test assumes this case is removed!
596 //
597 if (nominalSize == 1)
598 {
599 switch (mOp)
600 {
601 //
602 // Promote to conditional
603 //
604 case EOpEqual:
605 case EOpNotEqual:
606 case EOpLessThan:
607 case EOpGreaterThan:
608 case EOpLessThanEqual:
609 case EOpGreaterThanEqual:
610 setType(TType(EbtBool, EbpUndefined));
611 break;
612
613 //
614 // And and Or operate on conditionals
615 //
616 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200617 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400618 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200619 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400620 setType(TType(EbtBool, EbpUndefined));
621 break;
622
623 default:
624 break;
625 }
626 return true;
627 }
628
629 // If we reach here, at least one of the operands is vector or matrix.
630 // The other operand could be a scalar, vector, or matrix.
631 // Can these two operands be combined?
632 //
633 TBasicType basicType = mLeft->getBasicType();
634 switch (mOp)
635 {
636 case EOpMul:
637 if (!mLeft->isMatrix() && mRight->isMatrix())
638 {
639 if (mLeft->isVector())
640 {
641 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200642 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700643 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400644 }
645 else
646 {
647 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200648 setType(TType(basicType, higherPrecision, resultQualifier,
649 static_cast<unsigned char>(mRight->getCols()),
650 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400651 }
652 }
653 else if (mLeft->isMatrix() && !mRight->isMatrix())
654 {
655 if (mRight->isVector())
656 {
657 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200658 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700659 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400660 }
661 else
662 {
663 mOp = EOpMatrixTimesScalar;
664 }
665 }
666 else if (mLeft->isMatrix() && mRight->isMatrix())
667 {
668 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200669 setType(TType(basicType, higherPrecision, resultQualifier,
670 static_cast<unsigned char>(mRight->getCols()),
671 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400672 }
673 else if (!mLeft->isMatrix() && !mRight->isMatrix())
674 {
675 if (mLeft->isVector() && mRight->isVector())
676 {
677 // leave as component product
678 }
679 else if (mLeft->isVector() || mRight->isVector())
680 {
681 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200682 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700683 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400684 }
685 }
686 else
687 {
688 infoSink.info.message(EPrefixInternalError, getLine(),
689 "Missing elses");
690 return false;
691 }
692
693 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
694 {
695 return false;
696 }
697 break;
698
699 case EOpMulAssign:
700 if (!mLeft->isMatrix() && mRight->isMatrix())
701 {
702 if (mLeft->isVector())
703 {
704 mOp = EOpVectorTimesMatrixAssign;
705 }
706 else
707 {
708 return false;
709 }
710 }
711 else if (mLeft->isMatrix() && !mRight->isMatrix())
712 {
713 if (mRight->isVector())
714 {
715 return false;
716 }
717 else
718 {
719 mOp = EOpMatrixTimesScalarAssign;
720 }
721 }
722 else if (mLeft->isMatrix() && mRight->isMatrix())
723 {
724 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200725 setType(TType(basicType, higherPrecision, resultQualifier,
726 static_cast<unsigned char>(mRight->getCols()),
727 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728 }
729 else if (!mLeft->isMatrix() && !mRight->isMatrix())
730 {
731 if (mLeft->isVector() && mRight->isVector())
732 {
733 // leave as component product
734 }
735 else if (mLeft->isVector() || mRight->isVector())
736 {
737 if (!mLeft->isVector())
738 return false;
739 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200740 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700741 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400742 }
743 }
744 else
745 {
746 infoSink.info.message(EPrefixInternalError, getLine(),
747 "Missing elses");
748 return false;
749 }
750
751 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
752 {
753 return false;
754 }
755 break;
756
757 case EOpAssign:
758 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200759 // No more additional checks are needed.
760 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
761 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
762 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400763 case EOpAdd:
764 case EOpSub:
765 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200766 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200767 case EOpBitShiftLeft:
768 case EOpBitShiftRight:
769 case EOpBitwiseAnd:
770 case EOpBitwiseXor:
771 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400772 case EOpAddAssign:
773 case EOpSubAssign:
774 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200775 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200776 case EOpBitShiftLeftAssign:
777 case EOpBitShiftRightAssign:
778 case EOpBitwiseAndAssign:
779 case EOpBitwiseXorAssign:
780 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400781 if ((mLeft->isMatrix() && mRight->isVector()) ||
782 (mLeft->isVector() && mRight->isMatrix()))
783 {
784 return false;
785 }
786
787 // Are the sizes compatible?
788 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
789 mLeft->getSecondarySize() != mRight->getSecondarySize())
790 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200791 // If the nominal sizes of operands do not match:
792 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400793 if (!mLeft->isScalar() && !mRight->isScalar())
794 return false;
795
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200796 // In the case of compound assignment other than multiply-assign,
797 // the right side needs to be a scalar. Otherwise a vector/matrix
798 // would be assigned to a scalar. A scalar can't be shifted by a
799 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200800 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200801 (isAssignment() ||
802 mOp == EOpBitShiftLeft ||
803 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200804 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400805 }
806
807 {
808 const int secondarySize = std::max(
809 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200810 setType(TType(basicType, higherPrecision, resultQualifier,
811 static_cast<unsigned char>(nominalSize),
812 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200813 if (mLeft->isArray())
814 {
815 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
816 mType.setArraySize(mLeft->getArraySize());
817 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400818 }
819 break;
820
821 case EOpEqual:
822 case EOpNotEqual:
823 case EOpLessThan:
824 case EOpGreaterThan:
825 case EOpLessThanEqual:
826 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200827 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
828 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400829 setType(TType(EbtBool, EbpUndefined));
830 break;
831
832 default:
833 return false;
834 }
835 return true;
836}
837
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300838TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
839{
840 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
841 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
842 if (leftConstant == nullptr || rightConstant == nullptr)
843 {
844 return nullptr;
845 }
846 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200847
848 // Nodes may be constant folded without being qualified as constant.
849 TQualifier resultQualifier = EvqConst;
850 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
851 {
852 resultQualifier = EvqTemporary;
853 }
854 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300855}
856
Olli Etuaho95310b02015-06-02 17:43:38 +0300857TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
858{
859 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
860 if (operandConstant == nullptr)
861 {
862 return nullptr;
863 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530864
865 TConstantUnion *constArray = nullptr;
866 switch (mOp)
867 {
868 case EOpAny:
869 case EOpAll:
870 case EOpLength:
871 case EOpTranspose:
872 case EOpDeterminant:
873 case EOpInverse:
874 case EOpPackSnorm2x16:
875 case EOpUnpackSnorm2x16:
876 case EOpPackUnorm2x16:
877 case EOpUnpackUnorm2x16:
878 case EOpPackHalf2x16:
879 case EOpUnpackHalf2x16:
880 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
881 break;
882 default:
883 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
884 break;
885 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200886
887 // Nodes may be constant folded without being qualified as constant.
888 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
889 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300890}
891
892TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
893{
894 // Make sure that all params are constant before actual constant folding.
895 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300896 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300897 if (param->getAsConstantUnion() == nullptr)
898 {
899 return nullptr;
900 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300901 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200902 TConstantUnion *constArray = nullptr;
903 if (isConstructor())
904 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
905 else
906 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200907
908 // Nodes may be constant folded without being qualified as constant.
909 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
910 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300911}
912
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913//
914// The fold functions see if an operation on a constant can be done in place,
915// without generating run-time code.
916//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300917// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400918//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300919TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
920{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200921 const TConstantUnion *leftArray = getUnionArrayPointer();
922 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300923
924 if (!leftArray)
925 return nullptr;
926 if (!rightArray)
927 return nullptr;
928
929 size_t objectSize = getType().getObjectSize();
930
931 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
932 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
933 {
934 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
935 }
936 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
937 {
938 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
939 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
940 objectSize = rightNode->getType().getObjectSize();
941 }
942
943 TConstantUnion *resultArray = nullptr;
944
945 switch(op)
946 {
947 case EOpAdd:
948 resultArray = new TConstantUnion[objectSize];
949 for (size_t i = 0; i < objectSize; i++)
950 resultArray[i] = leftArray[i] + rightArray[i];
951 break;
952 case EOpSub:
953 resultArray = new TConstantUnion[objectSize];
954 for (size_t i = 0; i < objectSize; i++)
955 resultArray[i] = leftArray[i] - rightArray[i];
956 break;
957
958 case EOpMul:
959 case EOpVectorTimesScalar:
960 case EOpMatrixTimesScalar:
961 resultArray = new TConstantUnion[objectSize];
962 for (size_t i = 0; i < objectSize; i++)
963 resultArray[i] = leftArray[i] * rightArray[i];
964 break;
965
966 case EOpMatrixTimesMatrix:
967 {
968 if (getType().getBasicType() != EbtFloat ||
969 rightNode->getBasicType() != EbtFloat)
970 {
971 infoSink.info.message(
972 EPrefixInternalError, getLine(),
973 "Constant Folding cannot be done for matrix multiply");
974 return nullptr;
975 }
976
977 const int leftCols = getCols();
978 const int leftRows = getRows();
979 const int rightCols = rightNode->getType().getCols();
980 const int rightRows = rightNode->getType().getRows();
981 const int resultCols = rightCols;
982 const int resultRows = leftRows;
983
984 resultArray = new TConstantUnion[resultCols * resultRows];
985 for (int row = 0; row < resultRows; row++)
986 {
987 for (int column = 0; column < resultCols; column++)
988 {
989 resultArray[resultRows * column + row].setFConst(0.0f);
990 for (int i = 0; i < leftCols; i++)
991 {
992 resultArray[resultRows * column + row].setFConst(
993 resultArray[resultRows * column + row].getFConst() +
994 leftArray[i * leftRows + row].getFConst() *
995 rightArray[column * rightRows + i].getFConst());
996 }
997 }
998 }
999 }
1000 break;
1001
1002 case EOpDiv:
1003 case EOpIMod:
1004 {
1005 resultArray = new TConstantUnion[objectSize];
1006 for (size_t i = 0; i < objectSize; i++)
1007 {
1008 switch (getType().getBasicType())
1009 {
1010 case EbtFloat:
1011 if (rightArray[i] == 0.0f)
1012 {
1013 infoSink.info.message(EPrefixWarning, getLine(),
1014 "Divide by zero error during constant folding");
1015 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1016 }
1017 else
1018 {
1019 ASSERT(op == EOpDiv);
1020 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1021 }
1022 break;
1023
1024 case EbtInt:
1025 if (rightArray[i] == 0)
1026 {
1027 infoSink.info.message(EPrefixWarning, getLine(),
1028 "Divide by zero error during constant folding");
1029 resultArray[i].setIConst(INT_MAX);
1030 }
1031 else
1032 {
1033 if (op == EOpDiv)
1034 {
1035 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1036 }
1037 else
1038 {
1039 ASSERT(op == EOpIMod);
1040 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1041 }
1042 }
1043 break;
1044
1045 case EbtUInt:
1046 if (rightArray[i] == 0)
1047 {
1048 infoSink.info.message(EPrefixWarning, getLine(),
1049 "Divide by zero error during constant folding");
1050 resultArray[i].setUConst(UINT_MAX);
1051 }
1052 else
1053 {
1054 if (op == EOpDiv)
1055 {
1056 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1057 }
1058 else
1059 {
1060 ASSERT(op == EOpIMod);
1061 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1062 }
1063 }
1064 break;
1065
1066 default:
1067 infoSink.info.message(EPrefixInternalError, getLine(),
1068 "Constant folding cannot be done for \"/\"");
1069 return nullptr;
1070 }
1071 }
1072 }
1073 break;
1074
1075 case EOpMatrixTimesVector:
1076 {
1077 if (rightNode->getBasicType() != EbtFloat)
1078 {
1079 infoSink.info.message(EPrefixInternalError, getLine(),
1080 "Constant Folding cannot be done for matrix times vector");
1081 return nullptr;
1082 }
1083
1084 const int matrixCols = getCols();
1085 const int matrixRows = getRows();
1086
1087 resultArray = new TConstantUnion[matrixRows];
1088
1089 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1090 {
1091 resultArray[matrixRow].setFConst(0.0f);
1092 for (int col = 0; col < matrixCols; col++)
1093 {
1094 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1095 leftArray[col * matrixRows + matrixRow].getFConst() *
1096 rightArray[col].getFConst());
1097 }
1098 }
1099 }
1100 break;
1101
1102 case EOpVectorTimesMatrix:
1103 {
1104 if (getType().getBasicType() != EbtFloat)
1105 {
1106 infoSink.info.message(EPrefixInternalError, getLine(),
1107 "Constant Folding cannot be done for vector times matrix");
1108 return nullptr;
1109 }
1110
1111 const int matrixCols = rightNode->getType().getCols();
1112 const int matrixRows = rightNode->getType().getRows();
1113
1114 resultArray = new TConstantUnion[matrixCols];
1115
1116 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1117 {
1118 resultArray[matrixCol].setFConst(0.0f);
1119 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1120 {
1121 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1122 leftArray[matrixRow].getFConst() *
1123 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1124 }
1125 }
1126 }
1127 break;
1128
1129 case EOpLogicalAnd:
1130 {
1131 resultArray = new TConstantUnion[objectSize];
1132 for (size_t i = 0; i < objectSize; i++)
1133 {
1134 resultArray[i] = leftArray[i] && rightArray[i];
1135 }
1136 }
1137 break;
1138
1139 case EOpLogicalOr:
1140 {
1141 resultArray = new TConstantUnion[objectSize];
1142 for (size_t i = 0; i < objectSize; i++)
1143 {
1144 resultArray[i] = leftArray[i] || rightArray[i];
1145 }
1146 }
1147 break;
1148
1149 case EOpLogicalXor:
1150 {
1151 resultArray = new TConstantUnion[objectSize];
1152 for (size_t i = 0; i < objectSize; i++)
1153 {
1154 switch (getType().getBasicType())
1155 {
1156 case EbtBool:
1157 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1158 break;
1159 default:
1160 UNREACHABLE();
1161 break;
1162 }
1163 }
1164 }
1165 break;
1166
1167 case EOpBitwiseAnd:
1168 resultArray = new TConstantUnion[objectSize];
1169 for (size_t i = 0; i < objectSize; i++)
1170 resultArray[i] = leftArray[i] & rightArray[i];
1171 break;
1172 case EOpBitwiseXor:
1173 resultArray = new TConstantUnion[objectSize];
1174 for (size_t i = 0; i < objectSize; i++)
1175 resultArray[i] = leftArray[i] ^ rightArray[i];
1176 break;
1177 case EOpBitwiseOr:
1178 resultArray = new TConstantUnion[objectSize];
1179 for (size_t i = 0; i < objectSize; i++)
1180 resultArray[i] = leftArray[i] | rightArray[i];
1181 break;
1182 case EOpBitShiftLeft:
1183 resultArray = new TConstantUnion[objectSize];
1184 for (size_t i = 0; i < objectSize; i++)
1185 resultArray[i] = leftArray[i] << rightArray[i];
1186 break;
1187 case EOpBitShiftRight:
1188 resultArray = new TConstantUnion[objectSize];
1189 for (size_t i = 0; i < objectSize; i++)
1190 resultArray[i] = leftArray[i] >> rightArray[i];
1191 break;
1192
1193 case EOpLessThan:
1194 ASSERT(objectSize == 1);
1195 resultArray = new TConstantUnion[1];
1196 resultArray->setBConst(*leftArray < *rightArray);
1197 break;
1198
1199 case EOpGreaterThan:
1200 ASSERT(objectSize == 1);
1201 resultArray = new TConstantUnion[1];
1202 resultArray->setBConst(*leftArray > *rightArray);
1203 break;
1204
1205 case EOpLessThanEqual:
1206 ASSERT(objectSize == 1);
1207 resultArray = new TConstantUnion[1];
1208 resultArray->setBConst(!(*leftArray > *rightArray));
1209 break;
1210
1211 case EOpGreaterThanEqual:
1212 ASSERT(objectSize == 1);
1213 resultArray = new TConstantUnion[1];
1214 resultArray->setBConst(!(*leftArray < *rightArray));
1215 break;
1216
1217 case EOpEqual:
1218 case EOpNotEqual:
1219 {
1220 resultArray = new TConstantUnion[1];
1221 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001222 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001223 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001224 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001225 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001226 equal = false;
1227 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001228 }
1229 }
1230 if (op == EOpEqual)
1231 {
1232 resultArray->setBConst(equal);
1233 }
1234 else
1235 {
1236 resultArray->setBConst(!equal);
1237 }
1238 }
1239 break;
1240
1241 default:
1242 infoSink.info.message(
1243 EPrefixInternalError, getLine(),
1244 "Invalid operator for constant folding");
1245 return nullptr;
1246 }
1247 return resultArray;
1248}
1249
1250//
1251// The fold functions see if an operation on a constant can be done in place,
1252// without generating run-time code.
1253//
Olli Etuaho95310b02015-06-02 17:43:38 +03001254// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001255//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301256TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001257{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301258 //
1259 // Do operations where the return type has a different number of components compared to the operand type.
1260 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001261
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001262 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301263 if (!operandArray)
1264 return nullptr;
1265
1266 size_t objectSize = getType().getObjectSize();
1267 TConstantUnion *resultArray = nullptr;
1268 switch (op)
1269 {
1270 case EOpAny:
1271 if (getType().getBasicType() == EbtBool)
1272 {
1273 resultArray = new TConstantUnion();
1274 resultArray->setBConst(false);
1275 for (size_t i = 0; i < objectSize; i++)
1276 {
1277 if (operandArray[i].getBConst())
1278 {
1279 resultArray->setBConst(true);
1280 break;
1281 }
1282 }
1283 break;
1284 }
1285 else
1286 {
1287 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1288 return nullptr;
1289 }
1290
1291 case EOpAll:
1292 if (getType().getBasicType() == EbtBool)
1293 {
1294 resultArray = new TConstantUnion();
1295 resultArray->setBConst(true);
1296 for (size_t i = 0; i < objectSize; i++)
1297 {
1298 if (!operandArray[i].getBConst())
1299 {
1300 resultArray->setBConst(false);
1301 break;
1302 }
1303 }
1304 break;
1305 }
1306 else
1307 {
1308 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1309 return nullptr;
1310 }
1311
1312 case EOpLength:
1313 if (getType().getBasicType() == EbtFloat)
1314 {
1315 resultArray = new TConstantUnion();
1316 resultArray->setFConst(VectorLength(operandArray, objectSize));
1317 break;
1318 }
1319 else
1320 {
1321 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1322 return nullptr;
1323 }
1324
1325 case EOpTranspose:
1326 if (getType().getBasicType() == EbtFloat)
1327 {
1328 resultArray = new TConstantUnion[objectSize];
1329 angle::Matrix<float> result =
1330 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1331 SetUnionArrayFromMatrix(result, resultArray);
1332 break;
1333 }
1334 else
1335 {
1336 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1337 return nullptr;
1338 }
1339
1340 case EOpDeterminant:
1341 if (getType().getBasicType() == EbtFloat)
1342 {
1343 unsigned int size = getType().getNominalSize();
1344 ASSERT(size >= 2 && size <= 4);
1345 resultArray = new TConstantUnion();
1346 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1347 break;
1348 }
1349 else
1350 {
1351 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1352 return nullptr;
1353 }
1354
1355 case EOpInverse:
1356 if (getType().getBasicType() == EbtFloat)
1357 {
1358 unsigned int size = getType().getNominalSize();
1359 ASSERT(size >= 2 && size <= 4);
1360 resultArray = new TConstantUnion[objectSize];
1361 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1362 SetUnionArrayFromMatrix(result, resultArray);
1363 break;
1364 }
1365 else
1366 {
1367 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1368 return nullptr;
1369 }
1370
1371 case EOpPackSnorm2x16:
1372 if (getType().getBasicType() == EbtFloat)
1373 {
1374 ASSERT(getType().getNominalSize() == 2);
1375 resultArray = new TConstantUnion();
1376 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1377 break;
1378 }
1379 else
1380 {
1381 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1382 return nullptr;
1383 }
1384
1385 case EOpUnpackSnorm2x16:
1386 if (getType().getBasicType() == EbtUInt)
1387 {
1388 resultArray = new TConstantUnion[2];
1389 float f1, f2;
1390 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1391 resultArray[0].setFConst(f1);
1392 resultArray[1].setFConst(f2);
1393 break;
1394 }
1395 else
1396 {
1397 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1398 return nullptr;
1399 }
1400
1401 case EOpPackUnorm2x16:
1402 if (getType().getBasicType() == EbtFloat)
1403 {
1404 ASSERT(getType().getNominalSize() == 2);
1405 resultArray = new TConstantUnion();
1406 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1407 break;
1408 }
1409 else
1410 {
1411 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1412 return nullptr;
1413 }
1414
1415 case EOpUnpackUnorm2x16:
1416 if (getType().getBasicType() == EbtUInt)
1417 {
1418 resultArray = new TConstantUnion[2];
1419 float f1, f2;
1420 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1421 resultArray[0].setFConst(f1);
1422 resultArray[1].setFConst(f2);
1423 break;
1424 }
1425 else
1426 {
1427 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1428 return nullptr;
1429 }
1430
1431 case EOpPackHalf2x16:
1432 if (getType().getBasicType() == EbtFloat)
1433 {
1434 ASSERT(getType().getNominalSize() == 2);
1435 resultArray = new TConstantUnion();
1436 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1437 break;
1438 }
1439 else
1440 {
1441 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1442 return nullptr;
1443 }
1444
1445 case EOpUnpackHalf2x16:
1446 if (getType().getBasicType() == EbtUInt)
1447 {
1448 resultArray = new TConstantUnion[2];
1449 float f1, f2;
1450 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1451 resultArray[0].setFConst(f1);
1452 resultArray[1].setFConst(f2);
1453 break;
1454 }
1455 else
1456 {
1457 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1458 return nullptr;
1459 }
1460 break;
1461
1462 default:
1463 break;
1464 }
1465
1466 return resultArray;
1467}
1468
1469TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1470{
1471 //
1472 // Do unary operations where the return type is the same as operand type.
1473 //
1474
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001475 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001476 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301477 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001478
1479 size_t objectSize = getType().getObjectSize();
1480
Arun Patoleab2b9a22015-07-06 18:27:56 +05301481 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1482 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301483 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301484 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301485 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301486 case EOpNegative:
1487 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301488 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301489 case EbtFloat:
1490 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301491 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301492 case EbtInt:
1493 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301494 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301495 case EbtUInt:
1496 resultArray[i].setUConst(static_cast<unsigned int>(
1497 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301498 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301499 default:
1500 infoSink.info.message(
1501 EPrefixInternalError, getLine(),
1502 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301503 return nullptr;
1504 }
1505 break;
1506
Arun Patoleab2b9a22015-07-06 18:27:56 +05301507 case EOpPositive:
1508 switch (getType().getBasicType())
1509 {
1510 case EbtFloat:
1511 resultArray[i].setFConst(operandArray[i].getFConst());
1512 break;
1513 case EbtInt:
1514 resultArray[i].setIConst(operandArray[i].getIConst());
1515 break;
1516 case EbtUInt:
1517 resultArray[i].setUConst(static_cast<unsigned int>(
1518 static_cast<int>(operandArray[i].getUConst())));
1519 break;
1520 default:
1521 infoSink.info.message(
1522 EPrefixInternalError, getLine(),
1523 "Unary operation not folded into constant");
1524 return nullptr;
1525 }
1526 break;
1527
1528 case EOpLogicalNot:
1529 // this code is written for possible future use,
1530 // will not get executed currently
1531 switch (getType().getBasicType())
1532 {
1533 case EbtBool:
1534 resultArray[i].setBConst(!operandArray[i].getBConst());
1535 break;
1536 default:
1537 infoSink.info.message(
1538 EPrefixInternalError, getLine(),
1539 "Unary operation not folded into constant");
1540 return nullptr;
1541 }
1542 break;
1543
1544 case EOpBitwiseNot:
1545 switch (getType().getBasicType())
1546 {
1547 case EbtInt:
1548 resultArray[i].setIConst(~operandArray[i].getIConst());
1549 break;
1550 case EbtUInt:
1551 resultArray[i].setUConst(~operandArray[i].getUConst());
1552 break;
1553 default:
1554 infoSink.info.message(
1555 EPrefixInternalError, getLine(),
1556 "Unary operation not folded into constant");
1557 return nullptr;
1558 }
1559 break;
1560
1561 case EOpRadians:
1562 if (getType().getBasicType() == EbtFloat)
1563 {
1564 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1565 break;
1566 }
1567 infoSink.info.message(
1568 EPrefixInternalError, getLine(),
1569 "Unary operation not folded into constant");
1570 return nullptr;
1571
1572 case EOpDegrees:
1573 if (getType().getBasicType() == EbtFloat)
1574 {
1575 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1576 break;
1577 }
1578 infoSink.info.message(
1579 EPrefixInternalError, getLine(),
1580 "Unary operation not folded into constant");
1581 return nullptr;
1582
1583 case EOpSin:
1584 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1585 return nullptr;
1586 break;
1587
1588 case EOpCos:
1589 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1590 return nullptr;
1591 break;
1592
1593 case EOpTan:
1594 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1595 return nullptr;
1596 break;
1597
1598 case EOpAsin:
1599 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1600 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1601 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1602 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1603 return nullptr;
1604 break;
1605
1606 case EOpAcos:
1607 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1608 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1609 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1610 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1611 return nullptr;
1612 break;
1613
1614 case EOpAtan:
1615 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1616 return nullptr;
1617 break;
1618
1619 case EOpSinh:
1620 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1621 return nullptr;
1622 break;
1623
1624 case EOpCosh:
1625 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1626 return nullptr;
1627 break;
1628
1629 case EOpTanh:
1630 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1631 return nullptr;
1632 break;
1633
1634 case EOpAsinh:
1635 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1636 return nullptr;
1637 break;
1638
1639 case EOpAcosh:
1640 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1641 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1642 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1643 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1644 return nullptr;
1645 break;
1646
1647 case EOpAtanh:
1648 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1649 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1650 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1651 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1652 return nullptr;
1653 break;
1654
1655 case EOpAbs:
1656 switch (getType().getBasicType())
1657 {
1658 case EbtFloat:
1659 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1660 break;
1661 case EbtInt:
1662 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1663 break;
1664 default:
1665 infoSink.info.message(
1666 EPrefixInternalError, getLine(),
1667 "Unary operation not folded into constant");
1668 return nullptr;
1669 }
1670 break;
1671
1672 case EOpSign:
1673 switch (getType().getBasicType())
1674 {
1675 case EbtFloat:
1676 {
1677 float fConst = operandArray[i].getFConst();
1678 float fResult = 0.0f;
1679 if (fConst > 0.0f)
1680 fResult = 1.0f;
1681 else if (fConst < 0.0f)
1682 fResult = -1.0f;
1683 resultArray[i].setFConst(fResult);
1684 }
1685 break;
1686 case EbtInt:
1687 {
1688 int iConst = operandArray[i].getIConst();
1689 int iResult = 0;
1690 if (iConst > 0)
1691 iResult = 1;
1692 else if (iConst < 0)
1693 iResult = -1;
1694 resultArray[i].setIConst(iResult);
1695 }
1696 break;
1697 default:
1698 infoSink.info.message(
1699 EPrefixInternalError, getLine(),
1700 "Unary operation not folded into constant");
1701 return nullptr;
1702 }
1703 break;
1704
1705 case EOpFloor:
1706 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1707 return nullptr;
1708 break;
1709
1710 case EOpTrunc:
1711 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1712 return nullptr;
1713 break;
1714
1715 case EOpRound:
1716 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1717 return nullptr;
1718 break;
1719
1720 case EOpRoundEven:
1721 if (getType().getBasicType() == EbtFloat)
1722 {
1723 float x = operandArray[i].getFConst();
1724 float result;
1725 float fractPart = modff(x, &result);
1726 if (fabsf(fractPart) == 0.5f)
1727 result = 2.0f * roundf(x / 2.0f);
1728 else
1729 result = roundf(x);
1730 resultArray[i].setFConst(result);
1731 break;
1732 }
1733 infoSink.info.message(
1734 EPrefixInternalError, getLine(),
1735 "Unary operation not folded into constant");
1736 return nullptr;
1737
1738 case EOpCeil:
1739 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1740 return nullptr;
1741 break;
1742
1743 case EOpFract:
1744 if (getType().getBasicType() == EbtFloat)
1745 {
1746 float x = operandArray[i].getFConst();
1747 resultArray[i].setFConst(x - floorf(x));
1748 break;
1749 }
1750 infoSink.info.message(
1751 EPrefixInternalError, getLine(),
1752 "Unary operation not folded into constant");
1753 return nullptr;
1754
Arun Patole551279e2015-07-07 18:18:23 +05301755 case EOpIsNan:
1756 if (getType().getBasicType() == EbtFloat)
1757 {
1758 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1759 break;
1760 }
1761 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1762 return nullptr;
1763
1764 case EOpIsInf:
1765 if (getType().getBasicType() == EbtFloat)
1766 {
1767 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1768 break;
1769 }
1770 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1771 return nullptr;
1772
1773 case EOpFloatBitsToInt:
1774 if (getType().getBasicType() == EbtFloat)
1775 {
1776 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1777 break;
1778 }
1779 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1780 return nullptr;
1781
1782 case EOpFloatBitsToUint:
1783 if (getType().getBasicType() == EbtFloat)
1784 {
1785 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1786 break;
1787 }
1788 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1789 return nullptr;
1790
1791 case EOpIntBitsToFloat:
1792 if (getType().getBasicType() == EbtInt)
1793 {
1794 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1795 break;
1796 }
1797 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1798 return nullptr;
1799
1800 case EOpUintBitsToFloat:
1801 if (getType().getBasicType() == EbtUInt)
1802 {
1803 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1804 break;
1805 }
1806 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1807 return nullptr;
1808
Arun Patoleab2b9a22015-07-06 18:27:56 +05301809 case EOpExp:
1810 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1811 return nullptr;
1812 break;
1813
1814 case EOpLog:
1815 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1816 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1817 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1818 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1819 return nullptr;
1820 break;
1821
1822 case EOpExp2:
1823 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1824 return nullptr;
1825 break;
1826
1827 case EOpLog2:
1828 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1829 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1830 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1831 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1832 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1833 return nullptr;
1834 else
1835 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1836 break;
1837
1838 case EOpSqrt:
1839 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1840 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1841 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1842 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1843 return nullptr;
1844 break;
1845
1846 case EOpInverseSqrt:
1847 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1848 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1849 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1850 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1851 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1852 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1853 return nullptr;
1854 else
1855 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1856 break;
1857
1858 case EOpVectorLogicalNot:
1859 if (getType().getBasicType() == EbtBool)
1860 {
1861 resultArray[i].setBConst(!operandArray[i].getBConst());
1862 break;
1863 }
1864 infoSink.info.message(
1865 EPrefixInternalError, getLine(),
1866 "Unary operation not folded into constant");
1867 return nullptr;
1868
1869 case EOpNormalize:
1870 if (getType().getBasicType() == EbtFloat)
1871 {
1872 float x = operandArray[i].getFConst();
1873 float length = VectorLength(operandArray, objectSize);
1874 if (length)
1875 resultArray[i].setFConst(x / length);
1876 else
1877 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1878 &resultArray[i]);
1879 break;
1880 }
1881 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1882 return nullptr;
1883
Arun Patole0c5409f2015-07-08 15:17:53 +05301884 case EOpDFdx:
1885 case EOpDFdy:
1886 case EOpFwidth:
1887 if (getType().getBasicType() == EbtFloat)
1888 {
1889 // Derivatives of constant arguments should be 0.
1890 resultArray[i].setFConst(0.0f);
1891 break;
1892 }
1893 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1894 return nullptr;
1895
Arun Patole1155ddd2015-06-05 18:04:36 +05301896 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301897 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301898 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301899 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001900
Arun Patoleab2b9a22015-07-06 18:27:56 +05301901 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001902}
1903
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001904bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1905 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301906{
1907 ASSERT(builtinFunc);
1908
1909 if (getType().getBasicType() == EbtFloat)
1910 {
1911 result->setFConst(builtinFunc(parameter.getFConst()));
1912 return true;
1913 }
1914
1915 infoSink.info.message(
1916 EPrefixInternalError, getLine(),
1917 "Unary operation not folded into constant");
1918 return false;
1919}
1920
Jamie Madillb1a85f42014-08-19 15:23:24 -04001921// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001922TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1923 TInfoSink &infoSink)
1924{
1925 ASSERT(aggregate->getSequence()->size() > 0u);
1926 size_t resultSize = aggregate->getType().getObjectSize();
1927 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1928 TBasicType basicType = aggregate->getBasicType();
1929
1930 size_t resultIndex = 0u;
1931
1932 if (aggregate->getSequence()->size() == 1u)
1933 {
1934 TIntermNode *argument = aggregate->getSequence()->front();
1935 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1936 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1937 // Check the special case of constructing a matrix diagonal from a single scalar,
1938 // or a vector from a single scalar.
1939 if (argumentConstant->getType().getObjectSize() == 1u)
1940 {
1941 if (aggregate->isMatrix())
1942 {
1943 int resultCols = aggregate->getType().getCols();
1944 int resultRows = aggregate->getType().getRows();
1945 for (int col = 0; col < resultCols; ++col)
1946 {
1947 for (int row = 0; row < resultRows; ++row)
1948 {
1949 if (col == row)
1950 {
1951 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1952 }
1953 else
1954 {
1955 resultArray[resultIndex].setFConst(0.0f);
1956 }
1957 ++resultIndex;
1958 }
1959 }
1960 }
1961 else
1962 {
1963 while (resultIndex < resultSize)
1964 {
1965 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1966 ++resultIndex;
1967 }
1968 }
1969 ASSERT(resultIndex == resultSize);
1970 return resultArray;
1971 }
1972 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1973 {
1974 // The special case of constructing a matrix from a matrix.
1975 int argumentCols = argumentConstant->getType().getCols();
1976 int argumentRows = argumentConstant->getType().getRows();
1977 int resultCols = aggregate->getType().getCols();
1978 int resultRows = aggregate->getType().getRows();
1979 for (int col = 0; col < resultCols; ++col)
1980 {
1981 for (int row = 0; row < resultRows; ++row)
1982 {
1983 if (col < argumentCols && row < argumentRows)
1984 {
1985 resultArray[resultIndex].cast(basicType,
1986 argumentUnionArray[col * argumentRows + row]);
1987 }
1988 else if (col == row)
1989 {
1990 resultArray[resultIndex].setFConst(1.0f);
1991 }
1992 else
1993 {
1994 resultArray[resultIndex].setFConst(0.0f);
1995 }
1996 ++resultIndex;
1997 }
1998 }
1999 ASSERT(resultIndex == resultSize);
2000 return resultArray;
2001 }
2002 }
2003
2004 for (TIntermNode *&argument : *aggregate->getSequence())
2005 {
2006 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2007 size_t argumentSize = argumentConstant->getType().getObjectSize();
2008 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2009 for (size_t i = 0u; i < argumentSize; ++i)
2010 {
2011 if (resultIndex >= resultSize)
2012 break;
2013 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2014 ++resultIndex;
2015 }
2016 }
2017 ASSERT(resultIndex == resultSize);
2018 return resultArray;
2019}
2020
2021// static
Olli Etuahob43846e2015-06-02 18:18:57 +03002022TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05302023{
Olli Etuahob43846e2015-06-02 18:18:57 +03002024 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302025 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002026 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002027 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302028 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002029 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302030 TBasicType basicType = EbtVoid;
2031 TSourceLoc loc;
2032 for (unsigned int i = 0; i < paramsCount; i++)
2033 {
2034 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002035 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302036
2037 if (i == 0)
2038 {
2039 basicType = paramConstant->getType().getBasicType();
2040 loc = paramConstant->getLine();
2041 }
2042 unionArrays[i] = paramConstant->getUnionArrayPointer();
2043 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002044 if (objectSizes[i] > maxObjectSize)
2045 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302046 }
2047
Arun Patole7fa33552015-06-10 15:15:18 +05302048 if (!(*sequence)[0]->getAsTyped()->isMatrix())
2049 {
2050 for (unsigned int i = 0; i < paramsCount; i++)
2051 if (objectSizes[i] != maxObjectSize)
2052 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2053 }
Arun Patole274f0702015-05-05 13:33:30 +05302054
Olli Etuahob43846e2015-06-02 18:18:57 +03002055 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302056 if (paramsCount == 2)
2057 {
2058 //
2059 // Binary built-in
2060 //
2061 switch (op)
2062 {
Arun Patolebf790422015-05-18 17:53:04 +05302063 case EOpAtan:
2064 {
2065 if (basicType == EbtFloat)
2066 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002067 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302068 for (size_t i = 0; i < maxObjectSize; i++)
2069 {
2070 float y = unionArrays[0][i].getFConst();
2071 float x = unionArrays[1][i].getFConst();
2072 // Results are undefined if x and y are both 0.
2073 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002074 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302075 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002076 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302077 }
2078 }
2079 else
2080 UNREACHABLE();
2081 }
2082 break;
2083
2084 case EOpPow:
2085 {
2086 if (basicType == EbtFloat)
2087 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002088 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302089 for (size_t i = 0; i < maxObjectSize; i++)
2090 {
2091 float x = unionArrays[0][i].getFConst();
2092 float y = unionArrays[1][i].getFConst();
2093 // Results are undefined if x < 0.
2094 // Results are undefined if x = 0 and y <= 0.
2095 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002096 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302097 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002098 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302099 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002100 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302101 }
2102 }
2103 else
2104 UNREACHABLE();
2105 }
2106 break;
2107
2108 case EOpMod:
2109 {
2110 if (basicType == EbtFloat)
2111 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002112 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302113 for (size_t i = 0; i < maxObjectSize; i++)
2114 {
2115 float x = unionArrays[0][i].getFConst();
2116 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002117 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302118 }
2119 }
2120 else
2121 UNREACHABLE();
2122 }
2123 break;
2124
Arun Patole274f0702015-05-05 13:33:30 +05302125 case EOpMin:
2126 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002127 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302128 for (size_t i = 0; i < maxObjectSize; i++)
2129 {
2130 switch (basicType)
2131 {
2132 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002133 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302134 break;
2135 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002136 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302137 break;
2138 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002139 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302140 break;
2141 default:
2142 UNREACHABLE();
2143 break;
2144 }
2145 }
2146 }
2147 break;
2148
2149 case EOpMax:
2150 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002151 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302152 for (size_t i = 0; i < maxObjectSize; i++)
2153 {
2154 switch (basicType)
2155 {
2156 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002157 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302158 break;
2159 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002160 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302161 break;
2162 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002163 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302164 break;
2165 default:
2166 UNREACHABLE();
2167 break;
2168 }
2169 }
2170 }
2171 break;
2172
Arun Patolebf790422015-05-18 17:53:04 +05302173 case EOpStep:
2174 {
2175 if (basicType == EbtFloat)
2176 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002177 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302178 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002179 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302180 }
2181 else
2182 UNREACHABLE();
2183 }
2184 break;
2185
Arun Patole9d0b1f92015-05-20 14:27:17 +05302186 case EOpLessThan:
2187 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002188 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302189 for (size_t i = 0; i < maxObjectSize; i++)
2190 {
2191 switch (basicType)
2192 {
2193 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002194 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302195 break;
2196 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002197 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302198 break;
2199 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002200 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302201 break;
2202 default:
2203 UNREACHABLE();
2204 break;
2205 }
2206 }
2207 }
2208 break;
2209
2210 case EOpLessThanEqual:
2211 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002212 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302213 for (size_t i = 0; i < maxObjectSize; i++)
2214 {
2215 switch (basicType)
2216 {
2217 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002218 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302219 break;
2220 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002221 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302222 break;
2223 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002224 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302225 break;
2226 default:
2227 UNREACHABLE();
2228 break;
2229 }
2230 }
2231 }
2232 break;
2233
2234 case EOpGreaterThan:
2235 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002236 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302237 for (size_t i = 0; i < maxObjectSize; i++)
2238 {
2239 switch (basicType)
2240 {
2241 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002242 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302243 break;
2244 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002245 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302246 break;
2247 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002248 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302249 break;
2250 default:
2251 UNREACHABLE();
2252 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002253 }
2254 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302255 }
2256 break;
2257
2258 case EOpGreaterThanEqual:
2259 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002260 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302261 for (size_t i = 0; i < maxObjectSize; i++)
2262 {
2263 switch (basicType)
2264 {
2265 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002266 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302267 break;
2268 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002269 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302270 break;
2271 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002272 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302273 break;
2274 default:
2275 UNREACHABLE();
2276 break;
2277 }
2278 }
2279 }
2280 break;
2281
2282 case EOpVectorEqual:
2283 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002284 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302285 for (size_t i = 0; i < maxObjectSize; i++)
2286 {
2287 switch (basicType)
2288 {
2289 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002290 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302291 break;
2292 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002293 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302294 break;
2295 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002296 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302297 break;
2298 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002299 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302300 break;
2301 default:
2302 UNREACHABLE();
2303 break;
2304 }
2305 }
2306 }
2307 break;
2308
2309 case EOpVectorNotEqual:
2310 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002311 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302312 for (size_t i = 0; i < maxObjectSize; i++)
2313 {
2314 switch (basicType)
2315 {
2316 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002317 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302318 break;
2319 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002320 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302321 break;
2322 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002323 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302324 break;
2325 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002326 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302327 break;
2328 default:
2329 UNREACHABLE();
2330 break;
2331 }
2332 }
2333 }
2334 break;
2335
Arun Patole1155ddd2015-06-05 18:04:36 +05302336 case EOpDistance:
2337 if (basicType == EbtFloat)
2338 {
2339 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002340 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302341 for (size_t i = 0; i < maxObjectSize; i++)
2342 {
2343 float x = unionArrays[0][i].getFConst();
2344 float y = unionArrays[1][i].getFConst();
2345 distanceArray[i].setFConst(x - y);
2346 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002347 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302348 }
2349 else
2350 UNREACHABLE();
2351 break;
2352
2353 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002354
Arun Patole1155ddd2015-06-05 18:04:36 +05302355 if (basicType == EbtFloat)
2356 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002357 resultArray = new TConstantUnion();
2358 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302359 }
2360 else
2361 UNREACHABLE();
2362 break;
2363
2364 case EOpCross:
2365 if (basicType == EbtFloat && maxObjectSize == 3)
2366 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002367 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302368 float x0 = unionArrays[0][0].getFConst();
2369 float x1 = unionArrays[0][1].getFConst();
2370 float x2 = unionArrays[0][2].getFConst();
2371 float y0 = unionArrays[1][0].getFConst();
2372 float y1 = unionArrays[1][1].getFConst();
2373 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002374 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2375 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2376 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302377 }
2378 else
2379 UNREACHABLE();
2380 break;
2381
2382 case EOpReflect:
2383 if (basicType == EbtFloat)
2384 {
2385 // genType reflect (genType I, genType N) :
2386 // For the incident vector I and surface orientation N, returns the reflection direction:
2387 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002388 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302389 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2390 for (size_t i = 0; i < maxObjectSize; i++)
2391 {
2392 float result = unionArrays[0][i].getFConst() -
2393 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002394 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302395 }
2396 }
2397 else
2398 UNREACHABLE();
2399 break;
2400
Arun Patole7fa33552015-06-10 15:15:18 +05302401 case EOpMul:
2402 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2403 (*sequence)[1]->getAsTyped()->isMatrix())
2404 {
2405 // Perform component-wise matrix multiplication.
2406 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002407 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302408 angle::Matrix<float> result =
2409 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2410 SetUnionArrayFromMatrix(result, resultArray);
2411 }
2412 else
2413 UNREACHABLE();
2414 break;
2415
2416 case EOpOuterProduct:
2417 if (basicType == EbtFloat)
2418 {
2419 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2420 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2421 resultArray = new TConstantUnion[numRows * numCols];
2422 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002423 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2424 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302425 SetUnionArrayFromMatrix(result, resultArray);
2426 }
2427 else
2428 UNREACHABLE();
2429 break;
2430
Arun Patole274f0702015-05-05 13:33:30 +05302431 default:
2432 UNREACHABLE();
2433 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2434 return nullptr;
2435 }
2436 }
2437 else if (paramsCount == 3)
2438 {
2439 //
2440 // Ternary built-in
2441 //
2442 switch (op)
2443 {
2444 case EOpClamp:
2445 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002446 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302447 for (size_t i = 0; i < maxObjectSize; i++)
2448 {
2449 switch (basicType)
2450 {
2451 case EbtFloat:
2452 {
2453 float x = unionArrays[0][i].getFConst();
2454 float min = unionArrays[1][i].getFConst();
2455 float max = unionArrays[2][i].getFConst();
2456 // Results are undefined if min > max.
2457 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002458 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302459 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002460 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302461 }
2462 break;
2463 case EbtInt:
2464 {
2465 int x = unionArrays[0][i].getIConst();
2466 int min = unionArrays[1][i].getIConst();
2467 int max = unionArrays[2][i].getIConst();
2468 // Results are undefined if min > max.
2469 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002470 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302471 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002472 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302473 }
2474 break;
2475 case EbtUInt:
2476 {
2477 unsigned int x = unionArrays[0][i].getUConst();
2478 unsigned int min = unionArrays[1][i].getUConst();
2479 unsigned int max = unionArrays[2][i].getUConst();
2480 // Results are undefined if min > max.
2481 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002482 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302483 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002484 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302485 }
2486 break;
2487 default:
2488 UNREACHABLE();
2489 break;
2490 }
2491 }
2492 }
2493 break;
2494
Arun Patolebf790422015-05-18 17:53:04 +05302495 case EOpMix:
2496 {
2497 if (basicType == EbtFloat)
2498 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002499 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302500 for (size_t i = 0; i < maxObjectSize; i++)
2501 {
2502 float x = unionArrays[0][i].getFConst();
2503 float y = unionArrays[1][i].getFConst();
2504 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2505 if (type == EbtFloat)
2506 {
2507 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2508 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002509 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302510 }
2511 else // 3rd parameter is EbtBool
2512 {
2513 ASSERT(type == EbtBool);
2514 // Selects which vector each returned component comes from.
2515 // For a component of a that is false, the corresponding component of x is returned.
2516 // For a component of a that is true, the corresponding component of y is returned.
2517 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002518 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302519 }
2520 }
2521 }
2522 else
2523 UNREACHABLE();
2524 }
2525 break;
2526
2527 case EOpSmoothStep:
2528 {
2529 if (basicType == EbtFloat)
2530 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002531 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302532 for (size_t i = 0; i < maxObjectSize; i++)
2533 {
2534 float edge0 = unionArrays[0][i].getFConst();
2535 float edge1 = unionArrays[1][i].getFConst();
2536 float x = unionArrays[2][i].getFConst();
2537 // Results are undefined if edge0 >= edge1.
2538 if (edge0 >= edge1)
2539 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002540 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302541 }
2542 else
2543 {
2544 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2545 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2546 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002547 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302548 }
2549 }
2550 }
2551 else
2552 UNREACHABLE();
2553 }
2554 break;
2555
Arun Patole1155ddd2015-06-05 18:04:36 +05302556 case EOpFaceForward:
2557 if (basicType == EbtFloat)
2558 {
2559 // genType faceforward(genType N, genType I, genType Nref) :
2560 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002561 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302562 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2563 for (size_t i = 0; i < maxObjectSize; i++)
2564 {
2565 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002566 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302567 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002568 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302569 }
2570 }
2571 else
2572 UNREACHABLE();
2573 break;
2574
2575 case EOpRefract:
2576 if (basicType == EbtFloat)
2577 {
2578 // genType refract(genType I, genType N, float eta) :
2579 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2580 // return the refraction vector. The result is computed by
2581 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2582 // if (k < 0.0)
2583 // return genType(0.0)
2584 // else
2585 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002586 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302587 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2588 for (size_t i = 0; i < maxObjectSize; i++)
2589 {
2590 float eta = unionArrays[2][i].getFConst();
2591 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2592 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002593 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302594 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002595 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302596 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2597 }
2598 }
2599 else
2600 UNREACHABLE();
2601 break;
2602
Arun Patole274f0702015-05-05 13:33:30 +05302603 default:
2604 UNREACHABLE();
2605 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2606 return nullptr;
2607 }
2608 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002609 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302610}
2611
2612// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002613TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2614{
2615 if (hashFunction == NULL || name.empty())
2616 return name;
2617 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2618 TStringStream stream;
2619 stream << HASHED_NAME_PREFIX << std::hex << number;
2620 TString hashedName = stream.str();
2621 return hashedName;
2622}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002623
2624void TIntermTraverser::updateTree()
2625{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002626 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2627 {
2628 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2629 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002630 if (!insertion.insertionsAfter.empty())
2631 {
2632 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2633 insertion.insertionsAfter);
2634 ASSERT(inserted);
2635 UNUSED_ASSERTION_VARIABLE(inserted);
2636 }
2637 if (!insertion.insertionsBefore.empty())
2638 {
2639 bool inserted =
2640 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2641 ASSERT(inserted);
2642 UNUSED_ASSERTION_VARIABLE(inserted);
2643 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002644 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002645 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2646 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002647 const NodeUpdateEntry &replacement = mReplacements[ii];
2648 ASSERT(replacement.parent);
2649 bool replaced = replacement.parent->replaceChildNode(
2650 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002651 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002652 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002653
Olli Etuahocd94ef92015-04-16 19:18:10 +03002654 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002655 {
2656 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002657 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002658 // be replaced, we need to make sure we don't update the replaced
2659 // node; instead, we update the replacement node.
2660 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2661 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002662 NodeUpdateEntry &replacement2 = mReplacements[jj];
2663 if (replacement2.parent == replacement.original)
2664 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002665 }
2666 }
2667 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002668 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2669 {
2670 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2671 ASSERT(replacement.parent);
2672 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2673 replacement.original, replacement.replacements);
2674 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002675 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002676 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002677
2678 mInsertions.clear();
2679 mReplacements.clear();
2680 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002681}