blob: 0f7cc748d93936c9bb76763ce231d74f9ff13b7f [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
69bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040070 const TConstantUnion *rightUnionArray,
71 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040072
73bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040074 const TConstantUnion *rightUnionArray,
75 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040076{
77 const TFieldList &fields = leftNodeType.getStruct()->fields();
78
79 size_t structSize = fields.size();
80 size_t index = 0;
81
82 for (size_t j = 0; j < structSize; j++)
83 {
84 size_t size = fields[j]->type()->getObjectSize();
85 for (size_t i = 0; i < size; i++)
86 {
87 if (fields[j]->type()->getBasicType() == EbtStruct)
88 {
89 if (!CompareStructure(*fields[j]->type(),
90 &rightUnionArray[index],
91 &leftUnionArray[index]))
92 {
93 return false;
94 }
95 }
96 else
97 {
98 if (leftUnionArray[index] != rightUnionArray[index])
99 return false;
100 index++;
101 }
102 }
103 }
104 return true;
105}
106
107bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400108 const TConstantUnion *rightUnionArray,
109 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400110{
111 if (leftNodeType.isArray())
112 {
113 TType typeWithoutArrayness = leftNodeType;
114 typeWithoutArrayness.clearArrayness();
115
116 size_t arraySize = leftNodeType.getArraySize();
117
118 for (size_t i = 0; i < arraySize; ++i)
119 {
120 size_t offset = typeWithoutArrayness.getObjectSize() * i;
121 if (!CompareStruct(typeWithoutArrayness,
122 &rightUnionArray[offset],
123 &leftUnionArray[offset]))
124 {
125 return false;
126 }
127 }
128 }
129 else
130 {
131 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
132 }
133 return true;
134}
135
Arun Patole274f0702015-05-05 13:33:30 +0530136TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
137{
138 TConstantUnion *constUnion = new TConstantUnion[size];
139 for (unsigned int i = 0; i < size; ++i)
140 constUnion[i] = constant;
141
142 return constUnion;
143}
144
Arun Patolebf790422015-05-18 17:53:04 +0530145void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
146 TInfoSink &infoSink, TConstantUnion *result)
147{
148 std::stringstream constantFoldingErrorStream;
149 constantFoldingErrorStream << "'" << GetOperatorString(op)
150 << "' operation result is undefined for the values passed in";
151 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
152
153 switch (basicType)
154 {
155 case EbtFloat :
156 result->setFConst(0.0f);
157 break;
158 case EbtInt:
159 result->setIConst(0);
160 break;
161 case EbtUInt:
162 result->setUConst(0u);
163 break;
164 case EbtBool:
165 result->setBConst(false);
166 break;
167 default:
168 break;
169 }
170}
171
Arun Patole1155ddd2015-06-05 18:04:36 +0530172float VectorLength(TConstantUnion *paramArray, size_t paramArraySize)
173{
174 float result = 0.0f;
175 for (size_t i = 0; i < paramArraySize; i++)
176 {
177 float f = paramArray[i].getFConst();
178 result += f * f;
179 }
180 return sqrtf(result);
181}
182
183float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, size_t paramArraySize)
184{
185 float result = 0.0f;
186 for (size_t i = 0; i < paramArraySize; i++)
187 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
188 return result;
189}
190
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200191TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
192 const TIntermTyped *originalNode,
193 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300194{
195 if (constArray == nullptr)
196 {
197 return nullptr;
198 }
199 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200200 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300201 folded->setLine(originalNode->getLine());
202 return folded;
203}
204
Arun Patole7fa33552015-06-10 15:15:18 +0530205angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &rows, const unsigned int &cols)
206{
207 std::vector<float> elements;
208 for (size_t i = 0; i < rows * cols; i++)
209 elements.push_back(paramArray[i].getFConst());
210 // Transpose is used since the Matrix constructor expects arguments in row-major order,
211 // whereas the paramArray is in column-major order.
212 return angle::Matrix<float>(elements, rows, cols).transpose();
213}
214
215angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &size)
216{
217 std::vector<float> elements;
218 for (size_t i = 0; i < size * size; i++)
219 elements.push_back(paramArray[i].getFConst());
220 // Transpose is used since the Matrix constructor expects arguments in row-major order,
221 // whereas the paramArray is in column-major order.
222 return angle::Matrix<float>(elements, size).transpose();
223}
224
225void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
226{
227 // Transpose is used since the input Matrix is in row-major order,
228 // whereas the actual result should be in column-major order.
229 angle::Matrix<float> result = m.transpose();
230 std::vector<float> resultElements = result.elements();
231 for (size_t i = 0; i < resultElements.size(); i++)
232 resultArray[i].setFConst(resultElements[i]);
233}
234
Jamie Madillb1a85f42014-08-19 15:23:24 -0400235} // namespace anonymous
236
237
238////////////////////////////////////////////////////////////////
239//
240// Member functions of the nodes used for building the tree.
241//
242////////////////////////////////////////////////////////////////
243
Olli Etuahod2a67b92014-10-21 16:42:57 +0300244void TIntermTyped::setTypePreservePrecision(const TType &t)
245{
246 TPrecision precision = getPrecision();
247 mType = t;
248 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
249 mType.setPrecision(precision);
250}
251
Jamie Madillb1a85f42014-08-19 15:23:24 -0400252#define REPLACE_IF_IS(node, type, original, replacement) \
253 if (node == original) { \
254 node = static_cast<type *>(replacement); \
255 return true; \
256 }
257
258bool TIntermLoop::replaceChildNode(
259 TIntermNode *original, TIntermNode *replacement)
260{
261 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
262 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
263 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200264 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400265 return false;
266}
267
Jamie Madillb1a85f42014-08-19 15:23:24 -0400268bool TIntermBranch::replaceChildNode(
269 TIntermNode *original, TIntermNode *replacement)
270{
271 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
272 return false;
273}
274
Jamie Madillb1a85f42014-08-19 15:23:24 -0400275bool TIntermBinary::replaceChildNode(
276 TIntermNode *original, TIntermNode *replacement)
277{
278 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
279 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
280 return false;
281}
282
Jamie Madillb1a85f42014-08-19 15:23:24 -0400283bool TIntermUnary::replaceChildNode(
284 TIntermNode *original, TIntermNode *replacement)
285{
286 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
287 return false;
288}
289
Jamie Madillb1a85f42014-08-19 15:23:24 -0400290bool TIntermAggregate::replaceChildNode(
291 TIntermNode *original, TIntermNode *replacement)
292{
293 for (size_t ii = 0; ii < mSequence.size(); ++ii)
294 {
295 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
296 }
297 return false;
298}
299
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300300bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
301{
302 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
303 {
304 if (*it == original)
305 {
306 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300307 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300308 return true;
309 }
310 }
311 return false;
312}
313
Olli Etuahoa6f22092015-05-08 18:31:10 +0300314bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
315{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300316 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300317 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300318 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300319 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300320 auto it = mSequence.begin() + position;
321 mSequence.insert(it, insertions.begin(), insertions.end());
322 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300323}
324
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200325bool TIntermAggregate::areChildrenConstQualified()
326{
327 for (TIntermNode *&child : mSequence)
328 {
329 TIntermTyped *typed = child->getAsTyped();
330 if (typed && typed->getQualifier() != EvqConst)
331 {
332 return false;
333 }
334 }
335 return true;
336}
337
Olli Etuahod2a67b92014-10-21 16:42:57 +0300338void TIntermAggregate::setPrecisionFromChildren()
339{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300340 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300341 if (getBasicType() == EbtBool)
342 {
343 mType.setPrecision(EbpUndefined);
344 return;
345 }
346
347 TPrecision precision = EbpUndefined;
348 TIntermSequence::iterator childIter = mSequence.begin();
349 while (childIter != mSequence.end())
350 {
351 TIntermTyped *typed = (*childIter)->getAsTyped();
352 if (typed)
353 precision = GetHigherPrecision(typed->getPrecision(), precision);
354 ++childIter;
355 }
356 mType.setPrecision(precision);
357}
358
359void TIntermAggregate::setBuiltInFunctionPrecision()
360{
361 // All built-ins returning bool should be handled as ops, not functions.
362 ASSERT(getBasicType() != EbtBool);
363
364 TPrecision precision = EbpUndefined;
365 TIntermSequence::iterator childIter = mSequence.begin();
366 while (childIter != mSequence.end())
367 {
368 TIntermTyped *typed = (*childIter)->getAsTyped();
369 // ESSL spec section 8: texture functions get their precision from the sampler.
370 if (typed && IsSampler(typed->getBasicType()))
371 {
372 precision = typed->getPrecision();
373 break;
374 }
375 ++childIter;
376 }
377 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
378 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300379 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300380 mType.setPrecision(EbpHigh);
381 else
382 mType.setPrecision(precision);
383}
384
Jamie Madillb1a85f42014-08-19 15:23:24 -0400385bool TIntermSelection::replaceChildNode(
386 TIntermNode *original, TIntermNode *replacement)
387{
388 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
389 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
390 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
391 return false;
392}
393
Olli Etuahoa3a36662015-02-17 13:46:51 +0200394bool TIntermSwitch::replaceChildNode(
395 TIntermNode *original, TIntermNode *replacement)
396{
397 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
398 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
399 return false;
400}
401
402bool TIntermCase::replaceChildNode(
403 TIntermNode *original, TIntermNode *replacement)
404{
405 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
406 return false;
407}
408
Olli Etuahod7a25242015-08-18 13:49:45 +0300409TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
410{
411 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
412 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
413 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
414 mLine = node.mLine;
415}
416
417TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
418{
419 size_t arraySize = mType.getObjectSize();
420 mUnionArrayPointer = new TConstantUnion[arraySize];
421 for (size_t i = 0u; i < arraySize; ++i)
422 {
423 mUnionArrayPointer[i] = node.mUnionArrayPointer[i];
424 }
425}
426
427TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
428 : TIntermOperator(node),
429 mName(node.mName),
430 mUserDefined(node.mUserDefined),
431 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300432 mUseEmulatedFunction(node.mUseEmulatedFunction),
433 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
434{
435 for (TIntermNode *child : node.mSequence)
436 {
437 TIntermTyped *typedChild = child->getAsTyped();
438 ASSERT(typedChild != nullptr);
439 TIntermTyped *childCopy = typedChild->deepCopy();
440 mSequence.push_back(childCopy);
441 }
442}
443
444TIntermBinary::TIntermBinary(const TIntermBinary &node)
445 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
446{
447 TIntermTyped *leftCopy = node.mLeft->deepCopy();
448 TIntermTyped *rightCopy = node.mRight->deepCopy();
449 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
450 mLeft = leftCopy;
451 mRight = rightCopy;
452}
453
454TIntermUnary::TIntermUnary(const TIntermUnary &node)
455 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
456{
457 TIntermTyped *operandCopy = node.mOperand->deepCopy();
458 ASSERT(operandCopy != nullptr);
459 mOperand = operandCopy;
460}
461
462TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
463{
464 // Only supported for ternary nodes, not if statements.
465 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
466 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
467 ASSERT(trueTyped != nullptr);
468 ASSERT(falseTyped != nullptr);
469 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
470 TIntermTyped *trueCopy = trueTyped->deepCopy();
471 TIntermTyped *falseCopy = falseTyped->deepCopy();
472 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
473 mCondition = conditionCopy;
474 mTrueBlock = trueCopy;
475 mFalseBlock = falseCopy;
476}
477
Jamie Madillb1a85f42014-08-19 15:23:24 -0400478//
479// Say whether or not an operation node changes the value of a variable.
480//
481bool TIntermOperator::isAssignment() const
482{
483 switch (mOp)
484 {
485 case EOpPostIncrement:
486 case EOpPostDecrement:
487 case EOpPreIncrement:
488 case EOpPreDecrement:
489 case EOpAssign:
490 case EOpAddAssign:
491 case EOpSubAssign:
492 case EOpMulAssign:
493 case EOpVectorTimesMatrixAssign:
494 case EOpVectorTimesScalarAssign:
495 case EOpMatrixTimesScalarAssign:
496 case EOpMatrixTimesMatrixAssign:
497 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200498 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200499 case EOpBitShiftLeftAssign:
500 case EOpBitShiftRightAssign:
501 case EOpBitwiseAndAssign:
502 case EOpBitwiseXorAssign:
503 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400504 return true;
505 default:
506 return false;
507 }
508}
509
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300510bool TIntermOperator::isMultiplication() const
511{
512 switch (mOp)
513 {
514 case EOpMul:
515 case EOpMatrixTimesMatrix:
516 case EOpMatrixTimesVector:
517 case EOpMatrixTimesScalar:
518 case EOpVectorTimesMatrix:
519 case EOpVectorTimesScalar:
520 return true;
521 default:
522 return false;
523 }
524}
525
Jamie Madillb1a85f42014-08-19 15:23:24 -0400526//
527// returns true if the operator is for one of the constructors
528//
529bool TIntermOperator::isConstructor() const
530{
531 switch (mOp)
532 {
533 case EOpConstructVec2:
534 case EOpConstructVec3:
535 case EOpConstructVec4:
536 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400537 case EOpConstructMat2x3:
538 case EOpConstructMat2x4:
539 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400540 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400541 case EOpConstructMat3x4:
542 case EOpConstructMat4x2:
543 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400544 case EOpConstructMat4:
545 case EOpConstructFloat:
546 case EOpConstructIVec2:
547 case EOpConstructIVec3:
548 case EOpConstructIVec4:
549 case EOpConstructInt:
550 case EOpConstructUVec2:
551 case EOpConstructUVec3:
552 case EOpConstructUVec4:
553 case EOpConstructUInt:
554 case EOpConstructBVec2:
555 case EOpConstructBVec3:
556 case EOpConstructBVec4:
557 case EOpConstructBool:
558 case EOpConstructStruct:
559 return true;
560 default:
561 return false;
562 }
563}
564
565//
566// Make sure the type of a unary operator is appropriate for its
567// combination of operation and operand type.
568//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200569void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400570{
571 switch (mOp)
572 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200573 case EOpFloatBitsToInt:
574 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200575 case EOpIntBitsToFloat:
576 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200577 case EOpPackSnorm2x16:
578 case EOpPackUnorm2x16:
579 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200580 case EOpUnpackSnorm2x16:
581 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200582 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530583 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200584 case EOpUnpackHalf2x16:
585 mType.setPrecision(EbpMedium);
586 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400587 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200588 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400589 }
590
Olli Etuahof6c694b2015-03-26 14:50:53 +0200591 if (funcReturnType != nullptr)
592 {
593 if (funcReturnType->getBasicType() == EbtBool)
594 {
595 // Bool types should not have precision.
596 setType(*funcReturnType);
597 }
598 else
599 {
600 // Precision of the node has been set based on the operand.
601 setTypePreservePrecision(*funcReturnType);
602 }
603 }
604
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200605 if (mOperand->getQualifier() == EvqConst)
606 mType.setQualifier(EvqConst);
607 else
608 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400609}
610
611//
612// Establishes the type of the resultant operation, as well as
613// makes the operator the correct one for the operands.
614//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200615// For lots of operations it should already be established that the operand
616// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400617//
618bool TIntermBinary::promote(TInfoSink &infoSink)
619{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200620 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400621
Jamie Madillb1a85f42014-08-19 15:23:24 -0400622 //
623 // Base assumption: just make the type the same as the left
624 // operand. Then only deviations from this need be coded.
625 //
626 setType(mLeft->getType());
627
628 // The result gets promoted to the highest precision.
629 TPrecision higherPrecision = GetHigherPrecision(
630 mLeft->getPrecision(), mRight->getPrecision());
631 getTypePointer()->setPrecision(higherPrecision);
632
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200633 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400634 // Binary operations results in temporary variables unless both
635 // operands are const.
636 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
637 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200638 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400639 getTypePointer()->setQualifier(EvqTemporary);
640 }
641
642 const int nominalSize =
643 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
644
645 //
646 // All scalars or structs. Code after this test assumes this case is removed!
647 //
648 if (nominalSize == 1)
649 {
650 switch (mOp)
651 {
652 //
653 // Promote to conditional
654 //
655 case EOpEqual:
656 case EOpNotEqual:
657 case EOpLessThan:
658 case EOpGreaterThan:
659 case EOpLessThanEqual:
660 case EOpGreaterThanEqual:
661 setType(TType(EbtBool, EbpUndefined));
662 break;
663
664 //
665 // And and Or operate on conditionals
666 //
667 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200668 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400669 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200670 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400671 setType(TType(EbtBool, EbpUndefined));
672 break;
673
674 default:
675 break;
676 }
677 return true;
678 }
679
680 // If we reach here, at least one of the operands is vector or matrix.
681 // The other operand could be a scalar, vector, or matrix.
682 // Can these two operands be combined?
683 //
684 TBasicType basicType = mLeft->getBasicType();
685 switch (mOp)
686 {
687 case EOpMul:
688 if (!mLeft->isMatrix() && mRight->isMatrix())
689 {
690 if (mLeft->isVector())
691 {
692 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200693 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700694 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400695 }
696 else
697 {
698 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200699 setType(TType(basicType, higherPrecision, resultQualifier,
700 static_cast<unsigned char>(mRight->getCols()),
701 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400702 }
703 }
704 else if (mLeft->isMatrix() && !mRight->isMatrix())
705 {
706 if (mRight->isVector())
707 {
708 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200709 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700710 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400711 }
712 else
713 {
714 mOp = EOpMatrixTimesScalar;
715 }
716 }
717 else if (mLeft->isMatrix() && mRight->isMatrix())
718 {
719 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200720 setType(TType(basicType, higherPrecision, resultQualifier,
721 static_cast<unsigned char>(mRight->getCols()),
722 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400723 }
724 else if (!mLeft->isMatrix() && !mRight->isMatrix())
725 {
726 if (mLeft->isVector() && mRight->isVector())
727 {
728 // leave as component product
729 }
730 else if (mLeft->isVector() || mRight->isVector())
731 {
732 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200733 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700734 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400735 }
736 }
737 else
738 {
739 infoSink.info.message(EPrefixInternalError, getLine(),
740 "Missing elses");
741 return false;
742 }
743
744 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
745 {
746 return false;
747 }
748 break;
749
750 case EOpMulAssign:
751 if (!mLeft->isMatrix() && mRight->isMatrix())
752 {
753 if (mLeft->isVector())
754 {
755 mOp = EOpVectorTimesMatrixAssign;
756 }
757 else
758 {
759 return false;
760 }
761 }
762 else if (mLeft->isMatrix() && !mRight->isMatrix())
763 {
764 if (mRight->isVector())
765 {
766 return false;
767 }
768 else
769 {
770 mOp = EOpMatrixTimesScalarAssign;
771 }
772 }
773 else if (mLeft->isMatrix() && mRight->isMatrix())
774 {
775 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200776 setType(TType(basicType, higherPrecision, resultQualifier,
777 static_cast<unsigned char>(mRight->getCols()),
778 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400779 }
780 else if (!mLeft->isMatrix() && !mRight->isMatrix())
781 {
782 if (mLeft->isVector() && mRight->isVector())
783 {
784 // leave as component product
785 }
786 else if (mLeft->isVector() || mRight->isVector())
787 {
788 if (!mLeft->isVector())
789 return false;
790 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200791 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700792 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400793 }
794 }
795 else
796 {
797 infoSink.info.message(EPrefixInternalError, getLine(),
798 "Missing elses");
799 return false;
800 }
801
802 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
803 {
804 return false;
805 }
806 break;
807
808 case EOpAssign:
809 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200810 // No more additional checks are needed.
811 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
812 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
813 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400814 case EOpAdd:
815 case EOpSub:
816 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200817 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200818 case EOpBitShiftLeft:
819 case EOpBitShiftRight:
820 case EOpBitwiseAnd:
821 case EOpBitwiseXor:
822 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400823 case EOpAddAssign:
824 case EOpSubAssign:
825 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200826 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200827 case EOpBitShiftLeftAssign:
828 case EOpBitShiftRightAssign:
829 case EOpBitwiseAndAssign:
830 case EOpBitwiseXorAssign:
831 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400832 if ((mLeft->isMatrix() && mRight->isVector()) ||
833 (mLeft->isVector() && mRight->isMatrix()))
834 {
835 return false;
836 }
837
838 // Are the sizes compatible?
839 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
840 mLeft->getSecondarySize() != mRight->getSecondarySize())
841 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200842 // If the nominal sizes of operands do not match:
843 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400844 if (!mLeft->isScalar() && !mRight->isScalar())
845 return false;
846
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200847 // In the case of compound assignment other than multiply-assign,
848 // the right side needs to be a scalar. Otherwise a vector/matrix
849 // would be assigned to a scalar. A scalar can't be shifted by a
850 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200851 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200852 (isAssignment() ||
853 mOp == EOpBitShiftLeft ||
854 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200855 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400856 }
857
858 {
859 const int secondarySize = std::max(
860 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200861 setType(TType(basicType, higherPrecision, resultQualifier,
862 static_cast<unsigned char>(nominalSize),
863 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200864 if (mLeft->isArray())
865 {
866 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
867 mType.setArraySize(mLeft->getArraySize());
868 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400869 }
870 break;
871
872 case EOpEqual:
873 case EOpNotEqual:
874 case EOpLessThan:
875 case EOpGreaterThan:
876 case EOpLessThanEqual:
877 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200878 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
879 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400880 setType(TType(EbtBool, EbpUndefined));
881 break;
882
883 default:
884 return false;
885 }
886 return true;
887}
888
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300889TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
890{
891 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
892 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
893 if (leftConstant == nullptr || rightConstant == nullptr)
894 {
895 return nullptr;
896 }
897 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200898
899 // Nodes may be constant folded without being qualified as constant.
900 TQualifier resultQualifier = EvqConst;
901 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
902 {
903 resultQualifier = EvqTemporary;
904 }
905 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300906}
907
Olli Etuaho95310b02015-06-02 17:43:38 +0300908TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
909{
910 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
911 if (operandConstant == nullptr)
912 {
913 return nullptr;
914 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530915
916 TConstantUnion *constArray = nullptr;
917 switch (mOp)
918 {
919 case EOpAny:
920 case EOpAll:
921 case EOpLength:
922 case EOpTranspose:
923 case EOpDeterminant:
924 case EOpInverse:
925 case EOpPackSnorm2x16:
926 case EOpUnpackSnorm2x16:
927 case EOpPackUnorm2x16:
928 case EOpUnpackUnorm2x16:
929 case EOpPackHalf2x16:
930 case EOpUnpackHalf2x16:
931 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
932 break;
933 default:
934 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
935 break;
936 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200937
938 // Nodes may be constant folded without being qualified as constant.
939 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
940 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300941}
942
943TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
944{
945 // Make sure that all params are constant before actual constant folding.
946 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300947 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300948 if (param->getAsConstantUnion() == nullptr)
949 {
950 return nullptr;
951 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300952 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200953 TConstantUnion *constArray = nullptr;
954 if (isConstructor())
955 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
956 else
957 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200958
959 // Nodes may be constant folded without being qualified as constant.
960 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
961 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300962}
963
Jamie Madillb1a85f42014-08-19 15:23:24 -0400964//
965// The fold functions see if an operation on a constant can be done in place,
966// without generating run-time code.
967//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300968// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400969//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300970TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
971{
972 TConstantUnion *leftArray = getUnionArrayPointer();
973 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
974
975 if (!leftArray)
976 return nullptr;
977 if (!rightArray)
978 return nullptr;
979
980 size_t objectSize = getType().getObjectSize();
981
982 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
983 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
984 {
985 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
986 }
987 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
988 {
989 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
990 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
991 objectSize = rightNode->getType().getObjectSize();
992 }
993
994 TConstantUnion *resultArray = nullptr;
995
996 switch(op)
997 {
998 case EOpAdd:
999 resultArray = new TConstantUnion[objectSize];
1000 for (size_t i = 0; i < objectSize; i++)
1001 resultArray[i] = leftArray[i] + rightArray[i];
1002 break;
1003 case EOpSub:
1004 resultArray = new TConstantUnion[objectSize];
1005 for (size_t i = 0; i < objectSize; i++)
1006 resultArray[i] = leftArray[i] - rightArray[i];
1007 break;
1008
1009 case EOpMul:
1010 case EOpVectorTimesScalar:
1011 case EOpMatrixTimesScalar:
1012 resultArray = new TConstantUnion[objectSize];
1013 for (size_t i = 0; i < objectSize; i++)
1014 resultArray[i] = leftArray[i] * rightArray[i];
1015 break;
1016
1017 case EOpMatrixTimesMatrix:
1018 {
1019 if (getType().getBasicType() != EbtFloat ||
1020 rightNode->getBasicType() != EbtFloat)
1021 {
1022 infoSink.info.message(
1023 EPrefixInternalError, getLine(),
1024 "Constant Folding cannot be done for matrix multiply");
1025 return nullptr;
1026 }
1027
1028 const int leftCols = getCols();
1029 const int leftRows = getRows();
1030 const int rightCols = rightNode->getType().getCols();
1031 const int rightRows = rightNode->getType().getRows();
1032 const int resultCols = rightCols;
1033 const int resultRows = leftRows;
1034
1035 resultArray = new TConstantUnion[resultCols * resultRows];
1036 for (int row = 0; row < resultRows; row++)
1037 {
1038 for (int column = 0; column < resultCols; column++)
1039 {
1040 resultArray[resultRows * column + row].setFConst(0.0f);
1041 for (int i = 0; i < leftCols; i++)
1042 {
1043 resultArray[resultRows * column + row].setFConst(
1044 resultArray[resultRows * column + row].getFConst() +
1045 leftArray[i * leftRows + row].getFConst() *
1046 rightArray[column * rightRows + i].getFConst());
1047 }
1048 }
1049 }
1050 }
1051 break;
1052
1053 case EOpDiv:
1054 case EOpIMod:
1055 {
1056 resultArray = new TConstantUnion[objectSize];
1057 for (size_t i = 0; i < objectSize; i++)
1058 {
1059 switch (getType().getBasicType())
1060 {
1061 case EbtFloat:
1062 if (rightArray[i] == 0.0f)
1063 {
1064 infoSink.info.message(EPrefixWarning, getLine(),
1065 "Divide by zero error during constant folding");
1066 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1067 }
1068 else
1069 {
1070 ASSERT(op == EOpDiv);
1071 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1072 }
1073 break;
1074
1075 case EbtInt:
1076 if (rightArray[i] == 0)
1077 {
1078 infoSink.info.message(EPrefixWarning, getLine(),
1079 "Divide by zero error during constant folding");
1080 resultArray[i].setIConst(INT_MAX);
1081 }
1082 else
1083 {
1084 if (op == EOpDiv)
1085 {
1086 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1087 }
1088 else
1089 {
1090 ASSERT(op == EOpIMod);
1091 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1092 }
1093 }
1094 break;
1095
1096 case EbtUInt:
1097 if (rightArray[i] == 0)
1098 {
1099 infoSink.info.message(EPrefixWarning, getLine(),
1100 "Divide by zero error during constant folding");
1101 resultArray[i].setUConst(UINT_MAX);
1102 }
1103 else
1104 {
1105 if (op == EOpDiv)
1106 {
1107 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1108 }
1109 else
1110 {
1111 ASSERT(op == EOpIMod);
1112 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1113 }
1114 }
1115 break;
1116
1117 default:
1118 infoSink.info.message(EPrefixInternalError, getLine(),
1119 "Constant folding cannot be done for \"/\"");
1120 return nullptr;
1121 }
1122 }
1123 }
1124 break;
1125
1126 case EOpMatrixTimesVector:
1127 {
1128 if (rightNode->getBasicType() != EbtFloat)
1129 {
1130 infoSink.info.message(EPrefixInternalError, getLine(),
1131 "Constant Folding cannot be done for matrix times vector");
1132 return nullptr;
1133 }
1134
1135 const int matrixCols = getCols();
1136 const int matrixRows = getRows();
1137
1138 resultArray = new TConstantUnion[matrixRows];
1139
1140 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1141 {
1142 resultArray[matrixRow].setFConst(0.0f);
1143 for (int col = 0; col < matrixCols; col++)
1144 {
1145 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1146 leftArray[col * matrixRows + matrixRow].getFConst() *
1147 rightArray[col].getFConst());
1148 }
1149 }
1150 }
1151 break;
1152
1153 case EOpVectorTimesMatrix:
1154 {
1155 if (getType().getBasicType() != EbtFloat)
1156 {
1157 infoSink.info.message(EPrefixInternalError, getLine(),
1158 "Constant Folding cannot be done for vector times matrix");
1159 return nullptr;
1160 }
1161
1162 const int matrixCols = rightNode->getType().getCols();
1163 const int matrixRows = rightNode->getType().getRows();
1164
1165 resultArray = new TConstantUnion[matrixCols];
1166
1167 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1168 {
1169 resultArray[matrixCol].setFConst(0.0f);
1170 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1171 {
1172 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1173 leftArray[matrixRow].getFConst() *
1174 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1175 }
1176 }
1177 }
1178 break;
1179
1180 case EOpLogicalAnd:
1181 {
1182 resultArray = new TConstantUnion[objectSize];
1183 for (size_t i = 0; i < objectSize; i++)
1184 {
1185 resultArray[i] = leftArray[i] && rightArray[i];
1186 }
1187 }
1188 break;
1189
1190 case EOpLogicalOr:
1191 {
1192 resultArray = new TConstantUnion[objectSize];
1193 for (size_t i = 0; i < objectSize; i++)
1194 {
1195 resultArray[i] = leftArray[i] || rightArray[i];
1196 }
1197 }
1198 break;
1199
1200 case EOpLogicalXor:
1201 {
1202 resultArray = new TConstantUnion[objectSize];
1203 for (size_t i = 0; i < objectSize; i++)
1204 {
1205 switch (getType().getBasicType())
1206 {
1207 case EbtBool:
1208 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1209 break;
1210 default:
1211 UNREACHABLE();
1212 break;
1213 }
1214 }
1215 }
1216 break;
1217
1218 case EOpBitwiseAnd:
1219 resultArray = new TConstantUnion[objectSize];
1220 for (size_t i = 0; i < objectSize; i++)
1221 resultArray[i] = leftArray[i] & rightArray[i];
1222 break;
1223 case EOpBitwiseXor:
1224 resultArray = new TConstantUnion[objectSize];
1225 for (size_t i = 0; i < objectSize; i++)
1226 resultArray[i] = leftArray[i] ^ rightArray[i];
1227 break;
1228 case EOpBitwiseOr:
1229 resultArray = new TConstantUnion[objectSize];
1230 for (size_t i = 0; i < objectSize; i++)
1231 resultArray[i] = leftArray[i] | rightArray[i];
1232 break;
1233 case EOpBitShiftLeft:
1234 resultArray = new TConstantUnion[objectSize];
1235 for (size_t i = 0; i < objectSize; i++)
1236 resultArray[i] = leftArray[i] << rightArray[i];
1237 break;
1238 case EOpBitShiftRight:
1239 resultArray = new TConstantUnion[objectSize];
1240 for (size_t i = 0; i < objectSize; i++)
1241 resultArray[i] = leftArray[i] >> rightArray[i];
1242 break;
1243
1244 case EOpLessThan:
1245 ASSERT(objectSize == 1);
1246 resultArray = new TConstantUnion[1];
1247 resultArray->setBConst(*leftArray < *rightArray);
1248 break;
1249
1250 case EOpGreaterThan:
1251 ASSERT(objectSize == 1);
1252 resultArray = new TConstantUnion[1];
1253 resultArray->setBConst(*leftArray > *rightArray);
1254 break;
1255
1256 case EOpLessThanEqual:
1257 ASSERT(objectSize == 1);
1258 resultArray = new TConstantUnion[1];
1259 resultArray->setBConst(!(*leftArray > *rightArray));
1260 break;
1261
1262 case EOpGreaterThanEqual:
1263 ASSERT(objectSize == 1);
1264 resultArray = new TConstantUnion[1];
1265 resultArray->setBConst(!(*leftArray < *rightArray));
1266 break;
1267
1268 case EOpEqual:
1269 case EOpNotEqual:
1270 {
1271 resultArray = new TConstantUnion[1];
1272 bool equal = true;
1273 if (getType().getBasicType() == EbtStruct)
1274 {
1275 equal = CompareStructure(getType(), rightArray, leftArray);
1276 }
1277 else
1278 {
1279 for (size_t i = 0; i < objectSize; i++)
1280 {
1281 if (leftArray[i] != rightArray[i])
1282 {
1283 equal = false;
1284 break; // break out of for loop
1285 }
1286 }
1287 }
1288 if (op == EOpEqual)
1289 {
1290 resultArray->setBConst(equal);
1291 }
1292 else
1293 {
1294 resultArray->setBConst(!equal);
1295 }
1296 }
1297 break;
1298
1299 default:
1300 infoSink.info.message(
1301 EPrefixInternalError, getLine(),
1302 "Invalid operator for constant folding");
1303 return nullptr;
1304 }
1305 return resultArray;
1306}
1307
1308//
1309// The fold functions see if an operation on a constant can be done in place,
1310// without generating run-time code.
1311//
Olli Etuaho95310b02015-06-02 17:43:38 +03001312// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001313//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301314TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001315{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301316 //
1317 // Do operations where the return type has a different number of components compared to the operand type.
1318 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001319
Arun Patoleab2b9a22015-07-06 18:27:56 +05301320 TConstantUnion *operandArray = getUnionArrayPointer();
1321 if (!operandArray)
1322 return nullptr;
1323
1324 size_t objectSize = getType().getObjectSize();
1325 TConstantUnion *resultArray = nullptr;
1326 switch (op)
1327 {
1328 case EOpAny:
1329 if (getType().getBasicType() == EbtBool)
1330 {
1331 resultArray = new TConstantUnion();
1332 resultArray->setBConst(false);
1333 for (size_t i = 0; i < objectSize; i++)
1334 {
1335 if (operandArray[i].getBConst())
1336 {
1337 resultArray->setBConst(true);
1338 break;
1339 }
1340 }
1341 break;
1342 }
1343 else
1344 {
1345 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1346 return nullptr;
1347 }
1348
1349 case EOpAll:
1350 if (getType().getBasicType() == EbtBool)
1351 {
1352 resultArray = new TConstantUnion();
1353 resultArray->setBConst(true);
1354 for (size_t i = 0; i < objectSize; i++)
1355 {
1356 if (!operandArray[i].getBConst())
1357 {
1358 resultArray->setBConst(false);
1359 break;
1360 }
1361 }
1362 break;
1363 }
1364 else
1365 {
1366 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1367 return nullptr;
1368 }
1369
1370 case EOpLength:
1371 if (getType().getBasicType() == EbtFloat)
1372 {
1373 resultArray = new TConstantUnion();
1374 resultArray->setFConst(VectorLength(operandArray, objectSize));
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 EOpTranspose:
1384 if (getType().getBasicType() == EbtFloat)
1385 {
1386 resultArray = new TConstantUnion[objectSize];
1387 angle::Matrix<float> result =
1388 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1389 SetUnionArrayFromMatrix(result, resultArray);
1390 break;
1391 }
1392 else
1393 {
1394 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1395 return nullptr;
1396 }
1397
1398 case EOpDeterminant:
1399 if (getType().getBasicType() == EbtFloat)
1400 {
1401 unsigned int size = getType().getNominalSize();
1402 ASSERT(size >= 2 && size <= 4);
1403 resultArray = new TConstantUnion();
1404 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
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 EOpInverse:
1414 if (getType().getBasicType() == EbtFloat)
1415 {
1416 unsigned int size = getType().getNominalSize();
1417 ASSERT(size >= 2 && size <= 4);
1418 resultArray = new TConstantUnion[objectSize];
1419 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1420 SetUnionArrayFromMatrix(result, resultArray);
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 EOpPackSnorm2x16:
1430 if (getType().getBasicType() == EbtFloat)
1431 {
1432 ASSERT(getType().getNominalSize() == 2);
1433 resultArray = new TConstantUnion();
1434 resultArray->setUConst(gl::packSnorm2x16(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 EOpUnpackSnorm2x16:
1444 if (getType().getBasicType() == EbtUInt)
1445 {
1446 resultArray = new TConstantUnion[2];
1447 float f1, f2;
1448 gl::unpackSnorm2x16(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
1459 case EOpPackUnorm2x16:
1460 if (getType().getBasicType() == EbtFloat)
1461 {
1462 ASSERT(getType().getNominalSize() == 2);
1463 resultArray = new TConstantUnion();
1464 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1465 break;
1466 }
1467 else
1468 {
1469 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1470 return nullptr;
1471 }
1472
1473 case EOpUnpackUnorm2x16:
1474 if (getType().getBasicType() == EbtUInt)
1475 {
1476 resultArray = new TConstantUnion[2];
1477 float f1, f2;
1478 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1479 resultArray[0].setFConst(f1);
1480 resultArray[1].setFConst(f2);
1481 break;
1482 }
1483 else
1484 {
1485 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1486 return nullptr;
1487 }
1488
1489 case EOpPackHalf2x16:
1490 if (getType().getBasicType() == EbtFloat)
1491 {
1492 ASSERT(getType().getNominalSize() == 2);
1493 resultArray = new TConstantUnion();
1494 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1495 break;
1496 }
1497 else
1498 {
1499 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1500 return nullptr;
1501 }
1502
1503 case EOpUnpackHalf2x16:
1504 if (getType().getBasicType() == EbtUInt)
1505 {
1506 resultArray = new TConstantUnion[2];
1507 float f1, f2;
1508 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1509 resultArray[0].setFConst(f1);
1510 resultArray[1].setFConst(f2);
1511 break;
1512 }
1513 else
1514 {
1515 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1516 return nullptr;
1517 }
1518 break;
1519
1520 default:
1521 break;
1522 }
1523
1524 return resultArray;
1525}
1526
1527TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1528{
1529 //
1530 // Do unary operations where the return type is the same as operand type.
1531 //
1532
1533 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001534 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301535 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001536
1537 size_t objectSize = getType().getObjectSize();
1538
Arun Patoleab2b9a22015-07-06 18:27:56 +05301539 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1540 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301541 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301542 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301543 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301544 case EOpNegative:
1545 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301546 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301547 case EbtFloat:
1548 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301549 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301550 case EbtInt:
1551 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301552 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301553 case EbtUInt:
1554 resultArray[i].setUConst(static_cast<unsigned int>(
1555 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301556 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301557 default:
1558 infoSink.info.message(
1559 EPrefixInternalError, getLine(),
1560 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301561 return nullptr;
1562 }
1563 break;
1564
Arun Patoleab2b9a22015-07-06 18:27:56 +05301565 case EOpPositive:
1566 switch (getType().getBasicType())
1567 {
1568 case EbtFloat:
1569 resultArray[i].setFConst(operandArray[i].getFConst());
1570 break;
1571 case EbtInt:
1572 resultArray[i].setIConst(operandArray[i].getIConst());
1573 break;
1574 case EbtUInt:
1575 resultArray[i].setUConst(static_cast<unsigned int>(
1576 static_cast<int>(operandArray[i].getUConst())));
1577 break;
1578 default:
1579 infoSink.info.message(
1580 EPrefixInternalError, getLine(),
1581 "Unary operation not folded into constant");
1582 return nullptr;
1583 }
1584 break;
1585
1586 case EOpLogicalNot:
1587 // this code is written for possible future use,
1588 // will not get executed currently
1589 switch (getType().getBasicType())
1590 {
1591 case EbtBool:
1592 resultArray[i].setBConst(!operandArray[i].getBConst());
1593 break;
1594 default:
1595 infoSink.info.message(
1596 EPrefixInternalError, getLine(),
1597 "Unary operation not folded into constant");
1598 return nullptr;
1599 }
1600 break;
1601
1602 case EOpBitwiseNot:
1603 switch (getType().getBasicType())
1604 {
1605 case EbtInt:
1606 resultArray[i].setIConst(~operandArray[i].getIConst());
1607 break;
1608 case EbtUInt:
1609 resultArray[i].setUConst(~operandArray[i].getUConst());
1610 break;
1611 default:
1612 infoSink.info.message(
1613 EPrefixInternalError, getLine(),
1614 "Unary operation not folded into constant");
1615 return nullptr;
1616 }
1617 break;
1618
1619 case EOpRadians:
1620 if (getType().getBasicType() == EbtFloat)
1621 {
1622 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1623 break;
1624 }
1625 infoSink.info.message(
1626 EPrefixInternalError, getLine(),
1627 "Unary operation not folded into constant");
1628 return nullptr;
1629
1630 case EOpDegrees:
1631 if (getType().getBasicType() == EbtFloat)
1632 {
1633 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1634 break;
1635 }
1636 infoSink.info.message(
1637 EPrefixInternalError, getLine(),
1638 "Unary operation not folded into constant");
1639 return nullptr;
1640
1641 case EOpSin:
1642 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1643 return nullptr;
1644 break;
1645
1646 case EOpCos:
1647 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1648 return nullptr;
1649 break;
1650
1651 case EOpTan:
1652 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1653 return nullptr;
1654 break;
1655
1656 case EOpAsin:
1657 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1658 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1659 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1660 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1661 return nullptr;
1662 break;
1663
1664 case EOpAcos:
1665 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1666 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1667 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1668 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1669 return nullptr;
1670 break;
1671
1672 case EOpAtan:
1673 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1674 return nullptr;
1675 break;
1676
1677 case EOpSinh:
1678 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1679 return nullptr;
1680 break;
1681
1682 case EOpCosh:
1683 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1684 return nullptr;
1685 break;
1686
1687 case EOpTanh:
1688 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1689 return nullptr;
1690 break;
1691
1692 case EOpAsinh:
1693 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1694 return nullptr;
1695 break;
1696
1697 case EOpAcosh:
1698 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1699 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1700 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1701 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1702 return nullptr;
1703 break;
1704
1705 case EOpAtanh:
1706 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1707 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1708 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1709 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1710 return nullptr;
1711 break;
1712
1713 case EOpAbs:
1714 switch (getType().getBasicType())
1715 {
1716 case EbtFloat:
1717 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1718 break;
1719 case EbtInt:
1720 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1721 break;
1722 default:
1723 infoSink.info.message(
1724 EPrefixInternalError, getLine(),
1725 "Unary operation not folded into constant");
1726 return nullptr;
1727 }
1728 break;
1729
1730 case EOpSign:
1731 switch (getType().getBasicType())
1732 {
1733 case EbtFloat:
1734 {
1735 float fConst = operandArray[i].getFConst();
1736 float fResult = 0.0f;
1737 if (fConst > 0.0f)
1738 fResult = 1.0f;
1739 else if (fConst < 0.0f)
1740 fResult = -1.0f;
1741 resultArray[i].setFConst(fResult);
1742 }
1743 break;
1744 case EbtInt:
1745 {
1746 int iConst = operandArray[i].getIConst();
1747 int iResult = 0;
1748 if (iConst > 0)
1749 iResult = 1;
1750 else if (iConst < 0)
1751 iResult = -1;
1752 resultArray[i].setIConst(iResult);
1753 }
1754 break;
1755 default:
1756 infoSink.info.message(
1757 EPrefixInternalError, getLine(),
1758 "Unary operation not folded into constant");
1759 return nullptr;
1760 }
1761 break;
1762
1763 case EOpFloor:
1764 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1765 return nullptr;
1766 break;
1767
1768 case EOpTrunc:
1769 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1770 return nullptr;
1771 break;
1772
1773 case EOpRound:
1774 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1775 return nullptr;
1776 break;
1777
1778 case EOpRoundEven:
1779 if (getType().getBasicType() == EbtFloat)
1780 {
1781 float x = operandArray[i].getFConst();
1782 float result;
1783 float fractPart = modff(x, &result);
1784 if (fabsf(fractPart) == 0.5f)
1785 result = 2.0f * roundf(x / 2.0f);
1786 else
1787 result = roundf(x);
1788 resultArray[i].setFConst(result);
1789 break;
1790 }
1791 infoSink.info.message(
1792 EPrefixInternalError, getLine(),
1793 "Unary operation not folded into constant");
1794 return nullptr;
1795
1796 case EOpCeil:
1797 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1798 return nullptr;
1799 break;
1800
1801 case EOpFract:
1802 if (getType().getBasicType() == EbtFloat)
1803 {
1804 float x = operandArray[i].getFConst();
1805 resultArray[i].setFConst(x - floorf(x));
1806 break;
1807 }
1808 infoSink.info.message(
1809 EPrefixInternalError, getLine(),
1810 "Unary operation not folded into constant");
1811 return nullptr;
1812
Arun Patole551279e2015-07-07 18:18:23 +05301813 case EOpIsNan:
1814 if (getType().getBasicType() == EbtFloat)
1815 {
1816 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1817 break;
1818 }
1819 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1820 return nullptr;
1821
1822 case EOpIsInf:
1823 if (getType().getBasicType() == EbtFloat)
1824 {
1825 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1826 break;
1827 }
1828 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1829 return nullptr;
1830
1831 case EOpFloatBitsToInt:
1832 if (getType().getBasicType() == EbtFloat)
1833 {
1834 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1835 break;
1836 }
1837 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1838 return nullptr;
1839
1840 case EOpFloatBitsToUint:
1841 if (getType().getBasicType() == EbtFloat)
1842 {
1843 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1844 break;
1845 }
1846 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1847 return nullptr;
1848
1849 case EOpIntBitsToFloat:
1850 if (getType().getBasicType() == EbtInt)
1851 {
1852 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1853 break;
1854 }
1855 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1856 return nullptr;
1857
1858 case EOpUintBitsToFloat:
1859 if (getType().getBasicType() == EbtUInt)
1860 {
1861 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1862 break;
1863 }
1864 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1865 return nullptr;
1866
Arun Patoleab2b9a22015-07-06 18:27:56 +05301867 case EOpExp:
1868 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1869 return nullptr;
1870 break;
1871
1872 case EOpLog:
1873 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1874 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1875 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1876 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1877 return nullptr;
1878 break;
1879
1880 case EOpExp2:
1881 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1882 return nullptr;
1883 break;
1884
1885 case EOpLog2:
1886 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1887 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1888 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1889 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1890 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1891 return nullptr;
1892 else
1893 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1894 break;
1895
1896 case EOpSqrt:
1897 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1898 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1899 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1900 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1901 return nullptr;
1902 break;
1903
1904 case EOpInverseSqrt:
1905 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1906 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1907 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1908 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1909 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1910 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1911 return nullptr;
1912 else
1913 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1914 break;
1915
1916 case EOpVectorLogicalNot:
1917 if (getType().getBasicType() == EbtBool)
1918 {
1919 resultArray[i].setBConst(!operandArray[i].getBConst());
1920 break;
1921 }
1922 infoSink.info.message(
1923 EPrefixInternalError, getLine(),
1924 "Unary operation not folded into constant");
1925 return nullptr;
1926
1927 case EOpNormalize:
1928 if (getType().getBasicType() == EbtFloat)
1929 {
1930 float x = operandArray[i].getFConst();
1931 float length = VectorLength(operandArray, objectSize);
1932 if (length)
1933 resultArray[i].setFConst(x / length);
1934 else
1935 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1936 &resultArray[i]);
1937 break;
1938 }
1939 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1940 return nullptr;
1941
Arun Patole0c5409f2015-07-08 15:17:53 +05301942 case EOpDFdx:
1943 case EOpDFdy:
1944 case EOpFwidth:
1945 if (getType().getBasicType() == EbtFloat)
1946 {
1947 // Derivatives of constant arguments should be 0.
1948 resultArray[i].setFConst(0.0f);
1949 break;
1950 }
1951 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1952 return nullptr;
1953
Arun Patole1155ddd2015-06-05 18:04:36 +05301954 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301955 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301956 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301957 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001958
Arun Patoleab2b9a22015-07-06 18:27:56 +05301959 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001960}
1961
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001962bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1963 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301964{
1965 ASSERT(builtinFunc);
1966
1967 if (getType().getBasicType() == EbtFloat)
1968 {
1969 result->setFConst(builtinFunc(parameter.getFConst()));
1970 return true;
1971 }
1972
1973 infoSink.info.message(
1974 EPrefixInternalError, getLine(),
1975 "Unary operation not folded into constant");
1976 return false;
1977}
1978
Jamie Madillb1a85f42014-08-19 15:23:24 -04001979// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001980TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1981 TInfoSink &infoSink)
1982{
1983 ASSERT(aggregate->getSequence()->size() > 0u);
1984 size_t resultSize = aggregate->getType().getObjectSize();
1985 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1986 TBasicType basicType = aggregate->getBasicType();
1987
1988 size_t resultIndex = 0u;
1989
1990 if (aggregate->getSequence()->size() == 1u)
1991 {
1992 TIntermNode *argument = aggregate->getSequence()->front();
1993 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1994 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1995 // Check the special case of constructing a matrix diagonal from a single scalar,
1996 // or a vector from a single scalar.
1997 if (argumentConstant->getType().getObjectSize() == 1u)
1998 {
1999 if (aggregate->isMatrix())
2000 {
2001 int resultCols = aggregate->getType().getCols();
2002 int resultRows = aggregate->getType().getRows();
2003 for (int col = 0; col < resultCols; ++col)
2004 {
2005 for (int row = 0; row < resultRows; ++row)
2006 {
2007 if (col == row)
2008 {
2009 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2010 }
2011 else
2012 {
2013 resultArray[resultIndex].setFConst(0.0f);
2014 }
2015 ++resultIndex;
2016 }
2017 }
2018 }
2019 else
2020 {
2021 while (resultIndex < resultSize)
2022 {
2023 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2024 ++resultIndex;
2025 }
2026 }
2027 ASSERT(resultIndex == resultSize);
2028 return resultArray;
2029 }
2030 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2031 {
2032 // The special case of constructing a matrix from a matrix.
2033 int argumentCols = argumentConstant->getType().getCols();
2034 int argumentRows = argumentConstant->getType().getRows();
2035 int resultCols = aggregate->getType().getCols();
2036 int resultRows = aggregate->getType().getRows();
2037 for (int col = 0; col < resultCols; ++col)
2038 {
2039 for (int row = 0; row < resultRows; ++row)
2040 {
2041 if (col < argumentCols && row < argumentRows)
2042 {
2043 resultArray[resultIndex].cast(basicType,
2044 argumentUnionArray[col * argumentRows + row]);
2045 }
2046 else if (col == row)
2047 {
2048 resultArray[resultIndex].setFConst(1.0f);
2049 }
2050 else
2051 {
2052 resultArray[resultIndex].setFConst(0.0f);
2053 }
2054 ++resultIndex;
2055 }
2056 }
2057 ASSERT(resultIndex == resultSize);
2058 return resultArray;
2059 }
2060 }
2061
2062 for (TIntermNode *&argument : *aggregate->getSequence())
2063 {
2064 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2065 size_t argumentSize = argumentConstant->getType().getObjectSize();
2066 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2067 for (size_t i = 0u; i < argumentSize; ++i)
2068 {
2069 if (resultIndex >= resultSize)
2070 break;
2071 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2072 ++resultIndex;
2073 }
2074 }
2075 ASSERT(resultIndex == resultSize);
2076 return resultArray;
2077}
2078
2079// static
Olli Etuahob43846e2015-06-02 18:18:57 +03002080TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05302081{
Olli Etuahob43846e2015-06-02 18:18:57 +03002082 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302083 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002084 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Arun Patole274f0702015-05-05 13:33:30 +05302085 std::vector<TConstantUnion *> unionArrays(paramsCount);
2086 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002087 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302088 TBasicType basicType = EbtVoid;
2089 TSourceLoc loc;
2090 for (unsigned int i = 0; i < paramsCount; i++)
2091 {
2092 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002093 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302094
2095 if (i == 0)
2096 {
2097 basicType = paramConstant->getType().getBasicType();
2098 loc = paramConstant->getLine();
2099 }
2100 unionArrays[i] = paramConstant->getUnionArrayPointer();
2101 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002102 if (objectSizes[i] > maxObjectSize)
2103 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302104 }
2105
Arun Patole7fa33552015-06-10 15:15:18 +05302106 if (!(*sequence)[0]->getAsTyped()->isMatrix())
2107 {
2108 for (unsigned int i = 0; i < paramsCount; i++)
2109 if (objectSizes[i] != maxObjectSize)
2110 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2111 }
Arun Patole274f0702015-05-05 13:33:30 +05302112
Olli Etuahob43846e2015-06-02 18:18:57 +03002113 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302114 if (paramsCount == 2)
2115 {
2116 //
2117 // Binary built-in
2118 //
2119 switch (op)
2120 {
Arun Patolebf790422015-05-18 17:53:04 +05302121 case EOpAtan:
2122 {
2123 if (basicType == EbtFloat)
2124 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002125 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302126 for (size_t i = 0; i < maxObjectSize; i++)
2127 {
2128 float y = unionArrays[0][i].getFConst();
2129 float x = unionArrays[1][i].getFConst();
2130 // Results are undefined if x and y are both 0.
2131 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002132 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302133 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002134 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302135 }
2136 }
2137 else
2138 UNREACHABLE();
2139 }
2140 break;
2141
2142 case EOpPow:
2143 {
2144 if (basicType == EbtFloat)
2145 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002146 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302147 for (size_t i = 0; i < maxObjectSize; i++)
2148 {
2149 float x = unionArrays[0][i].getFConst();
2150 float y = unionArrays[1][i].getFConst();
2151 // Results are undefined if x < 0.
2152 // Results are undefined if x = 0 and y <= 0.
2153 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002154 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302155 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002156 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302157 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002158 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302159 }
2160 }
2161 else
2162 UNREACHABLE();
2163 }
2164 break;
2165
2166 case EOpMod:
2167 {
2168 if (basicType == EbtFloat)
2169 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002170 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302171 for (size_t i = 0; i < maxObjectSize; i++)
2172 {
2173 float x = unionArrays[0][i].getFConst();
2174 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002175 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302176 }
2177 }
2178 else
2179 UNREACHABLE();
2180 }
2181 break;
2182
Arun Patole274f0702015-05-05 13:33:30 +05302183 case EOpMin:
2184 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002185 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302186 for (size_t i = 0; i < maxObjectSize; i++)
2187 {
2188 switch (basicType)
2189 {
2190 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002191 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302192 break;
2193 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002194 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302195 break;
2196 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002197 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302198 break;
2199 default:
2200 UNREACHABLE();
2201 break;
2202 }
2203 }
2204 }
2205 break;
2206
2207 case EOpMax:
2208 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002209 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302210 for (size_t i = 0; i < maxObjectSize; i++)
2211 {
2212 switch (basicType)
2213 {
2214 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002215 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302216 break;
2217 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002218 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302219 break;
2220 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002221 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302222 break;
2223 default:
2224 UNREACHABLE();
2225 break;
2226 }
2227 }
2228 }
2229 break;
2230
Arun Patolebf790422015-05-18 17:53:04 +05302231 case EOpStep:
2232 {
2233 if (basicType == EbtFloat)
2234 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002235 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302236 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002237 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302238 }
2239 else
2240 UNREACHABLE();
2241 }
2242 break;
2243
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 case EOpLessThan:
2245 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002246 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302247 for (size_t i = 0; i < maxObjectSize; i++)
2248 {
2249 switch (basicType)
2250 {
2251 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002252 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302253 break;
2254 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002255 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302256 break;
2257 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002258 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302259 break;
2260 default:
2261 UNREACHABLE();
2262 break;
2263 }
2264 }
2265 }
2266 break;
2267
2268 case EOpLessThanEqual:
2269 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002270 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302271 for (size_t i = 0; i < maxObjectSize; i++)
2272 {
2273 switch (basicType)
2274 {
2275 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002276 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302277 break;
2278 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002279 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302280 break;
2281 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002282 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302283 break;
2284 default:
2285 UNREACHABLE();
2286 break;
2287 }
2288 }
2289 }
2290 break;
2291
2292 case EOpGreaterThan:
2293 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002294 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302295 for (size_t i = 0; i < maxObjectSize; i++)
2296 {
2297 switch (basicType)
2298 {
2299 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002300 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302301 break;
2302 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002303 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302304 break;
2305 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002306 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302307 break;
2308 default:
2309 UNREACHABLE();
2310 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002311 }
2312 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302313 }
2314 break;
2315
2316 case EOpGreaterThanEqual:
2317 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002318 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302319 for (size_t i = 0; i < maxObjectSize; i++)
2320 {
2321 switch (basicType)
2322 {
2323 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002324 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302325 break;
2326 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002327 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302328 break;
2329 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002330 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302331 break;
2332 default:
2333 UNREACHABLE();
2334 break;
2335 }
2336 }
2337 }
2338 break;
2339
2340 case EOpVectorEqual:
2341 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002342 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302343 for (size_t i = 0; i < maxObjectSize; i++)
2344 {
2345 switch (basicType)
2346 {
2347 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002348 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302349 break;
2350 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002351 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302352 break;
2353 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002354 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302355 break;
2356 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002357 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302358 break;
2359 default:
2360 UNREACHABLE();
2361 break;
2362 }
2363 }
2364 }
2365 break;
2366
2367 case EOpVectorNotEqual:
2368 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002369 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302370 for (size_t i = 0; i < maxObjectSize; i++)
2371 {
2372 switch (basicType)
2373 {
2374 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002375 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302376 break;
2377 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002378 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302379 break;
2380 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002381 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302382 break;
2383 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002384 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302385 break;
2386 default:
2387 UNREACHABLE();
2388 break;
2389 }
2390 }
2391 }
2392 break;
2393
Arun Patole1155ddd2015-06-05 18:04:36 +05302394 case EOpDistance:
2395 if (basicType == EbtFloat)
2396 {
2397 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002398 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302399 for (size_t i = 0; i < maxObjectSize; i++)
2400 {
2401 float x = unionArrays[0][i].getFConst();
2402 float y = unionArrays[1][i].getFConst();
2403 distanceArray[i].setFConst(x - y);
2404 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002405 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302406 }
2407 else
2408 UNREACHABLE();
2409 break;
2410
2411 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002412
Arun Patole1155ddd2015-06-05 18:04:36 +05302413 if (basicType == EbtFloat)
2414 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002415 resultArray = new TConstantUnion();
2416 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302417 }
2418 else
2419 UNREACHABLE();
2420 break;
2421
2422 case EOpCross:
2423 if (basicType == EbtFloat && maxObjectSize == 3)
2424 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002425 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302426 float x0 = unionArrays[0][0].getFConst();
2427 float x1 = unionArrays[0][1].getFConst();
2428 float x2 = unionArrays[0][2].getFConst();
2429 float y0 = unionArrays[1][0].getFConst();
2430 float y1 = unionArrays[1][1].getFConst();
2431 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002432 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2433 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2434 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302435 }
2436 else
2437 UNREACHABLE();
2438 break;
2439
2440 case EOpReflect:
2441 if (basicType == EbtFloat)
2442 {
2443 // genType reflect (genType I, genType N) :
2444 // For the incident vector I and surface orientation N, returns the reflection direction:
2445 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002446 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302447 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2448 for (size_t i = 0; i < maxObjectSize; i++)
2449 {
2450 float result = unionArrays[0][i].getFConst() -
2451 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002452 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302453 }
2454 }
2455 else
2456 UNREACHABLE();
2457 break;
2458
Arun Patole7fa33552015-06-10 15:15:18 +05302459 case EOpMul:
2460 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2461 (*sequence)[1]->getAsTyped()->isMatrix())
2462 {
2463 // Perform component-wise matrix multiplication.
2464 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002465 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302466 angle::Matrix<float> result =
2467 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2468 SetUnionArrayFromMatrix(result, resultArray);
2469 }
2470 else
2471 UNREACHABLE();
2472 break;
2473
2474 case EOpOuterProduct:
2475 if (basicType == EbtFloat)
2476 {
2477 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2478 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2479 resultArray = new TConstantUnion[numRows * numCols];
2480 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002481 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2482 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302483 SetUnionArrayFromMatrix(result, resultArray);
2484 }
2485 else
2486 UNREACHABLE();
2487 break;
2488
Arun Patole274f0702015-05-05 13:33:30 +05302489 default:
2490 UNREACHABLE();
2491 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2492 return nullptr;
2493 }
2494 }
2495 else if (paramsCount == 3)
2496 {
2497 //
2498 // Ternary built-in
2499 //
2500 switch (op)
2501 {
2502 case EOpClamp:
2503 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002504 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302505 for (size_t i = 0; i < maxObjectSize; i++)
2506 {
2507 switch (basicType)
2508 {
2509 case EbtFloat:
2510 {
2511 float x = unionArrays[0][i].getFConst();
2512 float min = unionArrays[1][i].getFConst();
2513 float max = unionArrays[2][i].getFConst();
2514 // Results are undefined if min > max.
2515 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002516 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302517 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002518 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302519 }
2520 break;
2521 case EbtInt:
2522 {
2523 int x = unionArrays[0][i].getIConst();
2524 int min = unionArrays[1][i].getIConst();
2525 int max = unionArrays[2][i].getIConst();
2526 // Results are undefined if min > max.
2527 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002528 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302529 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002530 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302531 }
2532 break;
2533 case EbtUInt:
2534 {
2535 unsigned int x = unionArrays[0][i].getUConst();
2536 unsigned int min = unionArrays[1][i].getUConst();
2537 unsigned int max = unionArrays[2][i].getUConst();
2538 // Results are undefined if min > max.
2539 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002540 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302541 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002542 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302543 }
2544 break;
2545 default:
2546 UNREACHABLE();
2547 break;
2548 }
2549 }
2550 }
2551 break;
2552
Arun Patolebf790422015-05-18 17:53:04 +05302553 case EOpMix:
2554 {
2555 if (basicType == EbtFloat)
2556 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002557 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302558 for (size_t i = 0; i < maxObjectSize; i++)
2559 {
2560 float x = unionArrays[0][i].getFConst();
2561 float y = unionArrays[1][i].getFConst();
2562 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2563 if (type == EbtFloat)
2564 {
2565 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2566 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002567 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302568 }
2569 else // 3rd parameter is EbtBool
2570 {
2571 ASSERT(type == EbtBool);
2572 // Selects which vector each returned component comes from.
2573 // For a component of a that is false, the corresponding component of x is returned.
2574 // For a component of a that is true, the corresponding component of y is returned.
2575 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002576 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302577 }
2578 }
2579 }
2580 else
2581 UNREACHABLE();
2582 }
2583 break;
2584
2585 case EOpSmoothStep:
2586 {
2587 if (basicType == EbtFloat)
2588 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002589 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302590 for (size_t i = 0; i < maxObjectSize; i++)
2591 {
2592 float edge0 = unionArrays[0][i].getFConst();
2593 float edge1 = unionArrays[1][i].getFConst();
2594 float x = unionArrays[2][i].getFConst();
2595 // Results are undefined if edge0 >= edge1.
2596 if (edge0 >= edge1)
2597 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002598 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302599 }
2600 else
2601 {
2602 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2603 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2604 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002605 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302606 }
2607 }
2608 }
2609 else
2610 UNREACHABLE();
2611 }
2612 break;
2613
Arun Patole1155ddd2015-06-05 18:04:36 +05302614 case EOpFaceForward:
2615 if (basicType == EbtFloat)
2616 {
2617 // genType faceforward(genType N, genType I, genType Nref) :
2618 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002619 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302620 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2621 for (size_t i = 0; i < maxObjectSize; i++)
2622 {
2623 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002624 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302625 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002626 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302627 }
2628 }
2629 else
2630 UNREACHABLE();
2631 break;
2632
2633 case EOpRefract:
2634 if (basicType == EbtFloat)
2635 {
2636 // genType refract(genType I, genType N, float eta) :
2637 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2638 // return the refraction vector. The result is computed by
2639 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2640 // if (k < 0.0)
2641 // return genType(0.0)
2642 // else
2643 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002644 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302645 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2646 for (size_t i = 0; i < maxObjectSize; i++)
2647 {
2648 float eta = unionArrays[2][i].getFConst();
2649 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2650 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002651 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302652 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002653 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302654 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2655 }
2656 }
2657 else
2658 UNREACHABLE();
2659 break;
2660
Arun Patole274f0702015-05-05 13:33:30 +05302661 default:
2662 UNREACHABLE();
2663 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2664 return nullptr;
2665 }
2666 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002667 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302668}
2669
2670// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002671TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2672{
2673 if (hashFunction == NULL || name.empty())
2674 return name;
2675 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2676 TStringStream stream;
2677 stream << HASHED_NAME_PREFIX << std::hex << number;
2678 TString hashedName = stream.str();
2679 return hashedName;
2680}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002681
2682void TIntermTraverser::updateTree()
2683{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002684 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2685 {
2686 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2687 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002688 if (!insertion.insertionsAfter.empty())
2689 {
2690 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2691 insertion.insertionsAfter);
2692 ASSERT(inserted);
2693 UNUSED_ASSERTION_VARIABLE(inserted);
2694 }
2695 if (!insertion.insertionsBefore.empty())
2696 {
2697 bool inserted =
2698 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2699 ASSERT(inserted);
2700 UNUSED_ASSERTION_VARIABLE(inserted);
2701 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002702 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002703 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2704 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002705 const NodeUpdateEntry &replacement = mReplacements[ii];
2706 ASSERT(replacement.parent);
2707 bool replaced = replacement.parent->replaceChildNode(
2708 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002709 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002710 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002711
Olli Etuahocd94ef92015-04-16 19:18:10 +03002712 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002713 {
2714 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002715 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002716 // be replaced, we need to make sure we don't update the replaced
2717 // node; instead, we update the replacement node.
2718 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2719 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002720 NodeUpdateEntry &replacement2 = mReplacements[jj];
2721 if (replacement2.parent == replacement.original)
2722 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002723 }
2724 }
2725 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002726 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2727 {
2728 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2729 ASSERT(replacement.parent);
2730 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2731 replacement.original, replacement.replacements);
2732 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002733 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002734 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002735
2736 mInsertions.clear();
2737 mReplacements.clear();
2738 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002739}