blob: 2a92860088924e9150832fa42b50031594883bc3 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040020#include "compiler/translator/HashNames.h"
21#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
23
24namespace
25{
26
Arun Patole9dea48f2015-04-02 11:45:09 +053027const float kPi = 3.14159265358979323846f;
28const float kDegreesToRadiansMultiplier = kPi / 180.0f;
29const float kRadiansToDegreesMultiplier = 180.0f / kPi;
30
Jamie Madillb1a85f42014-08-19 15:23:24 -040031TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
32{
33 return left > right ? left : right;
34}
35
36bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
37{
38 switch (op)
39 {
40 case EOpMul:
41 case EOpMulAssign:
42 return left.getNominalSize() == right.getNominalSize() &&
43 left.getSecondarySize() == right.getSecondarySize();
44 case EOpVectorTimesScalar:
45 case EOpVectorTimesScalarAssign:
46 return true;
47 case EOpVectorTimesMatrix:
48 return left.getNominalSize() == right.getRows();
49 case EOpVectorTimesMatrixAssign:
50 return left.getNominalSize() == right.getRows() &&
51 left.getNominalSize() == right.getCols();
52 case EOpMatrixTimesVector:
53 return left.getCols() == right.getNominalSize();
54 case EOpMatrixTimesScalar:
55 case EOpMatrixTimesScalarAssign:
56 return true;
57 case EOpMatrixTimesMatrix:
58 return left.getCols() == right.getRows();
59 case EOpMatrixTimesMatrixAssign:
60 return left.getCols() == right.getCols() &&
61 left.getRows() == right.getRows();
62
63 default:
64 UNREACHABLE();
65 return false;
66 }
67}
68
Arun Patole274f0702015-05-05 13:33:30 +053069TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
70{
71 TConstantUnion *constUnion = new TConstantUnion[size];
72 for (unsigned int i = 0; i < size; ++i)
73 constUnion[i] = constant;
74
75 return constUnion;
76}
77
Arun Patolebf790422015-05-18 17:53:04 +053078void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
79 TInfoSink &infoSink, TConstantUnion *result)
80{
81 std::stringstream constantFoldingErrorStream;
82 constantFoldingErrorStream << "'" << GetOperatorString(op)
83 << "' operation result is undefined for the values passed in";
84 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
85
86 switch (basicType)
87 {
88 case EbtFloat :
89 result->setFConst(0.0f);
90 break;
91 case EbtInt:
92 result->setIConst(0);
93 break;
94 case EbtUInt:
95 result->setUConst(0u);
96 break;
97 case EbtBool:
98 result->setBConst(false);
99 break;
100 default:
101 break;
102 }
103}
104
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200105float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530106{
107 float result = 0.0f;
108 for (size_t i = 0; i < paramArraySize; i++)
109 {
110 float f = paramArray[i].getFConst();
111 result += f * f;
112 }
113 return sqrtf(result);
114}
115
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200116float VectorDotProduct(const TConstantUnion *paramArray1,
117 const TConstantUnion *paramArray2,
118 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530119{
120 float result = 0.0f;
121 for (size_t i = 0; i < paramArraySize; i++)
122 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
123 return result;
124}
125
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200126TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
127 const TIntermTyped *originalNode,
128 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300129{
130 if (constArray == nullptr)
131 {
132 return nullptr;
133 }
134 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200135 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300136 folded->setLine(originalNode->getLine());
137 return folded;
138}
139
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200140angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
141 const unsigned int &rows,
142 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530143{
144 std::vector<float> elements;
145 for (size_t i = 0; i < rows * cols; i++)
146 elements.push_back(paramArray[i].getFConst());
147 // Transpose is used since the Matrix constructor expects arguments in row-major order,
148 // whereas the paramArray is in column-major order.
149 return angle::Matrix<float>(elements, rows, cols).transpose();
150}
151
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200152angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530153{
154 std::vector<float> elements;
155 for (size_t i = 0; i < size * size; i++)
156 elements.push_back(paramArray[i].getFConst());
157 // Transpose is used since the Matrix constructor expects arguments in row-major order,
158 // whereas the paramArray is in column-major order.
159 return angle::Matrix<float>(elements, size).transpose();
160}
161
162void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
163{
164 // Transpose is used since the input Matrix is in row-major order,
165 // whereas the actual result should be in column-major order.
166 angle::Matrix<float> result = m.transpose();
167 std::vector<float> resultElements = result.elements();
168 for (size_t i = 0; i < resultElements.size(); i++)
169 resultArray[i].setFConst(resultElements[i]);
170}
171
Jamie Madillb1a85f42014-08-19 15:23:24 -0400172} // namespace anonymous
173
174
175////////////////////////////////////////////////////////////////
176//
177// Member functions of the nodes used for building the tree.
178//
179////////////////////////////////////////////////////////////////
180
Olli Etuahod2a67b92014-10-21 16:42:57 +0300181void TIntermTyped::setTypePreservePrecision(const TType &t)
182{
183 TPrecision precision = getPrecision();
184 mType = t;
185 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
186 mType.setPrecision(precision);
187}
188
Jamie Madillb1a85f42014-08-19 15:23:24 -0400189#define REPLACE_IF_IS(node, type, original, replacement) \
190 if (node == original) { \
191 node = static_cast<type *>(replacement); \
192 return true; \
193 }
194
195bool TIntermLoop::replaceChildNode(
196 TIntermNode *original, TIntermNode *replacement)
197{
198 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
199 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
200 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200201 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202 return false;
203}
204
Jamie Madillb1a85f42014-08-19 15:23:24 -0400205bool TIntermBranch::replaceChildNode(
206 TIntermNode *original, TIntermNode *replacement)
207{
208 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
209 return false;
210}
211
Jamie Madillb1a85f42014-08-19 15:23:24 -0400212bool TIntermBinary::replaceChildNode(
213 TIntermNode *original, TIntermNode *replacement)
214{
215 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
216 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
217 return false;
218}
219
Jamie Madillb1a85f42014-08-19 15:23:24 -0400220bool TIntermUnary::replaceChildNode(
221 TIntermNode *original, TIntermNode *replacement)
222{
223 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
224 return false;
225}
226
Jamie Madillb1a85f42014-08-19 15:23:24 -0400227bool TIntermAggregate::replaceChildNode(
228 TIntermNode *original, TIntermNode *replacement)
229{
230 for (size_t ii = 0; ii < mSequence.size(); ++ii)
231 {
232 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
233 }
234 return false;
235}
236
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300237bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
238{
239 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
240 {
241 if (*it == original)
242 {
243 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300244 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300245 return true;
246 }
247 }
248 return false;
249}
250
Olli Etuahoa6f22092015-05-08 18:31:10 +0300251bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
252{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300253 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300254 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300255 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300256 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300257 auto it = mSequence.begin() + position;
258 mSequence.insert(it, insertions.begin(), insertions.end());
259 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300260}
261
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200262bool TIntermAggregate::areChildrenConstQualified()
263{
264 for (TIntermNode *&child : mSequence)
265 {
266 TIntermTyped *typed = child->getAsTyped();
267 if (typed && typed->getQualifier() != EvqConst)
268 {
269 return false;
270 }
271 }
272 return true;
273}
274
Olli Etuahod2a67b92014-10-21 16:42:57 +0300275void TIntermAggregate::setPrecisionFromChildren()
276{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300277 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300278 if (getBasicType() == EbtBool)
279 {
280 mType.setPrecision(EbpUndefined);
281 return;
282 }
283
284 TPrecision precision = EbpUndefined;
285 TIntermSequence::iterator childIter = mSequence.begin();
286 while (childIter != mSequence.end())
287 {
288 TIntermTyped *typed = (*childIter)->getAsTyped();
289 if (typed)
290 precision = GetHigherPrecision(typed->getPrecision(), precision);
291 ++childIter;
292 }
293 mType.setPrecision(precision);
294}
295
296void TIntermAggregate::setBuiltInFunctionPrecision()
297{
298 // All built-ins returning bool should be handled as ops, not functions.
299 ASSERT(getBasicType() != EbtBool);
300
301 TPrecision precision = EbpUndefined;
302 TIntermSequence::iterator childIter = mSequence.begin();
303 while (childIter != mSequence.end())
304 {
305 TIntermTyped *typed = (*childIter)->getAsTyped();
306 // ESSL spec section 8: texture functions get their precision from the sampler.
307 if (typed && IsSampler(typed->getBasicType()))
308 {
309 precision = typed->getPrecision();
310 break;
311 }
312 ++childIter;
313 }
314 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
315 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300316 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300317 mType.setPrecision(EbpHigh);
318 else
319 mType.setPrecision(precision);
320}
321
Jamie Madillb1a85f42014-08-19 15:23:24 -0400322bool TIntermSelection::replaceChildNode(
323 TIntermNode *original, TIntermNode *replacement)
324{
325 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
326 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
327 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
328 return false;
329}
330
Olli Etuahoa3a36662015-02-17 13:46:51 +0200331bool TIntermSwitch::replaceChildNode(
332 TIntermNode *original, TIntermNode *replacement)
333{
334 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
335 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
336 return false;
337}
338
339bool TIntermCase::replaceChildNode(
340 TIntermNode *original, TIntermNode *replacement)
341{
342 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
343 return false;
344}
345
Olli Etuahod7a25242015-08-18 13:49:45 +0300346TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
347{
348 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
349 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
350 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
351 mLine = node.mLine;
352}
353
354TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
355{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200356 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300357}
358
359TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
360 : TIntermOperator(node),
361 mName(node.mName),
362 mUserDefined(node.mUserDefined),
363 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300364 mUseEmulatedFunction(node.mUseEmulatedFunction),
365 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
366{
367 for (TIntermNode *child : node.mSequence)
368 {
369 TIntermTyped *typedChild = child->getAsTyped();
370 ASSERT(typedChild != nullptr);
371 TIntermTyped *childCopy = typedChild->deepCopy();
372 mSequence.push_back(childCopy);
373 }
374}
375
376TIntermBinary::TIntermBinary(const TIntermBinary &node)
377 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
378{
379 TIntermTyped *leftCopy = node.mLeft->deepCopy();
380 TIntermTyped *rightCopy = node.mRight->deepCopy();
381 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
382 mLeft = leftCopy;
383 mRight = rightCopy;
384}
385
386TIntermUnary::TIntermUnary(const TIntermUnary &node)
387 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
388{
389 TIntermTyped *operandCopy = node.mOperand->deepCopy();
390 ASSERT(operandCopy != nullptr);
391 mOperand = operandCopy;
392}
393
394TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
395{
396 // Only supported for ternary nodes, not if statements.
397 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
398 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
399 ASSERT(trueTyped != nullptr);
400 ASSERT(falseTyped != nullptr);
401 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
402 TIntermTyped *trueCopy = trueTyped->deepCopy();
403 TIntermTyped *falseCopy = falseTyped->deepCopy();
404 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
405 mCondition = conditionCopy;
406 mTrueBlock = trueCopy;
407 mFalseBlock = falseCopy;
408}
409
Jamie Madillb1a85f42014-08-19 15:23:24 -0400410//
411// Say whether or not an operation node changes the value of a variable.
412//
413bool TIntermOperator::isAssignment() const
414{
415 switch (mOp)
416 {
417 case EOpPostIncrement:
418 case EOpPostDecrement:
419 case EOpPreIncrement:
420 case EOpPreDecrement:
421 case EOpAssign:
422 case EOpAddAssign:
423 case EOpSubAssign:
424 case EOpMulAssign:
425 case EOpVectorTimesMatrixAssign:
426 case EOpVectorTimesScalarAssign:
427 case EOpMatrixTimesScalarAssign:
428 case EOpMatrixTimesMatrixAssign:
429 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200430 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200431 case EOpBitShiftLeftAssign:
432 case EOpBitShiftRightAssign:
433 case EOpBitwiseAndAssign:
434 case EOpBitwiseXorAssign:
435 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400436 return true;
437 default:
438 return false;
439 }
440}
441
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300442bool TIntermOperator::isMultiplication() const
443{
444 switch (mOp)
445 {
446 case EOpMul:
447 case EOpMatrixTimesMatrix:
448 case EOpMatrixTimesVector:
449 case EOpMatrixTimesScalar:
450 case EOpVectorTimesMatrix:
451 case EOpVectorTimesScalar:
452 return true;
453 default:
454 return false;
455 }
456}
457
Jamie Madillb1a85f42014-08-19 15:23:24 -0400458//
459// returns true if the operator is for one of the constructors
460//
461bool TIntermOperator::isConstructor() const
462{
463 switch (mOp)
464 {
465 case EOpConstructVec2:
466 case EOpConstructVec3:
467 case EOpConstructVec4:
468 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400469 case EOpConstructMat2x3:
470 case EOpConstructMat2x4:
471 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400472 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400473 case EOpConstructMat3x4:
474 case EOpConstructMat4x2:
475 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400476 case EOpConstructMat4:
477 case EOpConstructFloat:
478 case EOpConstructIVec2:
479 case EOpConstructIVec3:
480 case EOpConstructIVec4:
481 case EOpConstructInt:
482 case EOpConstructUVec2:
483 case EOpConstructUVec3:
484 case EOpConstructUVec4:
485 case EOpConstructUInt:
486 case EOpConstructBVec2:
487 case EOpConstructBVec3:
488 case EOpConstructBVec4:
489 case EOpConstructBool:
490 case EOpConstructStruct:
491 return true;
492 default:
493 return false;
494 }
495}
496
497//
498// Make sure the type of a unary operator is appropriate for its
499// combination of operation and operand type.
500//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200501void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400502{
503 switch (mOp)
504 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200505 case EOpFloatBitsToInt:
506 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200507 case EOpIntBitsToFloat:
508 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200509 case EOpPackSnorm2x16:
510 case EOpPackUnorm2x16:
511 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200512 case EOpUnpackSnorm2x16:
513 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200514 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530515 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200516 case EOpUnpackHalf2x16:
517 mType.setPrecision(EbpMedium);
518 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400519 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200520 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400521 }
522
Olli Etuahof6c694b2015-03-26 14:50:53 +0200523 if (funcReturnType != nullptr)
524 {
525 if (funcReturnType->getBasicType() == EbtBool)
526 {
527 // Bool types should not have precision.
528 setType(*funcReturnType);
529 }
530 else
531 {
532 // Precision of the node has been set based on the operand.
533 setTypePreservePrecision(*funcReturnType);
534 }
535 }
536
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200537 if (mOperand->getQualifier() == EvqConst)
538 mType.setQualifier(EvqConst);
539 else
540 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400541}
542
543//
544// Establishes the type of the resultant operation, as well as
545// makes the operator the correct one for the operands.
546//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200547// For lots of operations it should already be established that the operand
548// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400549//
550bool TIntermBinary::promote(TInfoSink &infoSink)
551{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200552 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400553
Jamie Madillb1a85f42014-08-19 15:23:24 -0400554 //
555 // Base assumption: just make the type the same as the left
556 // operand. Then only deviations from this need be coded.
557 //
558 setType(mLeft->getType());
559
560 // The result gets promoted to the highest precision.
561 TPrecision higherPrecision = GetHigherPrecision(
562 mLeft->getPrecision(), mRight->getPrecision());
563 getTypePointer()->setPrecision(higherPrecision);
564
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200565 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400566 // Binary operations results in temporary variables unless both
567 // operands are const.
568 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
569 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200570 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400571 getTypePointer()->setQualifier(EvqTemporary);
572 }
573
574 const int nominalSize =
575 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
576
577 //
578 // All scalars or structs. Code after this test assumes this case is removed!
579 //
580 if (nominalSize == 1)
581 {
582 switch (mOp)
583 {
584 //
585 // Promote to conditional
586 //
587 case EOpEqual:
588 case EOpNotEqual:
589 case EOpLessThan:
590 case EOpGreaterThan:
591 case EOpLessThanEqual:
592 case EOpGreaterThanEqual:
593 setType(TType(EbtBool, EbpUndefined));
594 break;
595
596 //
597 // And and Or operate on conditionals
598 //
599 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200600 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400601 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200602 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400603 setType(TType(EbtBool, EbpUndefined));
604 break;
605
606 default:
607 break;
608 }
609 return true;
610 }
611
612 // If we reach here, at least one of the operands is vector or matrix.
613 // The other operand could be a scalar, vector, or matrix.
614 // Can these two operands be combined?
615 //
616 TBasicType basicType = mLeft->getBasicType();
617 switch (mOp)
618 {
619 case EOpMul:
620 if (!mLeft->isMatrix() && mRight->isMatrix())
621 {
622 if (mLeft->isVector())
623 {
624 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200625 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700626 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400627 }
628 else
629 {
630 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200631 setType(TType(basicType, higherPrecision, resultQualifier,
632 static_cast<unsigned char>(mRight->getCols()),
633 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400634 }
635 }
636 else if (mLeft->isMatrix() && !mRight->isMatrix())
637 {
638 if (mRight->isVector())
639 {
640 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200641 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700642 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400643 }
644 else
645 {
646 mOp = EOpMatrixTimesScalar;
647 }
648 }
649 else if (mLeft->isMatrix() && mRight->isMatrix())
650 {
651 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200652 setType(TType(basicType, higherPrecision, resultQualifier,
653 static_cast<unsigned char>(mRight->getCols()),
654 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400655 }
656 else if (!mLeft->isMatrix() && !mRight->isMatrix())
657 {
658 if (mLeft->isVector() && mRight->isVector())
659 {
660 // leave as component product
661 }
662 else if (mLeft->isVector() || mRight->isVector())
663 {
664 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200665 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700666 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400667 }
668 }
669 else
670 {
671 infoSink.info.message(EPrefixInternalError, getLine(),
672 "Missing elses");
673 return false;
674 }
675
676 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
677 {
678 return false;
679 }
680 break;
681
682 case EOpMulAssign:
683 if (!mLeft->isMatrix() && mRight->isMatrix())
684 {
685 if (mLeft->isVector())
686 {
687 mOp = EOpVectorTimesMatrixAssign;
688 }
689 else
690 {
691 return false;
692 }
693 }
694 else if (mLeft->isMatrix() && !mRight->isMatrix())
695 {
696 if (mRight->isVector())
697 {
698 return false;
699 }
700 else
701 {
702 mOp = EOpMatrixTimesScalarAssign;
703 }
704 }
705 else if (mLeft->isMatrix() && mRight->isMatrix())
706 {
707 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200708 setType(TType(basicType, higherPrecision, resultQualifier,
709 static_cast<unsigned char>(mRight->getCols()),
710 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400711 }
712 else if (!mLeft->isMatrix() && !mRight->isMatrix())
713 {
714 if (mLeft->isVector() && mRight->isVector())
715 {
716 // leave as component product
717 }
718 else if (mLeft->isVector() || mRight->isVector())
719 {
720 if (!mLeft->isVector())
721 return false;
722 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200723 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700724 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400725 }
726 }
727 else
728 {
729 infoSink.info.message(EPrefixInternalError, getLine(),
730 "Missing elses");
731 return false;
732 }
733
734 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
735 {
736 return false;
737 }
738 break;
739
740 case EOpAssign:
741 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200742 // No more additional checks are needed.
743 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
744 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
745 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400746 case EOpAdd:
747 case EOpSub:
748 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200749 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200750 case EOpBitShiftLeft:
751 case EOpBitShiftRight:
752 case EOpBitwiseAnd:
753 case EOpBitwiseXor:
754 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400755 case EOpAddAssign:
756 case EOpSubAssign:
757 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200758 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200759 case EOpBitShiftLeftAssign:
760 case EOpBitShiftRightAssign:
761 case EOpBitwiseAndAssign:
762 case EOpBitwiseXorAssign:
763 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400764 if ((mLeft->isMatrix() && mRight->isVector()) ||
765 (mLeft->isVector() && mRight->isMatrix()))
766 {
767 return false;
768 }
769
770 // Are the sizes compatible?
771 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
772 mLeft->getSecondarySize() != mRight->getSecondarySize())
773 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200774 // If the nominal sizes of operands do not match:
775 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776 if (!mLeft->isScalar() && !mRight->isScalar())
777 return false;
778
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200779 // In the case of compound assignment other than multiply-assign,
780 // the right side needs to be a scalar. Otherwise a vector/matrix
781 // would be assigned to a scalar. A scalar can't be shifted by a
782 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200783 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200784 (isAssignment() ||
785 mOp == EOpBitShiftLeft ||
786 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200787 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400788 }
789
790 {
791 const int secondarySize = std::max(
792 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200793 setType(TType(basicType, higherPrecision, resultQualifier,
794 static_cast<unsigned char>(nominalSize),
795 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200796 if (mLeft->isArray())
797 {
798 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
799 mType.setArraySize(mLeft->getArraySize());
800 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400801 }
802 break;
803
804 case EOpEqual:
805 case EOpNotEqual:
806 case EOpLessThan:
807 case EOpGreaterThan:
808 case EOpLessThanEqual:
809 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200810 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
811 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400812 setType(TType(EbtBool, EbpUndefined));
813 break;
814
815 default:
816 return false;
817 }
818 return true;
819}
820
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300821TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
822{
823 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
824 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
825 if (leftConstant == nullptr || rightConstant == nullptr)
826 {
827 return nullptr;
828 }
829 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200830
831 // Nodes may be constant folded without being qualified as constant.
832 TQualifier resultQualifier = EvqConst;
833 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
834 {
835 resultQualifier = EvqTemporary;
836 }
837 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300838}
839
Olli Etuaho95310b02015-06-02 17:43:38 +0300840TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
841{
842 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
843 if (operandConstant == nullptr)
844 {
845 return nullptr;
846 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530847
848 TConstantUnion *constArray = nullptr;
849 switch (mOp)
850 {
851 case EOpAny:
852 case EOpAll:
853 case EOpLength:
854 case EOpTranspose:
855 case EOpDeterminant:
856 case EOpInverse:
857 case EOpPackSnorm2x16:
858 case EOpUnpackSnorm2x16:
859 case EOpPackUnorm2x16:
860 case EOpUnpackUnorm2x16:
861 case EOpPackHalf2x16:
862 case EOpUnpackHalf2x16:
863 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
864 break;
865 default:
866 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
867 break;
868 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200869
870 // Nodes may be constant folded without being qualified as constant.
871 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
872 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300873}
874
875TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
876{
877 // Make sure that all params are constant before actual constant folding.
878 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300879 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300880 if (param->getAsConstantUnion() == nullptr)
881 {
882 return nullptr;
883 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300884 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200885 TConstantUnion *constArray = nullptr;
886 if (isConstructor())
887 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
888 else
889 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200890
891 // Nodes may be constant folded without being qualified as constant.
892 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
893 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300894}
895
Jamie Madillb1a85f42014-08-19 15:23:24 -0400896//
897// The fold functions see if an operation on a constant can be done in place,
898// without generating run-time code.
899//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300900// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400901//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300902TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
903{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200904 const TConstantUnion *leftArray = getUnionArrayPointer();
905 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300906
907 if (!leftArray)
908 return nullptr;
909 if (!rightArray)
910 return nullptr;
911
912 size_t objectSize = getType().getObjectSize();
913
914 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
915 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
916 {
917 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
918 }
919 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
920 {
921 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
922 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
923 objectSize = rightNode->getType().getObjectSize();
924 }
925
926 TConstantUnion *resultArray = nullptr;
927
928 switch(op)
929 {
930 case EOpAdd:
931 resultArray = new TConstantUnion[objectSize];
932 for (size_t i = 0; i < objectSize; i++)
933 resultArray[i] = leftArray[i] + rightArray[i];
934 break;
935 case EOpSub:
936 resultArray = new TConstantUnion[objectSize];
937 for (size_t i = 0; i < objectSize; i++)
938 resultArray[i] = leftArray[i] - rightArray[i];
939 break;
940
941 case EOpMul:
942 case EOpVectorTimesScalar:
943 case EOpMatrixTimesScalar:
944 resultArray = new TConstantUnion[objectSize];
945 for (size_t i = 0; i < objectSize; i++)
946 resultArray[i] = leftArray[i] * rightArray[i];
947 break;
948
949 case EOpMatrixTimesMatrix:
950 {
951 if (getType().getBasicType() != EbtFloat ||
952 rightNode->getBasicType() != EbtFloat)
953 {
954 infoSink.info.message(
955 EPrefixInternalError, getLine(),
956 "Constant Folding cannot be done for matrix multiply");
957 return nullptr;
958 }
959
960 const int leftCols = getCols();
961 const int leftRows = getRows();
962 const int rightCols = rightNode->getType().getCols();
963 const int rightRows = rightNode->getType().getRows();
964 const int resultCols = rightCols;
965 const int resultRows = leftRows;
966
967 resultArray = new TConstantUnion[resultCols * resultRows];
968 for (int row = 0; row < resultRows; row++)
969 {
970 for (int column = 0; column < resultCols; column++)
971 {
972 resultArray[resultRows * column + row].setFConst(0.0f);
973 for (int i = 0; i < leftCols; i++)
974 {
975 resultArray[resultRows * column + row].setFConst(
976 resultArray[resultRows * column + row].getFConst() +
977 leftArray[i * leftRows + row].getFConst() *
978 rightArray[column * rightRows + i].getFConst());
979 }
980 }
981 }
982 }
983 break;
984
985 case EOpDiv:
986 case EOpIMod:
987 {
988 resultArray = new TConstantUnion[objectSize];
989 for (size_t i = 0; i < objectSize; i++)
990 {
991 switch (getType().getBasicType())
992 {
993 case EbtFloat:
994 if (rightArray[i] == 0.0f)
995 {
996 infoSink.info.message(EPrefixWarning, getLine(),
997 "Divide by zero error during constant folding");
998 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
999 }
1000 else
1001 {
1002 ASSERT(op == EOpDiv);
1003 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1004 }
1005 break;
1006
1007 case EbtInt:
1008 if (rightArray[i] == 0)
1009 {
1010 infoSink.info.message(EPrefixWarning, getLine(),
1011 "Divide by zero error during constant folding");
1012 resultArray[i].setIConst(INT_MAX);
1013 }
1014 else
1015 {
1016 if (op == EOpDiv)
1017 {
1018 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1019 }
1020 else
1021 {
1022 ASSERT(op == EOpIMod);
1023 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1024 }
1025 }
1026 break;
1027
1028 case EbtUInt:
1029 if (rightArray[i] == 0)
1030 {
1031 infoSink.info.message(EPrefixWarning, getLine(),
1032 "Divide by zero error during constant folding");
1033 resultArray[i].setUConst(UINT_MAX);
1034 }
1035 else
1036 {
1037 if (op == EOpDiv)
1038 {
1039 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1040 }
1041 else
1042 {
1043 ASSERT(op == EOpIMod);
1044 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1045 }
1046 }
1047 break;
1048
1049 default:
1050 infoSink.info.message(EPrefixInternalError, getLine(),
1051 "Constant folding cannot be done for \"/\"");
1052 return nullptr;
1053 }
1054 }
1055 }
1056 break;
1057
1058 case EOpMatrixTimesVector:
1059 {
1060 if (rightNode->getBasicType() != EbtFloat)
1061 {
1062 infoSink.info.message(EPrefixInternalError, getLine(),
1063 "Constant Folding cannot be done for matrix times vector");
1064 return nullptr;
1065 }
1066
1067 const int matrixCols = getCols();
1068 const int matrixRows = getRows();
1069
1070 resultArray = new TConstantUnion[matrixRows];
1071
1072 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1073 {
1074 resultArray[matrixRow].setFConst(0.0f);
1075 for (int col = 0; col < matrixCols; col++)
1076 {
1077 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1078 leftArray[col * matrixRows + matrixRow].getFConst() *
1079 rightArray[col].getFConst());
1080 }
1081 }
1082 }
1083 break;
1084
1085 case EOpVectorTimesMatrix:
1086 {
1087 if (getType().getBasicType() != EbtFloat)
1088 {
1089 infoSink.info.message(EPrefixInternalError, getLine(),
1090 "Constant Folding cannot be done for vector times matrix");
1091 return nullptr;
1092 }
1093
1094 const int matrixCols = rightNode->getType().getCols();
1095 const int matrixRows = rightNode->getType().getRows();
1096
1097 resultArray = new TConstantUnion[matrixCols];
1098
1099 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1100 {
1101 resultArray[matrixCol].setFConst(0.0f);
1102 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1103 {
1104 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1105 leftArray[matrixRow].getFConst() *
1106 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1107 }
1108 }
1109 }
1110 break;
1111
1112 case EOpLogicalAnd:
1113 {
1114 resultArray = new TConstantUnion[objectSize];
1115 for (size_t i = 0; i < objectSize; i++)
1116 {
1117 resultArray[i] = leftArray[i] && rightArray[i];
1118 }
1119 }
1120 break;
1121
1122 case EOpLogicalOr:
1123 {
1124 resultArray = new TConstantUnion[objectSize];
1125 for (size_t i = 0; i < objectSize; i++)
1126 {
1127 resultArray[i] = leftArray[i] || rightArray[i];
1128 }
1129 }
1130 break;
1131
1132 case EOpLogicalXor:
1133 {
1134 resultArray = new TConstantUnion[objectSize];
1135 for (size_t i = 0; i < objectSize; i++)
1136 {
1137 switch (getType().getBasicType())
1138 {
1139 case EbtBool:
1140 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1141 break;
1142 default:
1143 UNREACHABLE();
1144 break;
1145 }
1146 }
1147 }
1148 break;
1149
1150 case EOpBitwiseAnd:
1151 resultArray = new TConstantUnion[objectSize];
1152 for (size_t i = 0; i < objectSize; i++)
1153 resultArray[i] = leftArray[i] & rightArray[i];
1154 break;
1155 case EOpBitwiseXor:
1156 resultArray = new TConstantUnion[objectSize];
1157 for (size_t i = 0; i < objectSize; i++)
1158 resultArray[i] = leftArray[i] ^ rightArray[i];
1159 break;
1160 case EOpBitwiseOr:
1161 resultArray = new TConstantUnion[objectSize];
1162 for (size_t i = 0; i < objectSize; i++)
1163 resultArray[i] = leftArray[i] | rightArray[i];
1164 break;
1165 case EOpBitShiftLeft:
1166 resultArray = new TConstantUnion[objectSize];
1167 for (size_t i = 0; i < objectSize; i++)
1168 resultArray[i] = leftArray[i] << rightArray[i];
1169 break;
1170 case EOpBitShiftRight:
1171 resultArray = new TConstantUnion[objectSize];
1172 for (size_t i = 0; i < objectSize; i++)
1173 resultArray[i] = leftArray[i] >> rightArray[i];
1174 break;
1175
1176 case EOpLessThan:
1177 ASSERT(objectSize == 1);
1178 resultArray = new TConstantUnion[1];
1179 resultArray->setBConst(*leftArray < *rightArray);
1180 break;
1181
1182 case EOpGreaterThan:
1183 ASSERT(objectSize == 1);
1184 resultArray = new TConstantUnion[1];
1185 resultArray->setBConst(*leftArray > *rightArray);
1186 break;
1187
1188 case EOpLessThanEqual:
1189 ASSERT(objectSize == 1);
1190 resultArray = new TConstantUnion[1];
1191 resultArray->setBConst(!(*leftArray > *rightArray));
1192 break;
1193
1194 case EOpGreaterThanEqual:
1195 ASSERT(objectSize == 1);
1196 resultArray = new TConstantUnion[1];
1197 resultArray->setBConst(!(*leftArray < *rightArray));
1198 break;
1199
1200 case EOpEqual:
1201 case EOpNotEqual:
1202 {
1203 resultArray = new TConstantUnion[1];
1204 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001205 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001206 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001207 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001208 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001209 equal = false;
1210 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001211 }
1212 }
1213 if (op == EOpEqual)
1214 {
1215 resultArray->setBConst(equal);
1216 }
1217 else
1218 {
1219 resultArray->setBConst(!equal);
1220 }
1221 }
1222 break;
1223
1224 default:
1225 infoSink.info.message(
1226 EPrefixInternalError, getLine(),
1227 "Invalid operator for constant folding");
1228 return nullptr;
1229 }
1230 return resultArray;
1231}
1232
1233//
1234// The fold functions see if an operation on a constant can be done in place,
1235// without generating run-time code.
1236//
Olli Etuaho95310b02015-06-02 17:43:38 +03001237// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001238//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301239TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001240{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301241 //
1242 // Do operations where the return type has a different number of components compared to the operand type.
1243 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001244
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001245 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301246 if (!operandArray)
1247 return nullptr;
1248
1249 size_t objectSize = getType().getObjectSize();
1250 TConstantUnion *resultArray = nullptr;
1251 switch (op)
1252 {
1253 case EOpAny:
1254 if (getType().getBasicType() == EbtBool)
1255 {
1256 resultArray = new TConstantUnion();
1257 resultArray->setBConst(false);
1258 for (size_t i = 0; i < objectSize; i++)
1259 {
1260 if (operandArray[i].getBConst())
1261 {
1262 resultArray->setBConst(true);
1263 break;
1264 }
1265 }
1266 break;
1267 }
1268 else
1269 {
1270 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1271 return nullptr;
1272 }
1273
1274 case EOpAll:
1275 if (getType().getBasicType() == EbtBool)
1276 {
1277 resultArray = new TConstantUnion();
1278 resultArray->setBConst(true);
1279 for (size_t i = 0; i < objectSize; i++)
1280 {
1281 if (!operandArray[i].getBConst())
1282 {
1283 resultArray->setBConst(false);
1284 break;
1285 }
1286 }
1287 break;
1288 }
1289 else
1290 {
1291 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1292 return nullptr;
1293 }
1294
1295 case EOpLength:
1296 if (getType().getBasicType() == EbtFloat)
1297 {
1298 resultArray = new TConstantUnion();
1299 resultArray->setFConst(VectorLength(operandArray, objectSize));
1300 break;
1301 }
1302 else
1303 {
1304 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1305 return nullptr;
1306 }
1307
1308 case EOpTranspose:
1309 if (getType().getBasicType() == EbtFloat)
1310 {
1311 resultArray = new TConstantUnion[objectSize];
1312 angle::Matrix<float> result =
1313 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1314 SetUnionArrayFromMatrix(result, resultArray);
1315 break;
1316 }
1317 else
1318 {
1319 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1320 return nullptr;
1321 }
1322
1323 case EOpDeterminant:
1324 if (getType().getBasicType() == EbtFloat)
1325 {
1326 unsigned int size = getType().getNominalSize();
1327 ASSERT(size >= 2 && size <= 4);
1328 resultArray = new TConstantUnion();
1329 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1330 break;
1331 }
1332 else
1333 {
1334 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1335 return nullptr;
1336 }
1337
1338 case EOpInverse:
1339 if (getType().getBasicType() == EbtFloat)
1340 {
1341 unsigned int size = getType().getNominalSize();
1342 ASSERT(size >= 2 && size <= 4);
1343 resultArray = new TConstantUnion[objectSize];
1344 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1345 SetUnionArrayFromMatrix(result, resultArray);
1346 break;
1347 }
1348 else
1349 {
1350 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1351 return nullptr;
1352 }
1353
1354 case EOpPackSnorm2x16:
1355 if (getType().getBasicType() == EbtFloat)
1356 {
1357 ASSERT(getType().getNominalSize() == 2);
1358 resultArray = new TConstantUnion();
1359 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1360 break;
1361 }
1362 else
1363 {
1364 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1365 return nullptr;
1366 }
1367
1368 case EOpUnpackSnorm2x16:
1369 if (getType().getBasicType() == EbtUInt)
1370 {
1371 resultArray = new TConstantUnion[2];
1372 float f1, f2;
1373 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1374 resultArray[0].setFConst(f1);
1375 resultArray[1].setFConst(f2);
1376 break;
1377 }
1378 else
1379 {
1380 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1381 return nullptr;
1382 }
1383
1384 case EOpPackUnorm2x16:
1385 if (getType().getBasicType() == EbtFloat)
1386 {
1387 ASSERT(getType().getNominalSize() == 2);
1388 resultArray = new TConstantUnion();
1389 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1390 break;
1391 }
1392 else
1393 {
1394 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1395 return nullptr;
1396 }
1397
1398 case EOpUnpackUnorm2x16:
1399 if (getType().getBasicType() == EbtUInt)
1400 {
1401 resultArray = new TConstantUnion[2];
1402 float f1, f2;
1403 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1404 resultArray[0].setFConst(f1);
1405 resultArray[1].setFConst(f2);
1406 break;
1407 }
1408 else
1409 {
1410 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1411 return nullptr;
1412 }
1413
1414 case EOpPackHalf2x16:
1415 if (getType().getBasicType() == EbtFloat)
1416 {
1417 ASSERT(getType().getNominalSize() == 2);
1418 resultArray = new TConstantUnion();
1419 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1420 break;
1421 }
1422 else
1423 {
1424 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1425 return nullptr;
1426 }
1427
1428 case EOpUnpackHalf2x16:
1429 if (getType().getBasicType() == EbtUInt)
1430 {
1431 resultArray = new TConstantUnion[2];
1432 float f1, f2;
1433 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1434 resultArray[0].setFConst(f1);
1435 resultArray[1].setFConst(f2);
1436 break;
1437 }
1438 else
1439 {
1440 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1441 return nullptr;
1442 }
1443 break;
1444
1445 default:
1446 break;
1447 }
1448
1449 return resultArray;
1450}
1451
1452TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1453{
1454 //
1455 // Do unary operations where the return type is the same as operand type.
1456 //
1457
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001458 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001459 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301460 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001461
1462 size_t objectSize = getType().getObjectSize();
1463
Arun Patoleab2b9a22015-07-06 18:27:56 +05301464 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1465 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301466 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301467 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301468 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301469 case EOpNegative:
1470 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301471 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301472 case EbtFloat:
1473 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301474 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301475 case EbtInt:
1476 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301477 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301478 case EbtUInt:
1479 resultArray[i].setUConst(static_cast<unsigned int>(
1480 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301481 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301482 default:
1483 infoSink.info.message(
1484 EPrefixInternalError, getLine(),
1485 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301486 return nullptr;
1487 }
1488 break;
1489
Arun Patoleab2b9a22015-07-06 18:27:56 +05301490 case EOpPositive:
1491 switch (getType().getBasicType())
1492 {
1493 case EbtFloat:
1494 resultArray[i].setFConst(operandArray[i].getFConst());
1495 break;
1496 case EbtInt:
1497 resultArray[i].setIConst(operandArray[i].getIConst());
1498 break;
1499 case EbtUInt:
1500 resultArray[i].setUConst(static_cast<unsigned int>(
1501 static_cast<int>(operandArray[i].getUConst())));
1502 break;
1503 default:
1504 infoSink.info.message(
1505 EPrefixInternalError, getLine(),
1506 "Unary operation not folded into constant");
1507 return nullptr;
1508 }
1509 break;
1510
1511 case EOpLogicalNot:
1512 // this code is written for possible future use,
1513 // will not get executed currently
1514 switch (getType().getBasicType())
1515 {
1516 case EbtBool:
1517 resultArray[i].setBConst(!operandArray[i].getBConst());
1518 break;
1519 default:
1520 infoSink.info.message(
1521 EPrefixInternalError, getLine(),
1522 "Unary operation not folded into constant");
1523 return nullptr;
1524 }
1525 break;
1526
1527 case EOpBitwiseNot:
1528 switch (getType().getBasicType())
1529 {
1530 case EbtInt:
1531 resultArray[i].setIConst(~operandArray[i].getIConst());
1532 break;
1533 case EbtUInt:
1534 resultArray[i].setUConst(~operandArray[i].getUConst());
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 EOpRadians:
1545 if (getType().getBasicType() == EbtFloat)
1546 {
1547 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1548 break;
1549 }
1550 infoSink.info.message(
1551 EPrefixInternalError, getLine(),
1552 "Unary operation not folded into constant");
1553 return nullptr;
1554
1555 case EOpDegrees:
1556 if (getType().getBasicType() == EbtFloat)
1557 {
1558 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1559 break;
1560 }
1561 infoSink.info.message(
1562 EPrefixInternalError, getLine(),
1563 "Unary operation not folded into constant");
1564 return nullptr;
1565
1566 case EOpSin:
1567 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1568 return nullptr;
1569 break;
1570
1571 case EOpCos:
1572 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1573 return nullptr;
1574 break;
1575
1576 case EOpTan:
1577 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1578 return nullptr;
1579 break;
1580
1581 case EOpAsin:
1582 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1583 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1584 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1585 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1586 return nullptr;
1587 break;
1588
1589 case EOpAcos:
1590 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1591 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1592 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1593 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1594 return nullptr;
1595 break;
1596
1597 case EOpAtan:
1598 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1599 return nullptr;
1600 break;
1601
1602 case EOpSinh:
1603 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1604 return nullptr;
1605 break;
1606
1607 case EOpCosh:
1608 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1609 return nullptr;
1610 break;
1611
1612 case EOpTanh:
1613 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1614 return nullptr;
1615 break;
1616
1617 case EOpAsinh:
1618 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1619 return nullptr;
1620 break;
1621
1622 case EOpAcosh:
1623 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1624 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1625 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1626 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1627 return nullptr;
1628 break;
1629
1630 case EOpAtanh:
1631 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1632 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1633 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1634 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1635 return nullptr;
1636 break;
1637
1638 case EOpAbs:
1639 switch (getType().getBasicType())
1640 {
1641 case EbtFloat:
1642 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1643 break;
1644 case EbtInt:
1645 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1646 break;
1647 default:
1648 infoSink.info.message(
1649 EPrefixInternalError, getLine(),
1650 "Unary operation not folded into constant");
1651 return nullptr;
1652 }
1653 break;
1654
1655 case EOpSign:
1656 switch (getType().getBasicType())
1657 {
1658 case EbtFloat:
1659 {
1660 float fConst = operandArray[i].getFConst();
1661 float fResult = 0.0f;
1662 if (fConst > 0.0f)
1663 fResult = 1.0f;
1664 else if (fConst < 0.0f)
1665 fResult = -1.0f;
1666 resultArray[i].setFConst(fResult);
1667 }
1668 break;
1669 case EbtInt:
1670 {
1671 int iConst = operandArray[i].getIConst();
1672 int iResult = 0;
1673 if (iConst > 0)
1674 iResult = 1;
1675 else if (iConst < 0)
1676 iResult = -1;
1677 resultArray[i].setIConst(iResult);
1678 }
1679 break;
1680 default:
1681 infoSink.info.message(
1682 EPrefixInternalError, getLine(),
1683 "Unary operation not folded into constant");
1684 return nullptr;
1685 }
1686 break;
1687
1688 case EOpFloor:
1689 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1690 return nullptr;
1691 break;
1692
1693 case EOpTrunc:
1694 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1695 return nullptr;
1696 break;
1697
1698 case EOpRound:
1699 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1700 return nullptr;
1701 break;
1702
1703 case EOpRoundEven:
1704 if (getType().getBasicType() == EbtFloat)
1705 {
1706 float x = operandArray[i].getFConst();
1707 float result;
1708 float fractPart = modff(x, &result);
1709 if (fabsf(fractPart) == 0.5f)
1710 result = 2.0f * roundf(x / 2.0f);
1711 else
1712 result = roundf(x);
1713 resultArray[i].setFConst(result);
1714 break;
1715 }
1716 infoSink.info.message(
1717 EPrefixInternalError, getLine(),
1718 "Unary operation not folded into constant");
1719 return nullptr;
1720
1721 case EOpCeil:
1722 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1723 return nullptr;
1724 break;
1725
1726 case EOpFract:
1727 if (getType().getBasicType() == EbtFloat)
1728 {
1729 float x = operandArray[i].getFConst();
1730 resultArray[i].setFConst(x - floorf(x));
1731 break;
1732 }
1733 infoSink.info.message(
1734 EPrefixInternalError, getLine(),
1735 "Unary operation not folded into constant");
1736 return nullptr;
1737
Arun Patole551279e2015-07-07 18:18:23 +05301738 case EOpIsNan:
1739 if (getType().getBasicType() == EbtFloat)
1740 {
1741 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1742 break;
1743 }
1744 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1745 return nullptr;
1746
1747 case EOpIsInf:
1748 if (getType().getBasicType() == EbtFloat)
1749 {
1750 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1751 break;
1752 }
1753 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1754 return nullptr;
1755
1756 case EOpFloatBitsToInt:
1757 if (getType().getBasicType() == EbtFloat)
1758 {
1759 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1760 break;
1761 }
1762 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1763 return nullptr;
1764
1765 case EOpFloatBitsToUint:
1766 if (getType().getBasicType() == EbtFloat)
1767 {
1768 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1769 break;
1770 }
1771 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1772 return nullptr;
1773
1774 case EOpIntBitsToFloat:
1775 if (getType().getBasicType() == EbtInt)
1776 {
1777 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1778 break;
1779 }
1780 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1781 return nullptr;
1782
1783 case EOpUintBitsToFloat:
1784 if (getType().getBasicType() == EbtUInt)
1785 {
1786 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1787 break;
1788 }
1789 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1790 return nullptr;
1791
Arun Patoleab2b9a22015-07-06 18:27:56 +05301792 case EOpExp:
1793 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1794 return nullptr;
1795 break;
1796
1797 case EOpLog:
1798 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1799 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1800 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1801 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1802 return nullptr;
1803 break;
1804
1805 case EOpExp2:
1806 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1807 return nullptr;
1808 break;
1809
1810 case EOpLog2:
1811 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1812 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1813 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1814 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1815 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1816 return nullptr;
1817 else
1818 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1819 break;
1820
1821 case EOpSqrt:
1822 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1823 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1824 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1825 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1826 return nullptr;
1827 break;
1828
1829 case EOpInverseSqrt:
1830 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1831 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1832 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1833 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1834 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1835 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1836 return nullptr;
1837 else
1838 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1839 break;
1840
1841 case EOpVectorLogicalNot:
1842 if (getType().getBasicType() == EbtBool)
1843 {
1844 resultArray[i].setBConst(!operandArray[i].getBConst());
1845 break;
1846 }
1847 infoSink.info.message(
1848 EPrefixInternalError, getLine(),
1849 "Unary operation not folded into constant");
1850 return nullptr;
1851
1852 case EOpNormalize:
1853 if (getType().getBasicType() == EbtFloat)
1854 {
1855 float x = operandArray[i].getFConst();
1856 float length = VectorLength(operandArray, objectSize);
1857 if (length)
1858 resultArray[i].setFConst(x / length);
1859 else
1860 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1861 &resultArray[i]);
1862 break;
1863 }
1864 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1865 return nullptr;
1866
Arun Patole0c5409f2015-07-08 15:17:53 +05301867 case EOpDFdx:
1868 case EOpDFdy:
1869 case EOpFwidth:
1870 if (getType().getBasicType() == EbtFloat)
1871 {
1872 // Derivatives of constant arguments should be 0.
1873 resultArray[i].setFConst(0.0f);
1874 break;
1875 }
1876 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1877 return nullptr;
1878
Arun Patole1155ddd2015-06-05 18:04:36 +05301879 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301881 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301882 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001883
Arun Patoleab2b9a22015-07-06 18:27:56 +05301884 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001885}
1886
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001887bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1888 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301889{
1890 ASSERT(builtinFunc);
1891
1892 if (getType().getBasicType() == EbtFloat)
1893 {
1894 result->setFConst(builtinFunc(parameter.getFConst()));
1895 return true;
1896 }
1897
1898 infoSink.info.message(
1899 EPrefixInternalError, getLine(),
1900 "Unary operation not folded into constant");
1901 return false;
1902}
1903
Jamie Madillb1a85f42014-08-19 15:23:24 -04001904// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001905TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1906 TInfoSink &infoSink)
1907{
1908 ASSERT(aggregate->getSequence()->size() > 0u);
1909 size_t resultSize = aggregate->getType().getObjectSize();
1910 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1911 TBasicType basicType = aggregate->getBasicType();
1912
1913 size_t resultIndex = 0u;
1914
1915 if (aggregate->getSequence()->size() == 1u)
1916 {
1917 TIntermNode *argument = aggregate->getSequence()->front();
1918 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1919 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1920 // Check the special case of constructing a matrix diagonal from a single scalar,
1921 // or a vector from a single scalar.
1922 if (argumentConstant->getType().getObjectSize() == 1u)
1923 {
1924 if (aggregate->isMatrix())
1925 {
1926 int resultCols = aggregate->getType().getCols();
1927 int resultRows = aggregate->getType().getRows();
1928 for (int col = 0; col < resultCols; ++col)
1929 {
1930 for (int row = 0; row < resultRows; ++row)
1931 {
1932 if (col == row)
1933 {
1934 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1935 }
1936 else
1937 {
1938 resultArray[resultIndex].setFConst(0.0f);
1939 }
1940 ++resultIndex;
1941 }
1942 }
1943 }
1944 else
1945 {
1946 while (resultIndex < resultSize)
1947 {
1948 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1949 ++resultIndex;
1950 }
1951 }
1952 ASSERT(resultIndex == resultSize);
1953 return resultArray;
1954 }
1955 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1956 {
1957 // The special case of constructing a matrix from a matrix.
1958 int argumentCols = argumentConstant->getType().getCols();
1959 int argumentRows = argumentConstant->getType().getRows();
1960 int resultCols = aggregate->getType().getCols();
1961 int resultRows = aggregate->getType().getRows();
1962 for (int col = 0; col < resultCols; ++col)
1963 {
1964 for (int row = 0; row < resultRows; ++row)
1965 {
1966 if (col < argumentCols && row < argumentRows)
1967 {
1968 resultArray[resultIndex].cast(basicType,
1969 argumentUnionArray[col * argumentRows + row]);
1970 }
1971 else if (col == row)
1972 {
1973 resultArray[resultIndex].setFConst(1.0f);
1974 }
1975 else
1976 {
1977 resultArray[resultIndex].setFConst(0.0f);
1978 }
1979 ++resultIndex;
1980 }
1981 }
1982 ASSERT(resultIndex == resultSize);
1983 return resultArray;
1984 }
1985 }
1986
1987 for (TIntermNode *&argument : *aggregate->getSequence())
1988 {
1989 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1990 size_t argumentSize = argumentConstant->getType().getObjectSize();
1991 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1992 for (size_t i = 0u; i < argumentSize; ++i)
1993 {
1994 if (resultIndex >= resultSize)
1995 break;
1996 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1997 ++resultIndex;
1998 }
1999 }
2000 ASSERT(resultIndex == resultSize);
2001 return resultArray;
2002}
2003
2004// static
Olli Etuahob43846e2015-06-02 18:18:57 +03002005TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05302006{
Olli Etuahob43846e2015-06-02 18:18:57 +03002007 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302008 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002009 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002010 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302011 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002012 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302013 TBasicType basicType = EbtVoid;
2014 TSourceLoc loc;
2015 for (unsigned int i = 0; i < paramsCount; i++)
2016 {
2017 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002018 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302019
2020 if (i == 0)
2021 {
2022 basicType = paramConstant->getType().getBasicType();
2023 loc = paramConstant->getLine();
2024 }
2025 unionArrays[i] = paramConstant->getUnionArrayPointer();
2026 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002027 if (objectSizes[i] > maxObjectSize)
2028 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302029 }
2030
Arun Patole7fa33552015-06-10 15:15:18 +05302031 if (!(*sequence)[0]->getAsTyped()->isMatrix())
2032 {
2033 for (unsigned int i = 0; i < paramsCount; i++)
2034 if (objectSizes[i] != maxObjectSize)
2035 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2036 }
Arun Patole274f0702015-05-05 13:33:30 +05302037
Olli Etuahob43846e2015-06-02 18:18:57 +03002038 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302039 if (paramsCount == 2)
2040 {
2041 //
2042 // Binary built-in
2043 //
2044 switch (op)
2045 {
Arun Patolebf790422015-05-18 17:53:04 +05302046 case EOpAtan:
2047 {
2048 if (basicType == EbtFloat)
2049 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002050 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302051 for (size_t i = 0; i < maxObjectSize; i++)
2052 {
2053 float y = unionArrays[0][i].getFConst();
2054 float x = unionArrays[1][i].getFConst();
2055 // Results are undefined if x and y are both 0.
2056 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002057 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302058 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002059 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302060 }
2061 }
2062 else
2063 UNREACHABLE();
2064 }
2065 break;
2066
2067 case EOpPow:
2068 {
2069 if (basicType == EbtFloat)
2070 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002071 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302072 for (size_t i = 0; i < maxObjectSize; i++)
2073 {
2074 float x = unionArrays[0][i].getFConst();
2075 float y = unionArrays[1][i].getFConst();
2076 // Results are undefined if x < 0.
2077 // Results are undefined if x = 0 and y <= 0.
2078 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002079 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302080 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002081 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302082 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002083 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302084 }
2085 }
2086 else
2087 UNREACHABLE();
2088 }
2089 break;
2090
2091 case EOpMod:
2092 {
2093 if (basicType == EbtFloat)
2094 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002095 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302096 for (size_t i = 0; i < maxObjectSize; i++)
2097 {
2098 float x = unionArrays[0][i].getFConst();
2099 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002100 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302101 }
2102 }
2103 else
2104 UNREACHABLE();
2105 }
2106 break;
2107
Arun Patole274f0702015-05-05 13:33:30 +05302108 case EOpMin:
2109 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002110 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302111 for (size_t i = 0; i < maxObjectSize; i++)
2112 {
2113 switch (basicType)
2114 {
2115 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002116 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302117 break;
2118 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002119 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302120 break;
2121 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002122 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302123 break;
2124 default:
2125 UNREACHABLE();
2126 break;
2127 }
2128 }
2129 }
2130 break;
2131
2132 case EOpMax:
2133 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002134 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302135 for (size_t i = 0; i < maxObjectSize; i++)
2136 {
2137 switch (basicType)
2138 {
2139 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002140 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302141 break;
2142 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002143 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302144 break;
2145 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002146 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302147 break;
2148 default:
2149 UNREACHABLE();
2150 break;
2151 }
2152 }
2153 }
2154 break;
2155
Arun Patolebf790422015-05-18 17:53:04 +05302156 case EOpStep:
2157 {
2158 if (basicType == EbtFloat)
2159 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002160 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302161 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002162 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302163 }
2164 else
2165 UNREACHABLE();
2166 }
2167 break;
2168
Arun Patole9d0b1f92015-05-20 14:27:17 +05302169 case EOpLessThan:
2170 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002171 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302172 for (size_t i = 0; i < maxObjectSize; i++)
2173 {
2174 switch (basicType)
2175 {
2176 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002177 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302178 break;
2179 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002180 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302181 break;
2182 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002183 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302184 break;
2185 default:
2186 UNREACHABLE();
2187 break;
2188 }
2189 }
2190 }
2191 break;
2192
2193 case EOpLessThanEqual:
2194 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002195 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302196 for (size_t i = 0; i < maxObjectSize; i++)
2197 {
2198 switch (basicType)
2199 {
2200 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002201 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302202 break;
2203 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002204 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302205 break;
2206 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002207 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302208 break;
2209 default:
2210 UNREACHABLE();
2211 break;
2212 }
2213 }
2214 }
2215 break;
2216
2217 case EOpGreaterThan:
2218 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002219 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302220 for (size_t i = 0; i < maxObjectSize; i++)
2221 {
2222 switch (basicType)
2223 {
2224 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002225 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302226 break;
2227 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002228 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302229 break;
2230 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002231 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302232 break;
2233 default:
2234 UNREACHABLE();
2235 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002236 }
2237 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302238 }
2239 break;
2240
2241 case EOpGreaterThanEqual:
2242 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002243 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 for (size_t i = 0; i < maxObjectSize; i++)
2245 {
2246 switch (basicType)
2247 {
2248 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002249 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302250 break;
2251 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002252 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302253 break;
2254 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002255 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302256 break;
2257 default:
2258 UNREACHABLE();
2259 break;
2260 }
2261 }
2262 }
2263 break;
2264
2265 case EOpVectorEqual:
2266 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002267 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302268 for (size_t i = 0; i < maxObjectSize; i++)
2269 {
2270 switch (basicType)
2271 {
2272 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002273 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302274 break;
2275 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002276 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302277 break;
2278 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002279 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302280 break;
2281 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002282 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302283 break;
2284 default:
2285 UNREACHABLE();
2286 break;
2287 }
2288 }
2289 }
2290 break;
2291
2292 case EOpVectorNotEqual:
2293 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002294 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302295 for (size_t i = 0; i < maxObjectSize; i++)
2296 {
2297 switch (basicType)
2298 {
2299 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002300 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302301 break;
2302 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002303 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302304 break;
2305 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002306 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302307 break;
2308 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002309 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302310 break;
2311 default:
2312 UNREACHABLE();
2313 break;
2314 }
2315 }
2316 }
2317 break;
2318
Arun Patole1155ddd2015-06-05 18:04:36 +05302319 case EOpDistance:
2320 if (basicType == EbtFloat)
2321 {
2322 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002323 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302324 for (size_t i = 0; i < maxObjectSize; i++)
2325 {
2326 float x = unionArrays[0][i].getFConst();
2327 float y = unionArrays[1][i].getFConst();
2328 distanceArray[i].setFConst(x - y);
2329 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002330 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302331 }
2332 else
2333 UNREACHABLE();
2334 break;
2335
2336 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002337
Arun Patole1155ddd2015-06-05 18:04:36 +05302338 if (basicType == EbtFloat)
2339 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002340 resultArray = new TConstantUnion();
2341 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302342 }
2343 else
2344 UNREACHABLE();
2345 break;
2346
2347 case EOpCross:
2348 if (basicType == EbtFloat && maxObjectSize == 3)
2349 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002350 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302351 float x0 = unionArrays[0][0].getFConst();
2352 float x1 = unionArrays[0][1].getFConst();
2353 float x2 = unionArrays[0][2].getFConst();
2354 float y0 = unionArrays[1][0].getFConst();
2355 float y1 = unionArrays[1][1].getFConst();
2356 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002357 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2358 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2359 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302360 }
2361 else
2362 UNREACHABLE();
2363 break;
2364
2365 case EOpReflect:
2366 if (basicType == EbtFloat)
2367 {
2368 // genType reflect (genType I, genType N) :
2369 // For the incident vector I and surface orientation N, returns the reflection direction:
2370 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002371 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302372 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2373 for (size_t i = 0; i < maxObjectSize; i++)
2374 {
2375 float result = unionArrays[0][i].getFConst() -
2376 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002377 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302378 }
2379 }
2380 else
2381 UNREACHABLE();
2382 break;
2383
Arun Patole7fa33552015-06-10 15:15:18 +05302384 case EOpMul:
2385 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2386 (*sequence)[1]->getAsTyped()->isMatrix())
2387 {
2388 // Perform component-wise matrix multiplication.
2389 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002390 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302391 angle::Matrix<float> result =
2392 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2393 SetUnionArrayFromMatrix(result, resultArray);
2394 }
2395 else
2396 UNREACHABLE();
2397 break;
2398
2399 case EOpOuterProduct:
2400 if (basicType == EbtFloat)
2401 {
2402 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2403 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2404 resultArray = new TConstantUnion[numRows * numCols];
2405 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002406 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2407 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302408 SetUnionArrayFromMatrix(result, resultArray);
2409 }
2410 else
2411 UNREACHABLE();
2412 break;
2413
Arun Patole274f0702015-05-05 13:33:30 +05302414 default:
2415 UNREACHABLE();
2416 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2417 return nullptr;
2418 }
2419 }
2420 else if (paramsCount == 3)
2421 {
2422 //
2423 // Ternary built-in
2424 //
2425 switch (op)
2426 {
2427 case EOpClamp:
2428 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002429 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302430 for (size_t i = 0; i < maxObjectSize; i++)
2431 {
2432 switch (basicType)
2433 {
2434 case EbtFloat:
2435 {
2436 float x = unionArrays[0][i].getFConst();
2437 float min = unionArrays[1][i].getFConst();
2438 float max = unionArrays[2][i].getFConst();
2439 // Results are undefined if min > max.
2440 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002441 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302442 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002443 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302444 }
2445 break;
2446 case EbtInt:
2447 {
2448 int x = unionArrays[0][i].getIConst();
2449 int min = unionArrays[1][i].getIConst();
2450 int max = unionArrays[2][i].getIConst();
2451 // Results are undefined if min > max.
2452 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002453 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302454 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002455 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302456 }
2457 break;
2458 case EbtUInt:
2459 {
2460 unsigned int x = unionArrays[0][i].getUConst();
2461 unsigned int min = unionArrays[1][i].getUConst();
2462 unsigned int max = unionArrays[2][i].getUConst();
2463 // Results are undefined if min > max.
2464 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002465 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302466 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002467 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302468 }
2469 break;
2470 default:
2471 UNREACHABLE();
2472 break;
2473 }
2474 }
2475 }
2476 break;
2477
Arun Patolebf790422015-05-18 17:53:04 +05302478 case EOpMix:
2479 {
2480 if (basicType == EbtFloat)
2481 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002482 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302483 for (size_t i = 0; i < maxObjectSize; i++)
2484 {
2485 float x = unionArrays[0][i].getFConst();
2486 float y = unionArrays[1][i].getFConst();
2487 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2488 if (type == EbtFloat)
2489 {
2490 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2491 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002492 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302493 }
2494 else // 3rd parameter is EbtBool
2495 {
2496 ASSERT(type == EbtBool);
2497 // Selects which vector each returned component comes from.
2498 // For a component of a that is false, the corresponding component of x is returned.
2499 // For a component of a that is true, the corresponding component of y is returned.
2500 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002501 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302502 }
2503 }
2504 }
2505 else
2506 UNREACHABLE();
2507 }
2508 break;
2509
2510 case EOpSmoothStep:
2511 {
2512 if (basicType == EbtFloat)
2513 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002514 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302515 for (size_t i = 0; i < maxObjectSize; i++)
2516 {
2517 float edge0 = unionArrays[0][i].getFConst();
2518 float edge1 = unionArrays[1][i].getFConst();
2519 float x = unionArrays[2][i].getFConst();
2520 // Results are undefined if edge0 >= edge1.
2521 if (edge0 >= edge1)
2522 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002523 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302524 }
2525 else
2526 {
2527 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2528 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2529 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002530 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302531 }
2532 }
2533 }
2534 else
2535 UNREACHABLE();
2536 }
2537 break;
2538
Arun Patole1155ddd2015-06-05 18:04:36 +05302539 case EOpFaceForward:
2540 if (basicType == EbtFloat)
2541 {
2542 // genType faceforward(genType N, genType I, genType Nref) :
2543 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002544 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302545 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2546 for (size_t i = 0; i < maxObjectSize; i++)
2547 {
2548 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002549 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302550 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002551 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302552 }
2553 }
2554 else
2555 UNREACHABLE();
2556 break;
2557
2558 case EOpRefract:
2559 if (basicType == EbtFloat)
2560 {
2561 // genType refract(genType I, genType N, float eta) :
2562 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2563 // return the refraction vector. The result is computed by
2564 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2565 // if (k < 0.0)
2566 // return genType(0.0)
2567 // else
2568 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002569 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302570 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2571 for (size_t i = 0; i < maxObjectSize; i++)
2572 {
2573 float eta = unionArrays[2][i].getFConst();
2574 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2575 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002576 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302577 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002578 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302579 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2580 }
2581 }
2582 else
2583 UNREACHABLE();
2584 break;
2585
Arun Patole274f0702015-05-05 13:33:30 +05302586 default:
2587 UNREACHABLE();
2588 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2589 return nullptr;
2590 }
2591 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002592 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302593}
2594
2595// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002596TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2597{
2598 if (hashFunction == NULL || name.empty())
2599 return name;
2600 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2601 TStringStream stream;
2602 stream << HASHED_NAME_PREFIX << std::hex << number;
2603 TString hashedName = stream.str();
2604 return hashedName;
2605}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002606
2607void TIntermTraverser::updateTree()
2608{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002609 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2610 {
2611 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2612 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002613 if (!insertion.insertionsAfter.empty())
2614 {
2615 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2616 insertion.insertionsAfter);
2617 ASSERT(inserted);
2618 UNUSED_ASSERTION_VARIABLE(inserted);
2619 }
2620 if (!insertion.insertionsBefore.empty())
2621 {
2622 bool inserted =
2623 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2624 ASSERT(inserted);
2625 UNUSED_ASSERTION_VARIABLE(inserted);
2626 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002627 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002628 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2629 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002630 const NodeUpdateEntry &replacement = mReplacements[ii];
2631 ASSERT(replacement.parent);
2632 bool replaced = replacement.parent->replaceChildNode(
2633 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002634 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002635 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002636
Olli Etuahocd94ef92015-04-16 19:18:10 +03002637 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002638 {
2639 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002640 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002641 // be replaced, we need to make sure we don't update the replaced
2642 // node; instead, we update the replacement node.
2643 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2644 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002645 NodeUpdateEntry &replacement2 = mReplacements[jj];
2646 if (replacement2.parent == replacement.original)
2647 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002648 }
2649 }
2650 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002651 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2652 {
2653 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2654 ASSERT(replacement.parent);
2655 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2656 replacement.original, replacement.replacements);
2657 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002658 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002659 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002660
2661 mInsertions.clear();
2662 mReplacements.clear();
2663 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002664}