blob: 0d4104ea33be85cf97b267172d6a708679cbaba7 [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
Jamie Madillb1a85f42014-08-19 15:23:24 -0400303bool TIntermSelection::replaceChildNode(
304 TIntermNode *original, TIntermNode *replacement)
305{
306 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
307 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
308 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
309 return false;
310}
311
Olli Etuahoa3a36662015-02-17 13:46:51 +0200312bool TIntermSwitch::replaceChildNode(
313 TIntermNode *original, TIntermNode *replacement)
314{
315 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
316 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
317 return false;
318}
319
320bool TIntermCase::replaceChildNode(
321 TIntermNode *original, TIntermNode *replacement)
322{
323 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
324 return false;
325}
326
Olli Etuahod7a25242015-08-18 13:49:45 +0300327TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
328{
329 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
330 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
331 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
332 mLine = node.mLine;
333}
334
Olli Etuahod4f4c112016-04-15 15:11:24 +0300335bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
336{
337 TIntermAggregate *constructor = getAsAggregate();
338 if (!constructor || !constructor->isConstructor())
339 {
340 return false;
341 }
342 for (TIntermNode *&node : *constructor->getSequence())
343 {
344 if (!node->getAsConstantUnion())
345 return false;
346 }
347 return true;
348}
349
Corentin Wallez509e4562016-08-25 14:55:44 -0400350// static
351TIntermTyped *TIntermTyped::CreateIndexNode(int index)
352{
353 TConstantUnion *u = new TConstantUnion[1];
354 u[0].setIConst(index);
355
356 TType type(EbtInt, EbpUndefined, EvqConst, 1);
357 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
358 return node;
359}
360
361// static
362TIntermTyped *TIntermTyped::CreateZero(const TType &type)
363{
364 TType constType(type);
365 constType.setQualifier(EvqConst);
366
367 if (!type.isArray() && type.getBasicType() != EbtStruct)
368 {
369 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
370
371 size_t size = constType.getObjectSize();
372 TConstantUnion *u = new TConstantUnion[size];
373 for (size_t i = 0; i < size; ++i)
374 {
375 switch (type.getBasicType())
376 {
377 case EbtFloat:
378 u[i].setFConst(0.0f);
379 break;
380 case EbtInt:
381 u[i].setIConst(0);
382 break;
383 case EbtUInt:
384 u[i].setUConst(0u);
385 break;
386 case EbtBool:
387 u[i].setBConst(false);
388 break;
389 default:
390 UNREACHABLE();
391 return nullptr;
392 }
393 }
394
395 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
396 return node;
397 }
398
399 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
400 constructor->setType(constType);
401
402 if (type.isArray())
403 {
404 TType elementType(type);
405 elementType.clearArrayness();
406
407 size_t arraySize = type.getArraySize();
408 for (size_t i = 0; i < arraySize; ++i)
409 {
410 constructor->getSequence()->push_back(CreateZero(elementType));
411 }
412 }
413 else
414 {
415 ASSERT(type.getBasicType() == EbtStruct);
416
417 TStructure *structure = type.getStruct();
418 for (const auto &field : structure->fields())
419 {
420 constructor->getSequence()->push_back(CreateZero(*field->type()));
421 }
422 }
423
424 return constructor;
425}
426
Olli Etuahod7a25242015-08-18 13:49:45 +0300427TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
428{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200429 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300430}
431
432TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
433 : TIntermOperator(node),
434 mName(node.mName),
435 mUserDefined(node.mUserDefined),
436 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300437 mUseEmulatedFunction(node.mUseEmulatedFunction),
438 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
439{
440 for (TIntermNode *child : node.mSequence)
441 {
442 TIntermTyped *typedChild = child->getAsTyped();
443 ASSERT(typedChild != nullptr);
444 TIntermTyped *childCopy = typedChild->deepCopy();
445 mSequence.push_back(childCopy);
446 }
447}
448
449TIntermBinary::TIntermBinary(const TIntermBinary &node)
450 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
451{
452 TIntermTyped *leftCopy = node.mLeft->deepCopy();
453 TIntermTyped *rightCopy = node.mRight->deepCopy();
454 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
455 mLeft = leftCopy;
456 mRight = rightCopy;
457}
458
459TIntermUnary::TIntermUnary(const TIntermUnary &node)
460 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
461{
462 TIntermTyped *operandCopy = node.mOperand->deepCopy();
463 ASSERT(operandCopy != nullptr);
464 mOperand = operandCopy;
465}
466
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300467TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300468{
Olli Etuahod7a25242015-08-18 13:49:45 +0300469 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300470 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
471 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300472 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300473 mCondition = conditionCopy;
474 mTrueExpression = trueCopy;
475 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300476}
477
Jamie Madillb1a85f42014-08-19 15:23:24 -0400478bool TIntermOperator::isAssignment() const
479{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300480 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400481}
482
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300483bool TIntermOperator::isMultiplication() const
484{
485 switch (mOp)
486 {
487 case EOpMul:
488 case EOpMatrixTimesMatrix:
489 case EOpMatrixTimesVector:
490 case EOpMatrixTimesScalar:
491 case EOpVectorTimesMatrix:
492 case EOpVectorTimesScalar:
493 return true;
494 default:
495 return false;
496 }
497}
498
Jamie Madillb1a85f42014-08-19 15:23:24 -0400499//
500// returns true if the operator is for one of the constructors
501//
502bool TIntermOperator::isConstructor() const
503{
504 switch (mOp)
505 {
506 case EOpConstructVec2:
507 case EOpConstructVec3:
508 case EOpConstructVec4:
509 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400510 case EOpConstructMat2x3:
511 case EOpConstructMat2x4:
512 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400513 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400514 case EOpConstructMat3x4:
515 case EOpConstructMat4x2:
516 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400517 case EOpConstructMat4:
518 case EOpConstructFloat:
519 case EOpConstructIVec2:
520 case EOpConstructIVec3:
521 case EOpConstructIVec4:
522 case EOpConstructInt:
523 case EOpConstructUVec2:
524 case EOpConstructUVec3:
525 case EOpConstructUVec4:
526 case EOpConstructUInt:
527 case EOpConstructBVec2:
528 case EOpConstructBVec3:
529 case EOpConstructBVec4:
530 case EOpConstructBool:
531 case EOpConstructStruct:
532 return true;
533 default:
534 return false;
535 }
536}
537
Olli Etuaho1dded802016-08-18 18:13:13 +0300538TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
539{
540 if (left.isMatrix())
541 {
542 if (right.isMatrix())
543 {
544 return EOpMatrixTimesMatrix;
545 }
546 else
547 {
548 if (right.isVector())
549 {
550 return EOpMatrixTimesVector;
551 }
552 else
553 {
554 return EOpMatrixTimesScalar;
555 }
556 }
557 }
558 else
559 {
560 if (right.isMatrix())
561 {
562 if (left.isVector())
563 {
564 return EOpVectorTimesMatrix;
565 }
566 else
567 {
568 return EOpMatrixTimesScalar;
569 }
570 }
571 else
572 {
573 // Neither operand is a matrix.
574 if (left.isVector() == right.isVector())
575 {
576 // Leave as component product.
577 return EOpMul;
578 }
579 else
580 {
581 return EOpVectorTimesScalar;
582 }
583 }
584 }
585}
586
587TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
588{
589 if (left.isMatrix())
590 {
591 if (right.isMatrix())
592 {
593 return EOpMatrixTimesMatrixAssign;
594 }
595 else
596 {
597 // right should be scalar, but this may not be validated yet.
598 return EOpMatrixTimesScalarAssign;
599 }
600 }
601 else
602 {
603 if (right.isMatrix())
604 {
605 // Left should be a vector, but this may not be validated yet.
606 return EOpVectorTimesMatrixAssign;
607 }
608 else
609 {
610 // Neither operand is a matrix.
611 if (left.isVector() == right.isVector())
612 {
613 // Leave as component product.
614 return EOpMulAssign;
615 }
616 else
617 {
618 // left should be vector and right should be scalar, but this may not be validated
619 // yet.
620 return EOpVectorTimesScalarAssign;
621 }
622 }
623 }
624}
625
Jamie Madillb1a85f42014-08-19 15:23:24 -0400626//
627// Make sure the type of a unary operator is appropriate for its
628// combination of operation and operand type.
629//
Olli Etuahoa2234302016-08-31 12:05:39 +0300630void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400631{
Olli Etuahoa2234302016-08-31 12:05:39 +0300632 TQualifier resultQualifier = EvqTemporary;
633 if (mOperand->getQualifier() == EvqConst)
634 resultQualifier = EvqConst;
635
636 unsigned char operandPrimarySize =
637 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400638 switch (mOp)
639 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300640 case EOpFloatBitsToInt:
641 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
642 break;
643 case EOpFloatBitsToUint:
644 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
645 break;
646 case EOpIntBitsToFloat:
647 case EOpUintBitsToFloat:
648 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
649 break;
650 case EOpPackSnorm2x16:
651 case EOpPackUnorm2x16:
652 case EOpPackHalf2x16:
653 setType(TType(EbtUInt, EbpHigh, resultQualifier));
654 break;
655 case EOpUnpackSnorm2x16:
656 case EOpUnpackUnorm2x16:
657 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
658 break;
659 case EOpUnpackHalf2x16:
660 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
661 break;
662 case EOpAny:
663 case EOpAll:
664 setType(TType(EbtBool, EbpUndefined, resultQualifier));
665 break;
666 case EOpLength:
667 case EOpDeterminant:
668 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
669 break;
670 case EOpTranspose:
671 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
672 static_cast<unsigned char>(mOperand->getType().getRows()),
673 static_cast<unsigned char>(mOperand->getType().getCols())));
674 break;
675 case EOpIsInf:
676 case EOpIsNan:
677 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
678 break;
679 default:
680 setType(mOperand->getType());
681 mType.setQualifier(resultQualifier);
682 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400683 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300684}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400685
Olli Etuahoa2234302016-08-31 12:05:39 +0300686TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
687 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
688{
689 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400690}
691
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300692TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
693 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
694{
695 promote();
696}
697
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300698TIntermTernary::TIntermTernary(TIntermTyped *cond,
699 TIntermTyped *trueExpression,
700 TIntermTyped *falseExpression)
701 : TIntermTyped(trueExpression->getType()),
702 mCondition(cond),
703 mTrueExpression(trueExpression),
704 mFalseExpression(falseExpression)
705{
706 getTypePointer()->setQualifier(
707 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
708}
709
710// static
711TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
712 TIntermTyped *trueExpression,
713 TIntermTyped *falseExpression)
714{
715 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
716 falseExpression->getQualifier() == EvqConst)
717 {
718 return EvqConst;
719 }
720 return EvqTemporary;
721}
722
Jamie Madillb1a85f42014-08-19 15:23:24 -0400723//
724// Establishes the type of the resultant operation, as well as
725// makes the operator the correct one for the operands.
726//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200727// For lots of operations it should already be established that the operand
728// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400729//
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300730void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400731{
Olli Etuaho1dded802016-08-18 18:13:13 +0300732 ASSERT(!isMultiplication() ||
733 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
734
Jamie Madillb1a85f42014-08-19 15:23:24 -0400735 // Base assumption: just make the type the same as the left
736 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400737 setType(mLeft->getType());
738
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200739 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400740 // Binary operations results in temporary variables unless both
741 // operands are const.
742 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
743 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200744 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400745 getTypePointer()->setQualifier(EvqTemporary);
746 }
747
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300748 // Handle indexing ops.
749 switch (mOp)
750 {
751 case EOpIndexDirect:
752 case EOpIndexIndirect:
753 if (mLeft->isArray())
754 {
755 mType.clearArrayness();
756 }
757 else if (mLeft->isMatrix())
758 {
759 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
760 static_cast<unsigned char>(mLeft->getRows())));
761 }
762 else if (mLeft->isVector())
763 {
764 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
765 }
766 else
767 {
768 UNREACHABLE();
769 }
770 return;
771 case EOpIndexDirectStruct:
772 {
773 const TFieldList &fields = mLeft->getType().getStruct()->fields();
774 const int i = mRight->getAsConstantUnion()->getIConst(0);
775 setType(*fields[i]->type());
776 getTypePointer()->setQualifier(resultQualifier);
777 return;
778 }
779 case EOpIndexDirectInterfaceBlock:
780 {
781 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
782 const int i = mRight->getAsConstantUnion()->getIConst(0);
783 setType(*fields[i]->type());
784 getTypePointer()->setQualifier(resultQualifier);
785 return;
786 }
787 case EOpVectorSwizzle:
788 {
789 auto numFields = mRight->getAsAggregate()->getSequence()->size();
790 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
791 static_cast<unsigned char>(numFields)));
792 return;
793 }
794 default:
795 break;
796 }
797
798 ASSERT(mLeft->isArray() == mRight->isArray());
799
800 // The result gets promoted to the highest precision.
801 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
802 getTypePointer()->setPrecision(higherPrecision);
803
Jamie Madillb1a85f42014-08-19 15:23:24 -0400804 const int nominalSize =
805 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
806
807 //
808 // All scalars or structs. Code after this test assumes this case is removed!
809 //
810 if (nominalSize == 1)
811 {
812 switch (mOp)
813 {
814 //
815 // Promote to conditional
816 //
817 case EOpEqual:
818 case EOpNotEqual:
819 case EOpLessThan:
820 case EOpGreaterThan:
821 case EOpLessThanEqual:
822 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300823 setType(TType(EbtBool, EbpUndefined, resultQualifier));
824 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400825
826 //
827 // And and Or operate on conditionals
828 //
829 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200830 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400831 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200832 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300833 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400834 break;
835
836 default:
837 break;
838 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300839 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400840 }
841
842 // If we reach here, at least one of the operands is vector or matrix.
843 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400844 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300845
Jamie Madillb1a85f42014-08-19 15:23:24 -0400846 switch (mOp)
847 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300848 case EOpMul:
849 break;
850 case EOpMatrixTimesScalar:
851 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400852 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200853 setType(TType(basicType, higherPrecision, resultQualifier,
854 static_cast<unsigned char>(mRight->getCols()),
855 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400856 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300857 break;
858 case EOpMatrixTimesVector:
859 setType(TType(basicType, higherPrecision, resultQualifier,
860 static_cast<unsigned char>(mLeft->getRows()), 1));
861 break;
862 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200863 setType(TType(basicType, higherPrecision, resultQualifier,
864 static_cast<unsigned char>(mRight->getCols()),
865 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300866 break;
867 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200868 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300869 static_cast<unsigned char>(nominalSize), 1));
870 break;
871 case EOpVectorTimesMatrix:
872 setType(TType(basicType, higherPrecision, resultQualifier,
873 static_cast<unsigned char>(mRight->getCols()), 1));
874 break;
875 case EOpMulAssign:
876 case EOpVectorTimesScalarAssign:
877 case EOpVectorTimesMatrixAssign:
878 case EOpMatrixTimesScalarAssign:
879 case EOpMatrixTimesMatrixAssign:
880 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
881 break;
882 case EOpAssign:
883 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300884 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
885 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
886 break;
887 case EOpAdd:
888 case EOpSub:
889 case EOpDiv:
890 case EOpIMod:
891 case EOpBitShiftLeft:
892 case EOpBitShiftRight:
893 case EOpBitwiseAnd:
894 case EOpBitwiseXor:
895 case EOpBitwiseOr:
896 case EOpAddAssign:
897 case EOpSubAssign:
898 case EOpDivAssign:
899 case EOpIModAssign:
900 case EOpBitShiftLeftAssign:
901 case EOpBitShiftRightAssign:
902 case EOpBitwiseAndAssign:
903 case EOpBitwiseXorAssign:
904 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300905 {
906 const int secondarySize =
907 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
908 setType(TType(basicType, higherPrecision, resultQualifier,
909 static_cast<unsigned char>(nominalSize),
910 static_cast<unsigned char>(secondarySize)));
911 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300912 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300913 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300914 case EOpEqual:
915 case EOpNotEqual:
916 case EOpLessThan:
917 case EOpGreaterThan:
918 case EOpLessThanEqual:
919 case EOpGreaterThanEqual:
920 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
921 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300922 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300923 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400924
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300925 case EOpIndexDirect:
926 case EOpIndexIndirect:
927 case EOpIndexDirectInterfaceBlock:
928 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300929 case EOpVectorSwizzle:
930 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300931 UNREACHABLE();
932 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300933 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300934 UNREACHABLE();
935 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400936 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400937}
938
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300939const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300940{
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300941 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300942 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300943 ASSERT(index < static_cast<int>(getType().getArraySize()));
944 TType arrayElementType = getType();
945 arrayElementType.clearArrayness();
946 size_t arrayElementSize = arrayElementType.getObjectSize();
947 return &mUnionArrayPointer[arrayElementSize * index];
948 }
949 else if (isMatrix())
950 {
951 ASSERT(index < getType().getCols());
952 int size = getType().getRows();
953 return &mUnionArrayPointer[size * index];
954 }
955 else if (isVector())
956 {
957 ASSERT(index < getType().getNominalSize());
958 return &mUnionArrayPointer[index];
959 }
960 else
961 {
962 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300963 return nullptr;
964 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300965}
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200966
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300967TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
968{
969 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
970 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
971 switch (mOp)
972 {
973 case EOpIndexDirect:
974 {
975 if (leftConstant == nullptr || rightConstant == nullptr)
976 {
977 return nullptr;
978 }
979 int index = rightConstant->getIConst(0);
980
981 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
982 return CreateFoldedNode(constArray, this, mType.getQualifier());
983 }
984 case EOpIndexDirectStruct:
985 {
986 if (leftConstant == nullptr || rightConstant == nullptr)
987 {
988 return nullptr;
989 }
990 const TFieldList &fields = mLeft->getType().getStruct()->fields();
991 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
992
993 size_t previousFieldsSize = 0;
994 for (size_t i = 0; i < index; ++i)
995 {
996 previousFieldsSize += fields[i]->type()->getObjectSize();
997 }
998
999 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1000 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1001 }
1002 case EOpIndexIndirect:
1003 case EOpIndexDirectInterfaceBlock:
1004 // Can never be constant folded.
1005 return nullptr;
1006 case EOpVectorSwizzle:
1007 {
1008 if (leftConstant == nullptr)
1009 {
1010 return nullptr;
1011 }
1012 TIntermAggregate *fieldsAgg = mRight->getAsAggregate();
1013 TIntermSequence *fieldsSequence = fieldsAgg->getSequence();
1014 size_t numFields = fieldsSequence->size();
1015
1016 TConstantUnion *constArray = new TConstantUnion[numFields];
1017 for (size_t i = 0; i < numFields; i++)
1018 {
1019 int fieldOffset = fieldsSequence->at(i)->getAsConstantUnion()->getIConst(0);
1020 constArray[i] = *leftConstant->foldIndexing(fieldOffset);
1021 }
1022 return CreateFoldedNode(constArray, this, mType.getQualifier());
1023 }
1024 default:
1025 {
1026 if (leftConstant == nullptr || rightConstant == nullptr)
1027 {
1028 return nullptr;
1029 }
1030 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
1031
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,
1101 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001102{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001103 const TConstantUnion *leftArray = getUnionArrayPointer();
1104 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001105
Olli Etuahof119a262016-08-19 15:54:22 +03001106 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001107
1108 size_t objectSize = getType().getObjectSize();
1109
1110 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1111 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1112 {
1113 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1114 }
1115 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1116 {
1117 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1118 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1119 objectSize = rightNode->getType().getObjectSize();
1120 }
1121
1122 TConstantUnion *resultArray = nullptr;
1123
1124 switch(op)
1125 {
1126 case EOpAdd:
1127 resultArray = new TConstantUnion[objectSize];
1128 for (size_t i = 0; i < objectSize; i++)
1129 resultArray[i] = leftArray[i] + rightArray[i];
1130 break;
1131 case EOpSub:
1132 resultArray = new TConstantUnion[objectSize];
1133 for (size_t i = 0; i < objectSize; i++)
1134 resultArray[i] = leftArray[i] - rightArray[i];
1135 break;
1136
1137 case EOpMul:
1138 case EOpVectorTimesScalar:
1139 case EOpMatrixTimesScalar:
1140 resultArray = new TConstantUnion[objectSize];
1141 for (size_t i = 0; i < objectSize; i++)
1142 resultArray[i] = leftArray[i] * rightArray[i];
1143 break;
1144
1145 case EOpMatrixTimesMatrix:
1146 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001147 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001148
1149 const int leftCols = getCols();
1150 const int leftRows = getRows();
1151 const int rightCols = rightNode->getType().getCols();
1152 const int rightRows = rightNode->getType().getRows();
1153 const int resultCols = rightCols;
1154 const int resultRows = leftRows;
1155
1156 resultArray = new TConstantUnion[resultCols * resultRows];
1157 for (int row = 0; row < resultRows; row++)
1158 {
1159 for (int column = 0; column < resultCols; column++)
1160 {
1161 resultArray[resultRows * column + row].setFConst(0.0f);
1162 for (int i = 0; i < leftCols; i++)
1163 {
1164 resultArray[resultRows * column + row].setFConst(
1165 resultArray[resultRows * column + row].getFConst() +
1166 leftArray[i * leftRows + row].getFConst() *
1167 rightArray[column * rightRows + i].getFConst());
1168 }
1169 }
1170 }
1171 }
1172 break;
1173
1174 case EOpDiv:
1175 case EOpIMod:
1176 {
1177 resultArray = new TConstantUnion[objectSize];
1178 for (size_t i = 0; i < objectSize; i++)
1179 {
1180 switch (getType().getBasicType())
1181 {
1182 case EbtFloat:
1183 if (rightArray[i] == 0.0f)
1184 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001185 diagnostics->warning(
1186 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001187 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1188 }
1189 else
1190 {
1191 ASSERT(op == EOpDiv);
1192 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1193 }
1194 break;
1195
1196 case EbtInt:
1197 if (rightArray[i] == 0)
1198 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001199 diagnostics->warning(
1200 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001201 resultArray[i].setIConst(INT_MAX);
1202 }
1203 else
1204 {
1205 if (op == EOpDiv)
1206 {
1207 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1208 }
1209 else
1210 {
1211 ASSERT(op == EOpIMod);
1212 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1213 }
1214 }
1215 break;
1216
1217 case EbtUInt:
1218 if (rightArray[i] == 0)
1219 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001220 diagnostics->warning(
1221 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001222 resultArray[i].setUConst(UINT_MAX);
1223 }
1224 else
1225 {
1226 if (op == EOpDiv)
1227 {
1228 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1229 }
1230 else
1231 {
1232 ASSERT(op == EOpIMod);
1233 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1234 }
1235 }
1236 break;
1237
1238 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001239 UNREACHABLE();
1240 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001241 }
1242 }
1243 }
1244 break;
1245
1246 case EOpMatrixTimesVector:
1247 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001248 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001249
1250 const int matrixCols = getCols();
1251 const int matrixRows = getRows();
1252
1253 resultArray = new TConstantUnion[matrixRows];
1254
1255 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1256 {
1257 resultArray[matrixRow].setFConst(0.0f);
1258 for (int col = 0; col < matrixCols; col++)
1259 {
1260 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1261 leftArray[col * matrixRows + matrixRow].getFConst() *
1262 rightArray[col].getFConst());
1263 }
1264 }
1265 }
1266 break;
1267
1268 case EOpVectorTimesMatrix:
1269 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001270 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001271
1272 const int matrixCols = rightNode->getType().getCols();
1273 const int matrixRows = rightNode->getType().getRows();
1274
1275 resultArray = new TConstantUnion[matrixCols];
1276
1277 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1278 {
1279 resultArray[matrixCol].setFConst(0.0f);
1280 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1281 {
1282 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1283 leftArray[matrixRow].getFConst() *
1284 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1285 }
1286 }
1287 }
1288 break;
1289
1290 case EOpLogicalAnd:
1291 {
1292 resultArray = new TConstantUnion[objectSize];
1293 for (size_t i = 0; i < objectSize; i++)
1294 {
1295 resultArray[i] = leftArray[i] && rightArray[i];
1296 }
1297 }
1298 break;
1299
1300 case EOpLogicalOr:
1301 {
1302 resultArray = new TConstantUnion[objectSize];
1303 for (size_t i = 0; i < objectSize; i++)
1304 {
1305 resultArray[i] = leftArray[i] || rightArray[i];
1306 }
1307 }
1308 break;
1309
1310 case EOpLogicalXor:
1311 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001312 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001313 resultArray = new TConstantUnion[objectSize];
1314 for (size_t i = 0; i < objectSize; i++)
1315 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001316 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001317 }
1318 }
1319 break;
1320
1321 case EOpBitwiseAnd:
1322 resultArray = new TConstantUnion[objectSize];
1323 for (size_t i = 0; i < objectSize; i++)
1324 resultArray[i] = leftArray[i] & rightArray[i];
1325 break;
1326 case EOpBitwiseXor:
1327 resultArray = new TConstantUnion[objectSize];
1328 for (size_t i = 0; i < objectSize; i++)
1329 resultArray[i] = leftArray[i] ^ rightArray[i];
1330 break;
1331 case EOpBitwiseOr:
1332 resultArray = new TConstantUnion[objectSize];
1333 for (size_t i = 0; i < objectSize; i++)
1334 resultArray[i] = leftArray[i] | rightArray[i];
1335 break;
1336 case EOpBitShiftLeft:
1337 resultArray = new TConstantUnion[objectSize];
1338 for (size_t i = 0; i < objectSize; i++)
1339 resultArray[i] = leftArray[i] << rightArray[i];
1340 break;
1341 case EOpBitShiftRight:
1342 resultArray = new TConstantUnion[objectSize];
1343 for (size_t i = 0; i < objectSize; i++)
1344 resultArray[i] = leftArray[i] >> rightArray[i];
1345 break;
1346
1347 case EOpLessThan:
1348 ASSERT(objectSize == 1);
1349 resultArray = new TConstantUnion[1];
1350 resultArray->setBConst(*leftArray < *rightArray);
1351 break;
1352
1353 case EOpGreaterThan:
1354 ASSERT(objectSize == 1);
1355 resultArray = new TConstantUnion[1];
1356 resultArray->setBConst(*leftArray > *rightArray);
1357 break;
1358
1359 case EOpLessThanEqual:
1360 ASSERT(objectSize == 1);
1361 resultArray = new TConstantUnion[1];
1362 resultArray->setBConst(!(*leftArray > *rightArray));
1363 break;
1364
1365 case EOpGreaterThanEqual:
1366 ASSERT(objectSize == 1);
1367 resultArray = new TConstantUnion[1];
1368 resultArray->setBConst(!(*leftArray < *rightArray));
1369 break;
1370
1371 case EOpEqual:
1372 case EOpNotEqual:
1373 {
1374 resultArray = new TConstantUnion[1];
1375 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001376 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001377 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001378 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001379 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001380 equal = false;
1381 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001382 }
1383 }
1384 if (op == EOpEqual)
1385 {
1386 resultArray->setBConst(equal);
1387 }
1388 else
1389 {
1390 resultArray->setBConst(!equal);
1391 }
1392 }
1393 break;
1394
1395 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001396 UNREACHABLE();
1397 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001398 }
1399 return resultArray;
1400}
1401
Olli Etuahof119a262016-08-19 15:54:22 +03001402// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1403// code. Returns the constant value to keep using. Nullptr should not be returned.
1404TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001405{
Olli Etuahof119a262016-08-19 15:54:22 +03001406 // Do operations where the return type may have a different number of components compared to the
1407 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001408
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001409 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001410 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301411
1412 size_t objectSize = getType().getObjectSize();
1413 TConstantUnion *resultArray = nullptr;
1414 switch (op)
1415 {
Olli Etuahof119a262016-08-19 15:54:22 +03001416 case EOpAny:
1417 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301418 resultArray = new TConstantUnion();
1419 resultArray->setBConst(false);
1420 for (size_t i = 0; i < objectSize; i++)
1421 {
1422 if (operandArray[i].getBConst())
1423 {
1424 resultArray->setBConst(true);
1425 break;
1426 }
1427 }
1428 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301429
Olli Etuahof119a262016-08-19 15:54:22 +03001430 case EOpAll:
1431 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301432 resultArray = new TConstantUnion();
1433 resultArray->setBConst(true);
1434 for (size_t i = 0; i < objectSize; i++)
1435 {
1436 if (!operandArray[i].getBConst())
1437 {
1438 resultArray->setBConst(false);
1439 break;
1440 }
1441 }
1442 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301443
Olli Etuahof119a262016-08-19 15:54:22 +03001444 case EOpLength:
1445 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301446 resultArray = new TConstantUnion();
1447 resultArray->setFConst(VectorLength(operandArray, objectSize));
1448 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301449
Olli Etuahof119a262016-08-19 15:54:22 +03001450 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301451 {
Olli Etuahof119a262016-08-19 15:54:22 +03001452 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301453 resultArray = new TConstantUnion[objectSize];
1454 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001455 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301456 SetUnionArrayFromMatrix(result, resultArray);
1457 break;
1458 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301459
Olli Etuahof119a262016-08-19 15:54:22 +03001460 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301461 {
Olli Etuahof119a262016-08-19 15:54:22 +03001462 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301463 unsigned int size = getType().getNominalSize();
1464 ASSERT(size >= 2 && size <= 4);
1465 resultArray = new TConstantUnion();
1466 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1467 break;
1468 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301469
Olli Etuahof119a262016-08-19 15:54:22 +03001470 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301471 {
Olli Etuahof119a262016-08-19 15:54:22 +03001472 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301473 unsigned int size = getType().getNominalSize();
1474 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001475 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301476 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1477 SetUnionArrayFromMatrix(result, resultArray);
1478 break;
1479 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301480
Olli Etuahof119a262016-08-19 15:54:22 +03001481 case EOpPackSnorm2x16:
1482 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301483 ASSERT(getType().getNominalSize() == 2);
1484 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001485 resultArray->setUConst(
1486 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301487 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301488
Olli Etuahof119a262016-08-19 15:54:22 +03001489 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301490 {
Olli Etuahof119a262016-08-19 15:54:22 +03001491 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301492 resultArray = new TConstantUnion[2];
1493 float f1, f2;
1494 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1495 resultArray[0].setFConst(f1);
1496 resultArray[1].setFConst(f2);
1497 break;
1498 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301499
Olli Etuahof119a262016-08-19 15:54:22 +03001500 case EOpPackUnorm2x16:
1501 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301502 ASSERT(getType().getNominalSize() == 2);
1503 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001504 resultArray->setUConst(
1505 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301506 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301507
Olli Etuahof119a262016-08-19 15:54:22 +03001508 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301509 {
Olli Etuahof119a262016-08-19 15:54:22 +03001510 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301511 resultArray = new TConstantUnion[2];
1512 float f1, f2;
1513 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1514 resultArray[0].setFConst(f1);
1515 resultArray[1].setFConst(f2);
1516 break;
1517 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301518
Olli Etuahof119a262016-08-19 15:54:22 +03001519 case EOpPackHalf2x16:
1520 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301521 ASSERT(getType().getNominalSize() == 2);
1522 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001523 resultArray->setUConst(
1524 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301525 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301526
Olli Etuahof119a262016-08-19 15:54:22 +03001527 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301528 {
Olli Etuahof119a262016-08-19 15:54:22 +03001529 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301530 resultArray = new TConstantUnion[2];
1531 float f1, f2;
1532 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1533 resultArray[0].setFConst(f1);
1534 resultArray[1].setFConst(f2);
1535 break;
1536 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301537
Olli Etuahof119a262016-08-19 15:54:22 +03001538 default:
1539 UNREACHABLE();
1540 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301541 }
1542
1543 return resultArray;
1544}
1545
Olli Etuahof119a262016-08-19 15:54:22 +03001546TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1547 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301548{
Olli Etuahof119a262016-08-19 15:54:22 +03001549 // Do unary operations where each component of the result is computed based on the corresponding
1550 // component of the operand. Also folds normalize, though the divisor in that case takes all
1551 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301552
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001553 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001554 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001555
1556 size_t objectSize = getType().getObjectSize();
1557
Arun Patoleab2b9a22015-07-06 18:27:56 +05301558 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1559 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301560 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301561 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301562 {
Olli Etuahof119a262016-08-19 15:54:22 +03001563 case EOpNegative:
1564 switch (getType().getBasicType())
1565 {
1566 case EbtFloat:
1567 resultArray[i].setFConst(-operandArray[i].getFConst());
1568 break;
1569 case EbtInt:
1570 resultArray[i].setIConst(-operandArray[i].getIConst());
1571 break;
1572 case EbtUInt:
1573 resultArray[i].setUConst(static_cast<unsigned int>(
1574 -static_cast<int>(operandArray[i].getUConst())));
1575 break;
1576 default:
1577 UNREACHABLE();
1578 return nullptr;
1579 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301580 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301581
Olli Etuahof119a262016-08-19 15:54:22 +03001582 case EOpPositive:
1583 switch (getType().getBasicType())
1584 {
1585 case EbtFloat:
1586 resultArray[i].setFConst(operandArray[i].getFConst());
1587 break;
1588 case EbtInt:
1589 resultArray[i].setIConst(operandArray[i].getIConst());
1590 break;
1591 case EbtUInt:
1592 resultArray[i].setUConst(static_cast<unsigned int>(
1593 static_cast<int>(operandArray[i].getUConst())));
1594 break;
1595 default:
1596 UNREACHABLE();
1597 return nullptr;
1598 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301599 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301600
Olli Etuahof119a262016-08-19 15:54:22 +03001601 case EOpLogicalNot:
1602 switch (getType().getBasicType())
1603 {
1604 case EbtBool:
1605 resultArray[i].setBConst(!operandArray[i].getBConst());
1606 break;
1607 default:
1608 UNREACHABLE();
1609 return nullptr;
1610 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301611 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301612
Olli Etuahof119a262016-08-19 15:54:22 +03001613 case EOpBitwiseNot:
1614 switch (getType().getBasicType())
1615 {
1616 case EbtInt:
1617 resultArray[i].setIConst(~operandArray[i].getIConst());
1618 break;
1619 case EbtUInt:
1620 resultArray[i].setUConst(~operandArray[i].getUConst());
1621 break;
1622 default:
1623 UNREACHABLE();
1624 return nullptr;
1625 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301626 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301627
Olli Etuahof119a262016-08-19 15:54:22 +03001628 case EOpRadians:
1629 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301630 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1631 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301632
Olli Etuahof119a262016-08-19 15:54:22 +03001633 case EOpDegrees:
1634 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301635 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1636 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301637
Olli Etuahof119a262016-08-19 15:54:22 +03001638 case EOpSin:
1639 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301640 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301641
Olli Etuahof119a262016-08-19 15:54:22 +03001642 case EOpCos:
1643 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1644 break;
1645
1646 case EOpTan:
1647 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1648 break;
1649
1650 case EOpAsin:
1651 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1652 // 0.
1653 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1654 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1655 diagnostics, &resultArray[i]);
1656 else
1657 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1658 break;
1659
1660 case EOpAcos:
1661 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1662 // 0.
1663 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1664 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1665 diagnostics, &resultArray[i]);
1666 else
1667 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1668 break;
1669
1670 case EOpAtan:
1671 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1672 break;
1673
1674 case EOpSinh:
1675 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1676 break;
1677
1678 case EOpCosh:
1679 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1680 break;
1681
1682 case EOpTanh:
1683 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1684 break;
1685
1686 case EOpAsinh:
1687 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1688 break;
1689
1690 case EOpAcosh:
1691 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1692 if (operandArray[i].getFConst() < 1.0f)
1693 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1694 diagnostics, &resultArray[i]);
1695 else
1696 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1697 break;
1698
1699 case EOpAtanh:
1700 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1701 // 0.
1702 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1703 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1704 diagnostics, &resultArray[i]);
1705 else
1706 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1707 break;
1708
1709 case EOpAbs:
1710 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301711 {
Olli Etuahof119a262016-08-19 15:54:22 +03001712 case EbtFloat:
1713 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1714 break;
1715 case EbtInt:
1716 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1717 break;
1718 default:
1719 UNREACHABLE();
1720 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301721 }
1722 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001723
1724 case EOpSign:
1725 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301726 {
Olli Etuahof119a262016-08-19 15:54:22 +03001727 case EbtFloat:
1728 {
1729 float fConst = operandArray[i].getFConst();
1730 float fResult = 0.0f;
1731 if (fConst > 0.0f)
1732 fResult = 1.0f;
1733 else if (fConst < 0.0f)
1734 fResult = -1.0f;
1735 resultArray[i].setFConst(fResult);
1736 break;
1737 }
1738 case EbtInt:
1739 {
1740 int iConst = operandArray[i].getIConst();
1741 int iResult = 0;
1742 if (iConst > 0)
1743 iResult = 1;
1744 else if (iConst < 0)
1745 iResult = -1;
1746 resultArray[i].setIConst(iResult);
1747 break;
1748 }
1749 default:
1750 UNREACHABLE();
1751 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301752 }
1753 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301754
Olli Etuahof119a262016-08-19 15:54:22 +03001755 case EOpFloor:
1756 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1757 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301758
Olli Etuahof119a262016-08-19 15:54:22 +03001759 case EOpTrunc:
1760 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1761 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301762
Olli Etuahof119a262016-08-19 15:54:22 +03001763 case EOpRound:
1764 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1765 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301766
Olli Etuahof119a262016-08-19 15:54:22 +03001767 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301768 {
Olli Etuahof119a262016-08-19 15:54:22 +03001769 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301770 float x = operandArray[i].getFConst();
1771 float result;
1772 float fractPart = modff(x, &result);
1773 if (fabsf(fractPart) == 0.5f)
1774 result = 2.0f * roundf(x / 2.0f);
1775 else
1776 result = roundf(x);
1777 resultArray[i].setFConst(result);
1778 break;
1779 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301780
Olli Etuahof119a262016-08-19 15:54:22 +03001781 case EOpCeil:
1782 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
1783 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301784
Olli Etuahof119a262016-08-19 15:54:22 +03001785 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786 {
Olli Etuahof119a262016-08-19 15:54:22 +03001787 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301788 float x = operandArray[i].getFConst();
1789 resultArray[i].setFConst(x - floorf(x));
1790 break;
1791 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301792
Olli Etuahof119a262016-08-19 15:54:22 +03001793 case EOpIsNan:
1794 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301795 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1796 break;
Arun Patole551279e2015-07-07 18:18:23 +05301797
Olli Etuahof119a262016-08-19 15:54:22 +03001798 case EOpIsInf:
1799 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301800 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1801 break;
Arun Patole551279e2015-07-07 18:18:23 +05301802
Olli Etuahof119a262016-08-19 15:54:22 +03001803 case EOpFloatBitsToInt:
1804 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301805 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1806 break;
Arun Patole551279e2015-07-07 18:18:23 +05301807
Olli Etuahof119a262016-08-19 15:54:22 +03001808 case EOpFloatBitsToUint:
1809 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301810 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1811 break;
Arun Patole551279e2015-07-07 18:18:23 +05301812
Olli Etuahof119a262016-08-19 15:54:22 +03001813 case EOpIntBitsToFloat:
1814 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05301815 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1816 break;
Arun Patole551279e2015-07-07 18:18:23 +05301817
Olli Etuahof119a262016-08-19 15:54:22 +03001818 case EOpUintBitsToFloat:
1819 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05301820 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1821 break;
Arun Patole551279e2015-07-07 18:18:23 +05301822
Olli Etuahof119a262016-08-19 15:54:22 +03001823 case EOpExp:
1824 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
1825 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301826
Olli Etuahof119a262016-08-19 15:54:22 +03001827 case EOpLog:
1828 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1829 if (operandArray[i].getFConst() <= 0.0f)
1830 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1831 diagnostics, &resultArray[i]);
1832 else
1833 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1834 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301835
Olli Etuahof119a262016-08-19 15:54:22 +03001836 case EOpExp2:
1837 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
1838 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301839
Olli Etuahof119a262016-08-19 15:54:22 +03001840 case EOpLog2:
1841 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1842 // And log2f is not available on some plarforms like old android, so just using
1843 // log(x)/log(2) here.
1844 if (operandArray[i].getFConst() <= 0.0f)
1845 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1846 diagnostics, &resultArray[i]);
1847 else
1848 {
1849 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1850 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1851 }
1852 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301853
Olli Etuahof119a262016-08-19 15:54:22 +03001854 case EOpSqrt:
1855 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1856 if (operandArray[i].getFConst() < 0.0f)
1857 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1858 diagnostics, &resultArray[i]);
1859 else
1860 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1861 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301862
Olli Etuahof119a262016-08-19 15:54:22 +03001863 case EOpInverseSqrt:
1864 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1865 // so getting the square root first using builtin function sqrt() and then taking
1866 // its inverse.
1867 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
1868 // result to 0.
1869 if (operandArray[i].getFConst() <= 0.0f)
1870 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1871 diagnostics, &resultArray[i]);
1872 else
1873 {
1874 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1875 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1876 }
1877 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878
Olli Etuahof119a262016-08-19 15:54:22 +03001879 case EOpVectorLogicalNot:
1880 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301881 resultArray[i].setBConst(!operandArray[i].getBConst());
1882 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301883
Olli Etuahof119a262016-08-19 15:54:22 +03001884 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301885 {
Olli Etuahof119a262016-08-19 15:54:22 +03001886 ASSERT(getType().getBasicType() == EbtFloat);
1887 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888 float length = VectorLength(operandArray, objectSize);
1889 if (length)
1890 resultArray[i].setFConst(x / length);
1891 else
Olli Etuahof119a262016-08-19 15:54:22 +03001892 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1893 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301894 break;
1895 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301896
Olli Etuahof119a262016-08-19 15:54:22 +03001897 case EOpDFdx:
1898 case EOpDFdy:
1899 case EOpFwidth:
1900 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05301901 // Derivatives of constant arguments should be 0.
1902 resultArray[i].setFConst(0.0f);
1903 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05301904
Olli Etuahof119a262016-08-19 15:54:22 +03001905 default:
1906 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301907 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301908 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001909
Arun Patoleab2b9a22015-07-06 18:27:56 +05301910 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001911}
1912
Olli Etuahof119a262016-08-19 15:54:22 +03001913void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
1914 FloatTypeUnaryFunc builtinFunc,
1915 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301916{
1917 ASSERT(builtinFunc);
1918
Olli Etuahof119a262016-08-19 15:54:22 +03001919 ASSERT(getType().getBasicType() == EbtFloat);
1920 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05301921}
1922
Jamie Madillb1a85f42014-08-19 15:23:24 -04001923// static
Olli Etuahof119a262016-08-19 15:54:22 +03001924TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02001925{
1926 ASSERT(aggregate->getSequence()->size() > 0u);
1927 size_t resultSize = aggregate->getType().getObjectSize();
1928 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1929 TBasicType basicType = aggregate->getBasicType();
1930
1931 size_t resultIndex = 0u;
1932
1933 if (aggregate->getSequence()->size() == 1u)
1934 {
1935 TIntermNode *argument = aggregate->getSequence()->front();
1936 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1937 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1938 // Check the special case of constructing a matrix diagonal from a single scalar,
1939 // or a vector from a single scalar.
1940 if (argumentConstant->getType().getObjectSize() == 1u)
1941 {
1942 if (aggregate->isMatrix())
1943 {
1944 int resultCols = aggregate->getType().getCols();
1945 int resultRows = aggregate->getType().getRows();
1946 for (int col = 0; col < resultCols; ++col)
1947 {
1948 for (int row = 0; row < resultRows; ++row)
1949 {
1950 if (col == row)
1951 {
1952 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1953 }
1954 else
1955 {
1956 resultArray[resultIndex].setFConst(0.0f);
1957 }
1958 ++resultIndex;
1959 }
1960 }
1961 }
1962 else
1963 {
1964 while (resultIndex < resultSize)
1965 {
1966 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1967 ++resultIndex;
1968 }
1969 }
1970 ASSERT(resultIndex == resultSize);
1971 return resultArray;
1972 }
1973 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1974 {
1975 // The special case of constructing a matrix from a matrix.
1976 int argumentCols = argumentConstant->getType().getCols();
1977 int argumentRows = argumentConstant->getType().getRows();
1978 int resultCols = aggregate->getType().getCols();
1979 int resultRows = aggregate->getType().getRows();
1980 for (int col = 0; col < resultCols; ++col)
1981 {
1982 for (int row = 0; row < resultRows; ++row)
1983 {
1984 if (col < argumentCols && row < argumentRows)
1985 {
1986 resultArray[resultIndex].cast(basicType,
1987 argumentUnionArray[col * argumentRows + row]);
1988 }
1989 else if (col == row)
1990 {
1991 resultArray[resultIndex].setFConst(1.0f);
1992 }
1993 else
1994 {
1995 resultArray[resultIndex].setFConst(0.0f);
1996 }
1997 ++resultIndex;
1998 }
1999 }
2000 ASSERT(resultIndex == resultSize);
2001 return resultArray;
2002 }
2003 }
2004
2005 for (TIntermNode *&argument : *aggregate->getSequence())
2006 {
2007 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2008 size_t argumentSize = argumentConstant->getType().getObjectSize();
2009 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2010 for (size_t i = 0u; i < argumentSize; ++i)
2011 {
2012 if (resultIndex >= resultSize)
2013 break;
2014 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2015 ++resultIndex;
2016 }
2017 }
2018 ASSERT(resultIndex == resultSize);
2019 return resultArray;
2020}
2021
2022// static
Olli Etuahof119a262016-08-19 15:54:22 +03002023TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2024 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302025{
Olli Etuahob43846e2015-06-02 18:18:57 +03002026 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302027 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002028 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002029 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302030 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002031 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302032 TBasicType basicType = EbtVoid;
2033 TSourceLoc loc;
2034 for (unsigned int i = 0; i < paramsCount; i++)
2035 {
2036 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002037 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302038
2039 if (i == 0)
2040 {
2041 basicType = paramConstant->getType().getBasicType();
2042 loc = paramConstant->getLine();
2043 }
2044 unionArrays[i] = paramConstant->getUnionArrayPointer();
2045 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002046 if (objectSizes[i] > maxObjectSize)
2047 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302048 }
2049
Olli Etuahod5da5052016-08-29 13:16:55 +03002050 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302051 {
2052 for (unsigned int i = 0; i < paramsCount; i++)
2053 if (objectSizes[i] != maxObjectSize)
2054 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2055 }
Arun Patole274f0702015-05-05 13:33:30 +05302056
Olli Etuahob43846e2015-06-02 18:18:57 +03002057 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302058 if (paramsCount == 2)
2059 {
2060 //
2061 // Binary built-in
2062 //
2063 switch (op)
2064 {
Olli Etuahof119a262016-08-19 15:54:22 +03002065 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302066 {
Olli Etuahof119a262016-08-19 15:54:22 +03002067 ASSERT(basicType == EbtFloat);
2068 resultArray = new TConstantUnion[maxObjectSize];
2069 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302070 {
Olli Etuahof119a262016-08-19 15:54:22 +03002071 float y = unionArrays[0][i].getFConst();
2072 float x = unionArrays[1][i].getFConst();
2073 // Results are undefined if x and y are both 0.
2074 if (x == 0.0f && y == 0.0f)
2075 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2076 &resultArray[i]);
2077 else
2078 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302079 }
Olli Etuahof119a262016-08-19 15:54:22 +03002080 break;
Arun Patolebf790422015-05-18 17:53:04 +05302081 }
Arun Patolebf790422015-05-18 17:53:04 +05302082
Olli Etuahof119a262016-08-19 15:54:22 +03002083 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302084 {
Olli Etuahof119a262016-08-19 15:54:22 +03002085 ASSERT(basicType == EbtFloat);
2086 resultArray = new TConstantUnion[maxObjectSize];
2087 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302088 {
Olli Etuahof119a262016-08-19 15:54:22 +03002089 float x = unionArrays[0][i].getFConst();
2090 float y = unionArrays[1][i].getFConst();
2091 // Results are undefined if x < 0.
2092 // Results are undefined if x = 0 and y <= 0.
2093 if (x < 0.0f)
2094 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2095 &resultArray[i]);
2096 else if (x == 0.0f && y <= 0.0f)
2097 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2098 &resultArray[i]);
2099 else
2100 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302101 }
Olli Etuahof119a262016-08-19 15:54:22 +03002102 break;
Arun Patolebf790422015-05-18 17:53:04 +05302103 }
Arun Patolebf790422015-05-18 17:53:04 +05302104
Olli Etuahof119a262016-08-19 15:54:22 +03002105 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302106 {
Olli Etuahof119a262016-08-19 15:54:22 +03002107 ASSERT(basicType == EbtFloat);
2108 resultArray = new TConstantUnion[maxObjectSize];
2109 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302110 {
Olli Etuahof119a262016-08-19 15:54:22 +03002111 float x = unionArrays[0][i].getFConst();
2112 float y = unionArrays[1][i].getFConst();
2113 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302114 }
Olli Etuahof119a262016-08-19 15:54:22 +03002115 break;
Arun Patolebf790422015-05-18 17:53:04 +05302116 }
Arun Patolebf790422015-05-18 17:53:04 +05302117
Olli Etuahof119a262016-08-19 15:54:22 +03002118 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302119 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002120 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302121 for (size_t i = 0; i < maxObjectSize; i++)
2122 {
2123 switch (basicType)
2124 {
Olli Etuahof119a262016-08-19 15:54:22 +03002125 case EbtFloat:
2126 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2127 unionArrays[1][i].getFConst()));
2128 break;
2129 case EbtInt:
2130 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2131 unionArrays[1][i].getIConst()));
2132 break;
2133 case EbtUInt:
2134 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2135 unionArrays[1][i].getUConst()));
2136 break;
2137 default:
2138 UNREACHABLE();
2139 break;
Arun Patole274f0702015-05-05 13:33:30 +05302140 }
2141 }
Olli Etuahof119a262016-08-19 15:54:22 +03002142 break;
Arun Patole274f0702015-05-05 13:33:30 +05302143 }
Arun Patole274f0702015-05-05 13:33:30 +05302144
Olli Etuahof119a262016-08-19 15:54:22 +03002145 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302146 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002147 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302148 for (size_t i = 0; i < maxObjectSize; i++)
2149 {
2150 switch (basicType)
2151 {
Olli Etuahof119a262016-08-19 15:54:22 +03002152 case EbtFloat:
2153 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2154 unionArrays[1][i].getFConst()));
2155 break;
2156 case EbtInt:
2157 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2158 unionArrays[1][i].getIConst()));
2159 break;
2160 case EbtUInt:
2161 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2162 unionArrays[1][i].getUConst()));
2163 break;
2164 default:
2165 UNREACHABLE();
2166 break;
Arun Patole274f0702015-05-05 13:33:30 +05302167 }
2168 }
Olli Etuahof119a262016-08-19 15:54:22 +03002169 break;
Arun Patole274f0702015-05-05 13:33:30 +05302170 }
Arun Patole274f0702015-05-05 13:33:30 +05302171
Olli Etuahof119a262016-08-19 15:54:22 +03002172 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302173 {
Olli Etuahof119a262016-08-19 15:54:22 +03002174 ASSERT(basicType == EbtFloat);
2175 resultArray = new TConstantUnion[maxObjectSize];
2176 for (size_t i = 0; i < maxObjectSize; i++)
2177 resultArray[i].setFConst(
2178 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2179 : 1.0f);
2180 break;
Arun Patolebf790422015-05-18 17:53:04 +05302181 }
Arun Patolebf790422015-05-18 17:53:04 +05302182
Olli Etuahof119a262016-08-19 15:54:22 +03002183 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302184 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002185 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302186 for (size_t i = 0; i < maxObjectSize; i++)
2187 {
2188 switch (basicType)
2189 {
Olli Etuahof119a262016-08-19 15:54:22 +03002190 case EbtFloat:
2191 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2192 unionArrays[1][i].getFConst());
2193 break;
2194 case EbtInt:
2195 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2196 unionArrays[1][i].getIConst());
2197 break;
2198 case EbtUInt:
2199 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2200 unionArrays[1][i].getUConst());
2201 break;
2202 default:
2203 UNREACHABLE();
2204 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302205 }
2206 }
Olli Etuahof119a262016-08-19 15:54:22 +03002207 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302208 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302209
Olli Etuahof119a262016-08-19 15:54:22 +03002210 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302211 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002212 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302213 for (size_t i = 0; i < maxObjectSize; i++)
2214 {
2215 switch (basicType)
2216 {
Olli Etuahof119a262016-08-19 15:54:22 +03002217 case EbtFloat:
2218 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2219 unionArrays[1][i].getFConst());
2220 break;
2221 case EbtInt:
2222 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2223 unionArrays[1][i].getIConst());
2224 break;
2225 case EbtUInt:
2226 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2227 unionArrays[1][i].getUConst());
2228 break;
2229 default:
2230 UNREACHABLE();
2231 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302232 }
2233 }
Olli Etuahof119a262016-08-19 15:54:22 +03002234 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302235 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302236
Olli Etuahof119a262016-08-19 15:54:22 +03002237 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302238 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002239 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302240 for (size_t i = 0; i < maxObjectSize; i++)
2241 {
2242 switch (basicType)
2243 {
Olli Etuahof119a262016-08-19 15:54:22 +03002244 case EbtFloat:
2245 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2246 unionArrays[1][i].getFConst());
2247 break;
2248 case EbtInt:
2249 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2250 unionArrays[1][i].getIConst());
2251 break;
2252 case EbtUInt:
2253 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2254 unionArrays[1][i].getUConst());
2255 break;
2256 default:
2257 UNREACHABLE();
2258 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002259 }
2260 }
Olli Etuahof119a262016-08-19 15:54:22 +03002261 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302262 }
Olli Etuahof119a262016-08-19 15:54:22 +03002263 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302264 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002265 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302266 for (size_t i = 0; i < maxObjectSize; i++)
2267 {
2268 switch (basicType)
2269 {
Olli Etuahof119a262016-08-19 15:54:22 +03002270 case EbtFloat:
2271 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2272 unionArrays[1][i].getFConst());
2273 break;
2274 case EbtInt:
2275 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2276 unionArrays[1][i].getIConst());
2277 break;
2278 case EbtUInt:
2279 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2280 unionArrays[1][i].getUConst());
2281 break;
2282 default:
2283 UNREACHABLE();
2284 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302285 }
2286 }
2287 }
2288 break;
2289
Olli Etuahof119a262016-08-19 15:54:22 +03002290 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302291 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002292 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302293 for (size_t i = 0; i < maxObjectSize; i++)
2294 {
2295 switch (basicType)
2296 {
Olli Etuahof119a262016-08-19 15:54:22 +03002297 case EbtFloat:
2298 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2299 unionArrays[1][i].getFConst());
2300 break;
2301 case EbtInt:
2302 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2303 unionArrays[1][i].getIConst());
2304 break;
2305 case EbtUInt:
2306 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2307 unionArrays[1][i].getUConst());
2308 break;
2309 case EbtBool:
2310 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2311 unionArrays[1][i].getBConst());
2312 break;
2313 default:
2314 UNREACHABLE();
2315 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302316 }
2317 }
Olli Etuahof119a262016-08-19 15:54:22 +03002318 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302319 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302320
Olli Etuahof119a262016-08-19 15:54:22 +03002321 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302322 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002323 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302324 for (size_t i = 0; i < maxObjectSize; i++)
2325 {
2326 switch (basicType)
2327 {
Olli Etuahof119a262016-08-19 15:54:22 +03002328 case EbtFloat:
2329 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2330 unionArrays[1][i].getFConst());
2331 break;
2332 case EbtInt:
2333 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2334 unionArrays[1][i].getIConst());
2335 break;
2336 case EbtUInt:
2337 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2338 unionArrays[1][i].getUConst());
2339 break;
2340 case EbtBool:
2341 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2342 unionArrays[1][i].getBConst());
2343 break;
2344 default:
2345 UNREACHABLE();
2346 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302347 }
2348 }
Olli Etuahof119a262016-08-19 15:54:22 +03002349 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302350 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302351
Olli Etuahof119a262016-08-19 15:54:22 +03002352 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302353 {
Olli Etuahof119a262016-08-19 15:54:22 +03002354 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302355 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002356 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302357 for (size_t i = 0; i < maxObjectSize; i++)
2358 {
2359 float x = unionArrays[0][i].getFConst();
2360 float y = unionArrays[1][i].getFConst();
2361 distanceArray[i].setFConst(x - y);
2362 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002363 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002364 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302365 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302366
Olli Etuahof119a262016-08-19 15:54:22 +03002367 case EOpDot:
2368 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002369 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002370 resultArray->setFConst(
2371 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2372 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302373
Olli Etuahof119a262016-08-19 15:54:22 +03002374 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302375 {
Olli Etuahof119a262016-08-19 15:54:22 +03002376 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002377 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002378 float x0 = unionArrays[0][0].getFConst();
2379 float x1 = unionArrays[0][1].getFConst();
2380 float x2 = unionArrays[0][2].getFConst();
2381 float y0 = unionArrays[1][0].getFConst();
2382 float y1 = unionArrays[1][1].getFConst();
2383 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002384 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2385 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2386 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002387 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302388 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302389
Olli Etuahof119a262016-08-19 15:54:22 +03002390 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302391 {
Olli Etuahof119a262016-08-19 15:54:22 +03002392 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302393 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002394 // For the incident vector I and surface orientation N, returns the reflection
2395 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302396 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002397 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302398 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2399 for (size_t i = 0; i < maxObjectSize; i++)
2400 {
2401 float result = unionArrays[0][i].getFConst() -
2402 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002403 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302404 }
Olli Etuahof119a262016-08-19 15:54:22 +03002405 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302406 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302407
Olli Etuahof119a262016-08-19 15:54:22 +03002408 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302409 {
Olli Etuahof119a262016-08-19 15:54:22 +03002410 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2411 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302412 // Perform component-wise matrix multiplication.
2413 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002414 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302415 angle::Matrix<float> result =
2416 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2417 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002418 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302419 }
Arun Patole7fa33552015-06-10 15:15:18 +05302420
Olli Etuahof119a262016-08-19 15:54:22 +03002421 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302422 {
Olli Etuahof119a262016-08-19 15:54:22 +03002423 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302424 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2425 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002426 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302427 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002428 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2429 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302430 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002431 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302432 }
Arun Patole7fa33552015-06-10 15:15:18 +05302433
Olli Etuahof119a262016-08-19 15:54:22 +03002434 default:
2435 UNREACHABLE();
2436 // TODO: Add constant folding support for other built-in operations that take 2
2437 // parameters and not handled above.
2438 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302439 }
2440 }
2441 else if (paramsCount == 3)
2442 {
2443 //
2444 // Ternary built-in
2445 //
2446 switch (op)
2447 {
Olli Etuahof119a262016-08-19 15:54:22 +03002448 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302449 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002450 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302451 for (size_t i = 0; i < maxObjectSize; i++)
2452 {
2453 switch (basicType)
2454 {
Olli Etuahof119a262016-08-19 15:54:22 +03002455 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302456 {
Olli Etuahof119a262016-08-19 15:54:22 +03002457 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302458 float min = unionArrays[1][i].getFConst();
2459 float max = unionArrays[2][i].getFConst();
2460 // Results are undefined if min > max.
2461 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002462 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2463 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302464 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002465 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002466 break;
Arun Patole274f0702015-05-05 13:33:30 +05302467 }
Olli Etuahof119a262016-08-19 15:54:22 +03002468
2469 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302470 {
Olli Etuahof119a262016-08-19 15:54:22 +03002471 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302472 int min = unionArrays[1][i].getIConst();
2473 int max = unionArrays[2][i].getIConst();
2474 // Results are undefined if min > max.
2475 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002476 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2477 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302478 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002479 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002480 break;
Arun Patole274f0702015-05-05 13:33:30 +05302481 }
Olli Etuahof119a262016-08-19 15:54:22 +03002482 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302483 {
Olli Etuahof119a262016-08-19 15:54:22 +03002484 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302485 unsigned int min = unionArrays[1][i].getUConst();
2486 unsigned int max = unionArrays[2][i].getUConst();
2487 // Results are undefined if min > max.
2488 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002489 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2490 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302491 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002492 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002493 break;
Arun Patole274f0702015-05-05 13:33:30 +05302494 }
Olli Etuahof119a262016-08-19 15:54:22 +03002495 default:
2496 UNREACHABLE();
2497 break;
Arun Patole274f0702015-05-05 13:33:30 +05302498 }
2499 }
Olli Etuahof119a262016-08-19 15:54:22 +03002500 break;
Arun Patole274f0702015-05-05 13:33:30 +05302501 }
Arun Patole274f0702015-05-05 13:33:30 +05302502
Olli Etuahof119a262016-08-19 15:54:22 +03002503 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302504 {
Olli Etuahof119a262016-08-19 15:54:22 +03002505 ASSERT(basicType == EbtFloat);
2506 resultArray = new TConstantUnion[maxObjectSize];
2507 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302508 {
Olli Etuahof119a262016-08-19 15:54:22 +03002509 float x = unionArrays[0][i].getFConst();
2510 float y = unionArrays[1][i].getFConst();
2511 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2512 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302513 {
Olli Etuahof119a262016-08-19 15:54:22 +03002514 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2515 float a = unionArrays[2][i].getFConst();
2516 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2517 }
2518 else // 3rd parameter is EbtBool
2519 {
2520 ASSERT(type == EbtBool);
2521 // Selects which vector each returned component comes from.
2522 // For a component of a that is false, the corresponding component of x is
2523 // returned.
2524 // For a component of a that is true, the corresponding component of y is
2525 // returned.
2526 bool a = unionArrays[2][i].getBConst();
2527 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302528 }
2529 }
Olli Etuahof119a262016-08-19 15:54:22 +03002530 break;
Arun Patolebf790422015-05-18 17:53:04 +05302531 }
Arun Patolebf790422015-05-18 17:53:04 +05302532
Olli Etuahof119a262016-08-19 15:54:22 +03002533 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302534 {
Olli Etuahof119a262016-08-19 15:54:22 +03002535 ASSERT(basicType == EbtFloat);
2536 resultArray = new TConstantUnion[maxObjectSize];
2537 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302538 {
Olli Etuahof119a262016-08-19 15:54:22 +03002539 float edge0 = unionArrays[0][i].getFConst();
2540 float edge1 = unionArrays[1][i].getFConst();
2541 float x = unionArrays[2][i].getFConst();
2542 // Results are undefined if edge0 >= edge1.
2543 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302544 {
Olli Etuahof119a262016-08-19 15:54:22 +03002545 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2546 &resultArray[i]);
2547 }
2548 else
2549 {
2550 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2551 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2552 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2553 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302554 }
2555 }
Olli Etuahof119a262016-08-19 15:54:22 +03002556 break;
Arun Patolebf790422015-05-18 17:53:04 +05302557 }
Arun Patolebf790422015-05-18 17:53:04 +05302558
Olli Etuahof119a262016-08-19 15:54:22 +03002559 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302560 {
Olli Etuahof119a262016-08-19 15:54:22 +03002561 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302562 // genType faceforward(genType N, genType I, genType Nref) :
2563 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002564 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302565 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2566 for (size_t i = 0; i < maxObjectSize; i++)
2567 {
2568 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002569 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302570 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002571 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302572 }
Olli Etuahof119a262016-08-19 15:54:22 +03002573 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302574 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302575
Olli Etuahof119a262016-08-19 15:54:22 +03002576 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302577 {
Olli Etuahof119a262016-08-19 15:54:22 +03002578 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302579 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002580 // For the incident vector I and surface normal N, and the ratio of indices of
2581 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302582 // return the refraction vector. The result is computed by
2583 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2584 // if (k < 0.0)
2585 // return genType(0.0)
2586 // else
2587 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002588 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302589 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2590 for (size_t i = 0; i < maxObjectSize; i++)
2591 {
2592 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002593 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302594 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002595 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302596 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002597 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002598 (eta * dotProduct + sqrtf(k)) *
2599 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302600 }
Olli Etuahof119a262016-08-19 15:54:22 +03002601 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302602 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302603
Olli Etuahof119a262016-08-19 15:54:22 +03002604 default:
2605 UNREACHABLE();
2606 // TODO: Add constant folding support for other built-in operations that take 3
2607 // parameters and not handled above.
2608 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302609 }
2610 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002611 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302612}
2613
2614// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002615TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2616{
2617 if (hashFunction == NULL || name.empty())
2618 return name;
2619 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2620 TStringStream stream;
2621 stream << HASHED_NAME_PREFIX << std::hex << number;
2622 TString hashedName = stream.str();
2623 return hashedName;
2624}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002625
2626void TIntermTraverser::updateTree()
2627{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002628 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2629 {
2630 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2631 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002632 if (!insertion.insertionsAfter.empty())
2633 {
2634 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2635 insertion.insertionsAfter);
2636 ASSERT(inserted);
2637 UNUSED_ASSERTION_VARIABLE(inserted);
2638 }
2639 if (!insertion.insertionsBefore.empty())
2640 {
2641 bool inserted =
2642 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2643 ASSERT(inserted);
2644 UNUSED_ASSERTION_VARIABLE(inserted);
2645 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002646 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002647 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2648 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002649 const NodeUpdateEntry &replacement = mReplacements[ii];
2650 ASSERT(replacement.parent);
2651 bool replaced = replacement.parent->replaceChildNode(
2652 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002653 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002654 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002655
Olli Etuahocd94ef92015-04-16 19:18:10 +03002656 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002657 {
2658 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002659 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002660 // be replaced, we need to make sure we don't update the replaced
2661 // node; instead, we update the replacement node.
2662 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2663 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002664 NodeUpdateEntry &replacement2 = mReplacements[jj];
2665 if (replacement2.parent == replacement.original)
2666 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002667 }
2668 }
2669 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002670 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2671 {
2672 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2673 ASSERT(replacement.parent);
2674 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2675 replacement.original, replacement.replacements);
2676 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002677 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002678 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002679
Jamie Madill03d863c2016-07-27 18:15:53 -04002680 clearReplacementQueue();
2681}
2682
2683void TIntermTraverser::clearReplacementQueue()
2684{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002685 mReplacements.clear();
2686 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002687 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002688}
Jamie Madill1048e432016-07-23 18:51:28 -04002689
Jamie Madill03d863c2016-07-27 18:15:53 -04002690void TIntermTraverser::queueReplacement(TIntermNode *original,
2691 TIntermNode *replacement,
2692 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002693{
Jamie Madill03d863c2016-07-27 18:15:53 -04002694 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002695}
2696
Jamie Madill03d863c2016-07-27 18:15:53 -04002697void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2698 TIntermNode *original,
2699 TIntermNode *replacement,
2700 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002701{
Jamie Madill03d863c2016-07-27 18:15:53 -04002702 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2703 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002704}