blob: e17ac560166ff4b7b73d4dd23e7a39b5dd9ffa72 [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
Olli Etuahob6fa0432016-09-28 16:28:05 +0100184bool TIntermSwizzle::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
185{
186 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
187 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
188 return false;
189}
190
Jamie Madillb1a85f42014-08-19 15:23:24 -0400191bool TIntermBinary::replaceChildNode(
192 TIntermNode *original, TIntermNode *replacement)
193{
194 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
195 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
196 return false;
197}
198
Jamie Madillb1a85f42014-08-19 15:23:24 -0400199bool TIntermUnary::replaceChildNode(
200 TIntermNode *original, TIntermNode *replacement)
201{
Olli Etuahoa2234302016-08-31 12:05:39 +0300202 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400203 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
204 return false;
205}
206
Jamie Madillb1a85f42014-08-19 15:23:24 -0400207bool TIntermAggregate::replaceChildNode(
208 TIntermNode *original, TIntermNode *replacement)
209{
210 for (size_t ii = 0; ii < mSequence.size(); ++ii)
211 {
212 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
213 }
214 return false;
215}
216
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300217bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
218{
219 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
220 {
221 if (*it == original)
222 {
223 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300224 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300225 return true;
226 }
227 }
228 return false;
229}
230
Olli Etuahoa6f22092015-05-08 18:31:10 +0300231bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
232{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300233 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300234 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300235 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300236 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300237 auto it = mSequence.begin() + position;
238 mSequence.insert(it, insertions.begin(), insertions.end());
239 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300240}
241
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200242bool TIntermAggregate::areChildrenConstQualified()
243{
244 for (TIntermNode *&child : mSequence)
245 {
246 TIntermTyped *typed = child->getAsTyped();
247 if (typed && typed->getQualifier() != EvqConst)
248 {
249 return false;
250 }
251 }
252 return true;
253}
254
Olli Etuahod2a67b92014-10-21 16:42:57 +0300255void TIntermAggregate::setPrecisionFromChildren()
256{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300257 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300258 if (getBasicType() == EbtBool)
259 {
260 mType.setPrecision(EbpUndefined);
261 return;
262 }
263
264 TPrecision precision = EbpUndefined;
265 TIntermSequence::iterator childIter = mSequence.begin();
266 while (childIter != mSequence.end())
267 {
268 TIntermTyped *typed = (*childIter)->getAsTyped();
269 if (typed)
270 precision = GetHigherPrecision(typed->getPrecision(), precision);
271 ++childIter;
272 }
273 mType.setPrecision(precision);
274}
275
276void TIntermAggregate::setBuiltInFunctionPrecision()
277{
278 // All built-ins returning bool should be handled as ops, not functions.
279 ASSERT(getBasicType() != EbtBool);
280
281 TPrecision precision = EbpUndefined;
282 TIntermSequence::iterator childIter = mSequence.begin();
283 while (childIter != mSequence.end())
284 {
285 TIntermTyped *typed = (*childIter)->getAsTyped();
286 // ESSL spec section 8: texture functions get their precision from the sampler.
287 if (typed && IsSampler(typed->getBasicType()))
288 {
289 precision = typed->getPrecision();
290 break;
291 }
292 ++childIter;
293 }
294 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
295 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300296 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300297 mType.setPrecision(EbpHigh);
298 else
299 mType.setPrecision(precision);
300}
301
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300302bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
303{
304 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
305 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
306 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
307 return false;
308}
309
Olli Etuaho57961272016-09-14 13:57:46 +0300310bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400311{
312 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
313 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
314 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
315 return false;
316}
317
Olli Etuahoa3a36662015-02-17 13:46:51 +0200318bool TIntermSwitch::replaceChildNode(
319 TIntermNode *original, TIntermNode *replacement)
320{
321 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
322 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
323 return false;
324}
325
326bool TIntermCase::replaceChildNode(
327 TIntermNode *original, TIntermNode *replacement)
328{
329 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
330 return false;
331}
332
Olli Etuahod7a25242015-08-18 13:49:45 +0300333TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
334{
335 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
336 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
337 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
338 mLine = node.mLine;
339}
340
Olli Etuahod4f4c112016-04-15 15:11:24 +0300341bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
342{
343 TIntermAggregate *constructor = getAsAggregate();
344 if (!constructor || !constructor->isConstructor())
345 {
346 return false;
347 }
348 for (TIntermNode *&node : *constructor->getSequence())
349 {
350 if (!node->getAsConstantUnion())
351 return false;
352 }
353 return true;
354}
355
Corentin Wallez509e4562016-08-25 14:55:44 -0400356// static
357TIntermTyped *TIntermTyped::CreateIndexNode(int index)
358{
359 TConstantUnion *u = new TConstantUnion[1];
360 u[0].setIConst(index);
361
362 TType type(EbtInt, EbpUndefined, EvqConst, 1);
363 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
364 return node;
365}
366
367// static
368TIntermTyped *TIntermTyped::CreateZero(const TType &type)
369{
370 TType constType(type);
371 constType.setQualifier(EvqConst);
372
373 if (!type.isArray() && type.getBasicType() != EbtStruct)
374 {
375 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
376
377 size_t size = constType.getObjectSize();
378 TConstantUnion *u = new TConstantUnion[size];
379 for (size_t i = 0; i < size; ++i)
380 {
381 switch (type.getBasicType())
382 {
383 case EbtFloat:
384 u[i].setFConst(0.0f);
385 break;
386 case EbtInt:
387 u[i].setIConst(0);
388 break;
389 case EbtUInt:
390 u[i].setUConst(0u);
391 break;
392 case EbtBool:
393 u[i].setBConst(false);
394 break;
395 default:
396 UNREACHABLE();
397 return nullptr;
398 }
399 }
400
401 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
402 return node;
403 }
404
405 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
406 constructor->setType(constType);
407
408 if (type.isArray())
409 {
410 TType elementType(type);
411 elementType.clearArrayness();
412
413 size_t arraySize = type.getArraySize();
414 for (size_t i = 0; i < arraySize; ++i)
415 {
416 constructor->getSequence()->push_back(CreateZero(elementType));
417 }
418 }
419 else
420 {
421 ASSERT(type.getBasicType() == EbtStruct);
422
423 TStructure *structure = type.getStruct();
424 for (const auto &field : structure->fields())
425 {
426 constructor->getSequence()->push_back(CreateZero(*field->type()));
427 }
428 }
429
430 return constructor;
431}
432
Olli Etuahod7a25242015-08-18 13:49:45 +0300433TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
434{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200435 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300436}
437
438TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
439 : TIntermOperator(node),
440 mName(node.mName),
441 mUserDefined(node.mUserDefined),
442 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300443 mUseEmulatedFunction(node.mUseEmulatedFunction),
444 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
445{
446 for (TIntermNode *child : node.mSequence)
447 {
448 TIntermTyped *typedChild = child->getAsTyped();
449 ASSERT(typedChild != nullptr);
450 TIntermTyped *childCopy = typedChild->deepCopy();
451 mSequence.push_back(childCopy);
452 }
453}
454
Olli Etuahob6fa0432016-09-28 16:28:05 +0100455TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
456{
457 TIntermTyped *operandCopy = node.mOperand->deepCopy();
458 ASSERT(operandCopy != nullptr);
459 mOperand = operandCopy;
460}
461
Olli Etuahod7a25242015-08-18 13:49:45 +0300462TIntermBinary::TIntermBinary(const TIntermBinary &node)
463 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
464{
465 TIntermTyped *leftCopy = node.mLeft->deepCopy();
466 TIntermTyped *rightCopy = node.mRight->deepCopy();
467 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
468 mLeft = leftCopy;
469 mRight = rightCopy;
470}
471
472TIntermUnary::TIntermUnary(const TIntermUnary &node)
473 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
474{
475 TIntermTyped *operandCopy = node.mOperand->deepCopy();
476 ASSERT(operandCopy != nullptr);
477 mOperand = operandCopy;
478}
479
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300480TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300481{
Olli Etuahod7a25242015-08-18 13:49:45 +0300482 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300483 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
484 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300485 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300486 mCondition = conditionCopy;
487 mTrueExpression = trueCopy;
488 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300489}
490
Jamie Madillb1a85f42014-08-19 15:23:24 -0400491bool TIntermOperator::isAssignment() const
492{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300493 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400494}
495
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300496bool TIntermOperator::isMultiplication() const
497{
498 switch (mOp)
499 {
500 case EOpMul:
501 case EOpMatrixTimesMatrix:
502 case EOpMatrixTimesVector:
503 case EOpMatrixTimesScalar:
504 case EOpVectorTimesMatrix:
505 case EOpVectorTimesScalar:
506 return true;
507 default:
508 return false;
509 }
510}
511
Jamie Madillb1a85f42014-08-19 15:23:24 -0400512//
513// returns true if the operator is for one of the constructors
514//
515bool TIntermOperator::isConstructor() const
516{
517 switch (mOp)
518 {
519 case EOpConstructVec2:
520 case EOpConstructVec3:
521 case EOpConstructVec4:
522 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400523 case EOpConstructMat2x3:
524 case EOpConstructMat2x4:
525 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400526 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400527 case EOpConstructMat3x4:
528 case EOpConstructMat4x2:
529 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400530 case EOpConstructMat4:
531 case EOpConstructFloat:
532 case EOpConstructIVec2:
533 case EOpConstructIVec3:
534 case EOpConstructIVec4:
535 case EOpConstructInt:
536 case EOpConstructUVec2:
537 case EOpConstructUVec3:
538 case EOpConstructUVec4:
539 case EOpConstructUInt:
540 case EOpConstructBVec2:
541 case EOpConstructBVec3:
542 case EOpConstructBVec4:
543 case EOpConstructBool:
544 case EOpConstructStruct:
545 return true;
546 default:
547 return false;
548 }
549}
550
Olli Etuaho1dded802016-08-18 18:13:13 +0300551TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
552{
553 if (left.isMatrix())
554 {
555 if (right.isMatrix())
556 {
557 return EOpMatrixTimesMatrix;
558 }
559 else
560 {
561 if (right.isVector())
562 {
563 return EOpMatrixTimesVector;
564 }
565 else
566 {
567 return EOpMatrixTimesScalar;
568 }
569 }
570 }
571 else
572 {
573 if (right.isMatrix())
574 {
575 if (left.isVector())
576 {
577 return EOpVectorTimesMatrix;
578 }
579 else
580 {
581 return EOpMatrixTimesScalar;
582 }
583 }
584 else
585 {
586 // Neither operand is a matrix.
587 if (left.isVector() == right.isVector())
588 {
589 // Leave as component product.
590 return EOpMul;
591 }
592 else
593 {
594 return EOpVectorTimesScalar;
595 }
596 }
597 }
598}
599
600TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
601{
602 if (left.isMatrix())
603 {
604 if (right.isMatrix())
605 {
606 return EOpMatrixTimesMatrixAssign;
607 }
608 else
609 {
610 // right should be scalar, but this may not be validated yet.
611 return EOpMatrixTimesScalarAssign;
612 }
613 }
614 else
615 {
616 if (right.isMatrix())
617 {
618 // Left should be a vector, but this may not be validated yet.
619 return EOpVectorTimesMatrixAssign;
620 }
621 else
622 {
623 // Neither operand is a matrix.
624 if (left.isVector() == right.isVector())
625 {
626 // Leave as component product.
627 return EOpMulAssign;
628 }
629 else
630 {
631 // left should be vector and right should be scalar, but this may not be validated
632 // yet.
633 return EOpVectorTimesScalarAssign;
634 }
635 }
636 }
637}
638
Jamie Madillb1a85f42014-08-19 15:23:24 -0400639//
640// Make sure the type of a unary operator is appropriate for its
641// combination of operation and operand type.
642//
Olli Etuahoa2234302016-08-31 12:05:39 +0300643void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400644{
Olli Etuahoa2234302016-08-31 12:05:39 +0300645 TQualifier resultQualifier = EvqTemporary;
646 if (mOperand->getQualifier() == EvqConst)
647 resultQualifier = EvqConst;
648
649 unsigned char operandPrimarySize =
650 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400651 switch (mOp)
652 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300653 case EOpFloatBitsToInt:
654 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
655 break;
656 case EOpFloatBitsToUint:
657 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
658 break;
659 case EOpIntBitsToFloat:
660 case EOpUintBitsToFloat:
661 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
662 break;
663 case EOpPackSnorm2x16:
664 case EOpPackUnorm2x16:
665 case EOpPackHalf2x16:
666 setType(TType(EbtUInt, EbpHigh, resultQualifier));
667 break;
668 case EOpUnpackSnorm2x16:
669 case EOpUnpackUnorm2x16:
670 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
671 break;
672 case EOpUnpackHalf2x16:
673 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
674 break;
675 case EOpAny:
676 case EOpAll:
677 setType(TType(EbtBool, EbpUndefined, resultQualifier));
678 break;
679 case EOpLength:
680 case EOpDeterminant:
681 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
682 break;
683 case EOpTranspose:
684 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
685 static_cast<unsigned char>(mOperand->getType().getRows()),
686 static_cast<unsigned char>(mOperand->getType().getCols())));
687 break;
688 case EOpIsInf:
689 case EOpIsNan:
690 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
691 break;
692 default:
693 setType(mOperand->getType());
694 mType.setQualifier(resultQualifier);
695 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400696 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300697}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400698
Olli Etuahob6fa0432016-09-28 16:28:05 +0100699TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
700 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
701 mOperand(operand),
702 mSwizzleOffsets(swizzleOffsets)
703{
704 ASSERT(mSwizzleOffsets.size() <= 4);
705 promote();
706}
707
Olli Etuahoa2234302016-08-31 12:05:39 +0300708TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
709 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
710{
711 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400712}
713
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300714TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
715 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
716{
717 promote();
718}
719
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300720TIntermTernary::TIntermTernary(TIntermTyped *cond,
721 TIntermTyped *trueExpression,
722 TIntermTyped *falseExpression)
723 : TIntermTyped(trueExpression->getType()),
724 mCondition(cond),
725 mTrueExpression(trueExpression),
726 mFalseExpression(falseExpression)
727{
728 getTypePointer()->setQualifier(
729 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
730}
731
732// static
733TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
734 TIntermTyped *trueExpression,
735 TIntermTyped *falseExpression)
736{
737 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
738 falseExpression->getQualifier() == EvqConst)
739 {
740 return EvqConst;
741 }
742 return EvqTemporary;
743}
744
Olli Etuahob6fa0432016-09-28 16:28:05 +0100745void TIntermSwizzle::promote()
746{
747 TQualifier resultQualifier = EvqTemporary;
748 if (mOperand->getQualifier() == EvqConst)
749 resultQualifier = EvqConst;
750
751 auto numFields = mSwizzleOffsets.size();
752 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
753 static_cast<unsigned char>(numFields)));
754}
755
756bool TIntermSwizzle::hasDuplicateOffsets() const
757{
758 int offsetCount[4] = {0u, 0u, 0u, 0u};
759 for (const auto offset : mSwizzleOffsets)
760 {
761 offsetCount[offset]++;
762 if (offsetCount[offset] > 1)
763 {
764 return true;
765 }
766 }
767 return false;
768}
769
770void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
771{
772 for (const int offset : mSwizzleOffsets)
773 {
774 switch (offset)
775 {
776 case 0:
777 *out << "x";
778 break;
779 case 1:
780 *out << "y";
781 break;
782 case 2:
783 *out << "z";
784 break;
785 case 3:
786 *out << "w";
787 break;
788 default:
789 UNREACHABLE();
790 }
791 }
792}
793
794
795// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300796void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797{
Olli Etuaho1dded802016-08-18 18:13:13 +0300798 ASSERT(!isMultiplication() ||
799 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
800
Jamie Madillb1a85f42014-08-19 15:23:24 -0400801 // Base assumption: just make the type the same as the left
802 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400803 setType(mLeft->getType());
804
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200805 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400806 // Binary operations results in temporary variables unless both
807 // operands are const.
808 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
809 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200810 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400811 getTypePointer()->setQualifier(EvqTemporary);
812 }
813
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300814 // Handle indexing ops.
815 switch (mOp)
816 {
817 case EOpIndexDirect:
818 case EOpIndexIndirect:
819 if (mLeft->isArray())
820 {
821 mType.clearArrayness();
822 }
823 else if (mLeft->isMatrix())
824 {
825 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
826 static_cast<unsigned char>(mLeft->getRows())));
827 }
828 else if (mLeft->isVector())
829 {
830 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
831 }
832 else
833 {
834 UNREACHABLE();
835 }
836 return;
837 case EOpIndexDirectStruct:
838 {
839 const TFieldList &fields = mLeft->getType().getStruct()->fields();
840 const int i = mRight->getAsConstantUnion()->getIConst(0);
841 setType(*fields[i]->type());
842 getTypePointer()->setQualifier(resultQualifier);
843 return;
844 }
845 case EOpIndexDirectInterfaceBlock:
846 {
847 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
848 const int i = mRight->getAsConstantUnion()->getIConst(0);
849 setType(*fields[i]->type());
850 getTypePointer()->setQualifier(resultQualifier);
851 return;
852 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300853 default:
854 break;
855 }
856
857 ASSERT(mLeft->isArray() == mRight->isArray());
858
859 // The result gets promoted to the highest precision.
860 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
861 getTypePointer()->setPrecision(higherPrecision);
862
Jamie Madillb1a85f42014-08-19 15:23:24 -0400863 const int nominalSize =
864 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
865
866 //
867 // All scalars or structs. Code after this test assumes this case is removed!
868 //
869 if (nominalSize == 1)
870 {
871 switch (mOp)
872 {
873 //
874 // Promote to conditional
875 //
876 case EOpEqual:
877 case EOpNotEqual:
878 case EOpLessThan:
879 case EOpGreaterThan:
880 case EOpLessThanEqual:
881 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300882 setType(TType(EbtBool, EbpUndefined, resultQualifier));
883 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400884
885 //
886 // And and Or operate on conditionals
887 //
888 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200889 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400890 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200891 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300892 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400893 break;
894
895 default:
896 break;
897 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300898 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400899 }
900
901 // If we reach here, at least one of the operands is vector or matrix.
902 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400903 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300904
Jamie Madillb1a85f42014-08-19 15:23:24 -0400905 switch (mOp)
906 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300907 case EOpMul:
908 break;
909 case EOpMatrixTimesScalar:
910 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400911 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200912 setType(TType(basicType, higherPrecision, resultQualifier,
913 static_cast<unsigned char>(mRight->getCols()),
914 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400915 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300916 break;
917 case EOpMatrixTimesVector:
918 setType(TType(basicType, higherPrecision, resultQualifier,
919 static_cast<unsigned char>(mLeft->getRows()), 1));
920 break;
921 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200922 setType(TType(basicType, higherPrecision, resultQualifier,
923 static_cast<unsigned char>(mRight->getCols()),
924 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300925 break;
926 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200927 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300928 static_cast<unsigned char>(nominalSize), 1));
929 break;
930 case EOpVectorTimesMatrix:
931 setType(TType(basicType, higherPrecision, resultQualifier,
932 static_cast<unsigned char>(mRight->getCols()), 1));
933 break;
934 case EOpMulAssign:
935 case EOpVectorTimesScalarAssign:
936 case EOpVectorTimesMatrixAssign:
937 case EOpMatrixTimesScalarAssign:
938 case EOpMatrixTimesMatrixAssign:
939 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
940 break;
941 case EOpAssign:
942 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300943 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
944 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
945 break;
946 case EOpAdd:
947 case EOpSub:
948 case EOpDiv:
949 case EOpIMod:
950 case EOpBitShiftLeft:
951 case EOpBitShiftRight:
952 case EOpBitwiseAnd:
953 case EOpBitwiseXor:
954 case EOpBitwiseOr:
955 case EOpAddAssign:
956 case EOpSubAssign:
957 case EOpDivAssign:
958 case EOpIModAssign:
959 case EOpBitShiftLeftAssign:
960 case EOpBitShiftRightAssign:
961 case EOpBitwiseAndAssign:
962 case EOpBitwiseXorAssign:
963 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300964 {
965 const int secondarySize =
966 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
967 setType(TType(basicType, higherPrecision, resultQualifier,
968 static_cast<unsigned char>(nominalSize),
969 static_cast<unsigned char>(secondarySize)));
970 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300971 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300972 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300973 case EOpEqual:
974 case EOpNotEqual:
975 case EOpLessThan:
976 case EOpGreaterThan:
977 case EOpLessThanEqual:
978 case EOpGreaterThanEqual:
979 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
980 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300981 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300982 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400983
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300984 case EOpIndexDirect:
985 case EOpIndexIndirect:
986 case EOpIndexDirectInterfaceBlock:
987 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300988 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300989 UNREACHABLE();
990 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300991 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300992 UNREACHABLE();
993 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400994 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400995}
996
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300997const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300998{
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300999 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001000 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001001 ASSERT(index < static_cast<int>(getType().getArraySize()));
1002 TType arrayElementType = getType();
1003 arrayElementType.clearArrayness();
1004 size_t arrayElementSize = arrayElementType.getObjectSize();
1005 return &mUnionArrayPointer[arrayElementSize * index];
1006 }
1007 else if (isMatrix())
1008 {
1009 ASSERT(index < getType().getCols());
1010 int size = getType().getRows();
1011 return &mUnionArrayPointer[size * index];
1012 }
1013 else if (isVector())
1014 {
1015 ASSERT(index < getType().getNominalSize());
1016 return &mUnionArrayPointer[index];
1017 }
1018 else
1019 {
1020 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001021 return nullptr;
1022 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001023}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001024
Olli Etuahob6fa0432016-09-28 16:28:05 +01001025TIntermTyped *TIntermSwizzle::fold()
1026{
1027 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1028 if (operandConstant == nullptr)
1029 {
1030 return nullptr;
1031 }
1032
1033 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1034 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1035 {
1036 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1037 }
1038 return CreateFoldedNode(constArray, this, mType.getQualifier());
1039}
1040
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001041TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1042{
1043 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1044 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1045 switch (mOp)
1046 {
1047 case EOpIndexDirect:
1048 {
1049 if (leftConstant == nullptr || rightConstant == nullptr)
1050 {
1051 return nullptr;
1052 }
1053 int index = rightConstant->getIConst(0);
1054
1055 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1056 return CreateFoldedNode(constArray, this, mType.getQualifier());
1057 }
1058 case EOpIndexDirectStruct:
1059 {
1060 if (leftConstant == nullptr || rightConstant == nullptr)
1061 {
1062 return nullptr;
1063 }
1064 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1065 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1066
1067 size_t previousFieldsSize = 0;
1068 for (size_t i = 0; i < index; ++i)
1069 {
1070 previousFieldsSize += fields[i]->type()->getObjectSize();
1071 }
1072
1073 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1074 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1075 }
1076 case EOpIndexIndirect:
1077 case EOpIndexDirectInterfaceBlock:
1078 // Can never be constant folded.
1079 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001080 default:
1081 {
1082 if (leftConstant == nullptr || rightConstant == nullptr)
1083 {
1084 return nullptr;
1085 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001086 TConstantUnion *constArray =
1087 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001088
1089 // Nodes may be constant folded without being qualified as constant.
1090 return CreateFoldedNode(constArray, this, mType.getQualifier());
1091 }
1092 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001093}
1094
Olli Etuahof119a262016-08-19 15:54:22 +03001095TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001096{
1097 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1098 if (operandConstant == nullptr)
1099 {
1100 return nullptr;
1101 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301102
1103 TConstantUnion *constArray = nullptr;
1104 switch (mOp)
1105 {
1106 case EOpAny:
1107 case EOpAll:
1108 case EOpLength:
1109 case EOpTranspose:
1110 case EOpDeterminant:
1111 case EOpInverse:
1112 case EOpPackSnorm2x16:
1113 case EOpUnpackSnorm2x16:
1114 case EOpPackUnorm2x16:
1115 case EOpUnpackUnorm2x16:
1116 case EOpPackHalf2x16:
1117 case EOpUnpackHalf2x16:
Olli Etuahof119a262016-08-19 15:54:22 +03001118 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1119 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301120 default:
Olli Etuahof119a262016-08-19 15:54:22 +03001121 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1122 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301123 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001124
1125 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001126 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001127}
1128
Olli Etuahof119a262016-08-19 15:54:22 +03001129TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001130{
1131 // Make sure that all params are constant before actual constant folding.
1132 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001133 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001134 if (param->getAsConstantUnion() == nullptr)
1135 {
1136 return nullptr;
1137 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001138 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001139 TConstantUnion *constArray = nullptr;
1140 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001141 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001142 else
Olli Etuahof119a262016-08-19 15:54:22 +03001143 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001144
1145 // Nodes may be constant folded without being qualified as constant.
1146 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1147 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001148}
1149
Jamie Madillb1a85f42014-08-19 15:23:24 -04001150//
1151// The fold functions see if an operation on a constant can be done in place,
1152// without generating run-time code.
1153//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001154// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001155//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001156TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1157 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001158 TDiagnostics *diagnostics,
1159 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001160{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001161 const TConstantUnion *leftArray = getUnionArrayPointer();
1162 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001163
Olli Etuahof119a262016-08-19 15:54:22 +03001164 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001165
1166 size_t objectSize = getType().getObjectSize();
1167
1168 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1169 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1170 {
1171 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1172 }
1173 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1174 {
1175 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1176 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1177 objectSize = rightNode->getType().getObjectSize();
1178 }
1179
1180 TConstantUnion *resultArray = nullptr;
1181
1182 switch(op)
1183 {
1184 case EOpAdd:
1185 resultArray = new TConstantUnion[objectSize];
1186 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001187 resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001188 break;
1189 case EOpSub:
1190 resultArray = new TConstantUnion[objectSize];
1191 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001192 resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001193 break;
1194
1195 case EOpMul:
1196 case EOpVectorTimesScalar:
1197 case EOpMatrixTimesScalar:
1198 resultArray = new TConstantUnion[objectSize];
1199 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001200 resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001201 break;
1202
1203 case EOpMatrixTimesMatrix:
1204 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001205 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001206 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001207
1208 const int leftCols = getCols();
1209 const int leftRows = getRows();
1210 const int rightCols = rightNode->getType().getCols();
1211 const int rightRows = rightNode->getType().getRows();
1212 const int resultCols = rightCols;
1213 const int resultRows = leftRows;
1214
1215 resultArray = new TConstantUnion[resultCols * resultRows];
1216 for (int row = 0; row < resultRows; row++)
1217 {
1218 for (int column = 0; column < resultCols; column++)
1219 {
1220 resultArray[resultRows * column + row].setFConst(0.0f);
1221 for (int i = 0; i < leftCols; i++)
1222 {
1223 resultArray[resultRows * column + row].setFConst(
1224 resultArray[resultRows * column + row].getFConst() +
1225 leftArray[i * leftRows + row].getFConst() *
1226 rightArray[column * rightRows + i].getFConst());
1227 }
1228 }
1229 }
1230 }
1231 break;
1232
1233 case EOpDiv:
1234 case EOpIMod:
1235 {
1236 resultArray = new TConstantUnion[objectSize];
1237 for (size_t i = 0; i < objectSize; i++)
1238 {
1239 switch (getType().getBasicType())
1240 {
1241 case EbtFloat:
1242 if (rightArray[i] == 0.0f)
1243 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001244 diagnostics->warning(
1245 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001246 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1247 }
1248 else
1249 {
1250 ASSERT(op == EOpDiv);
1251 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1252 }
1253 break;
1254
1255 case EbtInt:
1256 if (rightArray[i] == 0)
1257 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001258 diagnostics->warning(
1259 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001260 resultArray[i].setIConst(INT_MAX);
1261 }
1262 else
1263 {
Olli Etuahod4453572016-09-27 13:21:46 +01001264 int lhs = leftArray[i].getIConst();
1265 int divisor = rightArray[i].getIConst();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001266 if (op == EOpDiv)
1267 {
Olli Etuahod4453572016-09-27 13:21:46 +01001268 // Check for the special case where the minimum representable number is
1269 // divided by -1. If left alone this leads to integer overflow in C++.
1270 // ESSL 3.00.6 section 4.1.3 Integers:
1271 // "However, for the case where the minimum representable value is
1272 // divided by -1, it is allowed to return either the minimum
1273 // representable value or the maximum representable value."
1274 if (lhs == -0x7fffffff - 1 && divisor == -1)
1275 {
1276 resultArray[i].setIConst(0x7fffffff);
1277 }
1278 else
1279 {
1280 resultArray[i].setIConst(lhs / divisor);
1281 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001282 }
1283 else
1284 {
1285 ASSERT(op == EOpIMod);
Olli Etuahod4453572016-09-27 13:21:46 +01001286 if (lhs < 0 || divisor < 0)
1287 {
1288 // ESSL 3.00.6 section 5.9: Results of modulus are undefined when
1289 // either one of the operands is negative.
1290 diagnostics->warning(getLine(),
1291 "Negative modulus operator operand "
1292 "encountered during constant folding",
1293 "%", "");
1294 resultArray[i].setIConst(0);
1295 }
1296 else
1297 {
1298 resultArray[i].setIConst(lhs % divisor);
1299 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001300 }
1301 }
1302 break;
1303
1304 case EbtUInt:
1305 if (rightArray[i] == 0)
1306 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001307 diagnostics->warning(
1308 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001309 resultArray[i].setUConst(UINT_MAX);
1310 }
1311 else
1312 {
1313 if (op == EOpDiv)
1314 {
1315 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1316 }
1317 else
1318 {
1319 ASSERT(op == EOpIMod);
1320 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1321 }
1322 }
1323 break;
1324
1325 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001326 UNREACHABLE();
1327 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001328 }
1329 }
1330 }
1331 break;
1332
1333 case EOpMatrixTimesVector:
1334 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001335 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001336 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001337
1338 const int matrixCols = getCols();
1339 const int matrixRows = getRows();
1340
1341 resultArray = new TConstantUnion[matrixRows];
1342
1343 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1344 {
1345 resultArray[matrixRow].setFConst(0.0f);
1346 for (int col = 0; col < matrixCols; col++)
1347 {
1348 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1349 leftArray[col * matrixRows + matrixRow].getFConst() *
1350 rightArray[col].getFConst());
1351 }
1352 }
1353 }
1354 break;
1355
1356 case EOpVectorTimesMatrix:
1357 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001358 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001359 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001360
1361 const int matrixCols = rightNode->getType().getCols();
1362 const int matrixRows = rightNode->getType().getRows();
1363
1364 resultArray = new TConstantUnion[matrixCols];
1365
1366 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1367 {
1368 resultArray[matrixCol].setFConst(0.0f);
1369 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1370 {
1371 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1372 leftArray[matrixRow].getFConst() *
1373 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1374 }
1375 }
1376 }
1377 break;
1378
1379 case EOpLogicalAnd:
1380 {
1381 resultArray = new TConstantUnion[objectSize];
1382 for (size_t i = 0; i < objectSize; i++)
1383 {
1384 resultArray[i] = leftArray[i] && rightArray[i];
1385 }
1386 }
1387 break;
1388
1389 case EOpLogicalOr:
1390 {
1391 resultArray = new TConstantUnion[objectSize];
1392 for (size_t i = 0; i < objectSize; i++)
1393 {
1394 resultArray[i] = leftArray[i] || rightArray[i];
1395 }
1396 }
1397 break;
1398
1399 case EOpLogicalXor:
1400 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001401 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001402 resultArray = new TConstantUnion[objectSize];
1403 for (size_t i = 0; i < objectSize; i++)
1404 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001405 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001406 }
1407 }
1408 break;
1409
1410 case EOpBitwiseAnd:
1411 resultArray = new TConstantUnion[objectSize];
1412 for (size_t i = 0; i < objectSize; i++)
1413 resultArray[i] = leftArray[i] & rightArray[i];
1414 break;
1415 case EOpBitwiseXor:
1416 resultArray = new TConstantUnion[objectSize];
1417 for (size_t i = 0; i < objectSize; i++)
1418 resultArray[i] = leftArray[i] ^ rightArray[i];
1419 break;
1420 case EOpBitwiseOr:
1421 resultArray = new TConstantUnion[objectSize];
1422 for (size_t i = 0; i < objectSize; i++)
1423 resultArray[i] = leftArray[i] | rightArray[i];
1424 break;
1425 case EOpBitShiftLeft:
1426 resultArray = new TConstantUnion[objectSize];
1427 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001428 resultArray[i] = TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001429 break;
1430 case EOpBitShiftRight:
1431 resultArray = new TConstantUnion[objectSize];
1432 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001433 resultArray[i] = TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001434 break;
1435
1436 case EOpLessThan:
1437 ASSERT(objectSize == 1);
1438 resultArray = new TConstantUnion[1];
1439 resultArray->setBConst(*leftArray < *rightArray);
1440 break;
1441
1442 case EOpGreaterThan:
1443 ASSERT(objectSize == 1);
1444 resultArray = new TConstantUnion[1];
1445 resultArray->setBConst(*leftArray > *rightArray);
1446 break;
1447
1448 case EOpLessThanEqual:
1449 ASSERT(objectSize == 1);
1450 resultArray = new TConstantUnion[1];
1451 resultArray->setBConst(!(*leftArray > *rightArray));
1452 break;
1453
1454 case EOpGreaterThanEqual:
1455 ASSERT(objectSize == 1);
1456 resultArray = new TConstantUnion[1];
1457 resultArray->setBConst(!(*leftArray < *rightArray));
1458 break;
1459
1460 case EOpEqual:
1461 case EOpNotEqual:
1462 {
1463 resultArray = new TConstantUnion[1];
1464 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001465 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001466 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001467 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001468 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001469 equal = false;
1470 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001471 }
1472 }
1473 if (op == EOpEqual)
1474 {
1475 resultArray->setBConst(equal);
1476 }
1477 else
1478 {
1479 resultArray->setBConst(!equal);
1480 }
1481 }
1482 break;
1483
1484 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001485 UNREACHABLE();
1486 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001487 }
1488 return resultArray;
1489}
1490
Olli Etuahof119a262016-08-19 15:54:22 +03001491// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1492// code. Returns the constant value to keep using. Nullptr should not be returned.
1493TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001494{
Olli Etuahof119a262016-08-19 15:54:22 +03001495 // Do operations where the return type may have a different number of components compared to the
1496 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001497
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001498 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001499 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301500
1501 size_t objectSize = getType().getObjectSize();
1502 TConstantUnion *resultArray = nullptr;
1503 switch (op)
1504 {
Olli Etuahof119a262016-08-19 15:54:22 +03001505 case EOpAny:
1506 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301507 resultArray = new TConstantUnion();
1508 resultArray->setBConst(false);
1509 for (size_t i = 0; i < objectSize; i++)
1510 {
1511 if (operandArray[i].getBConst())
1512 {
1513 resultArray->setBConst(true);
1514 break;
1515 }
1516 }
1517 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301518
Olli Etuahof119a262016-08-19 15:54:22 +03001519 case EOpAll:
1520 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301521 resultArray = new TConstantUnion();
1522 resultArray->setBConst(true);
1523 for (size_t i = 0; i < objectSize; i++)
1524 {
1525 if (!operandArray[i].getBConst())
1526 {
1527 resultArray->setBConst(false);
1528 break;
1529 }
1530 }
1531 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301532
Olli Etuahof119a262016-08-19 15:54:22 +03001533 case EOpLength:
1534 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301535 resultArray = new TConstantUnion();
1536 resultArray->setFConst(VectorLength(operandArray, objectSize));
1537 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301538
Olli Etuahof119a262016-08-19 15:54:22 +03001539 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301540 {
Olli Etuahof119a262016-08-19 15:54:22 +03001541 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301542 resultArray = new TConstantUnion[objectSize];
1543 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001544 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301545 SetUnionArrayFromMatrix(result, resultArray);
1546 break;
1547 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301548
Olli Etuahof119a262016-08-19 15:54:22 +03001549 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301550 {
Olli Etuahof119a262016-08-19 15:54:22 +03001551 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301552 unsigned int size = getType().getNominalSize();
1553 ASSERT(size >= 2 && size <= 4);
1554 resultArray = new TConstantUnion();
1555 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1556 break;
1557 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301558
Olli Etuahof119a262016-08-19 15:54:22 +03001559 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301560 {
Olli Etuahof119a262016-08-19 15:54:22 +03001561 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301562 unsigned int size = getType().getNominalSize();
1563 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001564 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301565 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1566 SetUnionArrayFromMatrix(result, resultArray);
1567 break;
1568 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301569
Olli Etuahof119a262016-08-19 15:54:22 +03001570 case EOpPackSnorm2x16:
1571 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301572 ASSERT(getType().getNominalSize() == 2);
1573 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001574 resultArray->setUConst(
1575 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301576 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301577
Olli Etuahof119a262016-08-19 15:54:22 +03001578 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301579 {
Olli Etuahof119a262016-08-19 15:54:22 +03001580 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301581 resultArray = new TConstantUnion[2];
1582 float f1, f2;
1583 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1584 resultArray[0].setFConst(f1);
1585 resultArray[1].setFConst(f2);
1586 break;
1587 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301588
Olli Etuahof119a262016-08-19 15:54:22 +03001589 case EOpPackUnorm2x16:
1590 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301591 ASSERT(getType().getNominalSize() == 2);
1592 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001593 resultArray->setUConst(
1594 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301595 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301596
Olli Etuahof119a262016-08-19 15:54:22 +03001597 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301598 {
Olli Etuahof119a262016-08-19 15:54:22 +03001599 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301600 resultArray = new TConstantUnion[2];
1601 float f1, f2;
1602 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1603 resultArray[0].setFConst(f1);
1604 resultArray[1].setFConst(f2);
1605 break;
1606 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301607
Olli Etuahof119a262016-08-19 15:54:22 +03001608 case EOpPackHalf2x16:
1609 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301610 ASSERT(getType().getNominalSize() == 2);
1611 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001612 resultArray->setUConst(
1613 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301614 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301615
Olli Etuahof119a262016-08-19 15:54:22 +03001616 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301617 {
Olli Etuahof119a262016-08-19 15:54:22 +03001618 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301619 resultArray = new TConstantUnion[2];
1620 float f1, f2;
1621 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1622 resultArray[0].setFConst(f1);
1623 resultArray[1].setFConst(f2);
1624 break;
1625 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301626
Olli Etuahof119a262016-08-19 15:54:22 +03001627 default:
1628 UNREACHABLE();
1629 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301630 }
1631
1632 return resultArray;
1633}
1634
Olli Etuahof119a262016-08-19 15:54:22 +03001635TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1636 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301637{
Olli Etuahof119a262016-08-19 15:54:22 +03001638 // Do unary operations where each component of the result is computed based on the corresponding
1639 // component of the operand. Also folds normalize, though the divisor in that case takes all
1640 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301641
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001642 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001643 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001644
1645 size_t objectSize = getType().getObjectSize();
1646
Arun Patoleab2b9a22015-07-06 18:27:56 +05301647 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1648 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301649 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301650 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301651 {
Olli Etuahof119a262016-08-19 15:54:22 +03001652 case EOpNegative:
1653 switch (getType().getBasicType())
1654 {
1655 case EbtFloat:
1656 resultArray[i].setFConst(-operandArray[i].getFConst());
1657 break;
1658 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001659 if (operandArray[i] == std::numeric_limits<int>::min())
1660 {
1661 // The minimum representable integer doesn't have a positive
1662 // counterpart, rather the negation overflows and in ESSL is supposed to
1663 // wrap back to the minimum representable integer. Make sure that we
1664 // don't actually let the negation overflow, which has undefined
1665 // behavior in C++.
1666 resultArray[i].setIConst(std::numeric_limits<int>::min());
1667 }
1668 else
1669 {
1670 resultArray[i].setIConst(-operandArray[i].getIConst());
1671 }
Olli Etuahof119a262016-08-19 15:54:22 +03001672 break;
1673 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001674 if (operandArray[i] == 0x80000000u)
1675 {
1676 resultArray[i].setUConst(0x80000000u);
1677 }
1678 else
1679 {
1680 resultArray[i].setUConst(static_cast<unsigned int>(
1681 -static_cast<int>(operandArray[i].getUConst())));
1682 }
Olli Etuahof119a262016-08-19 15:54:22 +03001683 break;
1684 default:
1685 UNREACHABLE();
1686 return nullptr;
1687 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301688 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301689
Olli Etuahof119a262016-08-19 15:54:22 +03001690 case EOpPositive:
1691 switch (getType().getBasicType())
1692 {
1693 case EbtFloat:
1694 resultArray[i].setFConst(operandArray[i].getFConst());
1695 break;
1696 case EbtInt:
1697 resultArray[i].setIConst(operandArray[i].getIConst());
1698 break;
1699 case EbtUInt:
1700 resultArray[i].setUConst(static_cast<unsigned int>(
1701 static_cast<int>(operandArray[i].getUConst())));
1702 break;
1703 default:
1704 UNREACHABLE();
1705 return nullptr;
1706 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301707 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301708
Olli Etuahof119a262016-08-19 15:54:22 +03001709 case EOpLogicalNot:
1710 switch (getType().getBasicType())
1711 {
1712 case EbtBool:
1713 resultArray[i].setBConst(!operandArray[i].getBConst());
1714 break;
1715 default:
1716 UNREACHABLE();
1717 return nullptr;
1718 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301719 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301720
Olli Etuahof119a262016-08-19 15:54:22 +03001721 case EOpBitwiseNot:
1722 switch (getType().getBasicType())
1723 {
1724 case EbtInt:
1725 resultArray[i].setIConst(~operandArray[i].getIConst());
1726 break;
1727 case EbtUInt:
1728 resultArray[i].setUConst(~operandArray[i].getUConst());
1729 break;
1730 default:
1731 UNREACHABLE();
1732 return nullptr;
1733 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301734 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301735
Olli Etuahof119a262016-08-19 15:54:22 +03001736 case EOpRadians:
1737 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301738 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1739 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301740
Olli Etuahof119a262016-08-19 15:54:22 +03001741 case EOpDegrees:
1742 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301743 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1744 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301745
Olli Etuahof119a262016-08-19 15:54:22 +03001746 case EOpSin:
1747 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301748 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301749
Olli Etuahof119a262016-08-19 15:54:22 +03001750 case EOpCos:
1751 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1752 break;
1753
1754 case EOpTan:
1755 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1756 break;
1757
1758 case EOpAsin:
1759 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1760 // 0.
1761 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1762 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1763 diagnostics, &resultArray[i]);
1764 else
1765 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1766 break;
1767
1768 case EOpAcos:
1769 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1770 // 0.
1771 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1772 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1773 diagnostics, &resultArray[i]);
1774 else
1775 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1776 break;
1777
1778 case EOpAtan:
1779 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1780 break;
1781
1782 case EOpSinh:
1783 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1784 break;
1785
1786 case EOpCosh:
1787 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1788 break;
1789
1790 case EOpTanh:
1791 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1792 break;
1793
1794 case EOpAsinh:
1795 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1796 break;
1797
1798 case EOpAcosh:
1799 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1800 if (operandArray[i].getFConst() < 1.0f)
1801 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1802 diagnostics, &resultArray[i]);
1803 else
1804 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1805 break;
1806
1807 case EOpAtanh:
1808 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1809 // 0.
1810 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1811 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1812 diagnostics, &resultArray[i]);
1813 else
1814 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1815 break;
1816
1817 case EOpAbs:
1818 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301819 {
Olli Etuahof119a262016-08-19 15:54:22 +03001820 case EbtFloat:
1821 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1822 break;
1823 case EbtInt:
1824 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1825 break;
1826 default:
1827 UNREACHABLE();
1828 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301829 }
1830 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001831
1832 case EOpSign:
1833 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301834 {
Olli Etuahof119a262016-08-19 15:54:22 +03001835 case EbtFloat:
1836 {
1837 float fConst = operandArray[i].getFConst();
1838 float fResult = 0.0f;
1839 if (fConst > 0.0f)
1840 fResult = 1.0f;
1841 else if (fConst < 0.0f)
1842 fResult = -1.0f;
1843 resultArray[i].setFConst(fResult);
1844 break;
1845 }
1846 case EbtInt:
1847 {
1848 int iConst = operandArray[i].getIConst();
1849 int iResult = 0;
1850 if (iConst > 0)
1851 iResult = 1;
1852 else if (iConst < 0)
1853 iResult = -1;
1854 resultArray[i].setIConst(iResult);
1855 break;
1856 }
1857 default:
1858 UNREACHABLE();
1859 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301860 }
1861 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301862
Olli Etuahof119a262016-08-19 15:54:22 +03001863 case EOpFloor:
1864 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1865 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301866
Olli Etuahof119a262016-08-19 15:54:22 +03001867 case EOpTrunc:
1868 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1869 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301870
Olli Etuahof119a262016-08-19 15:54:22 +03001871 case EOpRound:
1872 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1873 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874
Olli Etuahof119a262016-08-19 15:54:22 +03001875 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301876 {
Olli Etuahof119a262016-08-19 15:54:22 +03001877 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878 float x = operandArray[i].getFConst();
1879 float result;
1880 float fractPart = modff(x, &result);
1881 if (fabsf(fractPart) == 0.5f)
1882 result = 2.0f * roundf(x / 2.0f);
1883 else
1884 result = roundf(x);
1885 resultArray[i].setFConst(result);
1886 break;
1887 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301888
Olli Etuahof119a262016-08-19 15:54:22 +03001889 case EOpCeil:
1890 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
1891 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301892
Olli Etuahof119a262016-08-19 15:54:22 +03001893 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301894 {
Olli Etuahof119a262016-08-19 15:54:22 +03001895 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301896 float x = operandArray[i].getFConst();
1897 resultArray[i].setFConst(x - floorf(x));
1898 break;
1899 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301900
Olli Etuahof119a262016-08-19 15:54:22 +03001901 case EOpIsNan:
1902 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301903 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1904 break;
Arun Patole551279e2015-07-07 18:18:23 +05301905
Olli Etuahof119a262016-08-19 15:54:22 +03001906 case EOpIsInf:
1907 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301908 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1909 break;
Arun Patole551279e2015-07-07 18:18:23 +05301910
Olli Etuahof119a262016-08-19 15:54:22 +03001911 case EOpFloatBitsToInt:
1912 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301913 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1914 break;
Arun Patole551279e2015-07-07 18:18:23 +05301915
Olli Etuahof119a262016-08-19 15:54:22 +03001916 case EOpFloatBitsToUint:
1917 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301918 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1919 break;
Arun Patole551279e2015-07-07 18:18:23 +05301920
Olli Etuahof119a262016-08-19 15:54:22 +03001921 case EOpIntBitsToFloat:
1922 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05301923 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1924 break;
Arun Patole551279e2015-07-07 18:18:23 +05301925
Olli Etuahof119a262016-08-19 15:54:22 +03001926 case EOpUintBitsToFloat:
1927 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05301928 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1929 break;
Arun Patole551279e2015-07-07 18:18:23 +05301930
Olli Etuahof119a262016-08-19 15:54:22 +03001931 case EOpExp:
1932 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
1933 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301934
Olli Etuahof119a262016-08-19 15:54:22 +03001935 case EOpLog:
1936 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1937 if (operandArray[i].getFConst() <= 0.0f)
1938 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1939 diagnostics, &resultArray[i]);
1940 else
1941 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1942 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301943
Olli Etuahof119a262016-08-19 15:54:22 +03001944 case EOpExp2:
1945 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
1946 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301947
Olli Etuahof119a262016-08-19 15:54:22 +03001948 case EOpLog2:
1949 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1950 // And log2f is not available on some plarforms like old android, so just using
1951 // log(x)/log(2) here.
1952 if (operandArray[i].getFConst() <= 0.0f)
1953 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1954 diagnostics, &resultArray[i]);
1955 else
1956 {
1957 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1958 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1959 }
1960 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301961
Olli Etuahof119a262016-08-19 15:54:22 +03001962 case EOpSqrt:
1963 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1964 if (operandArray[i].getFConst() < 0.0f)
1965 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1966 diagnostics, &resultArray[i]);
1967 else
1968 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1969 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301970
Olli Etuahof119a262016-08-19 15:54:22 +03001971 case EOpInverseSqrt:
1972 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1973 // so getting the square root first using builtin function sqrt() and then taking
1974 // its inverse.
1975 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
1976 // result to 0.
1977 if (operandArray[i].getFConst() <= 0.0f)
1978 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1979 diagnostics, &resultArray[i]);
1980 else
1981 {
1982 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1983 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1984 }
1985 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301986
Olli Etuahof119a262016-08-19 15:54:22 +03001987 case EOpVectorLogicalNot:
1988 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301989 resultArray[i].setBConst(!operandArray[i].getBConst());
1990 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301991
Olli Etuahof119a262016-08-19 15:54:22 +03001992 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301993 {
Olli Etuahof119a262016-08-19 15:54:22 +03001994 ASSERT(getType().getBasicType() == EbtFloat);
1995 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301996 float length = VectorLength(operandArray, objectSize);
1997 if (length)
1998 resultArray[i].setFConst(x / length);
1999 else
Olli Etuahof119a262016-08-19 15:54:22 +03002000 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2001 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302002 break;
2003 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302004
Olli Etuahof119a262016-08-19 15:54:22 +03002005 case EOpDFdx:
2006 case EOpDFdy:
2007 case EOpFwidth:
2008 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302009 // Derivatives of constant arguments should be 0.
2010 resultArray[i].setFConst(0.0f);
2011 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302012
Olli Etuahof119a262016-08-19 15:54:22 +03002013 default:
2014 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302015 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302016 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002017
Arun Patoleab2b9a22015-07-06 18:27:56 +05302018 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002019}
2020
Olli Etuahof119a262016-08-19 15:54:22 +03002021void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2022 FloatTypeUnaryFunc builtinFunc,
2023 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302024{
2025 ASSERT(builtinFunc);
2026
Olli Etuahof119a262016-08-19 15:54:22 +03002027 ASSERT(getType().getBasicType() == EbtFloat);
2028 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302029}
2030
Jamie Madillb1a85f42014-08-19 15:23:24 -04002031// static
Olli Etuahof119a262016-08-19 15:54:22 +03002032TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002033{
2034 ASSERT(aggregate->getSequence()->size() > 0u);
2035 size_t resultSize = aggregate->getType().getObjectSize();
2036 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2037 TBasicType basicType = aggregate->getBasicType();
2038
2039 size_t resultIndex = 0u;
2040
2041 if (aggregate->getSequence()->size() == 1u)
2042 {
2043 TIntermNode *argument = aggregate->getSequence()->front();
2044 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2045 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2046 // Check the special case of constructing a matrix diagonal from a single scalar,
2047 // or a vector from a single scalar.
2048 if (argumentConstant->getType().getObjectSize() == 1u)
2049 {
2050 if (aggregate->isMatrix())
2051 {
2052 int resultCols = aggregate->getType().getCols();
2053 int resultRows = aggregate->getType().getRows();
2054 for (int col = 0; col < resultCols; ++col)
2055 {
2056 for (int row = 0; row < resultRows; ++row)
2057 {
2058 if (col == row)
2059 {
2060 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2061 }
2062 else
2063 {
2064 resultArray[resultIndex].setFConst(0.0f);
2065 }
2066 ++resultIndex;
2067 }
2068 }
2069 }
2070 else
2071 {
2072 while (resultIndex < resultSize)
2073 {
2074 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2075 ++resultIndex;
2076 }
2077 }
2078 ASSERT(resultIndex == resultSize);
2079 return resultArray;
2080 }
2081 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2082 {
2083 // The special case of constructing a matrix from a matrix.
2084 int argumentCols = argumentConstant->getType().getCols();
2085 int argumentRows = argumentConstant->getType().getRows();
2086 int resultCols = aggregate->getType().getCols();
2087 int resultRows = aggregate->getType().getRows();
2088 for (int col = 0; col < resultCols; ++col)
2089 {
2090 for (int row = 0; row < resultRows; ++row)
2091 {
2092 if (col < argumentCols && row < argumentRows)
2093 {
2094 resultArray[resultIndex].cast(basicType,
2095 argumentUnionArray[col * argumentRows + row]);
2096 }
2097 else if (col == row)
2098 {
2099 resultArray[resultIndex].setFConst(1.0f);
2100 }
2101 else
2102 {
2103 resultArray[resultIndex].setFConst(0.0f);
2104 }
2105 ++resultIndex;
2106 }
2107 }
2108 ASSERT(resultIndex == resultSize);
2109 return resultArray;
2110 }
2111 }
2112
2113 for (TIntermNode *&argument : *aggregate->getSequence())
2114 {
2115 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2116 size_t argumentSize = argumentConstant->getType().getObjectSize();
2117 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2118 for (size_t i = 0u; i < argumentSize; ++i)
2119 {
2120 if (resultIndex >= resultSize)
2121 break;
2122 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2123 ++resultIndex;
2124 }
2125 }
2126 ASSERT(resultIndex == resultSize);
2127 return resultArray;
2128}
2129
2130// static
Olli Etuahof119a262016-08-19 15:54:22 +03002131TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2132 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302133{
Olli Etuahob43846e2015-06-02 18:18:57 +03002134 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302135 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002136 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002137 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302138 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002139 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302140 TBasicType basicType = EbtVoid;
2141 TSourceLoc loc;
2142 for (unsigned int i = 0; i < paramsCount; i++)
2143 {
2144 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002145 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302146
2147 if (i == 0)
2148 {
2149 basicType = paramConstant->getType().getBasicType();
2150 loc = paramConstant->getLine();
2151 }
2152 unionArrays[i] = paramConstant->getUnionArrayPointer();
2153 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002154 if (objectSizes[i] > maxObjectSize)
2155 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302156 }
2157
Olli Etuahod5da5052016-08-29 13:16:55 +03002158 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302159 {
2160 for (unsigned int i = 0; i < paramsCount; i++)
2161 if (objectSizes[i] != maxObjectSize)
2162 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2163 }
Arun Patole274f0702015-05-05 13:33:30 +05302164
Olli Etuahob43846e2015-06-02 18:18:57 +03002165 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302166 if (paramsCount == 2)
2167 {
2168 //
2169 // Binary built-in
2170 //
2171 switch (op)
2172 {
Olli Etuahof119a262016-08-19 15:54:22 +03002173 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302174 {
Olli Etuahof119a262016-08-19 15:54:22 +03002175 ASSERT(basicType == EbtFloat);
2176 resultArray = new TConstantUnion[maxObjectSize];
2177 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302178 {
Olli Etuahof119a262016-08-19 15:54:22 +03002179 float y = unionArrays[0][i].getFConst();
2180 float x = unionArrays[1][i].getFConst();
2181 // Results are undefined if x and y are both 0.
2182 if (x == 0.0f && y == 0.0f)
2183 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2184 &resultArray[i]);
2185 else
2186 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302187 }
Olli Etuahof119a262016-08-19 15:54:22 +03002188 break;
Arun Patolebf790422015-05-18 17:53:04 +05302189 }
Arun Patolebf790422015-05-18 17:53:04 +05302190
Olli Etuahof119a262016-08-19 15:54:22 +03002191 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302192 {
Olli Etuahof119a262016-08-19 15:54:22 +03002193 ASSERT(basicType == EbtFloat);
2194 resultArray = new TConstantUnion[maxObjectSize];
2195 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302196 {
Olli Etuahof119a262016-08-19 15:54:22 +03002197 float x = unionArrays[0][i].getFConst();
2198 float y = unionArrays[1][i].getFConst();
2199 // Results are undefined if x < 0.
2200 // Results are undefined if x = 0 and y <= 0.
2201 if (x < 0.0f)
2202 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2203 &resultArray[i]);
2204 else if (x == 0.0f && y <= 0.0f)
2205 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2206 &resultArray[i]);
2207 else
2208 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302209 }
Olli Etuahof119a262016-08-19 15:54:22 +03002210 break;
Arun Patolebf790422015-05-18 17:53:04 +05302211 }
Arun Patolebf790422015-05-18 17:53:04 +05302212
Olli Etuahof119a262016-08-19 15:54:22 +03002213 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302214 {
Olli Etuahof119a262016-08-19 15:54:22 +03002215 ASSERT(basicType == EbtFloat);
2216 resultArray = new TConstantUnion[maxObjectSize];
2217 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302218 {
Olli Etuahof119a262016-08-19 15:54:22 +03002219 float x = unionArrays[0][i].getFConst();
2220 float y = unionArrays[1][i].getFConst();
2221 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302222 }
Olli Etuahof119a262016-08-19 15:54:22 +03002223 break;
Arun Patolebf790422015-05-18 17:53:04 +05302224 }
Arun Patolebf790422015-05-18 17:53:04 +05302225
Olli Etuahof119a262016-08-19 15:54:22 +03002226 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302227 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002228 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302229 for (size_t i = 0; i < maxObjectSize; i++)
2230 {
2231 switch (basicType)
2232 {
Olli Etuahof119a262016-08-19 15:54:22 +03002233 case EbtFloat:
2234 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2235 unionArrays[1][i].getFConst()));
2236 break;
2237 case EbtInt:
2238 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2239 unionArrays[1][i].getIConst()));
2240 break;
2241 case EbtUInt:
2242 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2243 unionArrays[1][i].getUConst()));
2244 break;
2245 default:
2246 UNREACHABLE();
2247 break;
Arun Patole274f0702015-05-05 13:33:30 +05302248 }
2249 }
Olli Etuahof119a262016-08-19 15:54:22 +03002250 break;
Arun Patole274f0702015-05-05 13:33:30 +05302251 }
Arun Patole274f0702015-05-05 13:33:30 +05302252
Olli Etuahof119a262016-08-19 15:54:22 +03002253 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302254 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002255 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302256 for (size_t i = 0; i < maxObjectSize; i++)
2257 {
2258 switch (basicType)
2259 {
Olli Etuahof119a262016-08-19 15:54:22 +03002260 case EbtFloat:
2261 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2262 unionArrays[1][i].getFConst()));
2263 break;
2264 case EbtInt:
2265 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2266 unionArrays[1][i].getIConst()));
2267 break;
2268 case EbtUInt:
2269 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2270 unionArrays[1][i].getUConst()));
2271 break;
2272 default:
2273 UNREACHABLE();
2274 break;
Arun Patole274f0702015-05-05 13:33:30 +05302275 }
2276 }
Olli Etuahof119a262016-08-19 15:54:22 +03002277 break;
Arun Patole274f0702015-05-05 13:33:30 +05302278 }
Arun Patole274f0702015-05-05 13:33:30 +05302279
Olli Etuahof119a262016-08-19 15:54:22 +03002280 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302281 {
Olli Etuahof119a262016-08-19 15:54:22 +03002282 ASSERT(basicType == EbtFloat);
2283 resultArray = new TConstantUnion[maxObjectSize];
2284 for (size_t i = 0; i < maxObjectSize; i++)
2285 resultArray[i].setFConst(
2286 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2287 : 1.0f);
2288 break;
Arun Patolebf790422015-05-18 17:53:04 +05302289 }
Arun Patolebf790422015-05-18 17:53:04 +05302290
Olli Etuahof119a262016-08-19 15:54:22 +03002291 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302292 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002293 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302294 for (size_t i = 0; i < maxObjectSize; i++)
2295 {
2296 switch (basicType)
2297 {
Olli Etuahof119a262016-08-19 15:54:22 +03002298 case EbtFloat:
2299 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2300 unionArrays[1][i].getFConst());
2301 break;
2302 case EbtInt:
2303 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2304 unionArrays[1][i].getIConst());
2305 break;
2306 case EbtUInt:
2307 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2308 unionArrays[1][i].getUConst());
2309 break;
2310 default:
2311 UNREACHABLE();
2312 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302313 }
2314 }
Olli Etuahof119a262016-08-19 15:54:22 +03002315 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302316 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302317
Olli Etuahof119a262016-08-19 15:54:22 +03002318 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302319 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002320 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302321 for (size_t i = 0; i < maxObjectSize; i++)
2322 {
2323 switch (basicType)
2324 {
Olli Etuahof119a262016-08-19 15:54:22 +03002325 case EbtFloat:
2326 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2327 unionArrays[1][i].getFConst());
2328 break;
2329 case EbtInt:
2330 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2331 unionArrays[1][i].getIConst());
2332 break;
2333 case EbtUInt:
2334 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2335 unionArrays[1][i].getUConst());
2336 break;
2337 default:
2338 UNREACHABLE();
2339 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302340 }
2341 }
Olli Etuahof119a262016-08-19 15:54:22 +03002342 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302343 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302344
Olli Etuahof119a262016-08-19 15:54:22 +03002345 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302346 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002347 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302348 for (size_t i = 0; i < maxObjectSize; i++)
2349 {
2350 switch (basicType)
2351 {
Olli Etuahof119a262016-08-19 15:54:22 +03002352 case EbtFloat:
2353 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2354 unionArrays[1][i].getFConst());
2355 break;
2356 case EbtInt:
2357 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2358 unionArrays[1][i].getIConst());
2359 break;
2360 case EbtUInt:
2361 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2362 unionArrays[1][i].getUConst());
2363 break;
2364 default:
2365 UNREACHABLE();
2366 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002367 }
2368 }
Olli Etuahof119a262016-08-19 15:54:22 +03002369 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302370 }
Olli Etuahof119a262016-08-19 15:54:22 +03002371 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302372 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002373 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302374 for (size_t i = 0; i < maxObjectSize; i++)
2375 {
2376 switch (basicType)
2377 {
Olli Etuahof119a262016-08-19 15:54:22 +03002378 case EbtFloat:
2379 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2380 unionArrays[1][i].getFConst());
2381 break;
2382 case EbtInt:
2383 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2384 unionArrays[1][i].getIConst());
2385 break;
2386 case EbtUInt:
2387 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2388 unionArrays[1][i].getUConst());
2389 break;
2390 default:
2391 UNREACHABLE();
2392 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302393 }
2394 }
2395 }
2396 break;
2397
Olli Etuahof119a262016-08-19 15:54:22 +03002398 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302399 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002400 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302401 for (size_t i = 0; i < maxObjectSize; i++)
2402 {
2403 switch (basicType)
2404 {
Olli Etuahof119a262016-08-19 15:54:22 +03002405 case EbtFloat:
2406 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2407 unionArrays[1][i].getFConst());
2408 break;
2409 case EbtInt:
2410 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2411 unionArrays[1][i].getIConst());
2412 break;
2413 case EbtUInt:
2414 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2415 unionArrays[1][i].getUConst());
2416 break;
2417 case EbtBool:
2418 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2419 unionArrays[1][i].getBConst());
2420 break;
2421 default:
2422 UNREACHABLE();
2423 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302424 }
2425 }
Olli Etuahof119a262016-08-19 15:54:22 +03002426 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302427 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302428
Olli Etuahof119a262016-08-19 15:54:22 +03002429 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302430 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002431 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302432 for (size_t i = 0; i < maxObjectSize; i++)
2433 {
2434 switch (basicType)
2435 {
Olli Etuahof119a262016-08-19 15:54:22 +03002436 case EbtFloat:
2437 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2438 unionArrays[1][i].getFConst());
2439 break;
2440 case EbtInt:
2441 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2442 unionArrays[1][i].getIConst());
2443 break;
2444 case EbtUInt:
2445 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2446 unionArrays[1][i].getUConst());
2447 break;
2448 case EbtBool:
2449 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2450 unionArrays[1][i].getBConst());
2451 break;
2452 default:
2453 UNREACHABLE();
2454 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302455 }
2456 }
Olli Etuahof119a262016-08-19 15:54:22 +03002457 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302458 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302459
Olli Etuahof119a262016-08-19 15:54:22 +03002460 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302461 {
Olli Etuahof119a262016-08-19 15:54:22 +03002462 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302463 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002464 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302465 for (size_t i = 0; i < maxObjectSize; i++)
2466 {
2467 float x = unionArrays[0][i].getFConst();
2468 float y = unionArrays[1][i].getFConst();
2469 distanceArray[i].setFConst(x - y);
2470 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002471 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002472 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302473 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302474
Olli Etuahof119a262016-08-19 15:54:22 +03002475 case EOpDot:
2476 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002477 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002478 resultArray->setFConst(
2479 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2480 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302481
Olli Etuahof119a262016-08-19 15:54:22 +03002482 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302483 {
Olli Etuahof119a262016-08-19 15:54:22 +03002484 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002485 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002486 float x0 = unionArrays[0][0].getFConst();
2487 float x1 = unionArrays[0][1].getFConst();
2488 float x2 = unionArrays[0][2].getFConst();
2489 float y0 = unionArrays[1][0].getFConst();
2490 float y1 = unionArrays[1][1].getFConst();
2491 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002492 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2493 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2494 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002495 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302496 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302497
Olli Etuahof119a262016-08-19 15:54:22 +03002498 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302499 {
Olli Etuahof119a262016-08-19 15:54:22 +03002500 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302501 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002502 // For the incident vector I and surface orientation N, returns the reflection
2503 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302504 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002505 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302506 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2507 for (size_t i = 0; i < maxObjectSize; i++)
2508 {
2509 float result = unionArrays[0][i].getFConst() -
2510 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002511 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302512 }
Olli Etuahof119a262016-08-19 15:54:22 +03002513 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302514 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302515
Olli Etuahof119a262016-08-19 15:54:22 +03002516 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302517 {
Olli Etuahof119a262016-08-19 15:54:22 +03002518 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2519 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302520 // Perform component-wise matrix multiplication.
2521 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002522 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302523 angle::Matrix<float> result =
2524 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2525 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002526 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302527 }
Arun Patole7fa33552015-06-10 15:15:18 +05302528
Olli Etuahof119a262016-08-19 15:54:22 +03002529 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302530 {
Olli Etuahof119a262016-08-19 15:54:22 +03002531 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302532 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2533 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002534 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302535 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002536 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2537 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302538 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002539 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302540 }
Arun Patole7fa33552015-06-10 15:15:18 +05302541
Olli Etuahof119a262016-08-19 15:54:22 +03002542 default:
2543 UNREACHABLE();
2544 // TODO: Add constant folding support for other built-in operations that take 2
2545 // parameters and not handled above.
2546 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302547 }
2548 }
2549 else if (paramsCount == 3)
2550 {
2551 //
2552 // Ternary built-in
2553 //
2554 switch (op)
2555 {
Olli Etuahof119a262016-08-19 15:54:22 +03002556 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302557 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002558 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302559 for (size_t i = 0; i < maxObjectSize; i++)
2560 {
2561 switch (basicType)
2562 {
Olli Etuahof119a262016-08-19 15:54:22 +03002563 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302564 {
Olli Etuahof119a262016-08-19 15:54:22 +03002565 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302566 float min = unionArrays[1][i].getFConst();
2567 float max = unionArrays[2][i].getFConst();
2568 // Results are undefined if min > max.
2569 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002570 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2571 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302572 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002573 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002574 break;
Arun Patole274f0702015-05-05 13:33:30 +05302575 }
Olli Etuahof119a262016-08-19 15:54:22 +03002576
2577 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302578 {
Olli Etuahof119a262016-08-19 15:54:22 +03002579 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302580 int min = unionArrays[1][i].getIConst();
2581 int max = unionArrays[2][i].getIConst();
2582 // Results are undefined if min > max.
2583 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002584 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2585 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302586 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002587 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002588 break;
Arun Patole274f0702015-05-05 13:33:30 +05302589 }
Olli Etuahof119a262016-08-19 15:54:22 +03002590 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302591 {
Olli Etuahof119a262016-08-19 15:54:22 +03002592 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302593 unsigned int min = unionArrays[1][i].getUConst();
2594 unsigned int max = unionArrays[2][i].getUConst();
2595 // Results are undefined if min > max.
2596 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002597 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2598 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302599 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002600 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002601 break;
Arun Patole274f0702015-05-05 13:33:30 +05302602 }
Olli Etuahof119a262016-08-19 15:54:22 +03002603 default:
2604 UNREACHABLE();
2605 break;
Arun Patole274f0702015-05-05 13:33:30 +05302606 }
2607 }
Olli Etuahof119a262016-08-19 15:54:22 +03002608 break;
Arun Patole274f0702015-05-05 13:33:30 +05302609 }
Arun Patole274f0702015-05-05 13:33:30 +05302610
Olli Etuahof119a262016-08-19 15:54:22 +03002611 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302612 {
Olli Etuahof119a262016-08-19 15:54:22 +03002613 ASSERT(basicType == EbtFloat);
2614 resultArray = new TConstantUnion[maxObjectSize];
2615 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302616 {
Olli Etuahof119a262016-08-19 15:54:22 +03002617 float x = unionArrays[0][i].getFConst();
2618 float y = unionArrays[1][i].getFConst();
2619 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2620 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302621 {
Olli Etuahof119a262016-08-19 15:54:22 +03002622 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2623 float a = unionArrays[2][i].getFConst();
2624 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2625 }
2626 else // 3rd parameter is EbtBool
2627 {
2628 ASSERT(type == EbtBool);
2629 // Selects which vector each returned component comes from.
2630 // For a component of a that is false, the corresponding component of x is
2631 // returned.
2632 // For a component of a that is true, the corresponding component of y is
2633 // returned.
2634 bool a = unionArrays[2][i].getBConst();
2635 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302636 }
2637 }
Olli Etuahof119a262016-08-19 15:54:22 +03002638 break;
Arun Patolebf790422015-05-18 17:53:04 +05302639 }
Arun Patolebf790422015-05-18 17:53:04 +05302640
Olli Etuahof119a262016-08-19 15:54:22 +03002641 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302642 {
Olli Etuahof119a262016-08-19 15:54:22 +03002643 ASSERT(basicType == EbtFloat);
2644 resultArray = new TConstantUnion[maxObjectSize];
2645 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302646 {
Olli Etuahof119a262016-08-19 15:54:22 +03002647 float edge0 = unionArrays[0][i].getFConst();
2648 float edge1 = unionArrays[1][i].getFConst();
2649 float x = unionArrays[2][i].getFConst();
2650 // Results are undefined if edge0 >= edge1.
2651 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302652 {
Olli Etuahof119a262016-08-19 15:54:22 +03002653 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2654 &resultArray[i]);
2655 }
2656 else
2657 {
2658 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2659 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2660 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2661 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302662 }
2663 }
Olli Etuahof119a262016-08-19 15:54:22 +03002664 break;
Arun Patolebf790422015-05-18 17:53:04 +05302665 }
Arun Patolebf790422015-05-18 17:53:04 +05302666
Olli Etuahof119a262016-08-19 15:54:22 +03002667 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302668 {
Olli Etuahof119a262016-08-19 15:54:22 +03002669 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302670 // genType faceforward(genType N, genType I, genType Nref) :
2671 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002672 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302673 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2674 for (size_t i = 0; i < maxObjectSize; i++)
2675 {
2676 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002677 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302678 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002679 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302680 }
Olli Etuahof119a262016-08-19 15:54:22 +03002681 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302682 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302683
Olli Etuahof119a262016-08-19 15:54:22 +03002684 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302685 {
Olli Etuahof119a262016-08-19 15:54:22 +03002686 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302687 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002688 // For the incident vector I and surface normal N, and the ratio of indices of
2689 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302690 // return the refraction vector. The result is computed by
2691 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2692 // if (k < 0.0)
2693 // return genType(0.0)
2694 // else
2695 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002696 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302697 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2698 for (size_t i = 0; i < maxObjectSize; i++)
2699 {
2700 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002701 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302702 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002703 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302704 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002705 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002706 (eta * dotProduct + sqrtf(k)) *
2707 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302708 }
Olli Etuahof119a262016-08-19 15:54:22 +03002709 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302710 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302711
Olli Etuahof119a262016-08-19 15:54:22 +03002712 default:
2713 UNREACHABLE();
2714 // TODO: Add constant folding support for other built-in operations that take 3
2715 // parameters and not handled above.
2716 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302717 }
2718 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002719 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302720}
2721
2722// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002723TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2724{
2725 if (hashFunction == NULL || name.empty())
2726 return name;
2727 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2728 TStringStream stream;
2729 stream << HASHED_NAME_PREFIX << std::hex << number;
2730 TString hashedName = stream.str();
2731 return hashedName;
2732}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002733
2734void TIntermTraverser::updateTree()
2735{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002736 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2737 {
2738 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2739 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002740 if (!insertion.insertionsAfter.empty())
2741 {
2742 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2743 insertion.insertionsAfter);
2744 ASSERT(inserted);
2745 UNUSED_ASSERTION_VARIABLE(inserted);
2746 }
2747 if (!insertion.insertionsBefore.empty())
2748 {
2749 bool inserted =
2750 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2751 ASSERT(inserted);
2752 UNUSED_ASSERTION_VARIABLE(inserted);
2753 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002754 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002755 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2756 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002757 const NodeUpdateEntry &replacement = mReplacements[ii];
2758 ASSERT(replacement.parent);
2759 bool replaced = replacement.parent->replaceChildNode(
2760 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002761 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002762 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002763
Olli Etuahocd94ef92015-04-16 19:18:10 +03002764 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002765 {
2766 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002767 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002768 // be replaced, we need to make sure we don't update the replaced
2769 // node; instead, we update the replacement node.
2770 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2771 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002772 NodeUpdateEntry &replacement2 = mReplacements[jj];
2773 if (replacement2.parent == replacement.original)
2774 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002775 }
2776 }
2777 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002778 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2779 {
2780 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2781 ASSERT(replacement.parent);
2782 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2783 replacement.original, replacement.replacements);
2784 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002785 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002786 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002787
Jamie Madill03d863c2016-07-27 18:15:53 -04002788 clearReplacementQueue();
2789}
2790
2791void TIntermTraverser::clearReplacementQueue()
2792{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002793 mReplacements.clear();
2794 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002795 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002796}
Jamie Madill1048e432016-07-23 18:51:28 -04002797
Jamie Madill03d863c2016-07-27 18:15:53 -04002798void TIntermTraverser::queueReplacement(TIntermNode *original,
2799 TIntermNode *replacement,
2800 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002801{
Jamie Madill03d863c2016-07-27 18:15:53 -04002802 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002803}
2804
Jamie Madill03d863c2016-07-27 18:15:53 -04002805void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2806 TIntermNode *original,
2807 TIntermNode *replacement,
2808 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002809{
Jamie Madill03d863c2016-07-27 18:15:53 -04002810 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2811 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002812}