blob: 83f8e004d830ddb0b371d32e54999c98ef2fe03b [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/HashNames.h"
22#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
24
25namespace
26{
27
Arun Patole9dea48f2015-04-02 11:45:09 +053028const float kPi = 3.14159265358979323846f;
29const float kDegreesToRadiansMultiplier = kPi / 180.0f;
30const float kRadiansToDegreesMultiplier = 180.0f / kPi;
31
Jamie Madillb1a85f42014-08-19 15:23:24 -040032TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
33{
34 return left > right ? left : right;
35}
36
37bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
38{
39 switch (op)
40 {
41 case EOpMul:
42 case EOpMulAssign:
43 return left.getNominalSize() == right.getNominalSize() &&
44 left.getSecondarySize() == right.getSecondarySize();
45 case EOpVectorTimesScalar:
46 case EOpVectorTimesScalarAssign:
47 return true;
48 case EOpVectorTimesMatrix:
49 return left.getNominalSize() == right.getRows();
50 case EOpVectorTimesMatrixAssign:
51 return left.getNominalSize() == right.getRows() &&
52 left.getNominalSize() == right.getCols();
53 case EOpMatrixTimesVector:
54 return left.getCols() == right.getNominalSize();
55 case EOpMatrixTimesScalar:
56 case EOpMatrixTimesScalarAssign:
57 return true;
58 case EOpMatrixTimesMatrix:
59 return left.getCols() == right.getRows();
60 case EOpMatrixTimesMatrixAssign:
Olli Etuahodcf12c72016-06-28 15:03:06 +030061 // We need to check two things:
62 // 1. The matrix multiplication step is valid.
63 // 2. The result will have the same number of columns as the lvalue.
64 return left.getCols() == right.getRows() && left.getCols() == right.getCols();
Jamie Madillb1a85f42014-08-19 15:23:24 -040065
66 default:
67 UNREACHABLE();
68 return false;
69 }
70}
71
Arun Patole274f0702015-05-05 13:33:30 +053072TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
73{
74 TConstantUnion *constUnion = new TConstantUnion[size];
75 for (unsigned int i = 0; i < size; ++i)
76 constUnion[i] = constant;
77
78 return constUnion;
79}
80
Arun Patolebf790422015-05-18 17:53:04 +053081void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
82 TInfoSink &infoSink, TConstantUnion *result)
83{
84 std::stringstream constantFoldingErrorStream;
85 constantFoldingErrorStream << "'" << GetOperatorString(op)
86 << "' operation result is undefined for the values passed in";
87 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
88
89 switch (basicType)
90 {
91 case EbtFloat :
92 result->setFConst(0.0f);
93 break;
94 case EbtInt:
95 result->setIConst(0);
96 break;
97 case EbtUInt:
98 result->setUConst(0u);
99 break;
100 case EbtBool:
101 result->setBConst(false);
102 break;
103 default:
104 break;
105 }
106}
107
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200108float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530109{
110 float result = 0.0f;
111 for (size_t i = 0; i < paramArraySize; i++)
112 {
113 float f = paramArray[i].getFConst();
114 result += f * f;
115 }
116 return sqrtf(result);
117}
118
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200119float VectorDotProduct(const TConstantUnion *paramArray1,
120 const TConstantUnion *paramArray2,
121 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +0530122{
123 float result = 0.0f;
124 for (size_t i = 0; i < paramArraySize; i++)
125 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
126 return result;
127}
128
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200129TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
130 const TIntermTyped *originalNode,
131 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +0300132{
133 if (constArray == nullptr)
134 {
135 return nullptr;
136 }
137 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200138 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300139 folded->setLine(originalNode->getLine());
140 return folded;
141}
142
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200143angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
144 const unsigned int &rows,
145 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530146{
147 std::vector<float> elements;
148 for (size_t i = 0; i < rows * cols; i++)
149 elements.push_back(paramArray[i].getFConst());
150 // Transpose is used since the Matrix constructor expects arguments in row-major order,
151 // whereas the paramArray is in column-major order.
152 return angle::Matrix<float>(elements, rows, cols).transpose();
153}
154
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200155angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530156{
157 std::vector<float> elements;
158 for (size_t i = 0; i < size * size; i++)
159 elements.push_back(paramArray[i].getFConst());
160 // Transpose is used since the Matrix constructor expects arguments in row-major order,
161 // whereas the paramArray is in column-major order.
162 return angle::Matrix<float>(elements, size).transpose();
163}
164
165void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
166{
167 // Transpose is used since the input Matrix is in row-major order,
168 // whereas the actual result should be in column-major order.
169 angle::Matrix<float> result = m.transpose();
170 std::vector<float> resultElements = result.elements();
171 for (size_t i = 0; i < resultElements.size(); i++)
172 resultArray[i].setFConst(resultElements[i]);
173}
174
Jamie Madillb1a85f42014-08-19 15:23:24 -0400175} // namespace anonymous
176
177
178////////////////////////////////////////////////////////////////
179//
180// Member functions of the nodes used for building the tree.
181//
182////////////////////////////////////////////////////////////////
183
Olli Etuahod2a67b92014-10-21 16:42:57 +0300184void TIntermTyped::setTypePreservePrecision(const TType &t)
185{
186 TPrecision precision = getPrecision();
187 mType = t;
188 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
189 mType.setPrecision(precision);
190}
191
Jamie Madillb1a85f42014-08-19 15:23:24 -0400192#define REPLACE_IF_IS(node, type, original, replacement) \
193 if (node == original) { \
194 node = static_cast<type *>(replacement); \
195 return true; \
196 }
197
198bool TIntermLoop::replaceChildNode(
199 TIntermNode *original, TIntermNode *replacement)
200{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300201 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400202 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
203 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
204 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200205 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400206 return false;
207}
208
Jamie Madillb1a85f42014-08-19 15:23:24 -0400209bool TIntermBranch::replaceChildNode(
210 TIntermNode *original, TIntermNode *replacement)
211{
212 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
213 return false;
214}
215
Jamie Madillb1a85f42014-08-19 15:23:24 -0400216bool TIntermBinary::replaceChildNode(
217 TIntermNode *original, TIntermNode *replacement)
218{
219 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
220 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
221 return false;
222}
223
Jamie Madillb1a85f42014-08-19 15:23:24 -0400224bool TIntermUnary::replaceChildNode(
225 TIntermNode *original, TIntermNode *replacement)
226{
227 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
228 return false;
229}
230
Jamie Madillb1a85f42014-08-19 15:23:24 -0400231bool TIntermAggregate::replaceChildNode(
232 TIntermNode *original, TIntermNode *replacement)
233{
234 for (size_t ii = 0; ii < mSequence.size(); ++ii)
235 {
236 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
237 }
238 return false;
239}
240
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300241bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
242{
243 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
244 {
245 if (*it == original)
246 {
247 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300248 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300249 return true;
250 }
251 }
252 return false;
253}
254
Olli Etuahoa6f22092015-05-08 18:31:10 +0300255bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
256{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300257 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300258 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300259 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300260 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300261 auto it = mSequence.begin() + position;
262 mSequence.insert(it, insertions.begin(), insertions.end());
263 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300264}
265
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200266bool TIntermAggregate::areChildrenConstQualified()
267{
268 for (TIntermNode *&child : mSequence)
269 {
270 TIntermTyped *typed = child->getAsTyped();
271 if (typed && typed->getQualifier() != EvqConst)
272 {
273 return false;
274 }
275 }
276 return true;
277}
278
Olli Etuahod2a67b92014-10-21 16:42:57 +0300279void TIntermAggregate::setPrecisionFromChildren()
280{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300281 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300282 if (getBasicType() == EbtBool)
283 {
284 mType.setPrecision(EbpUndefined);
285 return;
286 }
287
288 TPrecision precision = EbpUndefined;
289 TIntermSequence::iterator childIter = mSequence.begin();
290 while (childIter != mSequence.end())
291 {
292 TIntermTyped *typed = (*childIter)->getAsTyped();
293 if (typed)
294 precision = GetHigherPrecision(typed->getPrecision(), precision);
295 ++childIter;
296 }
297 mType.setPrecision(precision);
298}
299
300void TIntermAggregate::setBuiltInFunctionPrecision()
301{
302 // All built-ins returning bool should be handled as ops, not functions.
303 ASSERT(getBasicType() != EbtBool);
304
305 TPrecision precision = EbpUndefined;
306 TIntermSequence::iterator childIter = mSequence.begin();
307 while (childIter != mSequence.end())
308 {
309 TIntermTyped *typed = (*childIter)->getAsTyped();
310 // ESSL spec section 8: texture functions get their precision from the sampler.
311 if (typed && IsSampler(typed->getBasicType()))
312 {
313 precision = typed->getPrecision();
314 break;
315 }
316 ++childIter;
317 }
318 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
319 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300320 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300321 mType.setPrecision(EbpHigh);
322 else
323 mType.setPrecision(precision);
324}
325
Jamie Madillb1a85f42014-08-19 15:23:24 -0400326bool TIntermSelection::replaceChildNode(
327 TIntermNode *original, TIntermNode *replacement)
328{
329 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
330 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
331 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
332 return false;
333}
334
Olli Etuahoa3a36662015-02-17 13:46:51 +0200335bool TIntermSwitch::replaceChildNode(
336 TIntermNode *original, TIntermNode *replacement)
337{
338 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
339 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
340 return false;
341}
342
343bool TIntermCase::replaceChildNode(
344 TIntermNode *original, TIntermNode *replacement)
345{
346 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
347 return false;
348}
349
Olli Etuahod7a25242015-08-18 13:49:45 +0300350TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
351{
352 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
353 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
354 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
355 mLine = node.mLine;
356}
357
Olli Etuahod4f4c112016-04-15 15:11:24 +0300358bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
359{
360 TIntermAggregate *constructor = getAsAggregate();
361 if (!constructor || !constructor->isConstructor())
362 {
363 return false;
364 }
365 for (TIntermNode *&node : *constructor->getSequence())
366 {
367 if (!node->getAsConstantUnion())
368 return false;
369 }
370 return true;
371}
372
Olli Etuahod7a25242015-08-18 13:49:45 +0300373TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
374{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200375 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300376}
377
378TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
379 : TIntermOperator(node),
380 mName(node.mName),
381 mUserDefined(node.mUserDefined),
382 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300383 mUseEmulatedFunction(node.mUseEmulatedFunction),
384 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
385{
386 for (TIntermNode *child : node.mSequence)
387 {
388 TIntermTyped *typedChild = child->getAsTyped();
389 ASSERT(typedChild != nullptr);
390 TIntermTyped *childCopy = typedChild->deepCopy();
391 mSequence.push_back(childCopy);
392 }
393}
394
395TIntermBinary::TIntermBinary(const TIntermBinary &node)
396 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
397{
398 TIntermTyped *leftCopy = node.mLeft->deepCopy();
399 TIntermTyped *rightCopy = node.mRight->deepCopy();
400 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
401 mLeft = leftCopy;
402 mRight = rightCopy;
403}
404
405TIntermUnary::TIntermUnary(const TIntermUnary &node)
406 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
407{
408 TIntermTyped *operandCopy = node.mOperand->deepCopy();
409 ASSERT(operandCopy != nullptr);
410 mOperand = operandCopy;
411}
412
413TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
414{
415 // Only supported for ternary nodes, not if statements.
416 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
417 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
418 ASSERT(trueTyped != nullptr);
419 ASSERT(falseTyped != nullptr);
420 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
421 TIntermTyped *trueCopy = trueTyped->deepCopy();
422 TIntermTyped *falseCopy = falseTyped->deepCopy();
423 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
424 mCondition = conditionCopy;
425 mTrueBlock = trueCopy;
426 mFalseBlock = falseCopy;
427}
428
Jamie Madillb1a85f42014-08-19 15:23:24 -0400429//
430// Say whether or not an operation node changes the value of a variable.
431//
432bool TIntermOperator::isAssignment() const
433{
434 switch (mOp)
435 {
436 case EOpPostIncrement:
437 case EOpPostDecrement:
438 case EOpPreIncrement:
439 case EOpPreDecrement:
440 case EOpAssign:
441 case EOpAddAssign:
442 case EOpSubAssign:
443 case EOpMulAssign:
444 case EOpVectorTimesMatrixAssign:
445 case EOpVectorTimesScalarAssign:
446 case EOpMatrixTimesScalarAssign:
447 case EOpMatrixTimesMatrixAssign:
448 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200449 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200450 case EOpBitShiftLeftAssign:
451 case EOpBitShiftRightAssign:
452 case EOpBitwiseAndAssign:
453 case EOpBitwiseXorAssign:
454 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400455 return true;
456 default:
457 return false;
458 }
459}
460
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300461bool TIntermOperator::isMultiplication() const
462{
463 switch (mOp)
464 {
465 case EOpMul:
466 case EOpMatrixTimesMatrix:
467 case EOpMatrixTimesVector:
468 case EOpMatrixTimesScalar:
469 case EOpVectorTimesMatrix:
470 case EOpVectorTimesScalar:
471 return true;
472 default:
473 return false;
474 }
475}
476
Jamie Madillb1a85f42014-08-19 15:23:24 -0400477//
478// returns true if the operator is for one of the constructors
479//
480bool TIntermOperator::isConstructor() const
481{
482 switch (mOp)
483 {
484 case EOpConstructVec2:
485 case EOpConstructVec3:
486 case EOpConstructVec4:
487 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400488 case EOpConstructMat2x3:
489 case EOpConstructMat2x4:
490 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400491 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400492 case EOpConstructMat3x4:
493 case EOpConstructMat4x2:
494 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400495 case EOpConstructMat4:
496 case EOpConstructFloat:
497 case EOpConstructIVec2:
498 case EOpConstructIVec3:
499 case EOpConstructIVec4:
500 case EOpConstructInt:
501 case EOpConstructUVec2:
502 case EOpConstructUVec3:
503 case EOpConstructUVec4:
504 case EOpConstructUInt:
505 case EOpConstructBVec2:
506 case EOpConstructBVec3:
507 case EOpConstructBVec4:
508 case EOpConstructBool:
509 case EOpConstructStruct:
510 return true;
511 default:
512 return false;
513 }
514}
515
516//
517// Make sure the type of a unary operator is appropriate for its
518// combination of operation and operand type.
519//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200520void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400521{
522 switch (mOp)
523 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200524 case EOpFloatBitsToInt:
525 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200526 case EOpIntBitsToFloat:
527 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200528 case EOpPackSnorm2x16:
529 case EOpPackUnorm2x16:
530 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200531 case EOpUnpackSnorm2x16:
532 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200533 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530534 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200535 case EOpUnpackHalf2x16:
536 mType.setPrecision(EbpMedium);
537 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400538 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200539 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400540 }
541
Olli Etuahof6c694b2015-03-26 14:50:53 +0200542 if (funcReturnType != nullptr)
543 {
544 if (funcReturnType->getBasicType() == EbtBool)
545 {
546 // Bool types should not have precision.
547 setType(*funcReturnType);
548 }
549 else
550 {
551 // Precision of the node has been set based on the operand.
552 setTypePreservePrecision(*funcReturnType);
553 }
554 }
555
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200556 if (mOperand->getQualifier() == EvqConst)
557 mType.setQualifier(EvqConst);
558 else
559 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400560}
561
562//
563// Establishes the type of the resultant operation, as well as
564// makes the operator the correct one for the operands.
565//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200566// For lots of operations it should already be established that the operand
567// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400568//
Olli Etuaho3fdec912016-08-18 15:08:06 +0300569bool TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400570{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200571 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400572
Jamie Madillb1a85f42014-08-19 15:23:24 -0400573 //
574 // Base assumption: just make the type the same as the left
575 // operand. Then only deviations from this need be coded.
576 //
577 setType(mLeft->getType());
578
579 // The result gets promoted to the highest precision.
580 TPrecision higherPrecision = GetHigherPrecision(
581 mLeft->getPrecision(), mRight->getPrecision());
582 getTypePointer()->setPrecision(higherPrecision);
583
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200584 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400585 // Binary operations results in temporary variables unless both
586 // operands are const.
587 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
588 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200589 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400590 getTypePointer()->setQualifier(EvqTemporary);
591 }
592
593 const int nominalSize =
594 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
595
596 //
597 // All scalars or structs. Code after this test assumes this case is removed!
598 //
599 if (nominalSize == 1)
600 {
601 switch (mOp)
602 {
603 //
604 // Promote to conditional
605 //
606 case EOpEqual:
607 case EOpNotEqual:
608 case EOpLessThan:
609 case EOpGreaterThan:
610 case EOpLessThanEqual:
611 case EOpGreaterThanEqual:
612 setType(TType(EbtBool, EbpUndefined));
613 break;
614
615 //
616 // And and Or operate on conditionals
617 //
618 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200619 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400620 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200621 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400622 setType(TType(EbtBool, EbpUndefined));
623 break;
624
625 default:
626 break;
627 }
628 return true;
629 }
630
631 // If we reach here, at least one of the operands is vector or matrix.
632 // The other operand could be a scalar, vector, or matrix.
633 // Can these two operands be combined?
634 //
635 TBasicType basicType = mLeft->getBasicType();
636 switch (mOp)
637 {
638 case EOpMul:
639 if (!mLeft->isMatrix() && mRight->isMatrix())
640 {
641 if (mLeft->isVector())
642 {
643 mOp = EOpVectorTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200644 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700645 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400646 }
647 else
648 {
649 mOp = EOpMatrixTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200650 setType(TType(basicType, higherPrecision, resultQualifier,
651 static_cast<unsigned char>(mRight->getCols()),
652 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400653 }
654 }
655 else if (mLeft->isMatrix() && !mRight->isMatrix())
656 {
657 if (mRight->isVector())
658 {
659 mOp = EOpMatrixTimesVector;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200660 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700661 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400662 }
663 else
664 {
665 mOp = EOpMatrixTimesScalar;
666 }
667 }
668 else if (mLeft->isMatrix() && mRight->isMatrix())
669 {
670 mOp = EOpMatrixTimesMatrix;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200671 setType(TType(basicType, higherPrecision, resultQualifier,
672 static_cast<unsigned char>(mRight->getCols()),
673 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400674 }
675 else if (!mLeft->isMatrix() && !mRight->isMatrix())
676 {
677 if (mLeft->isVector() && mRight->isVector())
678 {
679 // leave as component product
680 }
681 else if (mLeft->isVector() || mRight->isVector())
682 {
683 mOp = EOpVectorTimesScalar;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200684 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700685 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400686 }
687 }
688 else
689 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300690 UNREACHABLE();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400691 return false;
692 }
693
694 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
695 {
696 return false;
697 }
698 break;
699
700 case EOpMulAssign:
701 if (!mLeft->isMatrix() && mRight->isMatrix())
702 {
703 if (mLeft->isVector())
704 {
705 mOp = EOpVectorTimesMatrixAssign;
706 }
707 else
708 {
709 return false;
710 }
711 }
712 else if (mLeft->isMatrix() && !mRight->isMatrix())
713 {
714 if (mRight->isVector())
715 {
716 return false;
717 }
718 else
719 {
720 mOp = EOpMatrixTimesScalarAssign;
721 }
722 }
723 else if (mLeft->isMatrix() && mRight->isMatrix())
724 {
725 mOp = EOpMatrixTimesMatrixAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200726 setType(TType(basicType, higherPrecision, resultQualifier,
727 static_cast<unsigned char>(mRight->getCols()),
728 static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400729 }
730 else if (!mLeft->isMatrix() && !mRight->isMatrix())
731 {
732 if (mLeft->isVector() && mRight->isVector())
733 {
734 // leave as component product
735 }
736 else if (mLeft->isVector() || mRight->isVector())
737 {
738 if (!mLeft->isVector())
739 return false;
740 mOp = EOpVectorTimesScalarAssign;
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200741 setType(TType(basicType, higherPrecision, resultQualifier,
Minmin Gong794e0002015-04-07 18:31:54 -0700742 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400743 }
744 }
745 else
746 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300747 UNREACHABLE();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400748 return false;
749 }
750
751 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
752 {
753 return false;
754 }
755 break;
756
757 case EOpAssign:
758 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200759 // No more additional checks are needed.
760 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
761 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
762 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400763 case EOpAdd:
764 case EOpSub:
765 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200766 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200767 case EOpBitShiftLeft:
768 case EOpBitShiftRight:
769 case EOpBitwiseAnd:
770 case EOpBitwiseXor:
771 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400772 case EOpAddAssign:
773 case EOpSubAssign:
774 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200775 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200776 case EOpBitShiftLeftAssign:
777 case EOpBitShiftRightAssign:
778 case EOpBitwiseAndAssign:
779 case EOpBitwiseXorAssign:
780 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400781 if ((mLeft->isMatrix() && mRight->isVector()) ||
782 (mLeft->isVector() && mRight->isMatrix()))
783 {
784 return false;
785 }
786
787 // Are the sizes compatible?
788 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
789 mLeft->getSecondarySize() != mRight->getSecondarySize())
790 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200791 // If the nominal sizes of operands do not match:
792 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400793 if (!mLeft->isScalar() && !mRight->isScalar())
794 return false;
795
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200796 // In the case of compound assignment other than multiply-assign,
797 // the right side needs to be a scalar. Otherwise a vector/matrix
798 // would be assigned to a scalar. A scalar can't be shifted by a
799 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200800 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200801 (isAssignment() ||
802 mOp == EOpBitShiftLeft ||
803 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200804 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400805 }
806
807 {
808 const int secondarySize = std::max(
809 mLeft->getSecondarySize(), mRight->getSecondarySize());
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200810 setType(TType(basicType, higherPrecision, resultQualifier,
811 static_cast<unsigned char>(nominalSize),
812 static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200813 if (mLeft->isArray())
814 {
815 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
816 mType.setArraySize(mLeft->getArraySize());
817 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400818 }
819 break;
820
821 case EOpEqual:
822 case EOpNotEqual:
823 case EOpLessThan:
824 case EOpGreaterThan:
825 case EOpLessThanEqual:
826 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200827 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
828 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400829 setType(TType(EbtBool, EbpUndefined));
830 break;
831
832 default:
833 return false;
834 }
835 return true;
836}
837
Olli Etuaho3fdec912016-08-18 15:08:06 +0300838TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300839{
840 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
841 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
842 if (leftConstant == nullptr || rightConstant == nullptr)
843 {
844 return nullptr;
845 }
Olli Etuaho3fdec912016-08-18 15:08:06 +0300846 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200847
848 // Nodes may be constant folded without being qualified as constant.
849 TQualifier resultQualifier = EvqConst;
850 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
851 {
852 resultQualifier = EvqTemporary;
853 }
854 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300855}
856
Olli Etuaho95310b02015-06-02 17:43:38 +0300857TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
858{
859 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
860 if (operandConstant == nullptr)
861 {
862 return nullptr;
863 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530864
865 TConstantUnion *constArray = nullptr;
866 switch (mOp)
867 {
868 case EOpAny:
869 case EOpAll:
870 case EOpLength:
871 case EOpTranspose:
872 case EOpDeterminant:
873 case EOpInverse:
874 case EOpPackSnorm2x16:
875 case EOpUnpackSnorm2x16:
876 case EOpPackUnorm2x16:
877 case EOpUnpackUnorm2x16:
878 case EOpPackHalf2x16:
879 case EOpUnpackHalf2x16:
880 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
881 break;
882 default:
883 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
884 break;
885 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200886
887 // Nodes may be constant folded without being qualified as constant.
888 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
889 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300890}
891
892TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
893{
894 // Make sure that all params are constant before actual constant folding.
895 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300896 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300897 if (param->getAsConstantUnion() == nullptr)
898 {
899 return nullptr;
900 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300901 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200902 TConstantUnion *constArray = nullptr;
903 if (isConstructor())
904 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
905 else
906 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200907
908 // Nodes may be constant folded without being qualified as constant.
909 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
910 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300911}
912
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913//
914// The fold functions see if an operation on a constant can be done in place,
915// without generating run-time code.
916//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300917// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400918//
Olli Etuaho3fdec912016-08-18 15:08:06 +0300919TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
920 TIntermConstantUnion *rightNode,
921 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300922{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200923 const TConstantUnion *leftArray = getUnionArrayPointer();
924 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300925
926 if (!leftArray)
927 return nullptr;
928 if (!rightArray)
929 return nullptr;
930
931 size_t objectSize = getType().getObjectSize();
932
933 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
934 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
935 {
936 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
937 }
938 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
939 {
940 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
941 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
942 objectSize = rightNode->getType().getObjectSize();
943 }
944
945 TConstantUnion *resultArray = nullptr;
946
947 switch(op)
948 {
949 case EOpAdd:
950 resultArray = new TConstantUnion[objectSize];
951 for (size_t i = 0; i < objectSize; i++)
952 resultArray[i] = leftArray[i] + rightArray[i];
953 break;
954 case EOpSub:
955 resultArray = new TConstantUnion[objectSize];
956 for (size_t i = 0; i < objectSize; i++)
957 resultArray[i] = leftArray[i] - rightArray[i];
958 break;
959
960 case EOpMul:
961 case EOpVectorTimesScalar:
962 case EOpMatrixTimesScalar:
963 resultArray = new TConstantUnion[objectSize];
964 for (size_t i = 0; i < objectSize; i++)
965 resultArray[i] = leftArray[i] * rightArray[i];
966 break;
967
968 case EOpMatrixTimesMatrix:
969 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300970 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300971
972 const int leftCols = getCols();
973 const int leftRows = getRows();
974 const int rightCols = rightNode->getType().getCols();
975 const int rightRows = rightNode->getType().getRows();
976 const int resultCols = rightCols;
977 const int resultRows = leftRows;
978
979 resultArray = new TConstantUnion[resultCols * resultRows];
980 for (int row = 0; row < resultRows; row++)
981 {
982 for (int column = 0; column < resultCols; column++)
983 {
984 resultArray[resultRows * column + row].setFConst(0.0f);
985 for (int i = 0; i < leftCols; i++)
986 {
987 resultArray[resultRows * column + row].setFConst(
988 resultArray[resultRows * column + row].getFConst() +
989 leftArray[i * leftRows + row].getFConst() *
990 rightArray[column * rightRows + i].getFConst());
991 }
992 }
993 }
994 }
995 break;
996
997 case EOpDiv:
998 case EOpIMod:
999 {
1000 resultArray = new TConstantUnion[objectSize];
1001 for (size_t i = 0; i < objectSize; i++)
1002 {
1003 switch (getType().getBasicType())
1004 {
1005 case EbtFloat:
1006 if (rightArray[i] == 0.0f)
1007 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001008 diagnostics->warning(
1009 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001010 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1011 }
1012 else
1013 {
1014 ASSERT(op == EOpDiv);
1015 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1016 }
1017 break;
1018
1019 case EbtInt:
1020 if (rightArray[i] == 0)
1021 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001022 diagnostics->warning(
1023 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001024 resultArray[i].setIConst(INT_MAX);
1025 }
1026 else
1027 {
1028 if (op == EOpDiv)
1029 {
1030 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1031 }
1032 else
1033 {
1034 ASSERT(op == EOpIMod);
1035 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1036 }
1037 }
1038 break;
1039
1040 case EbtUInt:
1041 if (rightArray[i] == 0)
1042 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001043 diagnostics->warning(
1044 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001045 resultArray[i].setUConst(UINT_MAX);
1046 }
1047 else
1048 {
1049 if (op == EOpDiv)
1050 {
1051 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1052 }
1053 else
1054 {
1055 ASSERT(op == EOpIMod);
1056 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1057 }
1058 }
1059 break;
1060
1061 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001062 UNREACHABLE();
1063 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001064 }
1065 }
1066 }
1067 break;
1068
1069 case EOpMatrixTimesVector:
1070 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001071 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001072
1073 const int matrixCols = getCols();
1074 const int matrixRows = getRows();
1075
1076 resultArray = new TConstantUnion[matrixRows];
1077
1078 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1079 {
1080 resultArray[matrixRow].setFConst(0.0f);
1081 for (int col = 0; col < matrixCols; col++)
1082 {
1083 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1084 leftArray[col * matrixRows + matrixRow].getFConst() *
1085 rightArray[col].getFConst());
1086 }
1087 }
1088 }
1089 break;
1090
1091 case EOpVectorTimesMatrix:
1092 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001093 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001094
1095 const int matrixCols = rightNode->getType().getCols();
1096 const int matrixRows = rightNode->getType().getRows();
1097
1098 resultArray = new TConstantUnion[matrixCols];
1099
1100 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1101 {
1102 resultArray[matrixCol].setFConst(0.0f);
1103 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1104 {
1105 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1106 leftArray[matrixRow].getFConst() *
1107 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1108 }
1109 }
1110 }
1111 break;
1112
1113 case EOpLogicalAnd:
1114 {
1115 resultArray = new TConstantUnion[objectSize];
1116 for (size_t i = 0; i < objectSize; i++)
1117 {
1118 resultArray[i] = leftArray[i] && rightArray[i];
1119 }
1120 }
1121 break;
1122
1123 case EOpLogicalOr:
1124 {
1125 resultArray = new TConstantUnion[objectSize];
1126 for (size_t i = 0; i < objectSize; i++)
1127 {
1128 resultArray[i] = leftArray[i] || rightArray[i];
1129 }
1130 }
1131 break;
1132
1133 case EOpLogicalXor:
1134 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001135 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001136 resultArray = new TConstantUnion[objectSize];
1137 for (size_t i = 0; i < objectSize; i++)
1138 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001139 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001140 }
1141 }
1142 break;
1143
1144 case EOpBitwiseAnd:
1145 resultArray = new TConstantUnion[objectSize];
1146 for (size_t i = 0; i < objectSize; i++)
1147 resultArray[i] = leftArray[i] & rightArray[i];
1148 break;
1149 case EOpBitwiseXor:
1150 resultArray = new TConstantUnion[objectSize];
1151 for (size_t i = 0; i < objectSize; i++)
1152 resultArray[i] = leftArray[i] ^ rightArray[i];
1153 break;
1154 case EOpBitwiseOr:
1155 resultArray = new TConstantUnion[objectSize];
1156 for (size_t i = 0; i < objectSize; i++)
1157 resultArray[i] = leftArray[i] | rightArray[i];
1158 break;
1159 case EOpBitShiftLeft:
1160 resultArray = new TConstantUnion[objectSize];
1161 for (size_t i = 0; i < objectSize; i++)
1162 resultArray[i] = leftArray[i] << rightArray[i];
1163 break;
1164 case EOpBitShiftRight:
1165 resultArray = new TConstantUnion[objectSize];
1166 for (size_t i = 0; i < objectSize; i++)
1167 resultArray[i] = leftArray[i] >> rightArray[i];
1168 break;
1169
1170 case EOpLessThan:
1171 ASSERT(objectSize == 1);
1172 resultArray = new TConstantUnion[1];
1173 resultArray->setBConst(*leftArray < *rightArray);
1174 break;
1175
1176 case EOpGreaterThan:
1177 ASSERT(objectSize == 1);
1178 resultArray = new TConstantUnion[1];
1179 resultArray->setBConst(*leftArray > *rightArray);
1180 break;
1181
1182 case EOpLessThanEqual:
1183 ASSERT(objectSize == 1);
1184 resultArray = new TConstantUnion[1];
1185 resultArray->setBConst(!(*leftArray > *rightArray));
1186 break;
1187
1188 case EOpGreaterThanEqual:
1189 ASSERT(objectSize == 1);
1190 resultArray = new TConstantUnion[1];
1191 resultArray->setBConst(!(*leftArray < *rightArray));
1192 break;
1193
1194 case EOpEqual:
1195 case EOpNotEqual:
1196 {
1197 resultArray = new TConstantUnion[1];
1198 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001199 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001200 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001201 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001202 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001203 equal = false;
1204 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001205 }
1206 }
1207 if (op == EOpEqual)
1208 {
1209 resultArray->setBConst(equal);
1210 }
1211 else
1212 {
1213 resultArray->setBConst(!equal);
1214 }
1215 }
1216 break;
1217
1218 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001219 UNREACHABLE();
1220 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001221 }
1222 return resultArray;
1223}
1224
1225//
1226// The fold functions see if an operation on a constant can be done in place,
1227// without generating run-time code.
1228//
Olli Etuaho95310b02015-06-02 17:43:38 +03001229// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001230//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301231TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001232{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301233 //
1234 // Do operations where the return type has a different number of components compared to the operand type.
1235 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001236
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001237 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301238 if (!operandArray)
1239 return nullptr;
1240
1241 size_t objectSize = getType().getObjectSize();
1242 TConstantUnion *resultArray = nullptr;
1243 switch (op)
1244 {
1245 case EOpAny:
1246 if (getType().getBasicType() == EbtBool)
1247 {
1248 resultArray = new TConstantUnion();
1249 resultArray->setBConst(false);
1250 for (size_t i = 0; i < objectSize; i++)
1251 {
1252 if (operandArray[i].getBConst())
1253 {
1254 resultArray->setBConst(true);
1255 break;
1256 }
1257 }
1258 break;
1259 }
1260 else
1261 {
1262 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1263 return nullptr;
1264 }
1265
1266 case EOpAll:
1267 if (getType().getBasicType() == EbtBool)
1268 {
1269 resultArray = new TConstantUnion();
1270 resultArray->setBConst(true);
1271 for (size_t i = 0; i < objectSize; i++)
1272 {
1273 if (!operandArray[i].getBConst())
1274 {
1275 resultArray->setBConst(false);
1276 break;
1277 }
1278 }
1279 break;
1280 }
1281 else
1282 {
1283 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1284 return nullptr;
1285 }
1286
1287 case EOpLength:
1288 if (getType().getBasicType() == EbtFloat)
1289 {
1290 resultArray = new TConstantUnion();
1291 resultArray->setFConst(VectorLength(operandArray, objectSize));
1292 break;
1293 }
1294 else
1295 {
1296 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1297 return nullptr;
1298 }
1299
1300 case EOpTranspose:
1301 if (getType().getBasicType() == EbtFloat)
1302 {
1303 resultArray = new TConstantUnion[objectSize];
1304 angle::Matrix<float> result =
1305 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1306 SetUnionArrayFromMatrix(result, resultArray);
1307 break;
1308 }
1309 else
1310 {
1311 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1312 return nullptr;
1313 }
1314
1315 case EOpDeterminant:
1316 if (getType().getBasicType() == EbtFloat)
1317 {
1318 unsigned int size = getType().getNominalSize();
1319 ASSERT(size >= 2 && size <= 4);
1320 resultArray = new TConstantUnion();
1321 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1322 break;
1323 }
1324 else
1325 {
1326 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1327 return nullptr;
1328 }
1329
1330 case EOpInverse:
1331 if (getType().getBasicType() == EbtFloat)
1332 {
1333 unsigned int size = getType().getNominalSize();
1334 ASSERT(size >= 2 && size <= 4);
1335 resultArray = new TConstantUnion[objectSize];
1336 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1337 SetUnionArrayFromMatrix(result, resultArray);
1338 break;
1339 }
1340 else
1341 {
1342 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1343 return nullptr;
1344 }
1345
1346 case EOpPackSnorm2x16:
1347 if (getType().getBasicType() == EbtFloat)
1348 {
1349 ASSERT(getType().getNominalSize() == 2);
1350 resultArray = new TConstantUnion();
1351 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1352 break;
1353 }
1354 else
1355 {
1356 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1357 return nullptr;
1358 }
1359
1360 case EOpUnpackSnorm2x16:
1361 if (getType().getBasicType() == EbtUInt)
1362 {
1363 resultArray = new TConstantUnion[2];
1364 float f1, f2;
1365 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1366 resultArray[0].setFConst(f1);
1367 resultArray[1].setFConst(f2);
1368 break;
1369 }
1370 else
1371 {
1372 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1373 return nullptr;
1374 }
1375
1376 case EOpPackUnorm2x16:
1377 if (getType().getBasicType() == EbtFloat)
1378 {
1379 ASSERT(getType().getNominalSize() == 2);
1380 resultArray = new TConstantUnion();
1381 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1382 break;
1383 }
1384 else
1385 {
1386 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1387 return nullptr;
1388 }
1389
1390 case EOpUnpackUnorm2x16:
1391 if (getType().getBasicType() == EbtUInt)
1392 {
1393 resultArray = new TConstantUnion[2];
1394 float f1, f2;
1395 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1396 resultArray[0].setFConst(f1);
1397 resultArray[1].setFConst(f2);
1398 break;
1399 }
1400 else
1401 {
1402 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1403 return nullptr;
1404 }
1405
1406 case EOpPackHalf2x16:
1407 if (getType().getBasicType() == EbtFloat)
1408 {
1409 ASSERT(getType().getNominalSize() == 2);
1410 resultArray = new TConstantUnion();
1411 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1412 break;
1413 }
1414 else
1415 {
1416 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1417 return nullptr;
1418 }
1419
1420 case EOpUnpackHalf2x16:
1421 if (getType().getBasicType() == EbtUInt)
1422 {
1423 resultArray = new TConstantUnion[2];
1424 float f1, f2;
1425 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1426 resultArray[0].setFConst(f1);
1427 resultArray[1].setFConst(f2);
1428 break;
1429 }
1430 else
1431 {
1432 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1433 return nullptr;
1434 }
1435 break;
1436
1437 default:
1438 break;
1439 }
1440
1441 return resultArray;
1442}
1443
1444TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1445{
1446 //
1447 // Do unary operations where the return type is the same as operand type.
1448 //
1449
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001450 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001451 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301452 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001453
1454 size_t objectSize = getType().getObjectSize();
1455
Arun Patoleab2b9a22015-07-06 18:27:56 +05301456 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1457 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301458 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301459 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301460 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301461 case EOpNegative:
1462 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301463 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301464 case EbtFloat:
1465 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301466 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301467 case EbtInt:
1468 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301469 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301470 case EbtUInt:
1471 resultArray[i].setUConst(static_cast<unsigned int>(
1472 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301473 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301474 default:
1475 infoSink.info.message(
1476 EPrefixInternalError, getLine(),
1477 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301478 return nullptr;
1479 }
1480 break;
1481
Arun Patoleab2b9a22015-07-06 18:27:56 +05301482 case EOpPositive:
1483 switch (getType().getBasicType())
1484 {
1485 case EbtFloat:
1486 resultArray[i].setFConst(operandArray[i].getFConst());
1487 break;
1488 case EbtInt:
1489 resultArray[i].setIConst(operandArray[i].getIConst());
1490 break;
1491 case EbtUInt:
1492 resultArray[i].setUConst(static_cast<unsigned int>(
1493 static_cast<int>(operandArray[i].getUConst())));
1494 break;
1495 default:
1496 infoSink.info.message(
1497 EPrefixInternalError, getLine(),
1498 "Unary operation not folded into constant");
1499 return nullptr;
1500 }
1501 break;
1502
1503 case EOpLogicalNot:
1504 // this code is written for possible future use,
1505 // will not get executed currently
1506 switch (getType().getBasicType())
1507 {
1508 case EbtBool:
1509 resultArray[i].setBConst(!operandArray[i].getBConst());
1510 break;
1511 default:
1512 infoSink.info.message(
1513 EPrefixInternalError, getLine(),
1514 "Unary operation not folded into constant");
1515 return nullptr;
1516 }
1517 break;
1518
1519 case EOpBitwiseNot:
1520 switch (getType().getBasicType())
1521 {
1522 case EbtInt:
1523 resultArray[i].setIConst(~operandArray[i].getIConst());
1524 break;
1525 case EbtUInt:
1526 resultArray[i].setUConst(~operandArray[i].getUConst());
1527 break;
1528 default:
1529 infoSink.info.message(
1530 EPrefixInternalError, getLine(),
1531 "Unary operation not folded into constant");
1532 return nullptr;
1533 }
1534 break;
1535
1536 case EOpRadians:
1537 if (getType().getBasicType() == EbtFloat)
1538 {
1539 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1540 break;
1541 }
1542 infoSink.info.message(
1543 EPrefixInternalError, getLine(),
1544 "Unary operation not folded into constant");
1545 return nullptr;
1546
1547 case EOpDegrees:
1548 if (getType().getBasicType() == EbtFloat)
1549 {
1550 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1551 break;
1552 }
1553 infoSink.info.message(
1554 EPrefixInternalError, getLine(),
1555 "Unary operation not folded into constant");
1556 return nullptr;
1557
1558 case EOpSin:
1559 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1560 return nullptr;
1561 break;
1562
1563 case EOpCos:
1564 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1565 return nullptr;
1566 break;
1567
1568 case EOpTan:
1569 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1570 return nullptr;
1571 break;
1572
1573 case EOpAsin:
1574 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1575 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1576 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1577 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1578 return nullptr;
1579 break;
1580
1581 case EOpAcos:
1582 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1583 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1584 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1585 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1586 return nullptr;
1587 break;
1588
1589 case EOpAtan:
1590 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1591 return nullptr;
1592 break;
1593
1594 case EOpSinh:
1595 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1596 return nullptr;
1597 break;
1598
1599 case EOpCosh:
1600 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1601 return nullptr;
1602 break;
1603
1604 case EOpTanh:
1605 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1606 return nullptr;
1607 break;
1608
1609 case EOpAsinh:
1610 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1611 return nullptr;
1612 break;
1613
1614 case EOpAcosh:
1615 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1616 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1617 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1618 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1619 return nullptr;
1620 break;
1621
1622 case EOpAtanh:
1623 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1624 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1625 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1626 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1627 return nullptr;
1628 break;
1629
1630 case EOpAbs:
1631 switch (getType().getBasicType())
1632 {
1633 case EbtFloat:
1634 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1635 break;
1636 case EbtInt:
1637 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1638 break;
1639 default:
1640 infoSink.info.message(
1641 EPrefixInternalError, getLine(),
1642 "Unary operation not folded into constant");
1643 return nullptr;
1644 }
1645 break;
1646
1647 case EOpSign:
1648 switch (getType().getBasicType())
1649 {
1650 case EbtFloat:
1651 {
1652 float fConst = operandArray[i].getFConst();
1653 float fResult = 0.0f;
1654 if (fConst > 0.0f)
1655 fResult = 1.0f;
1656 else if (fConst < 0.0f)
1657 fResult = -1.0f;
1658 resultArray[i].setFConst(fResult);
1659 }
1660 break;
1661 case EbtInt:
1662 {
1663 int iConst = operandArray[i].getIConst();
1664 int iResult = 0;
1665 if (iConst > 0)
1666 iResult = 1;
1667 else if (iConst < 0)
1668 iResult = -1;
1669 resultArray[i].setIConst(iResult);
1670 }
1671 break;
1672 default:
1673 infoSink.info.message(
1674 EPrefixInternalError, getLine(),
1675 "Unary operation not folded into constant");
1676 return nullptr;
1677 }
1678 break;
1679
1680 case EOpFloor:
1681 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1682 return nullptr;
1683 break;
1684
1685 case EOpTrunc:
1686 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1687 return nullptr;
1688 break;
1689
1690 case EOpRound:
1691 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1692 return nullptr;
1693 break;
1694
1695 case EOpRoundEven:
1696 if (getType().getBasicType() == EbtFloat)
1697 {
1698 float x = operandArray[i].getFConst();
1699 float result;
1700 float fractPart = modff(x, &result);
1701 if (fabsf(fractPart) == 0.5f)
1702 result = 2.0f * roundf(x / 2.0f);
1703 else
1704 result = roundf(x);
1705 resultArray[i].setFConst(result);
1706 break;
1707 }
1708 infoSink.info.message(
1709 EPrefixInternalError, getLine(),
1710 "Unary operation not folded into constant");
1711 return nullptr;
1712
1713 case EOpCeil:
1714 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1715 return nullptr;
1716 break;
1717
1718 case EOpFract:
1719 if (getType().getBasicType() == EbtFloat)
1720 {
1721 float x = operandArray[i].getFConst();
1722 resultArray[i].setFConst(x - floorf(x));
1723 break;
1724 }
1725 infoSink.info.message(
1726 EPrefixInternalError, getLine(),
1727 "Unary operation not folded into constant");
1728 return nullptr;
1729
Arun Patole551279e2015-07-07 18:18:23 +05301730 case EOpIsNan:
1731 if (getType().getBasicType() == EbtFloat)
1732 {
1733 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1734 break;
1735 }
1736 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1737 return nullptr;
1738
1739 case EOpIsInf:
1740 if (getType().getBasicType() == EbtFloat)
1741 {
1742 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1743 break;
1744 }
1745 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1746 return nullptr;
1747
1748 case EOpFloatBitsToInt:
1749 if (getType().getBasicType() == EbtFloat)
1750 {
1751 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1752 break;
1753 }
1754 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1755 return nullptr;
1756
1757 case EOpFloatBitsToUint:
1758 if (getType().getBasicType() == EbtFloat)
1759 {
1760 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1761 break;
1762 }
1763 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1764 return nullptr;
1765
1766 case EOpIntBitsToFloat:
1767 if (getType().getBasicType() == EbtInt)
1768 {
1769 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1770 break;
1771 }
1772 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1773 return nullptr;
1774
1775 case EOpUintBitsToFloat:
1776 if (getType().getBasicType() == EbtUInt)
1777 {
1778 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1779 break;
1780 }
1781 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1782 return nullptr;
1783
Arun Patoleab2b9a22015-07-06 18:27:56 +05301784 case EOpExp:
1785 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1786 return nullptr;
1787 break;
1788
1789 case EOpLog:
1790 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1791 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1792 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1793 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1794 return nullptr;
1795 break;
1796
1797 case EOpExp2:
1798 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1799 return nullptr;
1800 break;
1801
1802 case EOpLog2:
1803 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1804 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1805 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1806 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1807 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1808 return nullptr;
1809 else
1810 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1811 break;
1812
1813 case EOpSqrt:
1814 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1815 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1816 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1817 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1818 return nullptr;
1819 break;
1820
1821 case EOpInverseSqrt:
1822 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1823 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1824 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1825 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1826 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1827 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1828 return nullptr;
1829 else
1830 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1831 break;
1832
1833 case EOpVectorLogicalNot:
1834 if (getType().getBasicType() == EbtBool)
1835 {
1836 resultArray[i].setBConst(!operandArray[i].getBConst());
1837 break;
1838 }
1839 infoSink.info.message(
1840 EPrefixInternalError, getLine(),
1841 "Unary operation not folded into constant");
1842 return nullptr;
1843
1844 case EOpNormalize:
1845 if (getType().getBasicType() == EbtFloat)
1846 {
1847 float x = operandArray[i].getFConst();
1848 float length = VectorLength(operandArray, objectSize);
1849 if (length)
1850 resultArray[i].setFConst(x / length);
1851 else
1852 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1853 &resultArray[i]);
1854 break;
1855 }
1856 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1857 return nullptr;
1858
Arun Patole0c5409f2015-07-08 15:17:53 +05301859 case EOpDFdx:
1860 case EOpDFdy:
1861 case EOpFwidth:
1862 if (getType().getBasicType() == EbtFloat)
1863 {
1864 // Derivatives of constant arguments should be 0.
1865 resultArray[i].setFConst(0.0f);
1866 break;
1867 }
1868 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1869 return nullptr;
1870
Arun Patole1155ddd2015-06-05 18:04:36 +05301871 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301872 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301873 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301874 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001875
Arun Patoleab2b9a22015-07-06 18:27:56 +05301876 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001877}
1878
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001879bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1880 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301881{
1882 ASSERT(builtinFunc);
1883
1884 if (getType().getBasicType() == EbtFloat)
1885 {
1886 result->setFConst(builtinFunc(parameter.getFConst()));
1887 return true;
1888 }
1889
1890 infoSink.info.message(
1891 EPrefixInternalError, getLine(),
1892 "Unary operation not folded into constant");
1893 return false;
1894}
1895
Jamie Madillb1a85f42014-08-19 15:23:24 -04001896// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001897TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1898 TInfoSink &infoSink)
1899{
1900 ASSERT(aggregate->getSequence()->size() > 0u);
1901 size_t resultSize = aggregate->getType().getObjectSize();
1902 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1903 TBasicType basicType = aggregate->getBasicType();
1904
1905 size_t resultIndex = 0u;
1906
1907 if (aggregate->getSequence()->size() == 1u)
1908 {
1909 TIntermNode *argument = aggregate->getSequence()->front();
1910 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1911 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1912 // Check the special case of constructing a matrix diagonal from a single scalar,
1913 // or a vector from a single scalar.
1914 if (argumentConstant->getType().getObjectSize() == 1u)
1915 {
1916 if (aggregate->isMatrix())
1917 {
1918 int resultCols = aggregate->getType().getCols();
1919 int resultRows = aggregate->getType().getRows();
1920 for (int col = 0; col < resultCols; ++col)
1921 {
1922 for (int row = 0; row < resultRows; ++row)
1923 {
1924 if (col == row)
1925 {
1926 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1927 }
1928 else
1929 {
1930 resultArray[resultIndex].setFConst(0.0f);
1931 }
1932 ++resultIndex;
1933 }
1934 }
1935 }
1936 else
1937 {
1938 while (resultIndex < resultSize)
1939 {
1940 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1941 ++resultIndex;
1942 }
1943 }
1944 ASSERT(resultIndex == resultSize);
1945 return resultArray;
1946 }
1947 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1948 {
1949 // The special case of constructing a matrix from a matrix.
1950 int argumentCols = argumentConstant->getType().getCols();
1951 int argumentRows = argumentConstant->getType().getRows();
1952 int resultCols = aggregate->getType().getCols();
1953 int resultRows = aggregate->getType().getRows();
1954 for (int col = 0; col < resultCols; ++col)
1955 {
1956 for (int row = 0; row < resultRows; ++row)
1957 {
1958 if (col < argumentCols && row < argumentRows)
1959 {
1960 resultArray[resultIndex].cast(basicType,
1961 argumentUnionArray[col * argumentRows + row]);
1962 }
1963 else if (col == row)
1964 {
1965 resultArray[resultIndex].setFConst(1.0f);
1966 }
1967 else
1968 {
1969 resultArray[resultIndex].setFConst(0.0f);
1970 }
1971 ++resultIndex;
1972 }
1973 }
1974 ASSERT(resultIndex == resultSize);
1975 return resultArray;
1976 }
1977 }
1978
1979 for (TIntermNode *&argument : *aggregate->getSequence())
1980 {
1981 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1982 size_t argumentSize = argumentConstant->getType().getObjectSize();
1983 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1984 for (size_t i = 0u; i < argumentSize; ++i)
1985 {
1986 if (resultIndex >= resultSize)
1987 break;
1988 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1989 ++resultIndex;
1990 }
1991 }
1992 ASSERT(resultIndex == resultSize);
1993 return resultArray;
1994}
1995
1996// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001997TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301998{
Olli Etuahob43846e2015-06-02 18:18:57 +03001999 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302000 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002001 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002002 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302003 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002004 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302005 TBasicType basicType = EbtVoid;
2006 TSourceLoc loc;
2007 for (unsigned int i = 0; i < paramsCount; i++)
2008 {
2009 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002010 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302011
2012 if (i == 0)
2013 {
2014 basicType = paramConstant->getType().getBasicType();
2015 loc = paramConstant->getLine();
2016 }
2017 unionArrays[i] = paramConstant->getUnionArrayPointer();
2018 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002019 if (objectSizes[i] > maxObjectSize)
2020 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302021 }
2022
Arun Patole7fa33552015-06-10 15:15:18 +05302023 if (!(*sequence)[0]->getAsTyped()->isMatrix())
2024 {
2025 for (unsigned int i = 0; i < paramsCount; i++)
2026 if (objectSizes[i] != maxObjectSize)
2027 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2028 }
Arun Patole274f0702015-05-05 13:33:30 +05302029
Olli Etuahob43846e2015-06-02 18:18:57 +03002030 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302031 if (paramsCount == 2)
2032 {
2033 //
2034 // Binary built-in
2035 //
2036 switch (op)
2037 {
Arun Patolebf790422015-05-18 17:53:04 +05302038 case EOpAtan:
2039 {
2040 if (basicType == EbtFloat)
2041 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002042 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302043 for (size_t i = 0; i < maxObjectSize; i++)
2044 {
2045 float y = unionArrays[0][i].getFConst();
2046 float x = unionArrays[1][i].getFConst();
2047 // Results are undefined if x and y are both 0.
2048 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002049 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302050 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002051 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302052 }
2053 }
2054 else
2055 UNREACHABLE();
2056 }
2057 break;
2058
2059 case EOpPow:
2060 {
2061 if (basicType == EbtFloat)
2062 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002063 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302064 for (size_t i = 0; i < maxObjectSize; i++)
2065 {
2066 float x = unionArrays[0][i].getFConst();
2067 float y = unionArrays[1][i].getFConst();
2068 // Results are undefined if x < 0.
2069 // Results are undefined if x = 0 and y <= 0.
2070 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002071 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302072 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002073 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302074 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002075 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302076 }
2077 }
2078 else
2079 UNREACHABLE();
2080 }
2081 break;
2082
2083 case EOpMod:
2084 {
2085 if (basicType == EbtFloat)
2086 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002087 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302088 for (size_t i = 0; i < maxObjectSize; i++)
2089 {
2090 float x = unionArrays[0][i].getFConst();
2091 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002092 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302093 }
2094 }
2095 else
2096 UNREACHABLE();
2097 }
2098 break;
2099
Arun Patole274f0702015-05-05 13:33:30 +05302100 case EOpMin:
2101 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002102 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302103 for (size_t i = 0; i < maxObjectSize; i++)
2104 {
2105 switch (basicType)
2106 {
2107 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002108 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302109 break;
2110 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002111 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302112 break;
2113 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002114 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302115 break;
2116 default:
2117 UNREACHABLE();
2118 break;
2119 }
2120 }
2121 }
2122 break;
2123
2124 case EOpMax:
2125 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002126 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302127 for (size_t i = 0; i < maxObjectSize; i++)
2128 {
2129 switch (basicType)
2130 {
2131 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002132 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302133 break;
2134 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002135 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302136 break;
2137 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002138 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302139 break;
2140 default:
2141 UNREACHABLE();
2142 break;
2143 }
2144 }
2145 }
2146 break;
2147
Arun Patolebf790422015-05-18 17:53:04 +05302148 case EOpStep:
2149 {
2150 if (basicType == EbtFloat)
2151 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002152 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302153 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002154 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302155 }
2156 else
2157 UNREACHABLE();
2158 }
2159 break;
2160
Arun Patole9d0b1f92015-05-20 14:27:17 +05302161 case EOpLessThan:
2162 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002163 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302164 for (size_t i = 0; i < maxObjectSize; i++)
2165 {
2166 switch (basicType)
2167 {
2168 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002169 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302170 break;
2171 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002172 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302173 break;
2174 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002175 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302176 break;
2177 default:
2178 UNREACHABLE();
2179 break;
2180 }
2181 }
2182 }
2183 break;
2184
2185 case EOpLessThanEqual:
2186 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002187 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302188 for (size_t i = 0; i < maxObjectSize; i++)
2189 {
2190 switch (basicType)
2191 {
2192 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002193 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302194 break;
2195 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002196 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302197 break;
2198 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002199 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302200 break;
2201 default:
2202 UNREACHABLE();
2203 break;
2204 }
2205 }
2206 }
2207 break;
2208
2209 case EOpGreaterThan:
2210 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002211 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302212 for (size_t i = 0; i < maxObjectSize; i++)
2213 {
2214 switch (basicType)
2215 {
2216 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002217 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302218 break;
2219 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002220 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302221 break;
2222 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002223 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302224 break;
2225 default:
2226 UNREACHABLE();
2227 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002228 }
2229 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302230 }
2231 break;
2232
2233 case EOpGreaterThanEqual:
2234 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002235 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302236 for (size_t i = 0; i < maxObjectSize; i++)
2237 {
2238 switch (basicType)
2239 {
2240 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002241 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302242 break;
2243 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002244 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302245 break;
2246 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002247 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302248 break;
2249 default:
2250 UNREACHABLE();
2251 break;
2252 }
2253 }
2254 }
2255 break;
2256
2257 case EOpVectorEqual:
2258 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002259 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302260 for (size_t i = 0; i < maxObjectSize; i++)
2261 {
2262 switch (basicType)
2263 {
2264 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002265 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302266 break;
2267 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002268 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302269 break;
2270 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002271 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302272 break;
2273 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002274 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302275 break;
2276 default:
2277 UNREACHABLE();
2278 break;
2279 }
2280 }
2281 }
2282 break;
2283
2284 case EOpVectorNotEqual:
2285 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002286 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302287 for (size_t i = 0; i < maxObjectSize; i++)
2288 {
2289 switch (basicType)
2290 {
2291 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002292 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302293 break;
2294 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002295 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302296 break;
2297 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002298 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302299 break;
2300 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002301 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302302 break;
2303 default:
2304 UNREACHABLE();
2305 break;
2306 }
2307 }
2308 }
2309 break;
2310
Arun Patole1155ddd2015-06-05 18:04:36 +05302311 case EOpDistance:
2312 if (basicType == EbtFloat)
2313 {
2314 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002315 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302316 for (size_t i = 0; i < maxObjectSize; i++)
2317 {
2318 float x = unionArrays[0][i].getFConst();
2319 float y = unionArrays[1][i].getFConst();
2320 distanceArray[i].setFConst(x - y);
2321 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002322 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302323 }
2324 else
2325 UNREACHABLE();
2326 break;
2327
2328 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002329
Arun Patole1155ddd2015-06-05 18:04:36 +05302330 if (basicType == EbtFloat)
2331 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002332 resultArray = new TConstantUnion();
2333 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302334 }
2335 else
2336 UNREACHABLE();
2337 break;
2338
2339 case EOpCross:
2340 if (basicType == EbtFloat && maxObjectSize == 3)
2341 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002342 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302343 float x0 = unionArrays[0][0].getFConst();
2344 float x1 = unionArrays[0][1].getFConst();
2345 float x2 = unionArrays[0][2].getFConst();
2346 float y0 = unionArrays[1][0].getFConst();
2347 float y1 = unionArrays[1][1].getFConst();
2348 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002349 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2350 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2351 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302352 }
2353 else
2354 UNREACHABLE();
2355 break;
2356
2357 case EOpReflect:
2358 if (basicType == EbtFloat)
2359 {
2360 // genType reflect (genType I, genType N) :
2361 // For the incident vector I and surface orientation N, returns the reflection direction:
2362 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002363 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302364 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2365 for (size_t i = 0; i < maxObjectSize; i++)
2366 {
2367 float result = unionArrays[0][i].getFConst() -
2368 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002369 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302370 }
2371 }
2372 else
2373 UNREACHABLE();
2374 break;
2375
Arun Patole7fa33552015-06-10 15:15:18 +05302376 case EOpMul:
2377 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2378 (*sequence)[1]->getAsTyped()->isMatrix())
2379 {
2380 // Perform component-wise matrix multiplication.
2381 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002382 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302383 angle::Matrix<float> result =
2384 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2385 SetUnionArrayFromMatrix(result, resultArray);
2386 }
2387 else
2388 UNREACHABLE();
2389 break;
2390
2391 case EOpOuterProduct:
2392 if (basicType == EbtFloat)
2393 {
2394 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2395 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2396 resultArray = new TConstantUnion[numRows * numCols];
2397 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002398 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2399 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302400 SetUnionArrayFromMatrix(result, resultArray);
2401 }
2402 else
2403 UNREACHABLE();
2404 break;
2405
Arun Patole274f0702015-05-05 13:33:30 +05302406 default:
2407 UNREACHABLE();
2408 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2409 return nullptr;
2410 }
2411 }
2412 else if (paramsCount == 3)
2413 {
2414 //
2415 // Ternary built-in
2416 //
2417 switch (op)
2418 {
2419 case EOpClamp:
2420 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002421 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302422 for (size_t i = 0; i < maxObjectSize; i++)
2423 {
2424 switch (basicType)
2425 {
2426 case EbtFloat:
2427 {
2428 float x = unionArrays[0][i].getFConst();
2429 float min = unionArrays[1][i].getFConst();
2430 float max = unionArrays[2][i].getFConst();
2431 // Results are undefined if min > max.
2432 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002433 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302434 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002435 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302436 }
2437 break;
2438 case EbtInt:
2439 {
2440 int x = unionArrays[0][i].getIConst();
2441 int min = unionArrays[1][i].getIConst();
2442 int max = unionArrays[2][i].getIConst();
2443 // Results are undefined if min > max.
2444 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002445 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302446 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002447 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302448 }
2449 break;
2450 case EbtUInt:
2451 {
2452 unsigned int x = unionArrays[0][i].getUConst();
2453 unsigned int min = unionArrays[1][i].getUConst();
2454 unsigned int max = unionArrays[2][i].getUConst();
2455 // Results are undefined if min > max.
2456 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002457 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302458 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002459 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302460 }
2461 break;
2462 default:
2463 UNREACHABLE();
2464 break;
2465 }
2466 }
2467 }
2468 break;
2469
Arun Patolebf790422015-05-18 17:53:04 +05302470 case EOpMix:
2471 {
2472 if (basicType == EbtFloat)
2473 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002474 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302475 for (size_t i = 0; i < maxObjectSize; i++)
2476 {
2477 float x = unionArrays[0][i].getFConst();
2478 float y = unionArrays[1][i].getFConst();
2479 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2480 if (type == EbtFloat)
2481 {
2482 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2483 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002484 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302485 }
2486 else // 3rd parameter is EbtBool
2487 {
2488 ASSERT(type == EbtBool);
2489 // Selects which vector each returned component comes from.
2490 // For a component of a that is false, the corresponding component of x is returned.
2491 // For a component of a that is true, the corresponding component of y is returned.
2492 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002493 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302494 }
2495 }
2496 }
2497 else
2498 UNREACHABLE();
2499 }
2500 break;
2501
2502 case EOpSmoothStep:
2503 {
2504 if (basicType == EbtFloat)
2505 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002506 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302507 for (size_t i = 0; i < maxObjectSize; i++)
2508 {
2509 float edge0 = unionArrays[0][i].getFConst();
2510 float edge1 = unionArrays[1][i].getFConst();
2511 float x = unionArrays[2][i].getFConst();
2512 // Results are undefined if edge0 >= edge1.
2513 if (edge0 >= edge1)
2514 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002515 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302516 }
2517 else
2518 {
2519 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2520 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2521 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002522 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302523 }
2524 }
2525 }
2526 else
2527 UNREACHABLE();
2528 }
2529 break;
2530
Arun Patole1155ddd2015-06-05 18:04:36 +05302531 case EOpFaceForward:
2532 if (basicType == EbtFloat)
2533 {
2534 // genType faceforward(genType N, genType I, genType Nref) :
2535 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002536 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302537 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2538 for (size_t i = 0; i < maxObjectSize; i++)
2539 {
2540 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002541 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302542 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002543 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302544 }
2545 }
2546 else
2547 UNREACHABLE();
2548 break;
2549
2550 case EOpRefract:
2551 if (basicType == EbtFloat)
2552 {
2553 // genType refract(genType I, genType N, float eta) :
2554 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2555 // return the refraction vector. The result is computed by
2556 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2557 // if (k < 0.0)
2558 // return genType(0.0)
2559 // else
2560 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002561 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302562 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2563 for (size_t i = 0; i < maxObjectSize; i++)
2564 {
2565 float eta = unionArrays[2][i].getFConst();
2566 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2567 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002568 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302569 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002570 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302571 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2572 }
2573 }
2574 else
2575 UNREACHABLE();
2576 break;
2577
Arun Patole274f0702015-05-05 13:33:30 +05302578 default:
2579 UNREACHABLE();
2580 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2581 return nullptr;
2582 }
2583 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002584 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302585}
2586
2587// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002588TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2589{
2590 if (hashFunction == NULL || name.empty())
2591 return name;
2592 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2593 TStringStream stream;
2594 stream << HASHED_NAME_PREFIX << std::hex << number;
2595 TString hashedName = stream.str();
2596 return hashedName;
2597}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002598
2599void TIntermTraverser::updateTree()
2600{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002601 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2602 {
2603 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2604 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002605 if (!insertion.insertionsAfter.empty())
2606 {
2607 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2608 insertion.insertionsAfter);
2609 ASSERT(inserted);
2610 UNUSED_ASSERTION_VARIABLE(inserted);
2611 }
2612 if (!insertion.insertionsBefore.empty())
2613 {
2614 bool inserted =
2615 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2616 ASSERT(inserted);
2617 UNUSED_ASSERTION_VARIABLE(inserted);
2618 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002619 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002620 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2621 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002622 const NodeUpdateEntry &replacement = mReplacements[ii];
2623 ASSERT(replacement.parent);
2624 bool replaced = replacement.parent->replaceChildNode(
2625 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002626 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002627 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002628
Olli Etuahocd94ef92015-04-16 19:18:10 +03002629 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002630 {
2631 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002632 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002633 // be replaced, we need to make sure we don't update the replaced
2634 // node; instead, we update the replacement node.
2635 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2636 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002637 NodeUpdateEntry &replacement2 = mReplacements[jj];
2638 if (replacement2.parent == replacement.original)
2639 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002640 }
2641 }
2642 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002643 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2644 {
2645 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2646 ASSERT(replacement.parent);
2647 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2648 replacement.original, replacement.replacements);
2649 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002650 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002651 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002652
Jamie Madill03d863c2016-07-27 18:15:53 -04002653 clearReplacementQueue();
2654}
2655
2656void TIntermTraverser::clearReplacementQueue()
2657{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002658 mReplacements.clear();
2659 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002660 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002661}
Jamie Madill1048e432016-07-23 18:51:28 -04002662
Jamie Madill03d863c2016-07-27 18:15:53 -04002663void TIntermTraverser::queueReplacement(TIntermNode *original,
2664 TIntermNode *replacement,
2665 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002666{
Jamie Madill03d863c2016-07-27 18:15:53 -04002667 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002668}
2669
Jamie Madill03d863c2016-07-27 18:15:53 -04002670void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2671 TIntermNode *original,
2672 TIntermNode *replacement,
2673 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002674{
Jamie Madill03d863c2016-07-27 18:15:53 -04002675 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2676 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002677}