blob: 092238087184d35d9c67aaa5d7e6ff4de8df6762 [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"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
26namespace
27{
28
Arun Patole9dea48f2015-04-02 11:45:09 +053029const float kPi = 3.14159265358979323846f;
30const float kDegreesToRadiansMultiplier = kPi / 180.0f;
31const float kRadiansToDegreesMultiplier = 180.0f / kPi;
32
Jamie Madillb1a85f42014-08-19 15:23:24 -040033TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
34{
35 return left > right ? left : right;
36}
37
Arun Patole274f0702015-05-05 13:33:30 +053038TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
39{
40 TConstantUnion *constUnion = new TConstantUnion[size];
41 for (unsigned int i = 0; i < size; ++i)
42 constUnion[i] = constant;
43
44 return constUnion;
45}
46
Olli Etuahof119a262016-08-19 15:54:22 +030047void UndefinedConstantFoldingError(const TSourceLoc &loc,
48 TOperator op,
49 TBasicType basicType,
50 TDiagnostics *diagnostics,
51 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053052{
Olli Etuahof119a262016-08-19 15:54:22 +030053 diagnostics->warning(loc, "operation result is undefined for the values passed in",
54 GetOperatorString(op), "");
Arun Patolebf790422015-05-18 17:53:04 +053055
56 switch (basicType)
57 {
58 case EbtFloat :
59 result->setFConst(0.0f);
60 break;
61 case EbtInt:
62 result->setIConst(0);
63 break;
64 case EbtUInt:
65 result->setUConst(0u);
66 break;
67 case EbtBool:
68 result->setBConst(false);
69 break;
70 default:
71 break;
72 }
73}
74
Olli Etuaho5c0e0232015-11-11 15:55:59 +020075float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053076{
77 float result = 0.0f;
78 for (size_t i = 0; i < paramArraySize; i++)
79 {
80 float f = paramArray[i].getFConst();
81 result += f * f;
82 }
83 return sqrtf(result);
84}
85
Olli Etuaho5c0e0232015-11-11 15:55:59 +020086float VectorDotProduct(const TConstantUnion *paramArray1,
87 const TConstantUnion *paramArray2,
88 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053089{
90 float result = 0.0f;
91 for (size_t i = 0; i < paramArraySize; i++)
92 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
93 return result;
94}
95
Olli Etuaho3272a6d2016-08-29 17:54:50 +030096TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020097 const TIntermTyped *originalNode,
98 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +030099{
100 if (constArray == nullptr)
101 {
102 return nullptr;
103 }
104 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200105 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300106 folded->setLine(originalNode->getLine());
107 return folded;
108}
109
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200110angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
111 const unsigned int &rows,
112 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530113{
114 std::vector<float> elements;
115 for (size_t i = 0; i < rows * cols; i++)
116 elements.push_back(paramArray[i].getFConst());
117 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300118 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
119 // so that the created matrix will have the expected dimensions after the transpose.
120 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530121}
122
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200123angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530124{
125 std::vector<float> elements;
126 for (size_t i = 0; i < size * size; i++)
127 elements.push_back(paramArray[i].getFConst());
128 // Transpose is used since the Matrix constructor expects arguments in row-major order,
129 // whereas the paramArray is in column-major order.
130 return angle::Matrix<float>(elements, size).transpose();
131}
132
133void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
134{
135 // Transpose is used since the input Matrix is in row-major order,
136 // whereas the actual result should be in column-major order.
137 angle::Matrix<float> result = m.transpose();
138 std::vector<float> resultElements = result.elements();
139 for (size_t i = 0; i < resultElements.size(); i++)
140 resultArray[i].setFConst(resultElements[i]);
141}
142
Jamie Madillb1a85f42014-08-19 15:23:24 -0400143} // namespace anonymous
144
145
146////////////////////////////////////////////////////////////////
147//
148// Member functions of the nodes used for building the tree.
149//
150////////////////////////////////////////////////////////////////
151
Olli Etuahod2a67b92014-10-21 16:42:57 +0300152void TIntermTyped::setTypePreservePrecision(const TType &t)
153{
154 TPrecision precision = getPrecision();
155 mType = t;
156 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
157 mType.setPrecision(precision);
158}
159
Jamie Madillb1a85f42014-08-19 15:23:24 -0400160#define REPLACE_IF_IS(node, type, original, replacement) \
161 if (node == original) { \
162 node = static_cast<type *>(replacement); \
163 return true; \
164 }
165
166bool TIntermLoop::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300169 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
171 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
172 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200173 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174 return false;
175}
176
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177bool TIntermBranch::replaceChildNode(
178 TIntermNode *original, TIntermNode *replacement)
179{
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182}
183
Jamie Madillb1a85f42014-08-19 15:23:24 -0400184bool TIntermBinary::replaceChildNode(
185 TIntermNode *original, TIntermNode *replacement)
186{
187 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
188 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
189 return false;
190}
191
Jamie Madillb1a85f42014-08-19 15:23:24 -0400192bool TIntermUnary::replaceChildNode(
193 TIntermNode *original, TIntermNode *replacement)
194{
Olli Etuahoa2234302016-08-31 12:05:39 +0300195 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400196 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
197 return false;
198}
199
Jamie Madillb1a85f42014-08-19 15:23:24 -0400200bool TIntermAggregate::replaceChildNode(
201 TIntermNode *original, TIntermNode *replacement)
202{
203 for (size_t ii = 0; ii < mSequence.size(); ++ii)
204 {
205 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
206 }
207 return false;
208}
209
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300210bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
211{
212 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
213 {
214 if (*it == original)
215 {
216 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300217 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300218 return true;
219 }
220 }
221 return false;
222}
223
Olli Etuahoa6f22092015-05-08 18:31:10 +0300224bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
225{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300226 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300227 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300228 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300229 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300230 auto it = mSequence.begin() + position;
231 mSequence.insert(it, insertions.begin(), insertions.end());
232 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300233}
234
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200235bool TIntermAggregate::areChildrenConstQualified()
236{
237 for (TIntermNode *&child : mSequence)
238 {
239 TIntermTyped *typed = child->getAsTyped();
240 if (typed && typed->getQualifier() != EvqConst)
241 {
242 return false;
243 }
244 }
245 return true;
246}
247
Olli Etuahod2a67b92014-10-21 16:42:57 +0300248void TIntermAggregate::setPrecisionFromChildren()
249{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300250 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300251 if (getBasicType() == EbtBool)
252 {
253 mType.setPrecision(EbpUndefined);
254 return;
255 }
256
257 TPrecision precision = EbpUndefined;
258 TIntermSequence::iterator childIter = mSequence.begin();
259 while (childIter != mSequence.end())
260 {
261 TIntermTyped *typed = (*childIter)->getAsTyped();
262 if (typed)
263 precision = GetHigherPrecision(typed->getPrecision(), precision);
264 ++childIter;
265 }
266 mType.setPrecision(precision);
267}
268
269void TIntermAggregate::setBuiltInFunctionPrecision()
270{
271 // All built-ins returning bool should be handled as ops, not functions.
272 ASSERT(getBasicType() != EbtBool);
273
274 TPrecision precision = EbpUndefined;
275 TIntermSequence::iterator childIter = mSequence.begin();
276 while (childIter != mSequence.end())
277 {
278 TIntermTyped *typed = (*childIter)->getAsTyped();
279 // ESSL spec section 8: texture functions get their precision from the sampler.
280 if (typed && IsSampler(typed->getBasicType()))
281 {
282 precision = typed->getPrecision();
283 break;
284 }
285 ++childIter;
286 }
287 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
288 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300289 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300290 mType.setPrecision(EbpHigh);
291 else
292 mType.setPrecision(precision);
293}
294
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300295bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
296{
297 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
298 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
299 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
300 return false;
301}
302
Olli Etuaho57961272016-09-14 13:57:46 +0300303bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400304{
305 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
306 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
307 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
308 return false;
309}
310
Olli Etuahoa3a36662015-02-17 13:46:51 +0200311bool TIntermSwitch::replaceChildNode(
312 TIntermNode *original, TIntermNode *replacement)
313{
314 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
315 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
316 return false;
317}
318
319bool TIntermCase::replaceChildNode(
320 TIntermNode *original, TIntermNode *replacement)
321{
322 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
323 return false;
324}
325
Olli Etuahod7a25242015-08-18 13:49:45 +0300326TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
327{
328 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
329 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
330 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
331 mLine = node.mLine;
332}
333
Olli Etuahod4f4c112016-04-15 15:11:24 +0300334bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
335{
336 TIntermAggregate *constructor = getAsAggregate();
337 if (!constructor || !constructor->isConstructor())
338 {
339 return false;
340 }
341 for (TIntermNode *&node : *constructor->getSequence())
342 {
343 if (!node->getAsConstantUnion())
344 return false;
345 }
346 return true;
347}
348
Corentin Wallez509e4562016-08-25 14:55:44 -0400349// static
350TIntermTyped *TIntermTyped::CreateIndexNode(int index)
351{
352 TConstantUnion *u = new TConstantUnion[1];
353 u[0].setIConst(index);
354
355 TType type(EbtInt, EbpUndefined, EvqConst, 1);
356 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
357 return node;
358}
359
360// static
361TIntermTyped *TIntermTyped::CreateZero(const TType &type)
362{
363 TType constType(type);
364 constType.setQualifier(EvqConst);
365
366 if (!type.isArray() && type.getBasicType() != EbtStruct)
367 {
368 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
369
370 size_t size = constType.getObjectSize();
371 TConstantUnion *u = new TConstantUnion[size];
372 for (size_t i = 0; i < size; ++i)
373 {
374 switch (type.getBasicType())
375 {
376 case EbtFloat:
377 u[i].setFConst(0.0f);
378 break;
379 case EbtInt:
380 u[i].setIConst(0);
381 break;
382 case EbtUInt:
383 u[i].setUConst(0u);
384 break;
385 case EbtBool:
386 u[i].setBConst(false);
387 break;
388 default:
389 UNREACHABLE();
390 return nullptr;
391 }
392 }
393
394 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
395 return node;
396 }
397
398 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
399 constructor->setType(constType);
400
401 if (type.isArray())
402 {
403 TType elementType(type);
404 elementType.clearArrayness();
405
406 size_t arraySize = type.getArraySize();
407 for (size_t i = 0; i < arraySize; ++i)
408 {
409 constructor->getSequence()->push_back(CreateZero(elementType));
410 }
411 }
412 else
413 {
414 ASSERT(type.getBasicType() == EbtStruct);
415
416 TStructure *structure = type.getStruct();
417 for (const auto &field : structure->fields())
418 {
419 constructor->getSequence()->push_back(CreateZero(*field->type()));
420 }
421 }
422
423 return constructor;
424}
425
Olli Etuahod7a25242015-08-18 13:49:45 +0300426TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
427{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200428 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300429}
430
431TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
432 : TIntermOperator(node),
433 mName(node.mName),
434 mUserDefined(node.mUserDefined),
435 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300436 mUseEmulatedFunction(node.mUseEmulatedFunction),
437 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
438{
439 for (TIntermNode *child : node.mSequence)
440 {
441 TIntermTyped *typedChild = child->getAsTyped();
442 ASSERT(typedChild != nullptr);
443 TIntermTyped *childCopy = typedChild->deepCopy();
444 mSequence.push_back(childCopy);
445 }
446}
447
448TIntermBinary::TIntermBinary(const TIntermBinary &node)
449 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
450{
451 TIntermTyped *leftCopy = node.mLeft->deepCopy();
452 TIntermTyped *rightCopy = node.mRight->deepCopy();
453 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
454 mLeft = leftCopy;
455 mRight = rightCopy;
456}
457
458TIntermUnary::TIntermUnary(const TIntermUnary &node)
459 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
460{
461 TIntermTyped *operandCopy = node.mOperand->deepCopy();
462 ASSERT(operandCopy != nullptr);
463 mOperand = operandCopy;
464}
465
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300466TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300467{
Olli Etuahod7a25242015-08-18 13:49:45 +0300468 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300469 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
470 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300471 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300472 mCondition = conditionCopy;
473 mTrueExpression = trueCopy;
474 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300475}
476
Jamie Madillb1a85f42014-08-19 15:23:24 -0400477bool TIntermOperator::isAssignment() const
478{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300479 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400480}
481
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300482bool TIntermOperator::isMultiplication() const
483{
484 switch (mOp)
485 {
486 case EOpMul:
487 case EOpMatrixTimesMatrix:
488 case EOpMatrixTimesVector:
489 case EOpMatrixTimesScalar:
490 case EOpVectorTimesMatrix:
491 case EOpVectorTimesScalar:
492 return true;
493 default:
494 return false;
495 }
496}
497
Jamie Madillb1a85f42014-08-19 15:23:24 -0400498//
499// returns true if the operator is for one of the constructors
500//
501bool TIntermOperator::isConstructor() const
502{
503 switch (mOp)
504 {
505 case EOpConstructVec2:
506 case EOpConstructVec3:
507 case EOpConstructVec4:
508 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400509 case EOpConstructMat2x3:
510 case EOpConstructMat2x4:
511 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400512 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400513 case EOpConstructMat3x4:
514 case EOpConstructMat4x2:
515 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400516 case EOpConstructMat4:
517 case EOpConstructFloat:
518 case EOpConstructIVec2:
519 case EOpConstructIVec3:
520 case EOpConstructIVec4:
521 case EOpConstructInt:
522 case EOpConstructUVec2:
523 case EOpConstructUVec3:
524 case EOpConstructUVec4:
525 case EOpConstructUInt:
526 case EOpConstructBVec2:
527 case EOpConstructBVec3:
528 case EOpConstructBVec4:
529 case EOpConstructBool:
530 case EOpConstructStruct:
531 return true;
532 default:
533 return false;
534 }
535}
536
Olli Etuaho1dded802016-08-18 18:13:13 +0300537TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
538{
539 if (left.isMatrix())
540 {
541 if (right.isMatrix())
542 {
543 return EOpMatrixTimesMatrix;
544 }
545 else
546 {
547 if (right.isVector())
548 {
549 return EOpMatrixTimesVector;
550 }
551 else
552 {
553 return EOpMatrixTimesScalar;
554 }
555 }
556 }
557 else
558 {
559 if (right.isMatrix())
560 {
561 if (left.isVector())
562 {
563 return EOpVectorTimesMatrix;
564 }
565 else
566 {
567 return EOpMatrixTimesScalar;
568 }
569 }
570 else
571 {
572 // Neither operand is a matrix.
573 if (left.isVector() == right.isVector())
574 {
575 // Leave as component product.
576 return EOpMul;
577 }
578 else
579 {
580 return EOpVectorTimesScalar;
581 }
582 }
583 }
584}
585
586TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
587{
588 if (left.isMatrix())
589 {
590 if (right.isMatrix())
591 {
592 return EOpMatrixTimesMatrixAssign;
593 }
594 else
595 {
596 // right should be scalar, but this may not be validated yet.
597 return EOpMatrixTimesScalarAssign;
598 }
599 }
600 else
601 {
602 if (right.isMatrix())
603 {
604 // Left should be a vector, but this may not be validated yet.
605 return EOpVectorTimesMatrixAssign;
606 }
607 else
608 {
609 // Neither operand is a matrix.
610 if (left.isVector() == right.isVector())
611 {
612 // Leave as component product.
613 return EOpMulAssign;
614 }
615 else
616 {
617 // left should be vector and right should be scalar, but this may not be validated
618 // yet.
619 return EOpVectorTimesScalarAssign;
620 }
621 }
622 }
623}
624
Jamie Madillb1a85f42014-08-19 15:23:24 -0400625//
626// Make sure the type of a unary operator is appropriate for its
627// combination of operation and operand type.
628//
Olli Etuahoa2234302016-08-31 12:05:39 +0300629void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400630{
Olli Etuahoa2234302016-08-31 12:05:39 +0300631 TQualifier resultQualifier = EvqTemporary;
632 if (mOperand->getQualifier() == EvqConst)
633 resultQualifier = EvqConst;
634
635 unsigned char operandPrimarySize =
636 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400637 switch (mOp)
638 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300639 case EOpFloatBitsToInt:
640 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
641 break;
642 case EOpFloatBitsToUint:
643 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
644 break;
645 case EOpIntBitsToFloat:
646 case EOpUintBitsToFloat:
647 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
648 break;
649 case EOpPackSnorm2x16:
650 case EOpPackUnorm2x16:
651 case EOpPackHalf2x16:
652 setType(TType(EbtUInt, EbpHigh, resultQualifier));
653 break;
654 case EOpUnpackSnorm2x16:
655 case EOpUnpackUnorm2x16:
656 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
657 break;
658 case EOpUnpackHalf2x16:
659 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
660 break;
661 case EOpAny:
662 case EOpAll:
663 setType(TType(EbtBool, EbpUndefined, resultQualifier));
664 break;
665 case EOpLength:
666 case EOpDeterminant:
667 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
668 break;
669 case EOpTranspose:
670 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
671 static_cast<unsigned char>(mOperand->getType().getRows()),
672 static_cast<unsigned char>(mOperand->getType().getCols())));
673 break;
674 case EOpIsInf:
675 case EOpIsNan:
676 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
677 break;
678 default:
679 setType(mOperand->getType());
680 mType.setQualifier(resultQualifier);
681 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400682 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300683}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400684
Olli Etuahoa2234302016-08-31 12:05:39 +0300685TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
686 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
687{
688 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400689}
690
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300691TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
692 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
693{
694 promote();
695}
696
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300697TIntermTernary::TIntermTernary(TIntermTyped *cond,
698 TIntermTyped *trueExpression,
699 TIntermTyped *falseExpression)
700 : TIntermTyped(trueExpression->getType()),
701 mCondition(cond),
702 mTrueExpression(trueExpression),
703 mFalseExpression(falseExpression)
704{
705 getTypePointer()->setQualifier(
706 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
707}
708
709// static
710TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
711 TIntermTyped *trueExpression,
712 TIntermTyped *falseExpression)
713{
714 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
715 falseExpression->getQualifier() == EvqConst)
716 {
717 return EvqConst;
718 }
719 return EvqTemporary;
720}
721
Jamie Madillb1a85f42014-08-19 15:23:24 -0400722//
723// Establishes the type of the resultant operation, as well as
724// makes the operator the correct one for the operands.
725//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200726// For lots of operations it should already be established that the operand
727// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400728//
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300729void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400730{
Olli Etuaho1dded802016-08-18 18:13:13 +0300731 ASSERT(!isMultiplication() ||
732 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
733
Jamie Madillb1a85f42014-08-19 15:23:24 -0400734 // Base assumption: just make the type the same as the left
735 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400736 setType(mLeft->getType());
737
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200738 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400739 // Binary operations results in temporary variables unless both
740 // operands are const.
741 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
742 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200743 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400744 getTypePointer()->setQualifier(EvqTemporary);
745 }
746
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300747 // Handle indexing ops.
748 switch (mOp)
749 {
750 case EOpIndexDirect:
751 case EOpIndexIndirect:
752 if (mLeft->isArray())
753 {
754 mType.clearArrayness();
755 }
756 else if (mLeft->isMatrix())
757 {
758 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
759 static_cast<unsigned char>(mLeft->getRows())));
760 }
761 else if (mLeft->isVector())
762 {
763 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
764 }
765 else
766 {
767 UNREACHABLE();
768 }
769 return;
770 case EOpIndexDirectStruct:
771 {
772 const TFieldList &fields = mLeft->getType().getStruct()->fields();
773 const int i = mRight->getAsConstantUnion()->getIConst(0);
774 setType(*fields[i]->type());
775 getTypePointer()->setQualifier(resultQualifier);
776 return;
777 }
778 case EOpIndexDirectInterfaceBlock:
779 {
780 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
781 const int i = mRight->getAsConstantUnion()->getIConst(0);
782 setType(*fields[i]->type());
783 getTypePointer()->setQualifier(resultQualifier);
784 return;
785 }
786 case EOpVectorSwizzle:
787 {
788 auto numFields = mRight->getAsAggregate()->getSequence()->size();
789 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
790 static_cast<unsigned char>(numFields)));
791 return;
792 }
793 default:
794 break;
795 }
796
797 ASSERT(mLeft->isArray() == mRight->isArray());
798
799 // The result gets promoted to the highest precision.
800 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
801 getTypePointer()->setPrecision(higherPrecision);
802
Jamie Madillb1a85f42014-08-19 15:23:24 -0400803 const int nominalSize =
804 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
805
806 //
807 // All scalars or structs. Code after this test assumes this case is removed!
808 //
809 if (nominalSize == 1)
810 {
811 switch (mOp)
812 {
813 //
814 // Promote to conditional
815 //
816 case EOpEqual:
817 case EOpNotEqual:
818 case EOpLessThan:
819 case EOpGreaterThan:
820 case EOpLessThanEqual:
821 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300822 setType(TType(EbtBool, EbpUndefined, resultQualifier));
823 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400824
825 //
826 // And and Or operate on conditionals
827 //
828 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200829 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400830 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200831 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300832 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400833 break;
834
835 default:
836 break;
837 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300838 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400839 }
840
841 // If we reach here, at least one of the operands is vector or matrix.
842 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400843 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300844
Jamie Madillb1a85f42014-08-19 15:23:24 -0400845 switch (mOp)
846 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300847 case EOpMul:
848 break;
849 case EOpMatrixTimesScalar:
850 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400851 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200852 setType(TType(basicType, higherPrecision, resultQualifier,
853 static_cast<unsigned char>(mRight->getCols()),
854 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400855 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300856 break;
857 case EOpMatrixTimesVector:
858 setType(TType(basicType, higherPrecision, resultQualifier,
859 static_cast<unsigned char>(mLeft->getRows()), 1));
860 break;
861 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200862 setType(TType(basicType, higherPrecision, resultQualifier,
863 static_cast<unsigned char>(mRight->getCols()),
864 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300865 break;
866 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200867 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300868 static_cast<unsigned char>(nominalSize), 1));
869 break;
870 case EOpVectorTimesMatrix:
871 setType(TType(basicType, higherPrecision, resultQualifier,
872 static_cast<unsigned char>(mRight->getCols()), 1));
873 break;
874 case EOpMulAssign:
875 case EOpVectorTimesScalarAssign:
876 case EOpVectorTimesMatrixAssign:
877 case EOpMatrixTimesScalarAssign:
878 case EOpMatrixTimesMatrixAssign:
879 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
880 break;
881 case EOpAssign:
882 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300883 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
884 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
885 break;
886 case EOpAdd:
887 case EOpSub:
888 case EOpDiv:
889 case EOpIMod:
890 case EOpBitShiftLeft:
891 case EOpBitShiftRight:
892 case EOpBitwiseAnd:
893 case EOpBitwiseXor:
894 case EOpBitwiseOr:
895 case EOpAddAssign:
896 case EOpSubAssign:
897 case EOpDivAssign:
898 case EOpIModAssign:
899 case EOpBitShiftLeftAssign:
900 case EOpBitShiftRightAssign:
901 case EOpBitwiseAndAssign:
902 case EOpBitwiseXorAssign:
903 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300904 {
905 const int secondarySize =
906 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
907 setType(TType(basicType, higherPrecision, resultQualifier,
908 static_cast<unsigned char>(nominalSize),
909 static_cast<unsigned char>(secondarySize)));
910 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300911 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300912 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300913 case EOpEqual:
914 case EOpNotEqual:
915 case EOpLessThan:
916 case EOpGreaterThan:
917 case EOpLessThanEqual:
918 case EOpGreaterThanEqual:
919 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
920 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300921 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300922 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400923
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300924 case EOpIndexDirect:
925 case EOpIndexIndirect:
926 case EOpIndexDirectInterfaceBlock:
927 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300928 case EOpVectorSwizzle:
929 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300930 UNREACHABLE();
931 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300932 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300933 UNREACHABLE();
934 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400935 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400936}
937
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300938const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300939{
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300940 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300941 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300942 ASSERT(index < static_cast<int>(getType().getArraySize()));
943 TType arrayElementType = getType();
944 arrayElementType.clearArrayness();
945 size_t arrayElementSize = arrayElementType.getObjectSize();
946 return &mUnionArrayPointer[arrayElementSize * index];
947 }
948 else if (isMatrix())
949 {
950 ASSERT(index < getType().getCols());
951 int size = getType().getRows();
952 return &mUnionArrayPointer[size * index];
953 }
954 else if (isVector())
955 {
956 ASSERT(index < getType().getNominalSize());
957 return &mUnionArrayPointer[index];
958 }
959 else
960 {
961 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300962 return nullptr;
963 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300964}
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200965
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300966TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
967{
968 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
969 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
970 switch (mOp)
971 {
972 case EOpIndexDirect:
973 {
974 if (leftConstant == nullptr || rightConstant == nullptr)
975 {
976 return nullptr;
977 }
978 int index = rightConstant->getIConst(0);
979
980 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
981 return CreateFoldedNode(constArray, this, mType.getQualifier());
982 }
983 case EOpIndexDirectStruct:
984 {
985 if (leftConstant == nullptr || rightConstant == nullptr)
986 {
987 return nullptr;
988 }
989 const TFieldList &fields = mLeft->getType().getStruct()->fields();
990 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
991
992 size_t previousFieldsSize = 0;
993 for (size_t i = 0; i < index; ++i)
994 {
995 previousFieldsSize += fields[i]->type()->getObjectSize();
996 }
997
998 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
999 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1000 }
1001 case EOpIndexIndirect:
1002 case EOpIndexDirectInterfaceBlock:
1003 // Can never be constant folded.
1004 return nullptr;
1005 case EOpVectorSwizzle:
1006 {
1007 if (leftConstant == nullptr)
1008 {
1009 return nullptr;
1010 }
1011 TIntermAggregate *fieldsAgg = mRight->getAsAggregate();
1012 TIntermSequence *fieldsSequence = fieldsAgg->getSequence();
1013 size_t numFields = fieldsSequence->size();
1014
1015 TConstantUnion *constArray = new TConstantUnion[numFields];
1016 for (size_t i = 0; i < numFields; i++)
1017 {
1018 int fieldOffset = fieldsSequence->at(i)->getAsConstantUnion()->getIConst(0);
1019 constArray[i] = *leftConstant->foldIndexing(fieldOffset);
1020 }
1021 return CreateFoldedNode(constArray, this, mType.getQualifier());
1022 }
1023 default:
1024 {
1025 if (leftConstant == nullptr || rightConstant == nullptr)
1026 {
1027 return nullptr;
1028 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001029 TConstantUnion *constArray =
1030 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001031
1032 // Nodes may be constant folded without being qualified as constant.
1033 return CreateFoldedNode(constArray, this, mType.getQualifier());
1034 }
1035 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001036}
1037
Olli Etuahof119a262016-08-19 15:54:22 +03001038TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001039{
1040 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1041 if (operandConstant == nullptr)
1042 {
1043 return nullptr;
1044 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301045
1046 TConstantUnion *constArray = nullptr;
1047 switch (mOp)
1048 {
1049 case EOpAny:
1050 case EOpAll:
1051 case EOpLength:
1052 case EOpTranspose:
1053 case EOpDeterminant:
1054 case EOpInverse:
1055 case EOpPackSnorm2x16:
1056 case EOpUnpackSnorm2x16:
1057 case EOpPackUnorm2x16:
1058 case EOpUnpackUnorm2x16:
1059 case EOpPackHalf2x16:
1060 case EOpUnpackHalf2x16:
Olli Etuahof119a262016-08-19 15:54:22 +03001061 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1062 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301063 default:
Olli Etuahof119a262016-08-19 15:54:22 +03001064 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1065 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301066 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001067
1068 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001069 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001070}
1071
Olli Etuahof119a262016-08-19 15:54:22 +03001072TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001073{
1074 // Make sure that all params are constant before actual constant folding.
1075 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001076 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001077 if (param->getAsConstantUnion() == nullptr)
1078 {
1079 return nullptr;
1080 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001081 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001082 TConstantUnion *constArray = nullptr;
1083 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001084 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001085 else
Olli Etuahof119a262016-08-19 15:54:22 +03001086 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001087
1088 // Nodes may be constant folded without being qualified as constant.
1089 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1090 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001091}
1092
Jamie Madillb1a85f42014-08-19 15:23:24 -04001093//
1094// The fold functions see if an operation on a constant can be done in place,
1095// without generating run-time code.
1096//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001097// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001098//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001099TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1100 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001101 TDiagnostics *diagnostics,
1102 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001103{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001104 const TConstantUnion *leftArray = getUnionArrayPointer();
1105 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001106
Olli Etuahof119a262016-08-19 15:54:22 +03001107 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001108
1109 size_t objectSize = getType().getObjectSize();
1110
1111 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1112 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1113 {
1114 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1115 }
1116 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1117 {
1118 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1119 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1120 objectSize = rightNode->getType().getObjectSize();
1121 }
1122
1123 TConstantUnion *resultArray = nullptr;
1124
1125 switch(op)
1126 {
1127 case EOpAdd:
1128 resultArray = new TConstantUnion[objectSize];
1129 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001130 resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001131 break;
1132 case EOpSub:
1133 resultArray = new TConstantUnion[objectSize];
1134 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001135 resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001136 break;
1137
1138 case EOpMul:
1139 case EOpVectorTimesScalar:
1140 case EOpMatrixTimesScalar:
1141 resultArray = new TConstantUnion[objectSize];
1142 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001143 resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001144 break;
1145
1146 case EOpMatrixTimesMatrix:
1147 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001148 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001149 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001150
1151 const int leftCols = getCols();
1152 const int leftRows = getRows();
1153 const int rightCols = rightNode->getType().getCols();
1154 const int rightRows = rightNode->getType().getRows();
1155 const int resultCols = rightCols;
1156 const int resultRows = leftRows;
1157
1158 resultArray = new TConstantUnion[resultCols * resultRows];
1159 for (int row = 0; row < resultRows; row++)
1160 {
1161 for (int column = 0; column < resultCols; column++)
1162 {
1163 resultArray[resultRows * column + row].setFConst(0.0f);
1164 for (int i = 0; i < leftCols; i++)
1165 {
1166 resultArray[resultRows * column + row].setFConst(
1167 resultArray[resultRows * column + row].getFConst() +
1168 leftArray[i * leftRows + row].getFConst() *
1169 rightArray[column * rightRows + i].getFConst());
1170 }
1171 }
1172 }
1173 }
1174 break;
1175
1176 case EOpDiv:
1177 case EOpIMod:
1178 {
1179 resultArray = new TConstantUnion[objectSize];
1180 for (size_t i = 0; i < objectSize; i++)
1181 {
1182 switch (getType().getBasicType())
1183 {
1184 case EbtFloat:
1185 if (rightArray[i] == 0.0f)
1186 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001187 diagnostics->warning(
1188 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001189 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1190 }
1191 else
1192 {
1193 ASSERT(op == EOpDiv);
1194 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1195 }
1196 break;
1197
1198 case EbtInt:
1199 if (rightArray[i] == 0)
1200 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001201 diagnostics->warning(
1202 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001203 resultArray[i].setIConst(INT_MAX);
1204 }
1205 else
1206 {
Olli Etuahod4453572016-09-27 13:21:46 +01001207 int lhs = leftArray[i].getIConst();
1208 int divisor = rightArray[i].getIConst();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001209 if (op == EOpDiv)
1210 {
Olli Etuahod4453572016-09-27 13:21:46 +01001211 // Check for the special case where the minimum representable number is
1212 // divided by -1. If left alone this leads to integer overflow in C++.
1213 // ESSL 3.00.6 section 4.1.3 Integers:
1214 // "However, for the case where the minimum representable value is
1215 // divided by -1, it is allowed to return either the minimum
1216 // representable value or the maximum representable value."
1217 if (lhs == -0x7fffffff - 1 && divisor == -1)
1218 {
1219 resultArray[i].setIConst(0x7fffffff);
1220 }
1221 else
1222 {
1223 resultArray[i].setIConst(lhs / divisor);
1224 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001225 }
1226 else
1227 {
1228 ASSERT(op == EOpIMod);
Olli Etuahod4453572016-09-27 13:21:46 +01001229 if (lhs < 0 || divisor < 0)
1230 {
1231 // ESSL 3.00.6 section 5.9: Results of modulus are undefined when
1232 // either one of the operands is negative.
1233 diagnostics->warning(getLine(),
1234 "Negative modulus operator operand "
1235 "encountered during constant folding",
1236 "%", "");
1237 resultArray[i].setIConst(0);
1238 }
1239 else
1240 {
1241 resultArray[i].setIConst(lhs % divisor);
1242 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001243 }
1244 }
1245 break;
1246
1247 case EbtUInt:
1248 if (rightArray[i] == 0)
1249 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001250 diagnostics->warning(
1251 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001252 resultArray[i].setUConst(UINT_MAX);
1253 }
1254 else
1255 {
1256 if (op == EOpDiv)
1257 {
1258 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1259 }
1260 else
1261 {
1262 ASSERT(op == EOpIMod);
1263 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1264 }
1265 }
1266 break;
1267
1268 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001269 UNREACHABLE();
1270 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001271 }
1272 }
1273 }
1274 break;
1275
1276 case EOpMatrixTimesVector:
1277 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001278 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001279 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001280
1281 const int matrixCols = getCols();
1282 const int matrixRows = getRows();
1283
1284 resultArray = new TConstantUnion[matrixRows];
1285
1286 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1287 {
1288 resultArray[matrixRow].setFConst(0.0f);
1289 for (int col = 0; col < matrixCols; col++)
1290 {
1291 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1292 leftArray[col * matrixRows + matrixRow].getFConst() *
1293 rightArray[col].getFConst());
1294 }
1295 }
1296 }
1297 break;
1298
1299 case EOpVectorTimesMatrix:
1300 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001301 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001302 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001303
1304 const int matrixCols = rightNode->getType().getCols();
1305 const int matrixRows = rightNode->getType().getRows();
1306
1307 resultArray = new TConstantUnion[matrixCols];
1308
1309 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1310 {
1311 resultArray[matrixCol].setFConst(0.0f);
1312 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1313 {
1314 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1315 leftArray[matrixRow].getFConst() *
1316 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1317 }
1318 }
1319 }
1320 break;
1321
1322 case EOpLogicalAnd:
1323 {
1324 resultArray = new TConstantUnion[objectSize];
1325 for (size_t i = 0; i < objectSize; i++)
1326 {
1327 resultArray[i] = leftArray[i] && rightArray[i];
1328 }
1329 }
1330 break;
1331
1332 case EOpLogicalOr:
1333 {
1334 resultArray = new TConstantUnion[objectSize];
1335 for (size_t i = 0; i < objectSize; i++)
1336 {
1337 resultArray[i] = leftArray[i] || rightArray[i];
1338 }
1339 }
1340 break;
1341
1342 case EOpLogicalXor:
1343 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001344 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001345 resultArray = new TConstantUnion[objectSize];
1346 for (size_t i = 0; i < objectSize; i++)
1347 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001348 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001349 }
1350 }
1351 break;
1352
1353 case EOpBitwiseAnd:
1354 resultArray = new TConstantUnion[objectSize];
1355 for (size_t i = 0; i < objectSize; i++)
1356 resultArray[i] = leftArray[i] & rightArray[i];
1357 break;
1358 case EOpBitwiseXor:
1359 resultArray = new TConstantUnion[objectSize];
1360 for (size_t i = 0; i < objectSize; i++)
1361 resultArray[i] = leftArray[i] ^ rightArray[i];
1362 break;
1363 case EOpBitwiseOr:
1364 resultArray = new TConstantUnion[objectSize];
1365 for (size_t i = 0; i < objectSize; i++)
1366 resultArray[i] = leftArray[i] | rightArray[i];
1367 break;
1368 case EOpBitShiftLeft:
1369 resultArray = new TConstantUnion[objectSize];
1370 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001371 resultArray[i] = TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001372 break;
1373 case EOpBitShiftRight:
1374 resultArray = new TConstantUnion[objectSize];
1375 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001376 resultArray[i] = TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001377 break;
1378
1379 case EOpLessThan:
1380 ASSERT(objectSize == 1);
1381 resultArray = new TConstantUnion[1];
1382 resultArray->setBConst(*leftArray < *rightArray);
1383 break;
1384
1385 case EOpGreaterThan:
1386 ASSERT(objectSize == 1);
1387 resultArray = new TConstantUnion[1];
1388 resultArray->setBConst(*leftArray > *rightArray);
1389 break;
1390
1391 case EOpLessThanEqual:
1392 ASSERT(objectSize == 1);
1393 resultArray = new TConstantUnion[1];
1394 resultArray->setBConst(!(*leftArray > *rightArray));
1395 break;
1396
1397 case EOpGreaterThanEqual:
1398 ASSERT(objectSize == 1);
1399 resultArray = new TConstantUnion[1];
1400 resultArray->setBConst(!(*leftArray < *rightArray));
1401 break;
1402
1403 case EOpEqual:
1404 case EOpNotEqual:
1405 {
1406 resultArray = new TConstantUnion[1];
1407 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001408 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001409 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001410 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001411 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001412 equal = false;
1413 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001414 }
1415 }
1416 if (op == EOpEqual)
1417 {
1418 resultArray->setBConst(equal);
1419 }
1420 else
1421 {
1422 resultArray->setBConst(!equal);
1423 }
1424 }
1425 break;
1426
1427 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001428 UNREACHABLE();
1429 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001430 }
1431 return resultArray;
1432}
1433
Olli Etuahof119a262016-08-19 15:54:22 +03001434// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1435// code. Returns the constant value to keep using. Nullptr should not be returned.
1436TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001437{
Olli Etuahof119a262016-08-19 15:54:22 +03001438 // Do operations where the return type may have a different number of components compared to the
1439 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001440
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001441 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001442 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301443
1444 size_t objectSize = getType().getObjectSize();
1445 TConstantUnion *resultArray = nullptr;
1446 switch (op)
1447 {
Olli Etuahof119a262016-08-19 15:54:22 +03001448 case EOpAny:
1449 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301450 resultArray = new TConstantUnion();
1451 resultArray->setBConst(false);
1452 for (size_t i = 0; i < objectSize; i++)
1453 {
1454 if (operandArray[i].getBConst())
1455 {
1456 resultArray->setBConst(true);
1457 break;
1458 }
1459 }
1460 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301461
Olli Etuahof119a262016-08-19 15:54:22 +03001462 case EOpAll:
1463 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301464 resultArray = new TConstantUnion();
1465 resultArray->setBConst(true);
1466 for (size_t i = 0; i < objectSize; i++)
1467 {
1468 if (!operandArray[i].getBConst())
1469 {
1470 resultArray->setBConst(false);
1471 break;
1472 }
1473 }
1474 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301475
Olli Etuahof119a262016-08-19 15:54:22 +03001476 case EOpLength:
1477 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301478 resultArray = new TConstantUnion();
1479 resultArray->setFConst(VectorLength(operandArray, objectSize));
1480 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301481
Olli Etuahof119a262016-08-19 15:54:22 +03001482 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301483 {
Olli Etuahof119a262016-08-19 15:54:22 +03001484 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301485 resultArray = new TConstantUnion[objectSize];
1486 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001487 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301488 SetUnionArrayFromMatrix(result, resultArray);
1489 break;
1490 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301491
Olli Etuahof119a262016-08-19 15:54:22 +03001492 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301493 {
Olli Etuahof119a262016-08-19 15:54:22 +03001494 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301495 unsigned int size = getType().getNominalSize();
1496 ASSERT(size >= 2 && size <= 4);
1497 resultArray = new TConstantUnion();
1498 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1499 break;
1500 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301501
Olli Etuahof119a262016-08-19 15:54:22 +03001502 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301503 {
Olli Etuahof119a262016-08-19 15:54:22 +03001504 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301505 unsigned int size = getType().getNominalSize();
1506 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001507 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301508 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1509 SetUnionArrayFromMatrix(result, resultArray);
1510 break;
1511 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301512
Olli Etuahof119a262016-08-19 15:54:22 +03001513 case EOpPackSnorm2x16:
1514 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301515 ASSERT(getType().getNominalSize() == 2);
1516 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001517 resultArray->setUConst(
1518 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301519 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301520
Olli Etuahof119a262016-08-19 15:54:22 +03001521 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301522 {
Olli Etuahof119a262016-08-19 15:54:22 +03001523 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301524 resultArray = new TConstantUnion[2];
1525 float f1, f2;
1526 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1527 resultArray[0].setFConst(f1);
1528 resultArray[1].setFConst(f2);
1529 break;
1530 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301531
Olli Etuahof119a262016-08-19 15:54:22 +03001532 case EOpPackUnorm2x16:
1533 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301534 ASSERT(getType().getNominalSize() == 2);
1535 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001536 resultArray->setUConst(
1537 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301538 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301539
Olli Etuahof119a262016-08-19 15:54:22 +03001540 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301541 {
Olli Etuahof119a262016-08-19 15:54:22 +03001542 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301543 resultArray = new TConstantUnion[2];
1544 float f1, f2;
1545 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1546 resultArray[0].setFConst(f1);
1547 resultArray[1].setFConst(f2);
1548 break;
1549 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301550
Olli Etuahof119a262016-08-19 15:54:22 +03001551 case EOpPackHalf2x16:
1552 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301553 ASSERT(getType().getNominalSize() == 2);
1554 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001555 resultArray->setUConst(
1556 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301557 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301558
Olli Etuahof119a262016-08-19 15:54:22 +03001559 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301560 {
Olli Etuahof119a262016-08-19 15:54:22 +03001561 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301562 resultArray = new TConstantUnion[2];
1563 float f1, f2;
1564 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1565 resultArray[0].setFConst(f1);
1566 resultArray[1].setFConst(f2);
1567 break;
1568 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301569
Olli Etuahof119a262016-08-19 15:54:22 +03001570 default:
1571 UNREACHABLE();
1572 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301573 }
1574
1575 return resultArray;
1576}
1577
Olli Etuahof119a262016-08-19 15:54:22 +03001578TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1579 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301580{
Olli Etuahof119a262016-08-19 15:54:22 +03001581 // Do unary operations where each component of the result is computed based on the corresponding
1582 // component of the operand. Also folds normalize, though the divisor in that case takes all
1583 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301584
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001585 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001586 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001587
1588 size_t objectSize = getType().getObjectSize();
1589
Arun Patoleab2b9a22015-07-06 18:27:56 +05301590 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1591 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301592 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301593 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301594 {
Olli Etuahof119a262016-08-19 15:54:22 +03001595 case EOpNegative:
1596 switch (getType().getBasicType())
1597 {
1598 case EbtFloat:
1599 resultArray[i].setFConst(-operandArray[i].getFConst());
1600 break;
1601 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001602 if (operandArray[i] == std::numeric_limits<int>::min())
1603 {
1604 // The minimum representable integer doesn't have a positive
1605 // counterpart, rather the negation overflows and in ESSL is supposed to
1606 // wrap back to the minimum representable integer. Make sure that we
1607 // don't actually let the negation overflow, which has undefined
1608 // behavior in C++.
1609 resultArray[i].setIConst(std::numeric_limits<int>::min());
1610 }
1611 else
1612 {
1613 resultArray[i].setIConst(-operandArray[i].getIConst());
1614 }
Olli Etuahof119a262016-08-19 15:54:22 +03001615 break;
1616 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001617 if (operandArray[i] == 0x80000000u)
1618 {
1619 resultArray[i].setUConst(0x80000000u);
1620 }
1621 else
1622 {
1623 resultArray[i].setUConst(static_cast<unsigned int>(
1624 -static_cast<int>(operandArray[i].getUConst())));
1625 }
Olli Etuahof119a262016-08-19 15:54:22 +03001626 break;
1627 default:
1628 UNREACHABLE();
1629 return nullptr;
1630 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301631 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301632
Olli Etuahof119a262016-08-19 15:54:22 +03001633 case EOpPositive:
1634 switch (getType().getBasicType())
1635 {
1636 case EbtFloat:
1637 resultArray[i].setFConst(operandArray[i].getFConst());
1638 break;
1639 case EbtInt:
1640 resultArray[i].setIConst(operandArray[i].getIConst());
1641 break;
1642 case EbtUInt:
1643 resultArray[i].setUConst(static_cast<unsigned int>(
1644 static_cast<int>(operandArray[i].getUConst())));
1645 break;
1646 default:
1647 UNREACHABLE();
1648 return nullptr;
1649 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301650 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301651
Olli Etuahof119a262016-08-19 15:54:22 +03001652 case EOpLogicalNot:
1653 switch (getType().getBasicType())
1654 {
1655 case EbtBool:
1656 resultArray[i].setBConst(!operandArray[i].getBConst());
1657 break;
1658 default:
1659 UNREACHABLE();
1660 return nullptr;
1661 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301662 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301663
Olli Etuahof119a262016-08-19 15:54:22 +03001664 case EOpBitwiseNot:
1665 switch (getType().getBasicType())
1666 {
1667 case EbtInt:
1668 resultArray[i].setIConst(~operandArray[i].getIConst());
1669 break;
1670 case EbtUInt:
1671 resultArray[i].setUConst(~operandArray[i].getUConst());
1672 break;
1673 default:
1674 UNREACHABLE();
1675 return nullptr;
1676 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301677 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301678
Olli Etuahof119a262016-08-19 15:54:22 +03001679 case EOpRadians:
1680 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301681 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1682 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301683
Olli Etuahof119a262016-08-19 15:54:22 +03001684 case EOpDegrees:
1685 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301686 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1687 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301688
Olli Etuahof119a262016-08-19 15:54:22 +03001689 case EOpSin:
1690 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301691 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301692
Olli Etuahof119a262016-08-19 15:54:22 +03001693 case EOpCos:
1694 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1695 break;
1696
1697 case EOpTan:
1698 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1699 break;
1700
1701 case EOpAsin:
1702 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1703 // 0.
1704 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1705 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1706 diagnostics, &resultArray[i]);
1707 else
1708 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1709 break;
1710
1711 case EOpAcos:
1712 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1713 // 0.
1714 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1715 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1716 diagnostics, &resultArray[i]);
1717 else
1718 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1719 break;
1720
1721 case EOpAtan:
1722 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1723 break;
1724
1725 case EOpSinh:
1726 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1727 break;
1728
1729 case EOpCosh:
1730 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1731 break;
1732
1733 case EOpTanh:
1734 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1735 break;
1736
1737 case EOpAsinh:
1738 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1739 break;
1740
1741 case EOpAcosh:
1742 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1743 if (operandArray[i].getFConst() < 1.0f)
1744 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1745 diagnostics, &resultArray[i]);
1746 else
1747 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1748 break;
1749
1750 case EOpAtanh:
1751 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1752 // 0.
1753 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1754 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1755 diagnostics, &resultArray[i]);
1756 else
1757 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1758 break;
1759
1760 case EOpAbs:
1761 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301762 {
Olli Etuahof119a262016-08-19 15:54:22 +03001763 case EbtFloat:
1764 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1765 break;
1766 case EbtInt:
1767 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1768 break;
1769 default:
1770 UNREACHABLE();
1771 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301772 }
1773 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001774
1775 case EOpSign:
1776 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301777 {
Olli Etuahof119a262016-08-19 15:54:22 +03001778 case EbtFloat:
1779 {
1780 float fConst = operandArray[i].getFConst();
1781 float fResult = 0.0f;
1782 if (fConst > 0.0f)
1783 fResult = 1.0f;
1784 else if (fConst < 0.0f)
1785 fResult = -1.0f;
1786 resultArray[i].setFConst(fResult);
1787 break;
1788 }
1789 case EbtInt:
1790 {
1791 int iConst = operandArray[i].getIConst();
1792 int iResult = 0;
1793 if (iConst > 0)
1794 iResult = 1;
1795 else if (iConst < 0)
1796 iResult = -1;
1797 resultArray[i].setIConst(iResult);
1798 break;
1799 }
1800 default:
1801 UNREACHABLE();
1802 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301803 }
1804 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301805
Olli Etuahof119a262016-08-19 15:54:22 +03001806 case EOpFloor:
1807 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1808 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301809
Olli Etuahof119a262016-08-19 15:54:22 +03001810 case EOpTrunc:
1811 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1812 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301813
Olli Etuahof119a262016-08-19 15:54:22 +03001814 case EOpRound:
1815 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1816 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301817
Olli Etuahof119a262016-08-19 15:54:22 +03001818 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301819 {
Olli Etuahof119a262016-08-19 15:54:22 +03001820 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301821 float x = operandArray[i].getFConst();
1822 float result;
1823 float fractPart = modff(x, &result);
1824 if (fabsf(fractPart) == 0.5f)
1825 result = 2.0f * roundf(x / 2.0f);
1826 else
1827 result = roundf(x);
1828 resultArray[i].setFConst(result);
1829 break;
1830 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301831
Olli Etuahof119a262016-08-19 15:54:22 +03001832 case EOpCeil:
1833 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
1834 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301835
Olli Etuahof119a262016-08-19 15:54:22 +03001836 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301837 {
Olli Etuahof119a262016-08-19 15:54:22 +03001838 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301839 float x = operandArray[i].getFConst();
1840 resultArray[i].setFConst(x - floorf(x));
1841 break;
1842 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301843
Olli Etuahof119a262016-08-19 15:54:22 +03001844 case EOpIsNan:
1845 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301846 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1847 break;
Arun Patole551279e2015-07-07 18:18:23 +05301848
Olli Etuahof119a262016-08-19 15:54:22 +03001849 case EOpIsInf:
1850 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301851 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1852 break;
Arun Patole551279e2015-07-07 18:18:23 +05301853
Olli Etuahof119a262016-08-19 15:54:22 +03001854 case EOpFloatBitsToInt:
1855 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301856 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1857 break;
Arun Patole551279e2015-07-07 18:18:23 +05301858
Olli Etuahof119a262016-08-19 15:54:22 +03001859 case EOpFloatBitsToUint:
1860 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301861 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1862 break;
Arun Patole551279e2015-07-07 18:18:23 +05301863
Olli Etuahof119a262016-08-19 15:54:22 +03001864 case EOpIntBitsToFloat:
1865 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05301866 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1867 break;
Arun Patole551279e2015-07-07 18:18:23 +05301868
Olli Etuahof119a262016-08-19 15:54:22 +03001869 case EOpUintBitsToFloat:
1870 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05301871 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1872 break;
Arun Patole551279e2015-07-07 18:18:23 +05301873
Olli Etuahof119a262016-08-19 15:54:22 +03001874 case EOpExp:
1875 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
1876 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301877
Olli Etuahof119a262016-08-19 15:54:22 +03001878 case EOpLog:
1879 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1880 if (operandArray[i].getFConst() <= 0.0f)
1881 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1882 diagnostics, &resultArray[i]);
1883 else
1884 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1885 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301886
Olli Etuahof119a262016-08-19 15:54:22 +03001887 case EOpExp2:
1888 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
1889 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890
Olli Etuahof119a262016-08-19 15:54:22 +03001891 case EOpLog2:
1892 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1893 // And log2f is not available on some plarforms like old android, so just using
1894 // log(x)/log(2) here.
1895 if (operandArray[i].getFConst() <= 0.0f)
1896 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1897 diagnostics, &resultArray[i]);
1898 else
1899 {
1900 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1901 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1902 }
1903 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301904
Olli Etuahof119a262016-08-19 15:54:22 +03001905 case EOpSqrt:
1906 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1907 if (operandArray[i].getFConst() < 0.0f)
1908 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1909 diagnostics, &resultArray[i]);
1910 else
1911 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1912 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301913
Olli Etuahof119a262016-08-19 15:54:22 +03001914 case EOpInverseSqrt:
1915 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1916 // so getting the square root first using builtin function sqrt() and then taking
1917 // its inverse.
1918 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
1919 // result to 0.
1920 if (operandArray[i].getFConst() <= 0.0f)
1921 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1922 diagnostics, &resultArray[i]);
1923 else
1924 {
1925 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1926 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1927 }
1928 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301929
Olli Etuahof119a262016-08-19 15:54:22 +03001930 case EOpVectorLogicalNot:
1931 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301932 resultArray[i].setBConst(!operandArray[i].getBConst());
1933 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934
Olli Etuahof119a262016-08-19 15:54:22 +03001935 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301936 {
Olli Etuahof119a262016-08-19 15:54:22 +03001937 ASSERT(getType().getBasicType() == EbtFloat);
1938 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301939 float length = VectorLength(operandArray, objectSize);
1940 if (length)
1941 resultArray[i].setFConst(x / length);
1942 else
Olli Etuahof119a262016-08-19 15:54:22 +03001943 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1944 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301945 break;
1946 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947
Olli Etuahof119a262016-08-19 15:54:22 +03001948 case EOpDFdx:
1949 case EOpDFdy:
1950 case EOpFwidth:
1951 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05301952 // Derivatives of constant arguments should be 0.
1953 resultArray[i].setFConst(0.0f);
1954 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05301955
Olli Etuahof119a262016-08-19 15:54:22 +03001956 default:
1957 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301958 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301959 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001960
Arun Patoleab2b9a22015-07-06 18:27:56 +05301961 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001962}
1963
Olli Etuahof119a262016-08-19 15:54:22 +03001964void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
1965 FloatTypeUnaryFunc builtinFunc,
1966 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301967{
1968 ASSERT(builtinFunc);
1969
Olli Etuahof119a262016-08-19 15:54:22 +03001970 ASSERT(getType().getBasicType() == EbtFloat);
1971 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05301972}
1973
Jamie Madillb1a85f42014-08-19 15:23:24 -04001974// static
Olli Etuahof119a262016-08-19 15:54:22 +03001975TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02001976{
1977 ASSERT(aggregate->getSequence()->size() > 0u);
1978 size_t resultSize = aggregate->getType().getObjectSize();
1979 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1980 TBasicType basicType = aggregate->getBasicType();
1981
1982 size_t resultIndex = 0u;
1983
1984 if (aggregate->getSequence()->size() == 1u)
1985 {
1986 TIntermNode *argument = aggregate->getSequence()->front();
1987 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1988 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1989 // Check the special case of constructing a matrix diagonal from a single scalar,
1990 // or a vector from a single scalar.
1991 if (argumentConstant->getType().getObjectSize() == 1u)
1992 {
1993 if (aggregate->isMatrix())
1994 {
1995 int resultCols = aggregate->getType().getCols();
1996 int resultRows = aggregate->getType().getRows();
1997 for (int col = 0; col < resultCols; ++col)
1998 {
1999 for (int row = 0; row < resultRows; ++row)
2000 {
2001 if (col == row)
2002 {
2003 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2004 }
2005 else
2006 {
2007 resultArray[resultIndex].setFConst(0.0f);
2008 }
2009 ++resultIndex;
2010 }
2011 }
2012 }
2013 else
2014 {
2015 while (resultIndex < resultSize)
2016 {
2017 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2018 ++resultIndex;
2019 }
2020 }
2021 ASSERT(resultIndex == resultSize);
2022 return resultArray;
2023 }
2024 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2025 {
2026 // The special case of constructing a matrix from a matrix.
2027 int argumentCols = argumentConstant->getType().getCols();
2028 int argumentRows = argumentConstant->getType().getRows();
2029 int resultCols = aggregate->getType().getCols();
2030 int resultRows = aggregate->getType().getRows();
2031 for (int col = 0; col < resultCols; ++col)
2032 {
2033 for (int row = 0; row < resultRows; ++row)
2034 {
2035 if (col < argumentCols && row < argumentRows)
2036 {
2037 resultArray[resultIndex].cast(basicType,
2038 argumentUnionArray[col * argumentRows + row]);
2039 }
2040 else if (col == row)
2041 {
2042 resultArray[resultIndex].setFConst(1.0f);
2043 }
2044 else
2045 {
2046 resultArray[resultIndex].setFConst(0.0f);
2047 }
2048 ++resultIndex;
2049 }
2050 }
2051 ASSERT(resultIndex == resultSize);
2052 return resultArray;
2053 }
2054 }
2055
2056 for (TIntermNode *&argument : *aggregate->getSequence())
2057 {
2058 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2059 size_t argumentSize = argumentConstant->getType().getObjectSize();
2060 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2061 for (size_t i = 0u; i < argumentSize; ++i)
2062 {
2063 if (resultIndex >= resultSize)
2064 break;
2065 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2066 ++resultIndex;
2067 }
2068 }
2069 ASSERT(resultIndex == resultSize);
2070 return resultArray;
2071}
2072
2073// static
Olli Etuahof119a262016-08-19 15:54:22 +03002074TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2075 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302076{
Olli Etuahob43846e2015-06-02 18:18:57 +03002077 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302078 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002079 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002080 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302081 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002082 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302083 TBasicType basicType = EbtVoid;
2084 TSourceLoc loc;
2085 for (unsigned int i = 0; i < paramsCount; i++)
2086 {
2087 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002088 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302089
2090 if (i == 0)
2091 {
2092 basicType = paramConstant->getType().getBasicType();
2093 loc = paramConstant->getLine();
2094 }
2095 unionArrays[i] = paramConstant->getUnionArrayPointer();
2096 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002097 if (objectSizes[i] > maxObjectSize)
2098 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302099 }
2100
Olli Etuahod5da5052016-08-29 13:16:55 +03002101 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302102 {
2103 for (unsigned int i = 0; i < paramsCount; i++)
2104 if (objectSizes[i] != maxObjectSize)
2105 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2106 }
Arun Patole274f0702015-05-05 13:33:30 +05302107
Olli Etuahob43846e2015-06-02 18:18:57 +03002108 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302109 if (paramsCount == 2)
2110 {
2111 //
2112 // Binary built-in
2113 //
2114 switch (op)
2115 {
Olli Etuahof119a262016-08-19 15:54:22 +03002116 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302117 {
Olli Etuahof119a262016-08-19 15:54:22 +03002118 ASSERT(basicType == EbtFloat);
2119 resultArray = new TConstantUnion[maxObjectSize];
2120 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302121 {
Olli Etuahof119a262016-08-19 15:54:22 +03002122 float y = unionArrays[0][i].getFConst();
2123 float x = unionArrays[1][i].getFConst();
2124 // Results are undefined if x and y are both 0.
2125 if (x == 0.0f && y == 0.0f)
2126 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2127 &resultArray[i]);
2128 else
2129 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302130 }
Olli Etuahof119a262016-08-19 15:54:22 +03002131 break;
Arun Patolebf790422015-05-18 17:53:04 +05302132 }
Arun Patolebf790422015-05-18 17:53:04 +05302133
Olli Etuahof119a262016-08-19 15:54:22 +03002134 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302135 {
Olli Etuahof119a262016-08-19 15:54:22 +03002136 ASSERT(basicType == EbtFloat);
2137 resultArray = new TConstantUnion[maxObjectSize];
2138 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302139 {
Olli Etuahof119a262016-08-19 15:54:22 +03002140 float x = unionArrays[0][i].getFConst();
2141 float y = unionArrays[1][i].getFConst();
2142 // Results are undefined if x < 0.
2143 // Results are undefined if x = 0 and y <= 0.
2144 if (x < 0.0f)
2145 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2146 &resultArray[i]);
2147 else if (x == 0.0f && y <= 0.0f)
2148 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2149 &resultArray[i]);
2150 else
2151 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302152 }
Olli Etuahof119a262016-08-19 15:54:22 +03002153 break;
Arun Patolebf790422015-05-18 17:53:04 +05302154 }
Arun Patolebf790422015-05-18 17:53:04 +05302155
Olli Etuahof119a262016-08-19 15:54:22 +03002156 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302157 {
Olli Etuahof119a262016-08-19 15:54:22 +03002158 ASSERT(basicType == EbtFloat);
2159 resultArray = new TConstantUnion[maxObjectSize];
2160 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302161 {
Olli Etuahof119a262016-08-19 15:54:22 +03002162 float x = unionArrays[0][i].getFConst();
2163 float y = unionArrays[1][i].getFConst();
2164 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302165 }
Olli Etuahof119a262016-08-19 15:54:22 +03002166 break;
Arun Patolebf790422015-05-18 17:53:04 +05302167 }
Arun Patolebf790422015-05-18 17:53:04 +05302168
Olli Etuahof119a262016-08-19 15:54:22 +03002169 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302170 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002171 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302172 for (size_t i = 0; i < maxObjectSize; i++)
2173 {
2174 switch (basicType)
2175 {
Olli Etuahof119a262016-08-19 15:54:22 +03002176 case EbtFloat:
2177 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2178 unionArrays[1][i].getFConst()));
2179 break;
2180 case EbtInt:
2181 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2182 unionArrays[1][i].getIConst()));
2183 break;
2184 case EbtUInt:
2185 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2186 unionArrays[1][i].getUConst()));
2187 break;
2188 default:
2189 UNREACHABLE();
2190 break;
Arun Patole274f0702015-05-05 13:33:30 +05302191 }
2192 }
Olli Etuahof119a262016-08-19 15:54:22 +03002193 break;
Arun Patole274f0702015-05-05 13:33:30 +05302194 }
Arun Patole274f0702015-05-05 13:33:30 +05302195
Olli Etuahof119a262016-08-19 15:54:22 +03002196 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302197 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002198 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302199 for (size_t i = 0; i < maxObjectSize; i++)
2200 {
2201 switch (basicType)
2202 {
Olli Etuahof119a262016-08-19 15:54:22 +03002203 case EbtFloat:
2204 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2205 unionArrays[1][i].getFConst()));
2206 break;
2207 case EbtInt:
2208 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2209 unionArrays[1][i].getIConst()));
2210 break;
2211 case EbtUInt:
2212 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2213 unionArrays[1][i].getUConst()));
2214 break;
2215 default:
2216 UNREACHABLE();
2217 break;
Arun Patole274f0702015-05-05 13:33:30 +05302218 }
2219 }
Olli Etuahof119a262016-08-19 15:54:22 +03002220 break;
Arun Patole274f0702015-05-05 13:33:30 +05302221 }
Arun Patole274f0702015-05-05 13:33:30 +05302222
Olli Etuahof119a262016-08-19 15:54:22 +03002223 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302224 {
Olli Etuahof119a262016-08-19 15:54:22 +03002225 ASSERT(basicType == EbtFloat);
2226 resultArray = new TConstantUnion[maxObjectSize];
2227 for (size_t i = 0; i < maxObjectSize; i++)
2228 resultArray[i].setFConst(
2229 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2230 : 1.0f);
2231 break;
Arun Patolebf790422015-05-18 17:53:04 +05302232 }
Arun Patolebf790422015-05-18 17:53:04 +05302233
Olli Etuahof119a262016-08-19 15:54:22 +03002234 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302235 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002236 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302237 for (size_t i = 0; i < maxObjectSize; i++)
2238 {
2239 switch (basicType)
2240 {
Olli Etuahof119a262016-08-19 15:54:22 +03002241 case EbtFloat:
2242 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2243 unionArrays[1][i].getFConst());
2244 break;
2245 case EbtInt:
2246 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2247 unionArrays[1][i].getIConst());
2248 break;
2249 case EbtUInt:
2250 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2251 unionArrays[1][i].getUConst());
2252 break;
2253 default:
2254 UNREACHABLE();
2255 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302256 }
2257 }
Olli Etuahof119a262016-08-19 15:54:22 +03002258 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302259 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302260
Olli Etuahof119a262016-08-19 15:54:22 +03002261 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302262 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002263 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302264 for (size_t i = 0; i < maxObjectSize; i++)
2265 {
2266 switch (basicType)
2267 {
Olli Etuahof119a262016-08-19 15:54:22 +03002268 case EbtFloat:
2269 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2270 unionArrays[1][i].getFConst());
2271 break;
2272 case EbtInt:
2273 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2274 unionArrays[1][i].getIConst());
2275 break;
2276 case EbtUInt:
2277 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2278 unionArrays[1][i].getUConst());
2279 break;
2280 default:
2281 UNREACHABLE();
2282 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302283 }
2284 }
Olli Etuahof119a262016-08-19 15:54:22 +03002285 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302286 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302287
Olli Etuahof119a262016-08-19 15:54:22 +03002288 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302289 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002290 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302291 for (size_t i = 0; i < maxObjectSize; i++)
2292 {
2293 switch (basicType)
2294 {
Olli Etuahof119a262016-08-19 15:54:22 +03002295 case EbtFloat:
2296 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2297 unionArrays[1][i].getFConst());
2298 break;
2299 case EbtInt:
2300 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2301 unionArrays[1][i].getIConst());
2302 break;
2303 case EbtUInt:
2304 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2305 unionArrays[1][i].getUConst());
2306 break;
2307 default:
2308 UNREACHABLE();
2309 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002310 }
2311 }
Olli Etuahof119a262016-08-19 15:54:22 +03002312 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302313 }
Olli Etuahof119a262016-08-19 15:54:22 +03002314 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302315 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002316 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302317 for (size_t i = 0; i < maxObjectSize; i++)
2318 {
2319 switch (basicType)
2320 {
Olli Etuahof119a262016-08-19 15:54:22 +03002321 case EbtFloat:
2322 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2323 unionArrays[1][i].getFConst());
2324 break;
2325 case EbtInt:
2326 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2327 unionArrays[1][i].getIConst());
2328 break;
2329 case EbtUInt:
2330 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2331 unionArrays[1][i].getUConst());
2332 break;
2333 default:
2334 UNREACHABLE();
2335 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302336 }
2337 }
2338 }
2339 break;
2340
Olli Etuahof119a262016-08-19 15:54:22 +03002341 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302342 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002343 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302344 for (size_t i = 0; i < maxObjectSize; i++)
2345 {
2346 switch (basicType)
2347 {
Olli Etuahof119a262016-08-19 15:54:22 +03002348 case EbtFloat:
2349 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2350 unionArrays[1][i].getFConst());
2351 break;
2352 case EbtInt:
2353 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2354 unionArrays[1][i].getIConst());
2355 break;
2356 case EbtUInt:
2357 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2358 unionArrays[1][i].getUConst());
2359 break;
2360 case EbtBool:
2361 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2362 unionArrays[1][i].getBConst());
2363 break;
2364 default:
2365 UNREACHABLE();
2366 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302367 }
2368 }
Olli Etuahof119a262016-08-19 15:54:22 +03002369 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302370 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302371
Olli Etuahof119a262016-08-19 15:54:22 +03002372 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302373 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002374 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302375 for (size_t i = 0; i < maxObjectSize; i++)
2376 {
2377 switch (basicType)
2378 {
Olli Etuahof119a262016-08-19 15:54:22 +03002379 case EbtFloat:
2380 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2381 unionArrays[1][i].getFConst());
2382 break;
2383 case EbtInt:
2384 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2385 unionArrays[1][i].getIConst());
2386 break;
2387 case EbtUInt:
2388 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2389 unionArrays[1][i].getUConst());
2390 break;
2391 case EbtBool:
2392 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2393 unionArrays[1][i].getBConst());
2394 break;
2395 default:
2396 UNREACHABLE();
2397 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302398 }
2399 }
Olli Etuahof119a262016-08-19 15:54:22 +03002400 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302401 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302402
Olli Etuahof119a262016-08-19 15:54:22 +03002403 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302404 {
Olli Etuahof119a262016-08-19 15:54:22 +03002405 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302406 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002407 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302408 for (size_t i = 0; i < maxObjectSize; i++)
2409 {
2410 float x = unionArrays[0][i].getFConst();
2411 float y = unionArrays[1][i].getFConst();
2412 distanceArray[i].setFConst(x - y);
2413 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002414 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002415 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302416 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302417
Olli Etuahof119a262016-08-19 15:54:22 +03002418 case EOpDot:
2419 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002420 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002421 resultArray->setFConst(
2422 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2423 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302424
Olli Etuahof119a262016-08-19 15:54:22 +03002425 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302426 {
Olli Etuahof119a262016-08-19 15:54:22 +03002427 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002428 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002429 float x0 = unionArrays[0][0].getFConst();
2430 float x1 = unionArrays[0][1].getFConst();
2431 float x2 = unionArrays[0][2].getFConst();
2432 float y0 = unionArrays[1][0].getFConst();
2433 float y1 = unionArrays[1][1].getFConst();
2434 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002435 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2436 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2437 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002438 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302439 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302440
Olli Etuahof119a262016-08-19 15:54:22 +03002441 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302442 {
Olli Etuahof119a262016-08-19 15:54:22 +03002443 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302444 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002445 // For the incident vector I and surface orientation N, returns the reflection
2446 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302447 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002448 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302449 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2450 for (size_t i = 0; i < maxObjectSize; i++)
2451 {
2452 float result = unionArrays[0][i].getFConst() -
2453 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002454 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302455 }
Olli Etuahof119a262016-08-19 15:54:22 +03002456 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302457 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302458
Olli Etuahof119a262016-08-19 15:54:22 +03002459 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302460 {
Olli Etuahof119a262016-08-19 15:54:22 +03002461 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2462 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302463 // Perform component-wise matrix multiplication.
2464 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002465 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302466 angle::Matrix<float> result =
2467 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2468 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002469 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302470 }
Arun Patole7fa33552015-06-10 15:15:18 +05302471
Olli Etuahof119a262016-08-19 15:54:22 +03002472 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302473 {
Olli Etuahof119a262016-08-19 15:54:22 +03002474 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302475 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2476 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002477 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302478 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002479 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2480 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302481 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002482 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302483 }
Arun Patole7fa33552015-06-10 15:15:18 +05302484
Olli Etuahof119a262016-08-19 15:54:22 +03002485 default:
2486 UNREACHABLE();
2487 // TODO: Add constant folding support for other built-in operations that take 2
2488 // parameters and not handled above.
2489 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302490 }
2491 }
2492 else if (paramsCount == 3)
2493 {
2494 //
2495 // Ternary built-in
2496 //
2497 switch (op)
2498 {
Olli Etuahof119a262016-08-19 15:54:22 +03002499 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302500 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002501 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302502 for (size_t i = 0; i < maxObjectSize; i++)
2503 {
2504 switch (basicType)
2505 {
Olli Etuahof119a262016-08-19 15:54:22 +03002506 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302507 {
Olli Etuahof119a262016-08-19 15:54:22 +03002508 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302509 float min = unionArrays[1][i].getFConst();
2510 float max = unionArrays[2][i].getFConst();
2511 // Results are undefined if min > max.
2512 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002513 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2514 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302515 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002516 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002517 break;
Arun Patole274f0702015-05-05 13:33:30 +05302518 }
Olli Etuahof119a262016-08-19 15:54:22 +03002519
2520 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302521 {
Olli Etuahof119a262016-08-19 15:54:22 +03002522 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302523 int min = unionArrays[1][i].getIConst();
2524 int max = unionArrays[2][i].getIConst();
2525 // Results are undefined if min > max.
2526 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002527 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2528 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302529 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002530 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002531 break;
Arun Patole274f0702015-05-05 13:33:30 +05302532 }
Olli Etuahof119a262016-08-19 15:54:22 +03002533 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302534 {
Olli Etuahof119a262016-08-19 15:54:22 +03002535 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302536 unsigned int min = unionArrays[1][i].getUConst();
2537 unsigned int max = unionArrays[2][i].getUConst();
2538 // Results are undefined if min > max.
2539 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002540 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2541 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302542 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002543 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002544 break;
Arun Patole274f0702015-05-05 13:33:30 +05302545 }
Olli Etuahof119a262016-08-19 15:54:22 +03002546 default:
2547 UNREACHABLE();
2548 break;
Arun Patole274f0702015-05-05 13:33:30 +05302549 }
2550 }
Olli Etuahof119a262016-08-19 15:54:22 +03002551 break;
Arun Patole274f0702015-05-05 13:33:30 +05302552 }
Arun Patole274f0702015-05-05 13:33:30 +05302553
Olli Etuahof119a262016-08-19 15:54:22 +03002554 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302555 {
Olli Etuahof119a262016-08-19 15:54:22 +03002556 ASSERT(basicType == EbtFloat);
2557 resultArray = new TConstantUnion[maxObjectSize];
2558 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302559 {
Olli Etuahof119a262016-08-19 15:54:22 +03002560 float x = unionArrays[0][i].getFConst();
2561 float y = unionArrays[1][i].getFConst();
2562 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2563 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302564 {
Olli Etuahof119a262016-08-19 15:54:22 +03002565 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2566 float a = unionArrays[2][i].getFConst();
2567 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2568 }
2569 else // 3rd parameter is EbtBool
2570 {
2571 ASSERT(type == EbtBool);
2572 // Selects which vector each returned component comes from.
2573 // For a component of a that is false, the corresponding component of x is
2574 // returned.
2575 // For a component of a that is true, the corresponding component of y is
2576 // returned.
2577 bool a = unionArrays[2][i].getBConst();
2578 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302579 }
2580 }
Olli Etuahof119a262016-08-19 15:54:22 +03002581 break;
Arun Patolebf790422015-05-18 17:53:04 +05302582 }
Arun Patolebf790422015-05-18 17:53:04 +05302583
Olli Etuahof119a262016-08-19 15:54:22 +03002584 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302585 {
Olli Etuahof119a262016-08-19 15:54:22 +03002586 ASSERT(basicType == EbtFloat);
2587 resultArray = new TConstantUnion[maxObjectSize];
2588 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302589 {
Olli Etuahof119a262016-08-19 15:54:22 +03002590 float edge0 = unionArrays[0][i].getFConst();
2591 float edge1 = unionArrays[1][i].getFConst();
2592 float x = unionArrays[2][i].getFConst();
2593 // Results are undefined if edge0 >= edge1.
2594 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302595 {
Olli Etuahof119a262016-08-19 15:54:22 +03002596 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2597 &resultArray[i]);
2598 }
2599 else
2600 {
2601 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2602 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2603 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2604 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302605 }
2606 }
Olli Etuahof119a262016-08-19 15:54:22 +03002607 break;
Arun Patolebf790422015-05-18 17:53:04 +05302608 }
Arun Patolebf790422015-05-18 17:53:04 +05302609
Olli Etuahof119a262016-08-19 15:54:22 +03002610 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302611 {
Olli Etuahof119a262016-08-19 15:54:22 +03002612 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302613 // genType faceforward(genType N, genType I, genType Nref) :
2614 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002615 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302616 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2617 for (size_t i = 0; i < maxObjectSize; i++)
2618 {
2619 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002620 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302621 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002622 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302623 }
Olli Etuahof119a262016-08-19 15:54:22 +03002624 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302625 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302626
Olli Etuahof119a262016-08-19 15:54:22 +03002627 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302628 {
Olli Etuahof119a262016-08-19 15:54:22 +03002629 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302630 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002631 // For the incident vector I and surface normal N, and the ratio of indices of
2632 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302633 // return the refraction vector. The result is computed by
2634 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2635 // if (k < 0.0)
2636 // return genType(0.0)
2637 // else
2638 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002639 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302640 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2641 for (size_t i = 0; i < maxObjectSize; i++)
2642 {
2643 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002644 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302645 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002646 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302647 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002648 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002649 (eta * dotProduct + sqrtf(k)) *
2650 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302651 }
Olli Etuahof119a262016-08-19 15:54:22 +03002652 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302653 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302654
Olli Etuahof119a262016-08-19 15:54:22 +03002655 default:
2656 UNREACHABLE();
2657 // TODO: Add constant folding support for other built-in operations that take 3
2658 // parameters and not handled above.
2659 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302660 }
2661 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002662 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302663}
2664
2665// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002666TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2667{
2668 if (hashFunction == NULL || name.empty())
2669 return name;
2670 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2671 TStringStream stream;
2672 stream << HASHED_NAME_PREFIX << std::hex << number;
2673 TString hashedName = stream.str();
2674 return hashedName;
2675}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002676
2677void TIntermTraverser::updateTree()
2678{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002679 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2680 {
2681 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2682 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002683 if (!insertion.insertionsAfter.empty())
2684 {
2685 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2686 insertion.insertionsAfter);
2687 ASSERT(inserted);
2688 UNUSED_ASSERTION_VARIABLE(inserted);
2689 }
2690 if (!insertion.insertionsBefore.empty())
2691 {
2692 bool inserted =
2693 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2694 ASSERT(inserted);
2695 UNUSED_ASSERTION_VARIABLE(inserted);
2696 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002697 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002698 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2699 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002700 const NodeUpdateEntry &replacement = mReplacements[ii];
2701 ASSERT(replacement.parent);
2702 bool replaced = replacement.parent->replaceChildNode(
2703 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002704 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002705 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002706
Olli Etuahocd94ef92015-04-16 19:18:10 +03002707 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002708 {
2709 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002710 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002711 // be replaced, we need to make sure we don't update the replaced
2712 // node; instead, we update the replacement node.
2713 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2714 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002715 NodeUpdateEntry &replacement2 = mReplacements[jj];
2716 if (replacement2.parent == replacement.original)
2717 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002718 }
2719 }
2720 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002721 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2722 {
2723 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2724 ASSERT(replacement.parent);
2725 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2726 replacement.original, replacement.replacements);
2727 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002728 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002729 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002730
Jamie Madill03d863c2016-07-27 18:15:53 -04002731 clearReplacementQueue();
2732}
2733
2734void TIntermTraverser::clearReplacementQueue()
2735{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002736 mReplacements.clear();
2737 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002738 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002739}
Jamie Madill1048e432016-07-23 18:51:28 -04002740
Jamie Madill03d863c2016-07-27 18:15:53 -04002741void TIntermTraverser::queueReplacement(TIntermNode *original,
2742 TIntermNode *replacement,
2743 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002744{
Jamie Madill03d863c2016-07-27 18:15:53 -04002745 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002746}
2747
Jamie Madill03d863c2016-07-27 18:15:53 -04002748void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2749 TIntermNode *original,
2750 TIntermNode *replacement,
2751 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002752{
Jamie Madill03d863c2016-07-27 18:15:53 -04002753 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2754 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002755}