blob: fad6214ff13c0252c34ad7791845b2d12776d22d [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
Olli Etuahod4f4c112016-04-15 15:11:24 +0300354bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
355{
356 TIntermAggregate *constructor = getAsAggregate();
357 if (!constructor || !constructor->isConstructor())
358 {
359 return false;
360 }
361 for (TIntermNode *&node : *constructor->getSequence())
362 {
363 if (!node->getAsConstantUnion())
364 return false;
365 }
366 return true;
367}
368
Olli Etuahod7a25242015-08-18 13:49:45 +0300369TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
370{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200371 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300372}
373
374TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
375 : TIntermOperator(node),
376 mName(node.mName),
377 mUserDefined(node.mUserDefined),
378 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300379 mUseEmulatedFunction(node.mUseEmulatedFunction),
380 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
381{
382 for (TIntermNode *child : node.mSequence)
383 {
384 TIntermTyped *typedChild = child->getAsTyped();
385 ASSERT(typedChild != nullptr);
386 TIntermTyped *childCopy = typedChild->deepCopy();
387 mSequence.push_back(childCopy);
388 }
389}
390
391TIntermBinary::TIntermBinary(const TIntermBinary &node)
392 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
393{
394 TIntermTyped *leftCopy = node.mLeft->deepCopy();
395 TIntermTyped *rightCopy = node.mRight->deepCopy();
396 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
397 mLeft = leftCopy;
398 mRight = rightCopy;
399}
400
401TIntermUnary::TIntermUnary(const TIntermUnary &node)
402 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
403{
404 TIntermTyped *operandCopy = node.mOperand->deepCopy();
405 ASSERT(operandCopy != nullptr);
406 mOperand = operandCopy;
407}
408
409TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
410{
411 // Only supported for ternary nodes, not if statements.
412 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
413 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
414 ASSERT(trueTyped != nullptr);
415 ASSERT(falseTyped != nullptr);
416 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
417 TIntermTyped *trueCopy = trueTyped->deepCopy();
418 TIntermTyped *falseCopy = falseTyped->deepCopy();
419 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
420 mCondition = conditionCopy;
421 mTrueBlock = trueCopy;
422 mFalseBlock = falseCopy;
423}
424
Jamie Madillb1a85f42014-08-19 15:23:24 -0400425//
426// Say whether or not an operation node changes the value of a variable.
427//
428bool TIntermOperator::isAssignment() const
429{
430 switch (mOp)
431 {
432 case EOpPostIncrement:
433 case EOpPostDecrement:
434 case EOpPreIncrement:
435 case EOpPreDecrement:
436 case EOpAssign:
437 case EOpAddAssign:
438 case EOpSubAssign:
439 case EOpMulAssign:
440 case EOpVectorTimesMatrixAssign:
441 case EOpVectorTimesScalarAssign:
442 case EOpMatrixTimesScalarAssign:
443 case EOpMatrixTimesMatrixAssign:
444 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200445 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200446 case EOpBitShiftLeftAssign:
447 case EOpBitShiftRightAssign:
448 case EOpBitwiseAndAssign:
449 case EOpBitwiseXorAssign:
450 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400451 return true;
452 default:
453 return false;
454 }
455}
456
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300457bool TIntermOperator::isMultiplication() const
458{
459 switch (mOp)
460 {
461 case EOpMul:
462 case EOpMatrixTimesMatrix:
463 case EOpMatrixTimesVector:
464 case EOpMatrixTimesScalar:
465 case EOpVectorTimesMatrix:
466 case EOpVectorTimesScalar:
467 return true;
468 default:
469 return false;
470 }
471}
472
Jamie Madillb1a85f42014-08-19 15:23:24 -0400473//
474// returns true if the operator is for one of the constructors
475//
476bool TIntermOperator::isConstructor() const
477{
478 switch (mOp)
479 {
480 case EOpConstructVec2:
481 case EOpConstructVec3:
482 case EOpConstructVec4:
483 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400484 case EOpConstructMat2x3:
485 case EOpConstructMat2x4:
486 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400487 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400488 case EOpConstructMat3x4:
489 case EOpConstructMat4x2:
490 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400491 case EOpConstructMat4:
492 case EOpConstructFloat:
493 case EOpConstructIVec2:
494 case EOpConstructIVec3:
495 case EOpConstructIVec4:
496 case EOpConstructInt:
497 case EOpConstructUVec2:
498 case EOpConstructUVec3:
499 case EOpConstructUVec4:
500 case EOpConstructUInt:
501 case EOpConstructBVec2:
502 case EOpConstructBVec3:
503 case EOpConstructBVec4:
504 case EOpConstructBool:
505 case EOpConstructStruct:
506 return true;
507 default:
508 return false;
509 }
510}
511
512//
513// Make sure the type of a unary operator is appropriate for its
514// combination of operation and operand type.
515//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200516void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400517{
518 switch (mOp)
519 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200520 case EOpFloatBitsToInt:
521 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200522 case EOpIntBitsToFloat:
523 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200524 case EOpPackSnorm2x16:
525 case EOpPackUnorm2x16:
526 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200527 case EOpUnpackSnorm2x16:
528 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200529 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530530 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200531 case EOpUnpackHalf2x16:
532 mType.setPrecision(EbpMedium);
533 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400534 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200535 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400536 }
537
Olli Etuahof6c694b2015-03-26 14:50:53 +0200538 if (funcReturnType != nullptr)
539 {
540 if (funcReturnType->getBasicType() == EbtBool)
541 {
542 // Bool types should not have precision.
543 setType(*funcReturnType);
544 }
545 else
546 {
547 // Precision of the node has been set based on the operand.
548 setTypePreservePrecision(*funcReturnType);
549 }
550 }
551
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200552 if (mOperand->getQualifier() == EvqConst)
553 mType.setQualifier(EvqConst);
554 else
555 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400556}
557
558//
559// Establishes the type of the resultant operation, as well as
560// makes the operator the correct one for the operands.
561//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200562// For lots of operations it should already be established that the operand
563// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400564//
565bool TIntermBinary::promote(TInfoSink &infoSink)
566{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200567 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400568
Jamie Madillb1a85f42014-08-19 15:23:24 -0400569 //
570 // Base assumption: just make the type the same as the left
571 // operand. Then only deviations from this need be coded.
572 //
573 setType(mLeft->getType());
574
575 // The result gets promoted to the highest precision.
576 TPrecision higherPrecision = GetHigherPrecision(
577 mLeft->getPrecision(), mRight->getPrecision());
578 getTypePointer()->setPrecision(higherPrecision);
579
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200580 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400581 // Binary operations results in temporary variables unless both
582 // operands are const.
583 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
584 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200585 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400586 getTypePointer()->setQualifier(EvqTemporary);
587 }
588
589 const int nominalSize =
590 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
591
592 //
593 // All scalars or structs. Code after this test assumes this case is removed!
594 //
595 if (nominalSize == 1)
596 {
597 switch (mOp)
598 {
599 //
600 // Promote to conditional
601 //
602 case EOpEqual:
603 case EOpNotEqual:
604 case EOpLessThan:
605 case EOpGreaterThan:
606 case EOpLessThanEqual:
607 case EOpGreaterThanEqual:
608 setType(TType(EbtBool, EbpUndefined));
609 break;
610
611 //
612 // And and Or operate on conditionals
613 //
614 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200615 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400616 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200617 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400618 setType(TType(EbtBool, EbpUndefined));
619 break;
620
621 default:
622 break;
623 }
624 return true;
625 }
626
627 // If we reach here, at least one of the operands is vector or matrix.
628 // The other operand could be a scalar, vector, or matrix.
629 // Can these two operands be combined?
630 //
631 TBasicType basicType = mLeft->getBasicType();
632 switch (mOp)
633 {
634 case EOpMul:
635 if (!mLeft->isMatrix() && mRight->isMatrix())
636 {
637 if (mLeft->isVector())
638 {
639 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200640 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700641 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400642 }
643 else
644 {
645 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200646 setType(TType(basicType, higherPrecision, resultQualifier,
647 static_cast<unsigned char>(mRight->getCols()),
648 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400649 }
650 }
651 else if (mLeft->isMatrix() && !mRight->isMatrix())
652 {
653 if (mRight->isVector())
654 {
655 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200656 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700657 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400658 }
659 else
660 {
661 mOp = EOpMatrixTimesScalar;
662 }
663 }
664 else if (mLeft->isMatrix() && mRight->isMatrix())
665 {
666 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200667 setType(TType(basicType, higherPrecision, resultQualifier,
668 static_cast<unsigned char>(mRight->getCols()),
669 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400670 }
671 else if (!mLeft->isMatrix() && !mRight->isMatrix())
672 {
673 if (mLeft->isVector() && mRight->isVector())
674 {
675 // leave as component product
676 }
677 else if (mLeft->isVector() || mRight->isVector())
678 {
679 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200680 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700681 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400682 }
683 }
684 else
685 {
686 infoSink.info.message(EPrefixInternalError, getLine(),
687 "Missing elses");
688 return false;
689 }
690
691 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
692 {
693 return false;
694 }
695 break;
696
697 case EOpMulAssign:
698 if (!mLeft->isMatrix() && mRight->isMatrix())
699 {
700 if (mLeft->isVector())
701 {
702 mOp = EOpVectorTimesMatrixAssign;
703 }
704 else
705 {
706 return false;
707 }
708 }
709 else if (mLeft->isMatrix() && !mRight->isMatrix())
710 {
711 if (mRight->isVector())
712 {
713 return false;
714 }
715 else
716 {
717 mOp = EOpMatrixTimesScalarAssign;
718 }
719 }
720 else if (mLeft->isMatrix() && mRight->isMatrix())
721 {
722 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200723 setType(TType(basicType, higherPrecision, resultQualifier,
724 static_cast<unsigned char>(mRight->getCols()),
725 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400726 }
727 else if (!mLeft->isMatrix() && !mRight->isMatrix())
728 {
729 if (mLeft->isVector() && mRight->isVector())
730 {
731 // leave as component product
732 }
733 else if (mLeft->isVector() || mRight->isVector())
734 {
735 if (!mLeft->isVector())
736 return false;
737 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200738 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700739 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400740 }
741 }
742 else
743 {
744 infoSink.info.message(EPrefixInternalError, getLine(),
745 "Missing elses");
746 return false;
747 }
748
749 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
750 {
751 return false;
752 }
753 break;
754
755 case EOpAssign:
756 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200757 // No more additional checks are needed.
758 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
759 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
760 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400761 case EOpAdd:
762 case EOpSub:
763 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200764 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200765 case EOpBitShiftLeft:
766 case EOpBitShiftRight:
767 case EOpBitwiseAnd:
768 case EOpBitwiseXor:
769 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400770 case EOpAddAssign:
771 case EOpSubAssign:
772 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200773 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200774 case EOpBitShiftLeftAssign:
775 case EOpBitShiftRightAssign:
776 case EOpBitwiseAndAssign:
777 case EOpBitwiseXorAssign:
778 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400779 if ((mLeft->isMatrix() && mRight->isVector()) ||
780 (mLeft->isVector() && mRight->isMatrix()))
781 {
782 return false;
783 }
784
785 // Are the sizes compatible?
786 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
787 mLeft->getSecondarySize() != mRight->getSecondarySize())
788 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200789 // If the nominal sizes of operands do not match:
790 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400791 if (!mLeft->isScalar() && !mRight->isScalar())
792 return false;
793
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200794 // In the case of compound assignment other than multiply-assign,
795 // the right side needs to be a scalar. Otherwise a vector/matrix
796 // would be assigned to a scalar. A scalar can't be shifted by a
797 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200798 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200799 (isAssignment() ||
800 mOp == EOpBitShiftLeft ||
801 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200802 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400803 }
804
805 {
806 const int secondarySize = std::max(
807 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200808 setType(TType(basicType, higherPrecision, resultQualifier,
809 static_cast<unsigned char>(nominalSize),
810 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200811 if (mLeft->isArray())
812 {
813 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
814 mType.setArraySize(mLeft->getArraySize());
815 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400816 }
817 break;
818
819 case EOpEqual:
820 case EOpNotEqual:
821 case EOpLessThan:
822 case EOpGreaterThan:
823 case EOpLessThanEqual:
824 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200825 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
826 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400827 setType(TType(EbtBool, EbpUndefined));
828 break;
829
830 default:
831 return false;
832 }
833 return true;
834}
835
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300836TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
837{
838 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
839 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
840 if (leftConstant == nullptr || rightConstant == nullptr)
841 {
842 return nullptr;
843 }
844 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200845
846 // Nodes may be constant folded without being qualified as constant.
847 TQualifier resultQualifier = EvqConst;
848 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
849 {
850 resultQualifier = EvqTemporary;
851 }
852 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300853}
854
Olli Etuaho95310b02015-06-02 17:43:38 +0300855TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
856{
857 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
858 if (operandConstant == nullptr)
859 {
860 return nullptr;
861 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530862
863 TConstantUnion *constArray = nullptr;
864 switch (mOp)
865 {
866 case EOpAny:
867 case EOpAll:
868 case EOpLength:
869 case EOpTranspose:
870 case EOpDeterminant:
871 case EOpInverse:
872 case EOpPackSnorm2x16:
873 case EOpUnpackSnorm2x16:
874 case EOpPackUnorm2x16:
875 case EOpUnpackUnorm2x16:
876 case EOpPackHalf2x16:
877 case EOpUnpackHalf2x16:
878 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
879 break;
880 default:
881 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
882 break;
883 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200884
885 // Nodes may be constant folded without being qualified as constant.
886 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
887 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300888}
889
890TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
891{
892 // Make sure that all params are constant before actual constant folding.
893 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300894 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300895 if (param->getAsConstantUnion() == nullptr)
896 {
897 return nullptr;
898 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300899 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200900 TConstantUnion *constArray = nullptr;
901 if (isConstructor())
902 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
903 else
904 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200905
906 // Nodes may be constant folded without being qualified as constant.
907 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
908 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300909}
910
Jamie Madillb1a85f42014-08-19 15:23:24 -0400911//
912// The fold functions see if an operation on a constant can be done in place,
913// without generating run-time code.
914//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300915// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400916//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300917TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
918{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200919 const TConstantUnion *leftArray = getUnionArrayPointer();
920 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300921
922 if (!leftArray)
923 return nullptr;
924 if (!rightArray)
925 return nullptr;
926
927 size_t objectSize = getType().getObjectSize();
928
929 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
930 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
931 {
932 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
933 }
934 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
935 {
936 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
937 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
938 objectSize = rightNode->getType().getObjectSize();
939 }
940
941 TConstantUnion *resultArray = nullptr;
942
943 switch(op)
944 {
945 case EOpAdd:
946 resultArray = new TConstantUnion[objectSize];
947 for (size_t i = 0; i < objectSize; i++)
948 resultArray[i] = leftArray[i] + rightArray[i];
949 break;
950 case EOpSub:
951 resultArray = new TConstantUnion[objectSize];
952 for (size_t i = 0; i < objectSize; i++)
953 resultArray[i] = leftArray[i] - rightArray[i];
954 break;
955
956 case EOpMul:
957 case EOpVectorTimesScalar:
958 case EOpMatrixTimesScalar:
959 resultArray = new TConstantUnion[objectSize];
960 for (size_t i = 0; i < objectSize; i++)
961 resultArray[i] = leftArray[i] * rightArray[i];
962 break;
963
964 case EOpMatrixTimesMatrix:
965 {
966 if (getType().getBasicType() != EbtFloat ||
967 rightNode->getBasicType() != EbtFloat)
968 {
969 infoSink.info.message(
970 EPrefixInternalError, getLine(),
971 "Constant Folding cannot be done for matrix multiply");
972 return nullptr;
973 }
974
975 const int leftCols = getCols();
976 const int leftRows = getRows();
977 const int rightCols = rightNode->getType().getCols();
978 const int rightRows = rightNode->getType().getRows();
979 const int resultCols = rightCols;
980 const int resultRows = leftRows;
981
982 resultArray = new TConstantUnion[resultCols * resultRows];
983 for (int row = 0; row < resultRows; row++)
984 {
985 for (int column = 0; column < resultCols; column++)
986 {
987 resultArray[resultRows * column + row].setFConst(0.0f);
988 for (int i = 0; i < leftCols; i++)
989 {
990 resultArray[resultRows * column + row].setFConst(
991 resultArray[resultRows * column + row].getFConst() +
992 leftArray[i * leftRows + row].getFConst() *
993 rightArray[column * rightRows + i].getFConst());
994 }
995 }
996 }
997 }
998 break;
999
1000 case EOpDiv:
1001 case EOpIMod:
1002 {
1003 resultArray = new TConstantUnion[objectSize];
1004 for (size_t i = 0; i < objectSize; i++)
1005 {
1006 switch (getType().getBasicType())
1007 {
1008 case EbtFloat:
1009 if (rightArray[i] == 0.0f)
1010 {
1011 infoSink.info.message(EPrefixWarning, getLine(),
1012 "Divide by zero error during constant folding");
1013 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1014 }
1015 else
1016 {
1017 ASSERT(op == EOpDiv);
1018 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1019 }
1020 break;
1021
1022 case EbtInt:
1023 if (rightArray[i] == 0)
1024 {
1025 infoSink.info.message(EPrefixWarning, getLine(),
1026 "Divide by zero error during constant folding");
1027 resultArray[i].setIConst(INT_MAX);
1028 }
1029 else
1030 {
1031 if (op == EOpDiv)
1032 {
1033 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1034 }
1035 else
1036 {
1037 ASSERT(op == EOpIMod);
1038 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1039 }
1040 }
1041 break;
1042
1043 case EbtUInt:
1044 if (rightArray[i] == 0)
1045 {
1046 infoSink.info.message(EPrefixWarning, getLine(),
1047 "Divide by zero error during constant folding");
1048 resultArray[i].setUConst(UINT_MAX);
1049 }
1050 else
1051 {
1052 if (op == EOpDiv)
1053 {
1054 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1055 }
1056 else
1057 {
1058 ASSERT(op == EOpIMod);
1059 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1060 }
1061 }
1062 break;
1063
1064 default:
1065 infoSink.info.message(EPrefixInternalError, getLine(),
1066 "Constant folding cannot be done for \"/\"");
1067 return nullptr;
1068 }
1069 }
1070 }
1071 break;
1072
1073 case EOpMatrixTimesVector:
1074 {
1075 if (rightNode->getBasicType() != EbtFloat)
1076 {
1077 infoSink.info.message(EPrefixInternalError, getLine(),
1078 "Constant Folding cannot be done for matrix times vector");
1079 return nullptr;
1080 }
1081
1082 const int matrixCols = getCols();
1083 const int matrixRows = getRows();
1084
1085 resultArray = new TConstantUnion[matrixRows];
1086
1087 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1088 {
1089 resultArray[matrixRow].setFConst(0.0f);
1090 for (int col = 0; col < matrixCols; col++)
1091 {
1092 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1093 leftArray[col * matrixRows + matrixRow].getFConst() *
1094 rightArray[col].getFConst());
1095 }
1096 }
1097 }
1098 break;
1099
1100 case EOpVectorTimesMatrix:
1101 {
1102 if (getType().getBasicType() != EbtFloat)
1103 {
1104 infoSink.info.message(EPrefixInternalError, getLine(),
1105 "Constant Folding cannot be done for vector times matrix");
1106 return nullptr;
1107 }
1108
1109 const int matrixCols = rightNode->getType().getCols();
1110 const int matrixRows = rightNode->getType().getRows();
1111
1112 resultArray = new TConstantUnion[matrixCols];
1113
1114 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1115 {
1116 resultArray[matrixCol].setFConst(0.0f);
1117 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1118 {
1119 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1120 leftArray[matrixRow].getFConst() *
1121 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1122 }
1123 }
1124 }
1125 break;
1126
1127 case EOpLogicalAnd:
1128 {
1129 resultArray = new TConstantUnion[objectSize];
1130 for (size_t i = 0; i < objectSize; i++)
1131 {
1132 resultArray[i] = leftArray[i] && rightArray[i];
1133 }
1134 }
1135 break;
1136
1137 case EOpLogicalOr:
1138 {
1139 resultArray = new TConstantUnion[objectSize];
1140 for (size_t i = 0; i < objectSize; i++)
1141 {
1142 resultArray[i] = leftArray[i] || rightArray[i];
1143 }
1144 }
1145 break;
1146
1147 case EOpLogicalXor:
1148 {
1149 resultArray = new TConstantUnion[objectSize];
1150 for (size_t i = 0; i < objectSize; i++)
1151 {
1152 switch (getType().getBasicType())
1153 {
1154 case EbtBool:
1155 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1156 break;
1157 default:
1158 UNREACHABLE();
1159 break;
1160 }
1161 }
1162 }
1163 break;
1164
1165 case EOpBitwiseAnd:
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 EOpBitwiseXor:
1171 resultArray = new TConstantUnion[objectSize];
1172 for (size_t i = 0; i < objectSize; i++)
1173 resultArray[i] = leftArray[i] ^ rightArray[i];
1174 break;
1175 case EOpBitwiseOr:
1176 resultArray = new TConstantUnion[objectSize];
1177 for (size_t i = 0; i < objectSize; i++)
1178 resultArray[i] = leftArray[i] | rightArray[i];
1179 break;
1180 case EOpBitShiftLeft:
1181 resultArray = new TConstantUnion[objectSize];
1182 for (size_t i = 0; i < objectSize; i++)
1183 resultArray[i] = leftArray[i] << rightArray[i];
1184 break;
1185 case EOpBitShiftRight:
1186 resultArray = new TConstantUnion[objectSize];
1187 for (size_t i = 0; i < objectSize; i++)
1188 resultArray[i] = leftArray[i] >> rightArray[i];
1189 break;
1190
1191 case EOpLessThan:
1192 ASSERT(objectSize == 1);
1193 resultArray = new TConstantUnion[1];
1194 resultArray->setBConst(*leftArray < *rightArray);
1195 break;
1196
1197 case EOpGreaterThan:
1198 ASSERT(objectSize == 1);
1199 resultArray = new TConstantUnion[1];
1200 resultArray->setBConst(*leftArray > *rightArray);
1201 break;
1202
1203 case EOpLessThanEqual:
1204 ASSERT(objectSize == 1);
1205 resultArray = new TConstantUnion[1];
1206 resultArray->setBConst(!(*leftArray > *rightArray));
1207 break;
1208
1209 case EOpGreaterThanEqual:
1210 ASSERT(objectSize == 1);
1211 resultArray = new TConstantUnion[1];
1212 resultArray->setBConst(!(*leftArray < *rightArray));
1213 break;
1214
1215 case EOpEqual:
1216 case EOpNotEqual:
1217 {
1218 resultArray = new TConstantUnion[1];
1219 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001220 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001221 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001222 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001223 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001224 equal = false;
1225 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001226 }
1227 }
1228 if (op == EOpEqual)
1229 {
1230 resultArray->setBConst(equal);
1231 }
1232 else
1233 {
1234 resultArray->setBConst(!equal);
1235 }
1236 }
1237 break;
1238
1239 default:
1240 infoSink.info.message(
1241 EPrefixInternalError, getLine(),
1242 "Invalid operator for constant folding");
1243 return nullptr;
1244 }
1245 return resultArray;
1246}
1247
1248//
1249// The fold functions see if an operation on a constant can be done in place,
1250// without generating run-time code.
1251//
Olli Etuaho95310b02015-06-02 17:43:38 +03001252// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001253//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301254TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001255{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301256 //
1257 // Do operations where the return type has a different number of components compared to the operand type.
1258 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001259
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001260 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301261 if (!operandArray)
1262 return nullptr;
1263
1264 size_t objectSize = getType().getObjectSize();
1265 TConstantUnion *resultArray = nullptr;
1266 switch (op)
1267 {
1268 case EOpAny:
1269 if (getType().getBasicType() == EbtBool)
1270 {
1271 resultArray = new TConstantUnion();
1272 resultArray->setBConst(false);
1273 for (size_t i = 0; i < objectSize; i++)
1274 {
1275 if (operandArray[i].getBConst())
1276 {
1277 resultArray->setBConst(true);
1278 break;
1279 }
1280 }
1281 break;
1282 }
1283 else
1284 {
1285 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1286 return nullptr;
1287 }
1288
1289 case EOpAll:
1290 if (getType().getBasicType() == EbtBool)
1291 {
1292 resultArray = new TConstantUnion();
1293 resultArray->setBConst(true);
1294 for (size_t i = 0; i < objectSize; i++)
1295 {
1296 if (!operandArray[i].getBConst())
1297 {
1298 resultArray->setBConst(false);
1299 break;
1300 }
1301 }
1302 break;
1303 }
1304 else
1305 {
1306 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1307 return nullptr;
1308 }
1309
1310 case EOpLength:
1311 if (getType().getBasicType() == EbtFloat)
1312 {
1313 resultArray = new TConstantUnion();
1314 resultArray->setFConst(VectorLength(operandArray, objectSize));
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 EOpTranspose:
1324 if (getType().getBasicType() == EbtFloat)
1325 {
1326 resultArray = new TConstantUnion[objectSize];
1327 angle::Matrix<float> result =
1328 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1329 SetUnionArrayFromMatrix(result, resultArray);
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 EOpDeterminant:
1339 if (getType().getBasicType() == EbtFloat)
1340 {
1341 unsigned int size = getType().getNominalSize();
1342 ASSERT(size >= 2 && size <= 4);
1343 resultArray = new TConstantUnion();
1344 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1345 break;
1346 }
1347 else
1348 {
1349 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1350 return nullptr;
1351 }
1352
1353 case EOpInverse:
1354 if (getType().getBasicType() == EbtFloat)
1355 {
1356 unsigned int size = getType().getNominalSize();
1357 ASSERT(size >= 2 && size <= 4);
1358 resultArray = new TConstantUnion[objectSize];
1359 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1360 SetUnionArrayFromMatrix(result, resultArray);
1361 break;
1362 }
1363 else
1364 {
1365 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1366 return nullptr;
1367 }
1368
1369 case EOpPackSnorm2x16:
1370 if (getType().getBasicType() == EbtFloat)
1371 {
1372 ASSERT(getType().getNominalSize() == 2);
1373 resultArray = new TConstantUnion();
1374 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1375 break;
1376 }
1377 else
1378 {
1379 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1380 return nullptr;
1381 }
1382
1383 case EOpUnpackSnorm2x16:
1384 if (getType().getBasicType() == EbtUInt)
1385 {
1386 resultArray = new TConstantUnion[2];
1387 float f1, f2;
1388 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1389 resultArray[0].setFConst(f1);
1390 resultArray[1].setFConst(f2);
1391 break;
1392 }
1393 else
1394 {
1395 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1396 return nullptr;
1397 }
1398
1399 case EOpPackUnorm2x16:
1400 if (getType().getBasicType() == EbtFloat)
1401 {
1402 ASSERT(getType().getNominalSize() == 2);
1403 resultArray = new TConstantUnion();
1404 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1405 break;
1406 }
1407 else
1408 {
1409 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1410 return nullptr;
1411 }
1412
1413 case EOpUnpackUnorm2x16:
1414 if (getType().getBasicType() == EbtUInt)
1415 {
1416 resultArray = new TConstantUnion[2];
1417 float f1, f2;
1418 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1419 resultArray[0].setFConst(f1);
1420 resultArray[1].setFConst(f2);
1421 break;
1422 }
1423 else
1424 {
1425 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1426 return nullptr;
1427 }
1428
1429 case EOpPackHalf2x16:
1430 if (getType().getBasicType() == EbtFloat)
1431 {
1432 ASSERT(getType().getNominalSize() == 2);
1433 resultArray = new TConstantUnion();
1434 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1435 break;
1436 }
1437 else
1438 {
1439 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1440 return nullptr;
1441 }
1442
1443 case EOpUnpackHalf2x16:
1444 if (getType().getBasicType() == EbtUInt)
1445 {
1446 resultArray = new TConstantUnion[2];
1447 float f1, f2;
1448 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1449 resultArray[0].setFConst(f1);
1450 resultArray[1].setFConst(f2);
1451 break;
1452 }
1453 else
1454 {
1455 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1456 return nullptr;
1457 }
1458 break;
1459
1460 default:
1461 break;
1462 }
1463
1464 return resultArray;
1465}
1466
1467TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1468{
1469 //
1470 // Do unary operations where the return type is the same as operand type.
1471 //
1472
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001473 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001474 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301475 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001476
1477 size_t objectSize = getType().getObjectSize();
1478
Arun Patoleab2b9a22015-07-06 18:27:56 +05301479 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1480 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301481 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301482 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301483 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301484 case EOpNegative:
1485 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301486 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301487 case EbtFloat:
1488 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301489 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301490 case EbtInt:
1491 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301492 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301493 case EbtUInt:
1494 resultArray[i].setUConst(static_cast<unsigned int>(
1495 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301496 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301497 default:
1498 infoSink.info.message(
1499 EPrefixInternalError, getLine(),
1500 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301501 return nullptr;
1502 }
1503 break;
1504
Arun Patoleab2b9a22015-07-06 18:27:56 +05301505 case EOpPositive:
1506 switch (getType().getBasicType())
1507 {
1508 case EbtFloat:
1509 resultArray[i].setFConst(operandArray[i].getFConst());
1510 break;
1511 case EbtInt:
1512 resultArray[i].setIConst(operandArray[i].getIConst());
1513 break;
1514 case EbtUInt:
1515 resultArray[i].setUConst(static_cast<unsigned int>(
1516 static_cast<int>(operandArray[i].getUConst())));
1517 break;
1518 default:
1519 infoSink.info.message(
1520 EPrefixInternalError, getLine(),
1521 "Unary operation not folded into constant");
1522 return nullptr;
1523 }
1524 break;
1525
1526 case EOpLogicalNot:
1527 // this code is written for possible future use,
1528 // will not get executed currently
1529 switch (getType().getBasicType())
1530 {
1531 case EbtBool:
1532 resultArray[i].setBConst(!operandArray[i].getBConst());
1533 break;
1534 default:
1535 infoSink.info.message(
1536 EPrefixInternalError, getLine(),
1537 "Unary operation not folded into constant");
1538 return nullptr;
1539 }
1540 break;
1541
1542 case EOpBitwiseNot:
1543 switch (getType().getBasicType())
1544 {
1545 case EbtInt:
1546 resultArray[i].setIConst(~operandArray[i].getIConst());
1547 break;
1548 case EbtUInt:
1549 resultArray[i].setUConst(~operandArray[i].getUConst());
1550 break;
1551 default:
1552 infoSink.info.message(
1553 EPrefixInternalError, getLine(),
1554 "Unary operation not folded into constant");
1555 return nullptr;
1556 }
1557 break;
1558
1559 case EOpRadians:
1560 if (getType().getBasicType() == EbtFloat)
1561 {
1562 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1563 break;
1564 }
1565 infoSink.info.message(
1566 EPrefixInternalError, getLine(),
1567 "Unary operation not folded into constant");
1568 return nullptr;
1569
1570 case EOpDegrees:
1571 if (getType().getBasicType() == EbtFloat)
1572 {
1573 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1574 break;
1575 }
1576 infoSink.info.message(
1577 EPrefixInternalError, getLine(),
1578 "Unary operation not folded into constant");
1579 return nullptr;
1580
1581 case EOpSin:
1582 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1583 return nullptr;
1584 break;
1585
1586 case EOpCos:
1587 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1588 return nullptr;
1589 break;
1590
1591 case EOpTan:
1592 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1593 return nullptr;
1594 break;
1595
1596 case EOpAsin:
1597 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1598 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1599 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1600 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1601 return nullptr;
1602 break;
1603
1604 case EOpAcos:
1605 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1606 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1607 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1608 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1609 return nullptr;
1610 break;
1611
1612 case EOpAtan:
1613 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1614 return nullptr;
1615 break;
1616
1617 case EOpSinh:
1618 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1619 return nullptr;
1620 break;
1621
1622 case EOpCosh:
1623 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1624 return nullptr;
1625 break;
1626
1627 case EOpTanh:
1628 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1629 return nullptr;
1630 break;
1631
1632 case EOpAsinh:
1633 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1634 return nullptr;
1635 break;
1636
1637 case EOpAcosh:
1638 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1639 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1640 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1641 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1642 return nullptr;
1643 break;
1644
1645 case EOpAtanh:
1646 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1647 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1648 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1649 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1650 return nullptr;
1651 break;
1652
1653 case EOpAbs:
1654 switch (getType().getBasicType())
1655 {
1656 case EbtFloat:
1657 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1658 break;
1659 case EbtInt:
1660 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1661 break;
1662 default:
1663 infoSink.info.message(
1664 EPrefixInternalError, getLine(),
1665 "Unary operation not folded into constant");
1666 return nullptr;
1667 }
1668 break;
1669
1670 case EOpSign:
1671 switch (getType().getBasicType())
1672 {
1673 case EbtFloat:
1674 {
1675 float fConst = operandArray[i].getFConst();
1676 float fResult = 0.0f;
1677 if (fConst > 0.0f)
1678 fResult = 1.0f;
1679 else if (fConst < 0.0f)
1680 fResult = -1.0f;
1681 resultArray[i].setFConst(fResult);
1682 }
1683 break;
1684 case EbtInt:
1685 {
1686 int iConst = operandArray[i].getIConst();
1687 int iResult = 0;
1688 if (iConst > 0)
1689 iResult = 1;
1690 else if (iConst < 0)
1691 iResult = -1;
1692 resultArray[i].setIConst(iResult);
1693 }
1694 break;
1695 default:
1696 infoSink.info.message(
1697 EPrefixInternalError, getLine(),
1698 "Unary operation not folded into constant");
1699 return nullptr;
1700 }
1701 break;
1702
1703 case EOpFloor:
1704 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1705 return nullptr;
1706 break;
1707
1708 case EOpTrunc:
1709 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1710 return nullptr;
1711 break;
1712
1713 case EOpRound:
1714 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1715 return nullptr;
1716 break;
1717
1718 case EOpRoundEven:
1719 if (getType().getBasicType() == EbtFloat)
1720 {
1721 float x = operandArray[i].getFConst();
1722 float result;
1723 float fractPart = modff(x, &result);
1724 if (fabsf(fractPart) == 0.5f)
1725 result = 2.0f * roundf(x / 2.0f);
1726 else
1727 result = roundf(x);
1728 resultArray[i].setFConst(result);
1729 break;
1730 }
1731 infoSink.info.message(
1732 EPrefixInternalError, getLine(),
1733 "Unary operation not folded into constant");
1734 return nullptr;
1735
1736 case EOpCeil:
1737 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1738 return nullptr;
1739 break;
1740
1741 case EOpFract:
1742 if (getType().getBasicType() == EbtFloat)
1743 {
1744 float x = operandArray[i].getFConst();
1745 resultArray[i].setFConst(x - floorf(x));
1746 break;
1747 }
1748 infoSink.info.message(
1749 EPrefixInternalError, getLine(),
1750 "Unary operation not folded into constant");
1751 return nullptr;
1752
Arun Patole551279e2015-07-07 18:18:23 +05301753 case EOpIsNan:
1754 if (getType().getBasicType() == EbtFloat)
1755 {
1756 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1757 break;
1758 }
1759 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1760 return nullptr;
1761
1762 case EOpIsInf:
1763 if (getType().getBasicType() == EbtFloat)
1764 {
1765 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1766 break;
1767 }
1768 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1769 return nullptr;
1770
1771 case EOpFloatBitsToInt:
1772 if (getType().getBasicType() == EbtFloat)
1773 {
1774 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1775 break;
1776 }
1777 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1778 return nullptr;
1779
1780 case EOpFloatBitsToUint:
1781 if (getType().getBasicType() == EbtFloat)
1782 {
1783 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1784 break;
1785 }
1786 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1787 return nullptr;
1788
1789 case EOpIntBitsToFloat:
1790 if (getType().getBasicType() == EbtInt)
1791 {
1792 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1793 break;
1794 }
1795 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1796 return nullptr;
1797
1798 case EOpUintBitsToFloat:
1799 if (getType().getBasicType() == EbtUInt)
1800 {
1801 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1802 break;
1803 }
1804 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1805 return nullptr;
1806
Arun Patoleab2b9a22015-07-06 18:27:56 +05301807 case EOpExp:
1808 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1809 return nullptr;
1810 break;
1811
1812 case EOpLog:
1813 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1814 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1815 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1816 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1817 return nullptr;
1818 break;
1819
1820 case EOpExp2:
1821 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1822 return nullptr;
1823 break;
1824
1825 case EOpLog2:
1826 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1827 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1828 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1829 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1830 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1831 return nullptr;
1832 else
1833 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1834 break;
1835
1836 case EOpSqrt:
1837 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1838 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1839 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1840 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1841 return nullptr;
1842 break;
1843
1844 case EOpInverseSqrt:
1845 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1846 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1847 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1848 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1849 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1850 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1851 return nullptr;
1852 else
1853 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1854 break;
1855
1856 case EOpVectorLogicalNot:
1857 if (getType().getBasicType() == EbtBool)
1858 {
1859 resultArray[i].setBConst(!operandArray[i].getBConst());
1860 break;
1861 }
1862 infoSink.info.message(
1863 EPrefixInternalError, getLine(),
1864 "Unary operation not folded into constant");
1865 return nullptr;
1866
1867 case EOpNormalize:
1868 if (getType().getBasicType() == EbtFloat)
1869 {
1870 float x = operandArray[i].getFConst();
1871 float length = VectorLength(operandArray, objectSize);
1872 if (length)
1873 resultArray[i].setFConst(x / length);
1874 else
1875 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1876 &resultArray[i]);
1877 break;
1878 }
1879 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1880 return nullptr;
1881
Arun Patole0c5409f2015-07-08 15:17:53 +05301882 case EOpDFdx:
1883 case EOpDFdy:
1884 case EOpFwidth:
1885 if (getType().getBasicType() == EbtFloat)
1886 {
1887 // Derivatives of constant arguments should be 0.
1888 resultArray[i].setFConst(0.0f);
1889 break;
1890 }
1891 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1892 return nullptr;
1893
Arun Patole1155ddd2015-06-05 18:04:36 +05301894 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301895 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301896 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301897 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001898
Arun Patoleab2b9a22015-07-06 18:27:56 +05301899 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001900}
1901
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001902bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1903 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301904{
1905 ASSERT(builtinFunc);
1906
1907 if (getType().getBasicType() == EbtFloat)
1908 {
1909 result->setFConst(builtinFunc(parameter.getFConst()));
1910 return true;
1911 }
1912
1913 infoSink.info.message(
1914 EPrefixInternalError, getLine(),
1915 "Unary operation not folded into constant");
1916 return false;
1917}
1918
Jamie Madillb1a85f42014-08-19 15:23:24 -04001919// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001920TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1921 TInfoSink &infoSink)
1922{
1923 ASSERT(aggregate->getSequence()->size() > 0u);
1924 size_t resultSize = aggregate->getType().getObjectSize();
1925 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1926 TBasicType basicType = aggregate->getBasicType();
1927
1928 size_t resultIndex = 0u;
1929
1930 if (aggregate->getSequence()->size() == 1u)
1931 {
1932 TIntermNode *argument = aggregate->getSequence()->front();
1933 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1934 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1935 // Check the special case of constructing a matrix diagonal from a single scalar,
1936 // or a vector from a single scalar.
1937 if (argumentConstant->getType().getObjectSize() == 1u)
1938 {
1939 if (aggregate->isMatrix())
1940 {
1941 int resultCols = aggregate->getType().getCols();
1942 int resultRows = aggregate->getType().getRows();
1943 for (int col = 0; col < resultCols; ++col)
1944 {
1945 for (int row = 0; row < resultRows; ++row)
1946 {
1947 if (col == row)
1948 {
1949 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1950 }
1951 else
1952 {
1953 resultArray[resultIndex].setFConst(0.0f);
1954 }
1955 ++resultIndex;
1956 }
1957 }
1958 }
1959 else
1960 {
1961 while (resultIndex < resultSize)
1962 {
1963 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1964 ++resultIndex;
1965 }
1966 }
1967 ASSERT(resultIndex == resultSize);
1968 return resultArray;
1969 }
1970 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1971 {
1972 // The special case of constructing a matrix from a matrix.
1973 int argumentCols = argumentConstant->getType().getCols();
1974 int argumentRows = argumentConstant->getType().getRows();
1975 int resultCols = aggregate->getType().getCols();
1976 int resultRows = aggregate->getType().getRows();
1977 for (int col = 0; col < resultCols; ++col)
1978 {
1979 for (int row = 0; row < resultRows; ++row)
1980 {
1981 if (col < argumentCols && row < argumentRows)
1982 {
1983 resultArray[resultIndex].cast(basicType,
1984 argumentUnionArray[col * argumentRows + row]);
1985 }
1986 else if (col == row)
1987 {
1988 resultArray[resultIndex].setFConst(1.0f);
1989 }
1990 else
1991 {
1992 resultArray[resultIndex].setFConst(0.0f);
1993 }
1994 ++resultIndex;
1995 }
1996 }
1997 ASSERT(resultIndex == resultSize);
1998 return resultArray;
1999 }
2000 }
2001
2002 for (TIntermNode *&argument : *aggregate->getSequence())
2003 {
2004 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2005 size_t argumentSize = argumentConstant->getType().getObjectSize();
2006 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2007 for (size_t i = 0u; i < argumentSize; ++i)
2008 {
2009 if (resultIndex >= resultSize)
2010 break;
2011 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2012 ++resultIndex;
2013 }
2014 }
2015 ASSERT(resultIndex == resultSize);
2016 return resultArray;
2017}
2018
2019// static
Olli Etuahob43846e2015-06-02 18:18:57 +03002020TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05302021{
Olli Etuahob43846e2015-06-02 18:18:57 +03002022 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302023 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002024 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002025 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302026 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002027 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302028 TBasicType basicType = EbtVoid;
2029 TSourceLoc loc;
2030 for (unsigned int i = 0; i < paramsCount; i++)
2031 {
2032 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002033 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302034
2035 if (i == 0)
2036 {
2037 basicType = paramConstant->getType().getBasicType();
2038 loc = paramConstant->getLine();
2039 }
2040 unionArrays[i] = paramConstant->getUnionArrayPointer();
2041 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002042 if (objectSizes[i] > maxObjectSize)
2043 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302044 }
2045
Arun Patole7fa33552015-06-10 15:15:18 +05302046 if (!(*sequence)[0]->getAsTyped()->isMatrix())
2047 {
2048 for (unsigned int i = 0; i < paramsCount; i++)
2049 if (objectSizes[i] != maxObjectSize)
2050 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2051 }
Arun Patole274f0702015-05-05 13:33:30 +05302052
Olli Etuahob43846e2015-06-02 18:18:57 +03002053 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302054 if (paramsCount == 2)
2055 {
2056 //
2057 // Binary built-in
2058 //
2059 switch (op)
2060 {
Arun Patolebf790422015-05-18 17:53:04 +05302061 case EOpAtan:
2062 {
2063 if (basicType == EbtFloat)
2064 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002065 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302066 for (size_t i = 0; i < maxObjectSize; i++)
2067 {
2068 float y = unionArrays[0][i].getFConst();
2069 float x = unionArrays[1][i].getFConst();
2070 // Results are undefined if x and y are both 0.
2071 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002072 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302073 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002074 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302075 }
2076 }
2077 else
2078 UNREACHABLE();
2079 }
2080 break;
2081
2082 case EOpPow:
2083 {
2084 if (basicType == EbtFloat)
2085 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002086 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302087 for (size_t i = 0; i < maxObjectSize; i++)
2088 {
2089 float x = unionArrays[0][i].getFConst();
2090 float y = unionArrays[1][i].getFConst();
2091 // Results are undefined if x < 0.
2092 // Results are undefined if x = 0 and y <= 0.
2093 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002094 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302095 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002096 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302097 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002098 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302099 }
2100 }
2101 else
2102 UNREACHABLE();
2103 }
2104 break;
2105
2106 case EOpMod:
2107 {
2108 if (basicType == EbtFloat)
2109 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002110 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302111 for (size_t i = 0; i < maxObjectSize; i++)
2112 {
2113 float x = unionArrays[0][i].getFConst();
2114 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002115 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302116 }
2117 }
2118 else
2119 UNREACHABLE();
2120 }
2121 break;
2122
Arun Patole274f0702015-05-05 13:33:30 +05302123 case EOpMin:
2124 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002125 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302126 for (size_t i = 0; i < maxObjectSize; i++)
2127 {
2128 switch (basicType)
2129 {
2130 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002131 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302132 break;
2133 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002134 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302135 break;
2136 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002137 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302138 break;
2139 default:
2140 UNREACHABLE();
2141 break;
2142 }
2143 }
2144 }
2145 break;
2146
2147 case EOpMax:
2148 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002149 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302150 for (size_t i = 0; i < maxObjectSize; i++)
2151 {
2152 switch (basicType)
2153 {
2154 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002155 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302156 break;
2157 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002158 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302159 break;
2160 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002161 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302162 break;
2163 default:
2164 UNREACHABLE();
2165 break;
2166 }
2167 }
2168 }
2169 break;
2170
Arun Patolebf790422015-05-18 17:53:04 +05302171 case EOpStep:
2172 {
2173 if (basicType == EbtFloat)
2174 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002175 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302176 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002177 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302178 }
2179 else
2180 UNREACHABLE();
2181 }
2182 break;
2183
Arun Patole9d0b1f92015-05-20 14:27:17 +05302184 case EOpLessThan:
2185 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002186 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302187 for (size_t i = 0; i < maxObjectSize; i++)
2188 {
2189 switch (basicType)
2190 {
2191 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002192 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302193 break;
2194 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002195 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302196 break;
2197 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002198 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302199 break;
2200 default:
2201 UNREACHABLE();
2202 break;
2203 }
2204 }
2205 }
2206 break;
2207
2208 case EOpLessThanEqual:
2209 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002210 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302211 for (size_t i = 0; i < maxObjectSize; i++)
2212 {
2213 switch (basicType)
2214 {
2215 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002216 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302217 break;
2218 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002219 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302220 break;
2221 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002222 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302223 break;
2224 default:
2225 UNREACHABLE();
2226 break;
2227 }
2228 }
2229 }
2230 break;
2231
2232 case EOpGreaterThan:
2233 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002234 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302235 for (size_t i = 0; i < maxObjectSize; i++)
2236 {
2237 switch (basicType)
2238 {
2239 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002240 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302241 break;
2242 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002243 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 break;
2245 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002246 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302247 break;
2248 default:
2249 UNREACHABLE();
2250 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002251 }
2252 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302253 }
2254 break;
2255
2256 case EOpGreaterThanEqual:
2257 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002258 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302259 for (size_t i = 0; i < maxObjectSize; i++)
2260 {
2261 switch (basicType)
2262 {
2263 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002264 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302265 break;
2266 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002267 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302268 break;
2269 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002270 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302271 break;
2272 default:
2273 UNREACHABLE();
2274 break;
2275 }
2276 }
2277 }
2278 break;
2279
2280 case EOpVectorEqual:
2281 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002282 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302283 for (size_t i = 0; i < maxObjectSize; i++)
2284 {
2285 switch (basicType)
2286 {
2287 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002288 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302289 break;
2290 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002291 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302292 break;
2293 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002294 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302295 break;
2296 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002297 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302298 break;
2299 default:
2300 UNREACHABLE();
2301 break;
2302 }
2303 }
2304 }
2305 break;
2306
2307 case EOpVectorNotEqual:
2308 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002309 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302310 for (size_t i = 0; i < maxObjectSize; i++)
2311 {
2312 switch (basicType)
2313 {
2314 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002315 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302316 break;
2317 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002318 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302319 break;
2320 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002321 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302322 break;
2323 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002324 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302325 break;
2326 default:
2327 UNREACHABLE();
2328 break;
2329 }
2330 }
2331 }
2332 break;
2333
Arun Patole1155ddd2015-06-05 18:04:36 +05302334 case EOpDistance:
2335 if (basicType == EbtFloat)
2336 {
2337 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002338 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302339 for (size_t i = 0; i < maxObjectSize; i++)
2340 {
2341 float x = unionArrays[0][i].getFConst();
2342 float y = unionArrays[1][i].getFConst();
2343 distanceArray[i].setFConst(x - y);
2344 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002345 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302346 }
2347 else
2348 UNREACHABLE();
2349 break;
2350
2351 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002352
Arun Patole1155ddd2015-06-05 18:04:36 +05302353 if (basicType == EbtFloat)
2354 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002355 resultArray = new TConstantUnion();
2356 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302357 }
2358 else
2359 UNREACHABLE();
2360 break;
2361
2362 case EOpCross:
2363 if (basicType == EbtFloat && maxObjectSize == 3)
2364 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002365 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302366 float x0 = unionArrays[0][0].getFConst();
2367 float x1 = unionArrays[0][1].getFConst();
2368 float x2 = unionArrays[0][2].getFConst();
2369 float y0 = unionArrays[1][0].getFConst();
2370 float y1 = unionArrays[1][1].getFConst();
2371 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002372 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2373 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2374 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302375 }
2376 else
2377 UNREACHABLE();
2378 break;
2379
2380 case EOpReflect:
2381 if (basicType == EbtFloat)
2382 {
2383 // genType reflect (genType I, genType N) :
2384 // For the incident vector I and surface orientation N, returns the reflection direction:
2385 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002386 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302387 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2388 for (size_t i = 0; i < maxObjectSize; i++)
2389 {
2390 float result = unionArrays[0][i].getFConst() -
2391 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002392 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302393 }
2394 }
2395 else
2396 UNREACHABLE();
2397 break;
2398
Arun Patole7fa33552015-06-10 15:15:18 +05302399 case EOpMul:
2400 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2401 (*sequence)[1]->getAsTyped()->isMatrix())
2402 {
2403 // Perform component-wise matrix multiplication.
2404 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002405 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302406 angle::Matrix<float> result =
2407 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2408 SetUnionArrayFromMatrix(result, resultArray);
2409 }
2410 else
2411 UNREACHABLE();
2412 break;
2413
2414 case EOpOuterProduct:
2415 if (basicType == EbtFloat)
2416 {
2417 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2418 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2419 resultArray = new TConstantUnion[numRows * numCols];
2420 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002421 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2422 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302423 SetUnionArrayFromMatrix(result, resultArray);
2424 }
2425 else
2426 UNREACHABLE();
2427 break;
2428
Arun Patole274f0702015-05-05 13:33:30 +05302429 default:
2430 UNREACHABLE();
2431 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2432 return nullptr;
2433 }
2434 }
2435 else if (paramsCount == 3)
2436 {
2437 //
2438 // Ternary built-in
2439 //
2440 switch (op)
2441 {
2442 case EOpClamp:
2443 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002444 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302445 for (size_t i = 0; i < maxObjectSize; i++)
2446 {
2447 switch (basicType)
2448 {
2449 case EbtFloat:
2450 {
2451 float x = unionArrays[0][i].getFConst();
2452 float min = unionArrays[1][i].getFConst();
2453 float max = unionArrays[2][i].getFConst();
2454 // Results are undefined if min > max.
2455 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002456 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302457 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002458 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302459 }
2460 break;
2461 case EbtInt:
2462 {
2463 int x = unionArrays[0][i].getIConst();
2464 int min = unionArrays[1][i].getIConst();
2465 int max = unionArrays[2][i].getIConst();
2466 // Results are undefined if min > max.
2467 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002468 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302469 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002470 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302471 }
2472 break;
2473 case EbtUInt:
2474 {
2475 unsigned int x = unionArrays[0][i].getUConst();
2476 unsigned int min = unionArrays[1][i].getUConst();
2477 unsigned int max = unionArrays[2][i].getUConst();
2478 // Results are undefined if min > max.
2479 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002480 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302481 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002482 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302483 }
2484 break;
2485 default:
2486 UNREACHABLE();
2487 break;
2488 }
2489 }
2490 }
2491 break;
2492
Arun Patolebf790422015-05-18 17:53:04 +05302493 case EOpMix:
2494 {
2495 if (basicType == EbtFloat)
2496 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002497 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302498 for (size_t i = 0; i < maxObjectSize; i++)
2499 {
2500 float x = unionArrays[0][i].getFConst();
2501 float y = unionArrays[1][i].getFConst();
2502 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2503 if (type == EbtFloat)
2504 {
2505 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2506 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002507 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302508 }
2509 else // 3rd parameter is EbtBool
2510 {
2511 ASSERT(type == EbtBool);
2512 // Selects which vector each returned component comes from.
2513 // For a component of a that is false, the corresponding component of x is returned.
2514 // For a component of a that is true, the corresponding component of y is returned.
2515 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002516 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302517 }
2518 }
2519 }
2520 else
2521 UNREACHABLE();
2522 }
2523 break;
2524
2525 case EOpSmoothStep:
2526 {
2527 if (basicType == EbtFloat)
2528 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002529 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302530 for (size_t i = 0; i < maxObjectSize; i++)
2531 {
2532 float edge0 = unionArrays[0][i].getFConst();
2533 float edge1 = unionArrays[1][i].getFConst();
2534 float x = unionArrays[2][i].getFConst();
2535 // Results are undefined if edge0 >= edge1.
2536 if (edge0 >= edge1)
2537 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002538 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302539 }
2540 else
2541 {
2542 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2543 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2544 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002545 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302546 }
2547 }
2548 }
2549 else
2550 UNREACHABLE();
2551 }
2552 break;
2553
Arun Patole1155ddd2015-06-05 18:04:36 +05302554 case EOpFaceForward:
2555 if (basicType == EbtFloat)
2556 {
2557 // genType faceforward(genType N, genType I, genType Nref) :
2558 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002559 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302560 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2561 for (size_t i = 0; i < maxObjectSize; i++)
2562 {
2563 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002564 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302565 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002566 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302567 }
2568 }
2569 else
2570 UNREACHABLE();
2571 break;
2572
2573 case EOpRefract:
2574 if (basicType == EbtFloat)
2575 {
2576 // genType refract(genType I, genType N, float eta) :
2577 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2578 // return the refraction vector. The result is computed by
2579 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2580 // if (k < 0.0)
2581 // return genType(0.0)
2582 // else
2583 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002584 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302585 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2586 for (size_t i = 0; i < maxObjectSize; i++)
2587 {
2588 float eta = unionArrays[2][i].getFConst();
2589 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2590 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002591 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302592 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002593 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302594 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2595 }
2596 }
2597 else
2598 UNREACHABLE();
2599 break;
2600
Arun Patole274f0702015-05-05 13:33:30 +05302601 default:
2602 UNREACHABLE();
2603 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2604 return nullptr;
2605 }
2606 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002607 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302608}
2609
2610// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002611TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2612{
2613 if (hashFunction == NULL || name.empty())
2614 return name;
2615 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2616 TStringStream stream;
2617 stream << HASHED_NAME_PREFIX << std::hex << number;
2618 TString hashedName = stream.str();
2619 return hashedName;
2620}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002621
2622void TIntermTraverser::updateTree()
2623{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002624 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2625 {
2626 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2627 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002628 if (!insertion.insertionsAfter.empty())
2629 {
2630 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2631 insertion.insertionsAfter);
2632 ASSERT(inserted);
2633 UNUSED_ASSERTION_VARIABLE(inserted);
2634 }
2635 if (!insertion.insertionsBefore.empty())
2636 {
2637 bool inserted =
2638 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2639 ASSERT(inserted);
2640 UNUSED_ASSERTION_VARIABLE(inserted);
2641 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002642 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002643 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2644 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002645 const NodeUpdateEntry &replacement = mReplacements[ii];
2646 ASSERT(replacement.parent);
2647 bool replaced = replacement.parent->replaceChildNode(
2648 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002649 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002650 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002651
Olli Etuahocd94ef92015-04-16 19:18:10 +03002652 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002653 {
2654 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002655 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002656 // be replaced, we need to make sure we don't update the replaced
2657 // node; instead, we update the replacement node.
2658 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2659 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002660 NodeUpdateEntry &replacement2 = mReplacements[jj];
2661 if (replacement2.parent == replacement.original)
2662 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002663 }
2664 }
2665 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002666 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2667 {
2668 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2669 ASSERT(replacement.parent);
2670 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2671 replacement.original, replacement.replacements);
2672 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002673 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002674 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002675
2676 mInsertions.clear();
2677 mReplacements.clear();
2678 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002679}