blob: 4f09fac1a87d8cf4cfbee038dd3fc07c3f889df2 [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 Etuaho6d40bbd2016-09-30 13:49:38 +0100173 REPLACE_IF_IS(mBody, TIntermBlock, 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{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100210 return replaceChildNodeInternal(original, replacement);
211}
212
213bool TIntermBlock::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
214{
215 return replaceChildNodeInternal(original, replacement);
216}
217
218bool TIntermAggregateBase::replaceChildNodeInternal(TIntermNode *original, TIntermNode *replacement)
219{
220 for (size_t ii = 0; ii < getSequence()->size(); ++ii)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400221 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100222 REPLACE_IF_IS((*getSequence())[ii], TIntermNode, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400223 }
224 return false;
225}
226
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100227bool TIntermAggregateBase::replaceChildNodeWithMultiple(TIntermNode *original,
228 const TIntermSequence &replacements)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300229{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100230 for (auto it = getSequence()->begin(); it < getSequence()->end(); ++it)
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300231 {
232 if (*it == original)
233 {
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100234 it = getSequence()->erase(it);
235 getSequence()->insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300236 return true;
237 }
238 }
239 return false;
240}
241
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100242bool TIntermAggregateBase::insertChildNodes(TIntermSequence::size_type position,
243 const TIntermSequence &insertions)
Olli Etuahoa6f22092015-05-08 18:31:10 +0300244{
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100245 if (position > getSequence()->size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300246 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300247 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300248 }
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100249 auto it = getSequence()->begin() + position;
250 getSequence()->insert(it, insertions.begin(), insertions.end());
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300251 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300252}
253
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200254bool TIntermAggregate::areChildrenConstQualified()
255{
256 for (TIntermNode *&child : mSequence)
257 {
258 TIntermTyped *typed = child->getAsTyped();
259 if (typed && typed->getQualifier() != EvqConst)
260 {
261 return false;
262 }
263 }
264 return true;
265}
266
Olli Etuahod2a67b92014-10-21 16:42:57 +0300267void TIntermAggregate::setPrecisionFromChildren()
268{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300269 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300270 if (getBasicType() == EbtBool)
271 {
272 mType.setPrecision(EbpUndefined);
273 return;
274 }
275
276 TPrecision precision = EbpUndefined;
277 TIntermSequence::iterator childIter = mSequence.begin();
278 while (childIter != mSequence.end())
279 {
280 TIntermTyped *typed = (*childIter)->getAsTyped();
281 if (typed)
282 precision = GetHigherPrecision(typed->getPrecision(), precision);
283 ++childIter;
284 }
285 mType.setPrecision(precision);
286}
287
288void TIntermAggregate::setBuiltInFunctionPrecision()
289{
290 // All built-ins returning bool should be handled as ops, not functions.
291 ASSERT(getBasicType() != EbtBool);
292
293 TPrecision precision = EbpUndefined;
294 TIntermSequence::iterator childIter = mSequence.begin();
295 while (childIter != mSequence.end())
296 {
297 TIntermTyped *typed = (*childIter)->getAsTyped();
298 // ESSL spec section 8: texture functions get their precision from the sampler.
299 if (typed && IsSampler(typed->getBasicType()))
300 {
301 precision = typed->getPrecision();
302 break;
303 }
304 ++childIter;
305 }
306 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
307 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300308 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300309 mType.setPrecision(EbpHigh);
310 else
311 mType.setPrecision(precision);
312}
313
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100314void TIntermBlock::appendStatement(TIntermNode *statement)
315{
316 if (statement != nullptr)
317 {
318 mStatements.push_back(statement);
319 }
320}
321
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300322bool TIntermTernary::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
323{
324 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
325 REPLACE_IF_IS(mTrueExpression, TIntermTyped, original, replacement);
326 REPLACE_IF_IS(mFalseExpression, TIntermTyped, original, replacement);
327 return false;
328}
329
Olli Etuaho57961272016-09-14 13:57:46 +0300330bool TIntermIfElse::replaceChildNode(TIntermNode *original, TIntermNode *replacement)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400331{
332 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100333 REPLACE_IF_IS(mTrueBlock, TIntermBlock, original, replacement);
334 REPLACE_IF_IS(mFalseBlock, TIntermBlock, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400335 return false;
336}
337
Olli Etuahoa3a36662015-02-17 13:46:51 +0200338bool TIntermSwitch::replaceChildNode(
339 TIntermNode *original, TIntermNode *replacement)
340{
341 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
Olli Etuaho6d40bbd2016-09-30 13:49:38 +0100342 REPLACE_IF_IS(mStatementList, TIntermBlock, original, replacement);
Olli Etuahoa3a36662015-02-17 13:46:51 +0200343 return false;
344}
345
346bool TIntermCase::replaceChildNode(
347 TIntermNode *original, TIntermNode *replacement)
348{
349 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
350 return false;
351}
352
Olli Etuahod7a25242015-08-18 13:49:45 +0300353TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
354{
355 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
356 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
357 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
358 mLine = node.mLine;
359}
360
Olli Etuahod4f4c112016-04-15 15:11:24 +0300361bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
362{
363 TIntermAggregate *constructor = getAsAggregate();
364 if (!constructor || !constructor->isConstructor())
365 {
366 return false;
367 }
368 for (TIntermNode *&node : *constructor->getSequence())
369 {
370 if (!node->getAsConstantUnion())
371 return false;
372 }
373 return true;
374}
375
Corentin Wallez509e4562016-08-25 14:55:44 -0400376// static
377TIntermTyped *TIntermTyped::CreateIndexNode(int index)
378{
379 TConstantUnion *u = new TConstantUnion[1];
380 u[0].setIConst(index);
381
382 TType type(EbtInt, EbpUndefined, EvqConst, 1);
383 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
384 return node;
385}
386
387// static
388TIntermTyped *TIntermTyped::CreateZero(const TType &type)
389{
390 TType constType(type);
391 constType.setQualifier(EvqConst);
392
393 if (!type.isArray() && type.getBasicType() != EbtStruct)
394 {
395 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
396
397 size_t size = constType.getObjectSize();
398 TConstantUnion *u = new TConstantUnion[size];
399 for (size_t i = 0; i < size; ++i)
400 {
401 switch (type.getBasicType())
402 {
403 case EbtFloat:
404 u[i].setFConst(0.0f);
405 break;
406 case EbtInt:
407 u[i].setIConst(0);
408 break;
409 case EbtUInt:
410 u[i].setUConst(0u);
411 break;
412 case EbtBool:
413 u[i].setBConst(false);
414 break;
415 default:
416 UNREACHABLE();
417 return nullptr;
418 }
419 }
420
421 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
422 return node;
423 }
424
425 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
426 constructor->setType(constType);
427
428 if (type.isArray())
429 {
430 TType elementType(type);
431 elementType.clearArrayness();
432
433 size_t arraySize = type.getArraySize();
434 for (size_t i = 0; i < arraySize; ++i)
435 {
436 constructor->getSequence()->push_back(CreateZero(elementType));
437 }
438 }
439 else
440 {
441 ASSERT(type.getBasicType() == EbtStruct);
442
443 TStructure *structure = type.getStruct();
444 for (const auto &field : structure->fields())
445 {
446 constructor->getSequence()->push_back(CreateZero(*field->type()));
447 }
448 }
449
450 return constructor;
451}
452
Olli Etuahod7a25242015-08-18 13:49:45 +0300453TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
454{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200455 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300456}
457
458TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
459 : TIntermOperator(node),
460 mName(node.mName),
461 mUserDefined(node.mUserDefined),
462 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300463 mUseEmulatedFunction(node.mUseEmulatedFunction),
464 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
465{
466 for (TIntermNode *child : node.mSequence)
467 {
468 TIntermTyped *typedChild = child->getAsTyped();
469 ASSERT(typedChild != nullptr);
470 TIntermTyped *childCopy = typedChild->deepCopy();
471 mSequence.push_back(childCopy);
472 }
473}
474
Olli Etuahob6fa0432016-09-28 16:28:05 +0100475TIntermSwizzle::TIntermSwizzle(const TIntermSwizzle &node) : TIntermTyped(node)
476{
477 TIntermTyped *operandCopy = node.mOperand->deepCopy();
478 ASSERT(operandCopy != nullptr);
479 mOperand = operandCopy;
480}
481
Olli Etuahod7a25242015-08-18 13:49:45 +0300482TIntermBinary::TIntermBinary(const TIntermBinary &node)
483 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
484{
485 TIntermTyped *leftCopy = node.mLeft->deepCopy();
486 TIntermTyped *rightCopy = node.mRight->deepCopy();
487 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
488 mLeft = leftCopy;
489 mRight = rightCopy;
490}
491
492TIntermUnary::TIntermUnary(const TIntermUnary &node)
493 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
494{
495 TIntermTyped *operandCopy = node.mOperand->deepCopy();
496 ASSERT(operandCopy != nullptr);
497 mOperand = operandCopy;
498}
499
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300500TIntermTernary::TIntermTernary(const TIntermTernary &node) : TIntermTyped(node)
Olli Etuahod7a25242015-08-18 13:49:45 +0300501{
Olli Etuahod7a25242015-08-18 13:49:45 +0300502 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300503 TIntermTyped *trueCopy = node.mTrueExpression->deepCopy();
504 TIntermTyped *falseCopy = node.mFalseExpression->deepCopy();
Olli Etuahod7a25242015-08-18 13:49:45 +0300505 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300506 mCondition = conditionCopy;
507 mTrueExpression = trueCopy;
508 mFalseExpression = falseCopy;
Olli Etuahod7a25242015-08-18 13:49:45 +0300509}
510
Jamie Madillb1a85f42014-08-19 15:23:24 -0400511bool TIntermOperator::isAssignment() const
512{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300513 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400514}
515
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300516bool TIntermOperator::isMultiplication() const
517{
518 switch (mOp)
519 {
520 case EOpMul:
521 case EOpMatrixTimesMatrix:
522 case EOpMatrixTimesVector:
523 case EOpMatrixTimesScalar:
524 case EOpVectorTimesMatrix:
525 case EOpVectorTimesScalar:
526 return true;
527 default:
528 return false;
529 }
530}
531
Jamie Madillb1a85f42014-08-19 15:23:24 -0400532//
533// returns true if the operator is for one of the constructors
534//
535bool TIntermOperator::isConstructor() const
536{
537 switch (mOp)
538 {
539 case EOpConstructVec2:
540 case EOpConstructVec3:
541 case EOpConstructVec4:
542 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400543 case EOpConstructMat2x3:
544 case EOpConstructMat2x4:
545 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400546 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400547 case EOpConstructMat3x4:
548 case EOpConstructMat4x2:
549 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400550 case EOpConstructMat4:
551 case EOpConstructFloat:
552 case EOpConstructIVec2:
553 case EOpConstructIVec3:
554 case EOpConstructIVec4:
555 case EOpConstructInt:
556 case EOpConstructUVec2:
557 case EOpConstructUVec3:
558 case EOpConstructUVec4:
559 case EOpConstructUInt:
560 case EOpConstructBVec2:
561 case EOpConstructBVec3:
562 case EOpConstructBVec4:
563 case EOpConstructBool:
564 case EOpConstructStruct:
565 return true;
566 default:
567 return false;
568 }
569}
570
Olli Etuaho1dded802016-08-18 18:13:13 +0300571TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
572{
573 if (left.isMatrix())
574 {
575 if (right.isMatrix())
576 {
577 return EOpMatrixTimesMatrix;
578 }
579 else
580 {
581 if (right.isVector())
582 {
583 return EOpMatrixTimesVector;
584 }
585 else
586 {
587 return EOpMatrixTimesScalar;
588 }
589 }
590 }
591 else
592 {
593 if (right.isMatrix())
594 {
595 if (left.isVector())
596 {
597 return EOpVectorTimesMatrix;
598 }
599 else
600 {
601 return EOpMatrixTimesScalar;
602 }
603 }
604 else
605 {
606 // Neither operand is a matrix.
607 if (left.isVector() == right.isVector())
608 {
609 // Leave as component product.
610 return EOpMul;
611 }
612 else
613 {
614 return EOpVectorTimesScalar;
615 }
616 }
617 }
618}
619
620TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
621{
622 if (left.isMatrix())
623 {
624 if (right.isMatrix())
625 {
626 return EOpMatrixTimesMatrixAssign;
627 }
628 else
629 {
630 // right should be scalar, but this may not be validated yet.
631 return EOpMatrixTimesScalarAssign;
632 }
633 }
634 else
635 {
636 if (right.isMatrix())
637 {
638 // Left should be a vector, but this may not be validated yet.
639 return EOpVectorTimesMatrixAssign;
640 }
641 else
642 {
643 // Neither operand is a matrix.
644 if (left.isVector() == right.isVector())
645 {
646 // Leave as component product.
647 return EOpMulAssign;
648 }
649 else
650 {
651 // left should be vector and right should be scalar, but this may not be validated
652 // yet.
653 return EOpVectorTimesScalarAssign;
654 }
655 }
656 }
657}
658
Jamie Madillb1a85f42014-08-19 15:23:24 -0400659//
660// Make sure the type of a unary operator is appropriate for its
661// combination of operation and operand type.
662//
Olli Etuahoa2234302016-08-31 12:05:39 +0300663void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400664{
Olli Etuahoa2234302016-08-31 12:05:39 +0300665 TQualifier resultQualifier = EvqTemporary;
666 if (mOperand->getQualifier() == EvqConst)
667 resultQualifier = EvqConst;
668
669 unsigned char operandPrimarySize =
670 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400671 switch (mOp)
672 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300673 case EOpFloatBitsToInt:
674 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
675 break;
676 case EOpFloatBitsToUint:
677 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
678 break;
679 case EOpIntBitsToFloat:
680 case EOpUintBitsToFloat:
681 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
682 break;
683 case EOpPackSnorm2x16:
684 case EOpPackUnorm2x16:
685 case EOpPackHalf2x16:
686 setType(TType(EbtUInt, EbpHigh, resultQualifier));
687 break;
688 case EOpUnpackSnorm2x16:
689 case EOpUnpackUnorm2x16:
690 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
691 break;
692 case EOpUnpackHalf2x16:
693 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
694 break;
695 case EOpAny:
696 case EOpAll:
697 setType(TType(EbtBool, EbpUndefined, resultQualifier));
698 break;
699 case EOpLength:
700 case EOpDeterminant:
701 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
702 break;
703 case EOpTranspose:
704 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
705 static_cast<unsigned char>(mOperand->getType().getRows()),
706 static_cast<unsigned char>(mOperand->getType().getCols())));
707 break;
708 case EOpIsInf:
709 case EOpIsNan:
710 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
711 break;
712 default:
713 setType(mOperand->getType());
714 mType.setQualifier(resultQualifier);
715 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400716 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300717}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400718
Olli Etuahob6fa0432016-09-28 16:28:05 +0100719TIntermSwizzle::TIntermSwizzle(TIntermTyped *operand, const TVector<int> &swizzleOffsets)
720 : TIntermTyped(TType(EbtFloat, EbpUndefined)),
721 mOperand(operand),
722 mSwizzleOffsets(swizzleOffsets)
723{
724 ASSERT(mSwizzleOffsets.size() <= 4);
725 promote();
726}
727
Olli Etuahoa2234302016-08-31 12:05:39 +0300728TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
729 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
730{
731 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400732}
733
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300734TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
735 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
736{
737 promote();
738}
739
Olli Etuahod0bad2c2016-09-09 18:01:16 +0300740TIntermTernary::TIntermTernary(TIntermTyped *cond,
741 TIntermTyped *trueExpression,
742 TIntermTyped *falseExpression)
743 : TIntermTyped(trueExpression->getType()),
744 mCondition(cond),
745 mTrueExpression(trueExpression),
746 mFalseExpression(falseExpression)
747{
748 getTypePointer()->setQualifier(
749 TIntermTernary::DetermineQualifier(cond, trueExpression, falseExpression));
750}
751
752// static
753TQualifier TIntermTernary::DetermineQualifier(TIntermTyped *cond,
754 TIntermTyped *trueExpression,
755 TIntermTyped *falseExpression)
756{
757 if (cond->getQualifier() == EvqConst && trueExpression->getQualifier() == EvqConst &&
758 falseExpression->getQualifier() == EvqConst)
759 {
760 return EvqConst;
761 }
762 return EvqTemporary;
763}
764
Olli Etuahob6fa0432016-09-28 16:28:05 +0100765void TIntermSwizzle::promote()
766{
767 TQualifier resultQualifier = EvqTemporary;
768 if (mOperand->getQualifier() == EvqConst)
769 resultQualifier = EvqConst;
770
771 auto numFields = mSwizzleOffsets.size();
772 setType(TType(mOperand->getBasicType(), mOperand->getPrecision(), resultQualifier,
773 static_cast<unsigned char>(numFields)));
774}
775
776bool TIntermSwizzle::hasDuplicateOffsets() const
777{
778 int offsetCount[4] = {0u, 0u, 0u, 0u};
779 for (const auto offset : mSwizzleOffsets)
780 {
781 offsetCount[offset]++;
782 if (offsetCount[offset] > 1)
783 {
784 return true;
785 }
786 }
787 return false;
788}
789
790void TIntermSwizzle::writeOffsetsAsXYZW(TInfoSinkBase *out) const
791{
792 for (const int offset : mSwizzleOffsets)
793 {
794 switch (offset)
795 {
796 case 0:
797 *out << "x";
798 break;
799 case 1:
800 *out << "y";
801 break;
802 case 2:
803 *out << "z";
804 break;
805 case 3:
806 *out << "w";
807 break;
808 default:
809 UNREACHABLE();
810 }
811 }
812}
813
814
815// Establishes the type of the result of the binary operation.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300816void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400817{
Olli Etuaho1dded802016-08-18 18:13:13 +0300818 ASSERT(!isMultiplication() ||
819 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
820
Jamie Madillb1a85f42014-08-19 15:23:24 -0400821 // Base assumption: just make the type the same as the left
822 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400823 setType(mLeft->getType());
824
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200825 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400826 // Binary operations results in temporary variables unless both
827 // operands are const.
828 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
829 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200830 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400831 getTypePointer()->setQualifier(EvqTemporary);
832 }
833
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300834 // Handle indexing ops.
835 switch (mOp)
836 {
837 case EOpIndexDirect:
838 case EOpIndexIndirect:
839 if (mLeft->isArray())
840 {
841 mType.clearArrayness();
842 }
843 else if (mLeft->isMatrix())
844 {
845 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
846 static_cast<unsigned char>(mLeft->getRows())));
847 }
848 else if (mLeft->isVector())
849 {
850 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
851 }
852 else
853 {
854 UNREACHABLE();
855 }
856 return;
857 case EOpIndexDirectStruct:
858 {
859 const TFieldList &fields = mLeft->getType().getStruct()->fields();
860 const int i = mRight->getAsConstantUnion()->getIConst(0);
861 setType(*fields[i]->type());
862 getTypePointer()->setQualifier(resultQualifier);
863 return;
864 }
865 case EOpIndexDirectInterfaceBlock:
866 {
867 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
868 const int i = mRight->getAsConstantUnion()->getIConst(0);
869 setType(*fields[i]->type());
870 getTypePointer()->setQualifier(resultQualifier);
871 return;
872 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300873 default:
874 break;
875 }
876
877 ASSERT(mLeft->isArray() == mRight->isArray());
878
879 // The result gets promoted to the highest precision.
880 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
881 getTypePointer()->setPrecision(higherPrecision);
882
Jamie Madillb1a85f42014-08-19 15:23:24 -0400883 const int nominalSize =
884 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
885
886 //
887 // All scalars or structs. Code after this test assumes this case is removed!
888 //
889 if (nominalSize == 1)
890 {
891 switch (mOp)
892 {
893 //
894 // Promote to conditional
895 //
896 case EOpEqual:
897 case EOpNotEqual:
898 case EOpLessThan:
899 case EOpGreaterThan:
900 case EOpLessThanEqual:
901 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300902 setType(TType(EbtBool, EbpUndefined, resultQualifier));
903 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400904
905 //
906 // And and Or operate on conditionals
907 //
908 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200909 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400910 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200911 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300912 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400913 break;
914
915 default:
916 break;
917 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300918 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400919 }
920
921 // If we reach here, at least one of the operands is vector or matrix.
922 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400923 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300924
Jamie Madillb1a85f42014-08-19 15:23:24 -0400925 switch (mOp)
926 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300927 case EOpMul:
928 break;
929 case EOpMatrixTimesScalar:
930 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400931 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200932 setType(TType(basicType, higherPrecision, resultQualifier,
933 static_cast<unsigned char>(mRight->getCols()),
934 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400935 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300936 break;
937 case EOpMatrixTimesVector:
938 setType(TType(basicType, higherPrecision, resultQualifier,
939 static_cast<unsigned char>(mLeft->getRows()), 1));
940 break;
941 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200942 setType(TType(basicType, higherPrecision, resultQualifier,
943 static_cast<unsigned char>(mRight->getCols()),
944 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300945 break;
946 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200947 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300948 static_cast<unsigned char>(nominalSize), 1));
949 break;
950 case EOpVectorTimesMatrix:
951 setType(TType(basicType, higherPrecision, resultQualifier,
952 static_cast<unsigned char>(mRight->getCols()), 1));
953 break;
954 case EOpMulAssign:
955 case EOpVectorTimesScalarAssign:
956 case EOpVectorTimesMatrixAssign:
957 case EOpMatrixTimesScalarAssign:
958 case EOpMatrixTimesMatrixAssign:
959 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
960 break;
961 case EOpAssign:
962 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300963 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
964 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
965 break;
966 case EOpAdd:
967 case EOpSub:
968 case EOpDiv:
969 case EOpIMod:
970 case EOpBitShiftLeft:
971 case EOpBitShiftRight:
972 case EOpBitwiseAnd:
973 case EOpBitwiseXor:
974 case EOpBitwiseOr:
975 case EOpAddAssign:
976 case EOpSubAssign:
977 case EOpDivAssign:
978 case EOpIModAssign:
979 case EOpBitShiftLeftAssign:
980 case EOpBitShiftRightAssign:
981 case EOpBitwiseAndAssign:
982 case EOpBitwiseXorAssign:
983 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300984 {
985 const int secondarySize =
986 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
987 setType(TType(basicType, higherPrecision, resultQualifier,
988 static_cast<unsigned char>(nominalSize),
989 static_cast<unsigned char>(secondarySize)));
990 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300991 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300992 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300993 case EOpEqual:
994 case EOpNotEqual:
995 case EOpLessThan:
996 case EOpGreaterThan:
997 case EOpLessThanEqual:
998 case EOpGreaterThanEqual:
999 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
1000 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001001 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +03001002 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001003
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001004 case EOpIndexDirect:
1005 case EOpIndexIndirect:
1006 case EOpIndexDirectInterfaceBlock:
1007 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001008 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001009 UNREACHABLE();
1010 break;
Olli Etuaho1dded802016-08-18 18:13:13 +03001011 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +03001012 UNREACHABLE();
1013 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001014 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001015}
1016
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001017const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001018{
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001019 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001020 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001021 ASSERT(index < static_cast<int>(getType().getArraySize()));
1022 TType arrayElementType = getType();
1023 arrayElementType.clearArrayness();
1024 size_t arrayElementSize = arrayElementType.getObjectSize();
1025 return &mUnionArrayPointer[arrayElementSize * index];
1026 }
1027 else if (isMatrix())
1028 {
1029 ASSERT(index < getType().getCols());
1030 int size = getType().getRows();
1031 return &mUnionArrayPointer[size * index];
1032 }
1033 else if (isVector())
1034 {
1035 ASSERT(index < getType().getNominalSize());
1036 return &mUnionArrayPointer[index];
1037 }
1038 else
1039 {
1040 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001041 return nullptr;
1042 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001043}
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001044
Olli Etuahob6fa0432016-09-28 16:28:05 +01001045TIntermTyped *TIntermSwizzle::fold()
1046{
1047 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1048 if (operandConstant == nullptr)
1049 {
1050 return nullptr;
1051 }
1052
1053 TConstantUnion *constArray = new TConstantUnion[mSwizzleOffsets.size()];
1054 for (size_t i = 0; i < mSwizzleOffsets.size(); ++i)
1055 {
1056 constArray[i] = *operandConstant->foldIndexing(mSwizzleOffsets.at(i));
1057 }
1058 return CreateFoldedNode(constArray, this, mType.getQualifier());
1059}
1060
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001061TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
1062{
1063 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
1064 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
1065 switch (mOp)
1066 {
1067 case EOpIndexDirect:
1068 {
1069 if (leftConstant == nullptr || rightConstant == nullptr)
1070 {
1071 return nullptr;
1072 }
1073 int index = rightConstant->getIConst(0);
1074
1075 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
1076 return CreateFoldedNode(constArray, this, mType.getQualifier());
1077 }
1078 case EOpIndexDirectStruct:
1079 {
1080 if (leftConstant == nullptr || rightConstant == nullptr)
1081 {
1082 return nullptr;
1083 }
1084 const TFieldList &fields = mLeft->getType().getStruct()->fields();
1085 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
1086
1087 size_t previousFieldsSize = 0;
1088 for (size_t i = 0; i < index; ++i)
1089 {
1090 previousFieldsSize += fields[i]->type()->getObjectSize();
1091 }
1092
1093 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
1094 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
1095 }
1096 case EOpIndexIndirect:
1097 case EOpIndexDirectInterfaceBlock:
1098 // Can never be constant folded.
1099 return nullptr;
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001100 default:
1101 {
1102 if (leftConstant == nullptr || rightConstant == nullptr)
1103 {
1104 return nullptr;
1105 }
Jamie Madill5db69f52016-09-15 12:47:32 -04001106 TConstantUnion *constArray =
1107 leftConstant->foldBinary(mOp, rightConstant, diagnostics, mLeft->getLine());
Olli Etuaho3272a6d2016-08-29 17:54:50 +03001108
1109 // Nodes may be constant folded without being qualified as constant.
1110 return CreateFoldedNode(constArray, this, mType.getQualifier());
1111 }
1112 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001113}
1114
Olli Etuahof119a262016-08-19 15:54:22 +03001115TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001116{
1117 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1118 if (operandConstant == nullptr)
1119 {
1120 return nullptr;
1121 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301122
1123 TConstantUnion *constArray = nullptr;
1124 switch (mOp)
1125 {
1126 case EOpAny:
1127 case EOpAll:
1128 case EOpLength:
1129 case EOpTranspose:
1130 case EOpDeterminant:
1131 case EOpInverse:
1132 case EOpPackSnorm2x16:
1133 case EOpUnpackSnorm2x16:
1134 case EOpPackUnorm2x16:
1135 case EOpUnpackUnorm2x16:
1136 case EOpPackHalf2x16:
1137 case EOpUnpackHalf2x16:
Olli Etuahof119a262016-08-19 15:54:22 +03001138 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1139 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301140 default:
Olli Etuahof119a262016-08-19 15:54:22 +03001141 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1142 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301143 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001144
1145 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001146 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001147}
1148
Olli Etuahof119a262016-08-19 15:54:22 +03001149TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001150{
1151 // Make sure that all params are constant before actual constant folding.
1152 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001153 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001154 if (param->getAsConstantUnion() == nullptr)
1155 {
1156 return nullptr;
1157 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001158 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001159 TConstantUnion *constArray = nullptr;
1160 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001161 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001162 else
Olli Etuahof119a262016-08-19 15:54:22 +03001163 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001164
1165 // Nodes may be constant folded without being qualified as constant.
1166 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1167 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001168}
1169
Jamie Madillb1a85f42014-08-19 15:23:24 -04001170//
1171// The fold functions see if an operation on a constant can be done in place,
1172// without generating run-time code.
1173//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001174// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001175//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001176TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1177 TIntermConstantUnion *rightNode,
Jamie Madill5db69f52016-09-15 12:47:32 -04001178 TDiagnostics *diagnostics,
1179 const TSourceLoc &line)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001180{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001181 const TConstantUnion *leftArray = getUnionArrayPointer();
1182 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001183
Olli Etuahof119a262016-08-19 15:54:22 +03001184 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001185
1186 size_t objectSize = getType().getObjectSize();
1187
1188 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1189 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1190 {
1191 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1192 }
1193 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1194 {
1195 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1196 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1197 objectSize = rightNode->getType().getObjectSize();
1198 }
1199
1200 TConstantUnion *resultArray = nullptr;
1201
1202 switch(op)
1203 {
1204 case EOpAdd:
1205 resultArray = new TConstantUnion[objectSize];
1206 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001207 resultArray[i] = TConstantUnion::add(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001208 break;
1209 case EOpSub:
1210 resultArray = new TConstantUnion[objectSize];
1211 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001212 resultArray[i] = TConstantUnion::sub(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001213 break;
1214
1215 case EOpMul:
1216 case EOpVectorTimesScalar:
1217 case EOpMatrixTimesScalar:
1218 resultArray = new TConstantUnion[objectSize];
1219 for (size_t i = 0; i < objectSize; i++)
Jamie Madill5db69f52016-09-15 12:47:32 -04001220 resultArray[i] = TConstantUnion::mul(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001221 break;
1222
1223 case EOpMatrixTimesMatrix:
1224 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001225 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001226 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001227
1228 const int leftCols = getCols();
1229 const int leftRows = getRows();
1230 const int rightCols = rightNode->getType().getCols();
1231 const int rightRows = rightNode->getType().getRows();
1232 const int resultCols = rightCols;
1233 const int resultRows = leftRows;
1234
1235 resultArray = new TConstantUnion[resultCols * resultRows];
1236 for (int row = 0; row < resultRows; row++)
1237 {
1238 for (int column = 0; column < resultCols; column++)
1239 {
1240 resultArray[resultRows * column + row].setFConst(0.0f);
1241 for (int i = 0; i < leftCols; i++)
1242 {
1243 resultArray[resultRows * column + row].setFConst(
1244 resultArray[resultRows * column + row].getFConst() +
1245 leftArray[i * leftRows + row].getFConst() *
1246 rightArray[column * rightRows + i].getFConst());
1247 }
1248 }
1249 }
1250 }
1251 break;
1252
1253 case EOpDiv:
1254 case EOpIMod:
1255 {
1256 resultArray = new TConstantUnion[objectSize];
1257 for (size_t i = 0; i < objectSize; i++)
1258 {
1259 switch (getType().getBasicType())
1260 {
1261 case EbtFloat:
1262 if (rightArray[i] == 0.0f)
1263 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001264 diagnostics->warning(
1265 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001266 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1267 }
1268 else
1269 {
1270 ASSERT(op == EOpDiv);
1271 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1272 }
1273 break;
1274
1275 case EbtInt:
1276 if (rightArray[i] == 0)
1277 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001278 diagnostics->warning(
1279 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001280 resultArray[i].setIConst(INT_MAX);
1281 }
1282 else
1283 {
Olli Etuahod4453572016-09-27 13:21:46 +01001284 int lhs = leftArray[i].getIConst();
1285 int divisor = rightArray[i].getIConst();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001286 if (op == EOpDiv)
1287 {
Olli Etuahod4453572016-09-27 13:21:46 +01001288 // Check for the special case where the minimum representable number is
1289 // divided by -1. If left alone this leads to integer overflow in C++.
1290 // ESSL 3.00.6 section 4.1.3 Integers:
1291 // "However, for the case where the minimum representable value is
1292 // divided by -1, it is allowed to return either the minimum
1293 // representable value or the maximum representable value."
1294 if (lhs == -0x7fffffff - 1 && divisor == -1)
1295 {
1296 resultArray[i].setIConst(0x7fffffff);
1297 }
1298 else
1299 {
1300 resultArray[i].setIConst(lhs / divisor);
1301 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001302 }
1303 else
1304 {
1305 ASSERT(op == EOpIMod);
Olli Etuahod4453572016-09-27 13:21:46 +01001306 if (lhs < 0 || divisor < 0)
1307 {
1308 // ESSL 3.00.6 section 5.9: Results of modulus are undefined when
1309 // either one of the operands is negative.
1310 diagnostics->warning(getLine(),
1311 "Negative modulus operator operand "
1312 "encountered during constant folding",
1313 "%", "");
1314 resultArray[i].setIConst(0);
1315 }
1316 else
1317 {
1318 resultArray[i].setIConst(lhs % divisor);
1319 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001320 }
1321 }
1322 break;
1323
1324 case EbtUInt:
1325 if (rightArray[i] == 0)
1326 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001327 diagnostics->warning(
1328 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001329 resultArray[i].setUConst(UINT_MAX);
1330 }
1331 else
1332 {
1333 if (op == EOpDiv)
1334 {
1335 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1336 }
1337 else
1338 {
1339 ASSERT(op == EOpIMod);
1340 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1341 }
1342 }
1343 break;
1344
1345 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001346 UNREACHABLE();
1347 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001348 }
1349 }
1350 }
1351 break;
1352
1353 case EOpMatrixTimesVector:
1354 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001355 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001356 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001357
1358 const int matrixCols = getCols();
1359 const int matrixRows = getRows();
1360
1361 resultArray = new TConstantUnion[matrixRows];
1362
1363 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1364 {
1365 resultArray[matrixRow].setFConst(0.0f);
1366 for (int col = 0; col < matrixCols; col++)
1367 {
1368 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1369 leftArray[col * matrixRows + matrixRow].getFConst() *
1370 rightArray[col].getFConst());
1371 }
1372 }
1373 }
1374 break;
1375
1376 case EOpVectorTimesMatrix:
1377 {
Jamie Madill5db69f52016-09-15 12:47:32 -04001378 // TODO(jmadll): This code should check for overflows.
Olli Etuaho3fdec912016-08-18 15:08:06 +03001379 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001380
1381 const int matrixCols = rightNode->getType().getCols();
1382 const int matrixRows = rightNode->getType().getRows();
1383
1384 resultArray = new TConstantUnion[matrixCols];
1385
1386 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1387 {
1388 resultArray[matrixCol].setFConst(0.0f);
1389 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1390 {
1391 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1392 leftArray[matrixRow].getFConst() *
1393 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1394 }
1395 }
1396 }
1397 break;
1398
1399 case EOpLogicalAnd:
1400 {
1401 resultArray = new TConstantUnion[objectSize];
1402 for (size_t i = 0; i < objectSize; i++)
1403 {
1404 resultArray[i] = leftArray[i] && rightArray[i];
1405 }
1406 }
1407 break;
1408
1409 case EOpLogicalOr:
1410 {
1411 resultArray = new TConstantUnion[objectSize];
1412 for (size_t i = 0; i < objectSize; i++)
1413 {
1414 resultArray[i] = leftArray[i] || rightArray[i];
1415 }
1416 }
1417 break;
1418
1419 case EOpLogicalXor:
1420 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001421 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001422 resultArray = new TConstantUnion[objectSize];
1423 for (size_t i = 0; i < objectSize; i++)
1424 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001425 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001426 }
1427 }
1428 break;
1429
1430 case EOpBitwiseAnd:
1431 resultArray = new TConstantUnion[objectSize];
1432 for (size_t i = 0; i < objectSize; i++)
1433 resultArray[i] = leftArray[i] & rightArray[i];
1434 break;
1435 case EOpBitwiseXor:
1436 resultArray = new TConstantUnion[objectSize];
1437 for (size_t i = 0; i < objectSize; i++)
1438 resultArray[i] = leftArray[i] ^ rightArray[i];
1439 break;
1440 case EOpBitwiseOr:
1441 resultArray = new TConstantUnion[objectSize];
1442 for (size_t i = 0; i < objectSize; i++)
1443 resultArray[i] = leftArray[i] | rightArray[i];
1444 break;
1445 case EOpBitShiftLeft:
1446 resultArray = new TConstantUnion[objectSize];
1447 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001448 resultArray[i] = TConstantUnion::lshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001449 break;
1450 case EOpBitShiftRight:
1451 resultArray = new TConstantUnion[objectSize];
1452 for (size_t i = 0; i < objectSize; i++)
Jamie Madill596018c2016-09-21 12:57:03 -04001453 resultArray[i] = TConstantUnion::rshift(leftArray[i], rightArray[i], diagnostics, line);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001454 break;
1455
1456 case EOpLessThan:
1457 ASSERT(objectSize == 1);
1458 resultArray = new TConstantUnion[1];
1459 resultArray->setBConst(*leftArray < *rightArray);
1460 break;
1461
1462 case EOpGreaterThan:
1463 ASSERT(objectSize == 1);
1464 resultArray = new TConstantUnion[1];
1465 resultArray->setBConst(*leftArray > *rightArray);
1466 break;
1467
1468 case EOpLessThanEqual:
1469 ASSERT(objectSize == 1);
1470 resultArray = new TConstantUnion[1];
1471 resultArray->setBConst(!(*leftArray > *rightArray));
1472 break;
1473
1474 case EOpGreaterThanEqual:
1475 ASSERT(objectSize == 1);
1476 resultArray = new TConstantUnion[1];
1477 resultArray->setBConst(!(*leftArray < *rightArray));
1478 break;
1479
1480 case EOpEqual:
1481 case EOpNotEqual:
1482 {
1483 resultArray = new TConstantUnion[1];
1484 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001485 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001486 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001487 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001488 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001489 equal = false;
1490 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001491 }
1492 }
1493 if (op == EOpEqual)
1494 {
1495 resultArray->setBConst(equal);
1496 }
1497 else
1498 {
1499 resultArray->setBConst(!equal);
1500 }
1501 }
1502 break;
1503
1504 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001505 UNREACHABLE();
1506 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001507 }
1508 return resultArray;
1509}
1510
Olli Etuahof119a262016-08-19 15:54:22 +03001511// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1512// code. Returns the constant value to keep using. Nullptr should not be returned.
1513TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001514{
Olli Etuahof119a262016-08-19 15:54:22 +03001515 // Do operations where the return type may have a different number of components compared to the
1516 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001517
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001518 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001519 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301520
1521 size_t objectSize = getType().getObjectSize();
1522 TConstantUnion *resultArray = nullptr;
1523 switch (op)
1524 {
Olli Etuahof119a262016-08-19 15:54:22 +03001525 case EOpAny:
1526 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301527 resultArray = new TConstantUnion();
1528 resultArray->setBConst(false);
1529 for (size_t i = 0; i < objectSize; i++)
1530 {
1531 if (operandArray[i].getBConst())
1532 {
1533 resultArray->setBConst(true);
1534 break;
1535 }
1536 }
1537 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301538
Olli Etuahof119a262016-08-19 15:54:22 +03001539 case EOpAll:
1540 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301541 resultArray = new TConstantUnion();
1542 resultArray->setBConst(true);
1543 for (size_t i = 0; i < objectSize; i++)
1544 {
1545 if (!operandArray[i].getBConst())
1546 {
1547 resultArray->setBConst(false);
1548 break;
1549 }
1550 }
1551 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301552
Olli Etuahof119a262016-08-19 15:54:22 +03001553 case EOpLength:
1554 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301555 resultArray = new TConstantUnion();
1556 resultArray->setFConst(VectorLength(operandArray, objectSize));
1557 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301558
Olli Etuahof119a262016-08-19 15:54:22 +03001559 case EOpTranspose:
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 resultArray = new TConstantUnion[objectSize];
1563 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001564 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301565 SetUnionArrayFromMatrix(result, resultArray);
1566 break;
1567 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301568
Olli Etuahof119a262016-08-19 15:54:22 +03001569 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301570 {
Olli Etuahof119a262016-08-19 15:54:22 +03001571 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301572 unsigned int size = getType().getNominalSize();
1573 ASSERT(size >= 2 && size <= 4);
1574 resultArray = new TConstantUnion();
1575 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1576 break;
1577 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301578
Olli Etuahof119a262016-08-19 15:54:22 +03001579 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301580 {
Olli Etuahof119a262016-08-19 15:54:22 +03001581 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301582 unsigned int size = getType().getNominalSize();
1583 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001584 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301585 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1586 SetUnionArrayFromMatrix(result, resultArray);
1587 break;
1588 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301589
Olli Etuahof119a262016-08-19 15:54:22 +03001590 case EOpPackSnorm2x16:
1591 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301592 ASSERT(getType().getNominalSize() == 2);
1593 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001594 resultArray->setUConst(
1595 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301596 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301597
Olli Etuahof119a262016-08-19 15:54:22 +03001598 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301599 {
Olli Etuahof119a262016-08-19 15:54:22 +03001600 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301601 resultArray = new TConstantUnion[2];
1602 float f1, f2;
1603 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1604 resultArray[0].setFConst(f1);
1605 resultArray[1].setFConst(f2);
1606 break;
1607 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301608
Olli Etuahof119a262016-08-19 15:54:22 +03001609 case EOpPackUnorm2x16:
1610 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301611 ASSERT(getType().getNominalSize() == 2);
1612 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001613 resultArray->setUConst(
1614 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301615 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301616
Olli Etuahof119a262016-08-19 15:54:22 +03001617 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301618 {
Olli Etuahof119a262016-08-19 15:54:22 +03001619 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301620 resultArray = new TConstantUnion[2];
1621 float f1, f2;
1622 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1623 resultArray[0].setFConst(f1);
1624 resultArray[1].setFConst(f2);
1625 break;
1626 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301627
Olli Etuahof119a262016-08-19 15:54:22 +03001628 case EOpPackHalf2x16:
1629 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301630 ASSERT(getType().getNominalSize() == 2);
1631 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001632 resultArray->setUConst(
1633 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301634 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301635
Olli Etuahof119a262016-08-19 15:54:22 +03001636 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301637 {
Olli Etuahof119a262016-08-19 15:54:22 +03001638 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301639 resultArray = new TConstantUnion[2];
1640 float f1, f2;
1641 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1642 resultArray[0].setFConst(f1);
1643 resultArray[1].setFConst(f2);
1644 break;
1645 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301646
Olli Etuahof119a262016-08-19 15:54:22 +03001647 default:
1648 UNREACHABLE();
1649 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301650 }
1651
1652 return resultArray;
1653}
1654
Olli Etuahof119a262016-08-19 15:54:22 +03001655TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1656 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301657{
Olli Etuahof119a262016-08-19 15:54:22 +03001658 // Do unary operations where each component of the result is computed based on the corresponding
1659 // component of the operand. Also folds normalize, though the divisor in that case takes all
1660 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301661
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001662 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001663 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001664
1665 size_t objectSize = getType().getObjectSize();
1666
Arun Patoleab2b9a22015-07-06 18:27:56 +05301667 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1668 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301669 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301670 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301671 {
Olli Etuahof119a262016-08-19 15:54:22 +03001672 case EOpNegative:
1673 switch (getType().getBasicType())
1674 {
1675 case EbtFloat:
1676 resultArray[i].setFConst(-operandArray[i].getFConst());
1677 break;
1678 case EbtInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001679 if (operandArray[i] == std::numeric_limits<int>::min())
1680 {
1681 // The minimum representable integer doesn't have a positive
1682 // counterpart, rather the negation overflows and in ESSL is supposed to
1683 // wrap back to the minimum representable integer. Make sure that we
1684 // don't actually let the negation overflow, which has undefined
1685 // behavior in C++.
1686 resultArray[i].setIConst(std::numeric_limits<int>::min());
1687 }
1688 else
1689 {
1690 resultArray[i].setIConst(-operandArray[i].getIConst());
1691 }
Olli Etuahof119a262016-08-19 15:54:22 +03001692 break;
1693 case EbtUInt:
Olli Etuaho42fad762016-09-28 10:06:29 +01001694 if (operandArray[i] == 0x80000000u)
1695 {
1696 resultArray[i].setUConst(0x80000000u);
1697 }
1698 else
1699 {
1700 resultArray[i].setUConst(static_cast<unsigned int>(
1701 -static_cast<int>(operandArray[i].getUConst())));
1702 }
Olli Etuahof119a262016-08-19 15:54:22 +03001703 break;
1704 default:
1705 UNREACHABLE();
1706 return nullptr;
1707 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301708 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301709
Olli Etuahof119a262016-08-19 15:54:22 +03001710 case EOpPositive:
1711 switch (getType().getBasicType())
1712 {
1713 case EbtFloat:
1714 resultArray[i].setFConst(operandArray[i].getFConst());
1715 break;
1716 case EbtInt:
1717 resultArray[i].setIConst(operandArray[i].getIConst());
1718 break;
1719 case EbtUInt:
1720 resultArray[i].setUConst(static_cast<unsigned int>(
1721 static_cast<int>(operandArray[i].getUConst())));
1722 break;
1723 default:
1724 UNREACHABLE();
1725 return nullptr;
1726 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301727 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301728
Olli Etuahof119a262016-08-19 15:54:22 +03001729 case EOpLogicalNot:
1730 switch (getType().getBasicType())
1731 {
1732 case EbtBool:
1733 resultArray[i].setBConst(!operandArray[i].getBConst());
1734 break;
1735 default:
1736 UNREACHABLE();
1737 return nullptr;
1738 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301739 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301740
Olli Etuahof119a262016-08-19 15:54:22 +03001741 case EOpBitwiseNot:
1742 switch (getType().getBasicType())
1743 {
1744 case EbtInt:
1745 resultArray[i].setIConst(~operandArray[i].getIConst());
1746 break;
1747 case EbtUInt:
1748 resultArray[i].setUConst(~operandArray[i].getUConst());
1749 break;
1750 default:
1751 UNREACHABLE();
1752 return nullptr;
1753 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301754 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301755
Olli Etuahof119a262016-08-19 15:54:22 +03001756 case EOpRadians:
1757 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301758 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1759 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301760
Olli Etuahof119a262016-08-19 15:54:22 +03001761 case EOpDegrees:
1762 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301763 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1764 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301765
Olli Etuahof119a262016-08-19 15:54:22 +03001766 case EOpSin:
1767 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301768 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301769
Olli Etuahof119a262016-08-19 15:54:22 +03001770 case EOpCos:
1771 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1772 break;
1773
1774 case EOpTan:
1775 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1776 break;
1777
1778 case EOpAsin:
1779 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1780 // 0.
1781 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1782 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1783 diagnostics, &resultArray[i]);
1784 else
1785 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1786 break;
1787
1788 case EOpAcos:
1789 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1790 // 0.
1791 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1792 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1793 diagnostics, &resultArray[i]);
1794 else
1795 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1796 break;
1797
1798 case EOpAtan:
1799 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1800 break;
1801
1802 case EOpSinh:
1803 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1804 break;
1805
1806 case EOpCosh:
1807 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1808 break;
1809
1810 case EOpTanh:
1811 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1812 break;
1813
1814 case EOpAsinh:
1815 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1816 break;
1817
1818 case EOpAcosh:
1819 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1820 if (operandArray[i].getFConst() < 1.0f)
1821 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1822 diagnostics, &resultArray[i]);
1823 else
1824 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1825 break;
1826
1827 case EOpAtanh:
1828 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1829 // 0.
1830 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1831 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1832 diagnostics, &resultArray[i]);
1833 else
1834 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1835 break;
1836
1837 case EOpAbs:
1838 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301839 {
Olli Etuahof119a262016-08-19 15:54:22 +03001840 case EbtFloat:
1841 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1842 break;
1843 case EbtInt:
1844 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1845 break;
1846 default:
1847 UNREACHABLE();
1848 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301849 }
1850 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001851
1852 case EOpSign:
1853 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301854 {
Olli Etuahof119a262016-08-19 15:54:22 +03001855 case EbtFloat:
1856 {
1857 float fConst = operandArray[i].getFConst();
1858 float fResult = 0.0f;
1859 if (fConst > 0.0f)
1860 fResult = 1.0f;
1861 else if (fConst < 0.0f)
1862 fResult = -1.0f;
1863 resultArray[i].setFConst(fResult);
1864 break;
1865 }
1866 case EbtInt:
1867 {
1868 int iConst = operandArray[i].getIConst();
1869 int iResult = 0;
1870 if (iConst > 0)
1871 iResult = 1;
1872 else if (iConst < 0)
1873 iResult = -1;
1874 resultArray[i].setIConst(iResult);
1875 break;
1876 }
1877 default:
1878 UNREACHABLE();
1879 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301880 }
1881 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882
Olli Etuahof119a262016-08-19 15:54:22 +03001883 case EOpFloor:
1884 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1885 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301886
Olli Etuahof119a262016-08-19 15:54:22 +03001887 case EOpTrunc:
1888 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1889 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301890
Olli Etuahof119a262016-08-19 15:54:22 +03001891 case EOpRound:
1892 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1893 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301894
Olli Etuahof119a262016-08-19 15:54:22 +03001895 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301896 {
Olli Etuahof119a262016-08-19 15:54:22 +03001897 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301898 float x = operandArray[i].getFConst();
1899 float result;
1900 float fractPart = modff(x, &result);
1901 if (fabsf(fractPart) == 0.5f)
1902 result = 2.0f * roundf(x / 2.0f);
1903 else
1904 result = roundf(x);
1905 resultArray[i].setFConst(result);
1906 break;
1907 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301908
Olli Etuahof119a262016-08-19 15:54:22 +03001909 case EOpCeil:
1910 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
1911 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301912
Olli Etuahof119a262016-08-19 15:54:22 +03001913 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301914 {
Olli Etuahof119a262016-08-19 15:54:22 +03001915 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301916 float x = operandArray[i].getFConst();
1917 resultArray[i].setFConst(x - floorf(x));
1918 break;
1919 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301920
Olli Etuahof119a262016-08-19 15:54:22 +03001921 case EOpIsNan:
1922 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301923 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1924 break;
Arun Patole551279e2015-07-07 18:18:23 +05301925
Olli Etuahof119a262016-08-19 15:54:22 +03001926 case EOpIsInf:
1927 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301928 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1929 break;
Arun Patole551279e2015-07-07 18:18:23 +05301930
Olli Etuahof119a262016-08-19 15:54:22 +03001931 case EOpFloatBitsToInt:
1932 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301933 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1934 break;
Arun Patole551279e2015-07-07 18:18:23 +05301935
Olli Etuahof119a262016-08-19 15:54:22 +03001936 case EOpFloatBitsToUint:
1937 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301938 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1939 break;
Arun Patole551279e2015-07-07 18:18:23 +05301940
Olli Etuahof119a262016-08-19 15:54:22 +03001941 case EOpIntBitsToFloat:
1942 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05301943 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1944 break;
Arun Patole551279e2015-07-07 18:18:23 +05301945
Olli Etuahof119a262016-08-19 15:54:22 +03001946 case EOpUintBitsToFloat:
1947 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05301948 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1949 break;
Arun Patole551279e2015-07-07 18:18:23 +05301950
Olli Etuahof119a262016-08-19 15:54:22 +03001951 case EOpExp:
1952 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
1953 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301954
Olli Etuahof119a262016-08-19 15:54:22 +03001955 case EOpLog:
1956 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1957 if (operandArray[i].getFConst() <= 0.0f)
1958 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1959 diagnostics, &resultArray[i]);
1960 else
1961 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1962 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301963
Olli Etuahof119a262016-08-19 15:54:22 +03001964 case EOpExp2:
1965 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
1966 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301967
Olli Etuahof119a262016-08-19 15:54:22 +03001968 case EOpLog2:
1969 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1970 // And log2f is not available on some plarforms like old android, so just using
1971 // log(x)/log(2) here.
1972 if (operandArray[i].getFConst() <= 0.0f)
1973 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1974 diagnostics, &resultArray[i]);
1975 else
1976 {
1977 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1978 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1979 }
1980 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301981
Olli Etuahof119a262016-08-19 15:54:22 +03001982 case EOpSqrt:
1983 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1984 if (operandArray[i].getFConst() < 0.0f)
1985 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1986 diagnostics, &resultArray[i]);
1987 else
1988 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1989 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301990
Olli Etuahof119a262016-08-19 15:54:22 +03001991 case EOpInverseSqrt:
1992 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1993 // so getting the square root first using builtin function sqrt() and then taking
1994 // its inverse.
1995 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
1996 // result to 0.
1997 if (operandArray[i].getFConst() <= 0.0f)
1998 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1999 diagnostics, &resultArray[i]);
2000 else
2001 {
2002 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
2003 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
2004 }
2005 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302006
Olli Etuahof119a262016-08-19 15:54:22 +03002007 case EOpVectorLogicalNot:
2008 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302009 resultArray[i].setBConst(!operandArray[i].getBConst());
2010 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05302011
Olli Etuahof119a262016-08-19 15:54:22 +03002012 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05302013 {
Olli Etuahof119a262016-08-19 15:54:22 +03002014 ASSERT(getType().getBasicType() == EbtFloat);
2015 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05302016 float length = VectorLength(operandArray, objectSize);
2017 if (length)
2018 resultArray[i].setFConst(x / length);
2019 else
Olli Etuahof119a262016-08-19 15:54:22 +03002020 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
2021 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05302022 break;
2023 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05302024
Olli Etuahof119a262016-08-19 15:54:22 +03002025 case EOpDFdx:
2026 case EOpDFdy:
2027 case EOpFwidth:
2028 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05302029 // Derivatives of constant arguments should be 0.
2030 resultArray[i].setFConst(0.0f);
2031 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05302032
Olli Etuahof119a262016-08-19 15:54:22 +03002033 default:
2034 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302035 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302036 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04002037
Arun Patoleab2b9a22015-07-06 18:27:56 +05302038 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04002039}
2040
Olli Etuahof119a262016-08-19 15:54:22 +03002041void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
2042 FloatTypeUnaryFunc builtinFunc,
2043 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05302044{
2045 ASSERT(builtinFunc);
2046
Olli Etuahof119a262016-08-19 15:54:22 +03002047 ASSERT(getType().getBasicType() == EbtFloat);
2048 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05302049}
2050
Jamie Madillb1a85f42014-08-19 15:23:24 -04002051// static
Olli Etuahof119a262016-08-19 15:54:22 +03002052TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02002053{
2054 ASSERT(aggregate->getSequence()->size() > 0u);
2055 size_t resultSize = aggregate->getType().getObjectSize();
2056 TConstantUnion *resultArray = new TConstantUnion[resultSize];
2057 TBasicType basicType = aggregate->getBasicType();
2058
2059 size_t resultIndex = 0u;
2060
2061 if (aggregate->getSequence()->size() == 1u)
2062 {
2063 TIntermNode *argument = aggregate->getSequence()->front();
2064 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2065 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2066 // Check the special case of constructing a matrix diagonal from a single scalar,
2067 // or a vector from a single scalar.
2068 if (argumentConstant->getType().getObjectSize() == 1u)
2069 {
2070 if (aggregate->isMatrix())
2071 {
2072 int resultCols = aggregate->getType().getCols();
2073 int resultRows = aggregate->getType().getRows();
2074 for (int col = 0; col < resultCols; ++col)
2075 {
2076 for (int row = 0; row < resultRows; ++row)
2077 {
2078 if (col == row)
2079 {
2080 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2081 }
2082 else
2083 {
2084 resultArray[resultIndex].setFConst(0.0f);
2085 }
2086 ++resultIndex;
2087 }
2088 }
2089 }
2090 else
2091 {
2092 while (resultIndex < resultSize)
2093 {
2094 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
2095 ++resultIndex;
2096 }
2097 }
2098 ASSERT(resultIndex == resultSize);
2099 return resultArray;
2100 }
2101 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
2102 {
2103 // The special case of constructing a matrix from a matrix.
2104 int argumentCols = argumentConstant->getType().getCols();
2105 int argumentRows = argumentConstant->getType().getRows();
2106 int resultCols = aggregate->getType().getCols();
2107 int resultRows = aggregate->getType().getRows();
2108 for (int col = 0; col < resultCols; ++col)
2109 {
2110 for (int row = 0; row < resultRows; ++row)
2111 {
2112 if (col < argumentCols && row < argumentRows)
2113 {
2114 resultArray[resultIndex].cast(basicType,
2115 argumentUnionArray[col * argumentRows + row]);
2116 }
2117 else if (col == row)
2118 {
2119 resultArray[resultIndex].setFConst(1.0f);
2120 }
2121 else
2122 {
2123 resultArray[resultIndex].setFConst(0.0f);
2124 }
2125 ++resultIndex;
2126 }
2127 }
2128 ASSERT(resultIndex == resultSize);
2129 return resultArray;
2130 }
2131 }
2132
2133 for (TIntermNode *&argument : *aggregate->getSequence())
2134 {
2135 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
2136 size_t argumentSize = argumentConstant->getType().getObjectSize();
2137 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
2138 for (size_t i = 0u; i < argumentSize; ++i)
2139 {
2140 if (resultIndex >= resultSize)
2141 break;
2142 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
2143 ++resultIndex;
2144 }
2145 }
2146 ASSERT(resultIndex == resultSize);
2147 return resultArray;
2148}
2149
2150// static
Olli Etuahof119a262016-08-19 15:54:22 +03002151TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
2152 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05302153{
Olli Etuahob43846e2015-06-02 18:18:57 +03002154 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302155 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002156 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002157 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302158 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002159 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302160 TBasicType basicType = EbtVoid;
2161 TSourceLoc loc;
2162 for (unsigned int i = 0; i < paramsCount; i++)
2163 {
2164 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002165 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302166
2167 if (i == 0)
2168 {
2169 basicType = paramConstant->getType().getBasicType();
2170 loc = paramConstant->getLine();
2171 }
2172 unionArrays[i] = paramConstant->getUnionArrayPointer();
2173 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002174 if (objectSizes[i] > maxObjectSize)
2175 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302176 }
2177
Olli Etuahod5da5052016-08-29 13:16:55 +03002178 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302179 {
2180 for (unsigned int i = 0; i < paramsCount; i++)
2181 if (objectSizes[i] != maxObjectSize)
2182 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2183 }
Arun Patole274f0702015-05-05 13:33:30 +05302184
Olli Etuahob43846e2015-06-02 18:18:57 +03002185 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302186 if (paramsCount == 2)
2187 {
2188 //
2189 // Binary built-in
2190 //
2191 switch (op)
2192 {
Olli Etuahof119a262016-08-19 15:54:22 +03002193 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302194 {
Olli Etuahof119a262016-08-19 15:54:22 +03002195 ASSERT(basicType == EbtFloat);
2196 resultArray = new TConstantUnion[maxObjectSize];
2197 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302198 {
Olli Etuahof119a262016-08-19 15:54:22 +03002199 float y = unionArrays[0][i].getFConst();
2200 float x = unionArrays[1][i].getFConst();
2201 // Results are undefined if x and y are both 0.
2202 if (x == 0.0f && y == 0.0f)
2203 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2204 &resultArray[i]);
2205 else
2206 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302207 }
Olli Etuahof119a262016-08-19 15:54:22 +03002208 break;
Arun Patolebf790422015-05-18 17:53:04 +05302209 }
Arun Patolebf790422015-05-18 17:53:04 +05302210
Olli Etuahof119a262016-08-19 15:54:22 +03002211 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302212 {
Olli Etuahof119a262016-08-19 15:54:22 +03002213 ASSERT(basicType == EbtFloat);
2214 resultArray = new TConstantUnion[maxObjectSize];
2215 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302216 {
Olli Etuahof119a262016-08-19 15:54:22 +03002217 float x = unionArrays[0][i].getFConst();
2218 float y = unionArrays[1][i].getFConst();
2219 // Results are undefined if x < 0.
2220 // Results are undefined if x = 0 and y <= 0.
2221 if (x < 0.0f)
2222 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2223 &resultArray[i]);
2224 else if (x == 0.0f && y <= 0.0f)
2225 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2226 &resultArray[i]);
2227 else
2228 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302229 }
Olli Etuahof119a262016-08-19 15:54:22 +03002230 break;
Arun Patolebf790422015-05-18 17:53:04 +05302231 }
Arun Patolebf790422015-05-18 17:53:04 +05302232
Olli Etuahof119a262016-08-19 15:54:22 +03002233 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302234 {
Olli Etuahof119a262016-08-19 15:54:22 +03002235 ASSERT(basicType == EbtFloat);
2236 resultArray = new TConstantUnion[maxObjectSize];
2237 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302238 {
Olli Etuahof119a262016-08-19 15:54:22 +03002239 float x = unionArrays[0][i].getFConst();
2240 float y = unionArrays[1][i].getFConst();
2241 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302242 }
Olli Etuahof119a262016-08-19 15:54:22 +03002243 break;
Arun Patolebf790422015-05-18 17:53:04 +05302244 }
Arun Patolebf790422015-05-18 17:53:04 +05302245
Olli Etuahof119a262016-08-19 15:54:22 +03002246 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302247 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002248 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302249 for (size_t i = 0; i < maxObjectSize; i++)
2250 {
2251 switch (basicType)
2252 {
Olli Etuahof119a262016-08-19 15:54:22 +03002253 case EbtFloat:
2254 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2255 unionArrays[1][i].getFConst()));
2256 break;
2257 case EbtInt:
2258 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2259 unionArrays[1][i].getIConst()));
2260 break;
2261 case EbtUInt:
2262 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2263 unionArrays[1][i].getUConst()));
2264 break;
2265 default:
2266 UNREACHABLE();
2267 break;
Arun Patole274f0702015-05-05 13:33:30 +05302268 }
2269 }
Olli Etuahof119a262016-08-19 15:54:22 +03002270 break;
Arun Patole274f0702015-05-05 13:33:30 +05302271 }
Arun Patole274f0702015-05-05 13:33:30 +05302272
Olli Etuahof119a262016-08-19 15:54:22 +03002273 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302274 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002275 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302276 for (size_t i = 0; i < maxObjectSize; i++)
2277 {
2278 switch (basicType)
2279 {
Olli Etuahof119a262016-08-19 15:54:22 +03002280 case EbtFloat:
2281 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2282 unionArrays[1][i].getFConst()));
2283 break;
2284 case EbtInt:
2285 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2286 unionArrays[1][i].getIConst()));
2287 break;
2288 case EbtUInt:
2289 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2290 unionArrays[1][i].getUConst()));
2291 break;
2292 default:
2293 UNREACHABLE();
2294 break;
Arun Patole274f0702015-05-05 13:33:30 +05302295 }
2296 }
Olli Etuahof119a262016-08-19 15:54:22 +03002297 break;
Arun Patole274f0702015-05-05 13:33:30 +05302298 }
Arun Patole274f0702015-05-05 13:33:30 +05302299
Olli Etuahof119a262016-08-19 15:54:22 +03002300 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302301 {
Olli Etuahof119a262016-08-19 15:54:22 +03002302 ASSERT(basicType == EbtFloat);
2303 resultArray = new TConstantUnion[maxObjectSize];
2304 for (size_t i = 0; i < maxObjectSize; i++)
2305 resultArray[i].setFConst(
2306 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2307 : 1.0f);
2308 break;
Arun Patolebf790422015-05-18 17:53:04 +05302309 }
Arun Patolebf790422015-05-18 17:53:04 +05302310
Olli Etuahof119a262016-08-19 15:54:22 +03002311 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302312 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002313 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302314 for (size_t i = 0; i < maxObjectSize; i++)
2315 {
2316 switch (basicType)
2317 {
Olli Etuahof119a262016-08-19 15:54:22 +03002318 case EbtFloat:
2319 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2320 unionArrays[1][i].getFConst());
2321 break;
2322 case EbtInt:
2323 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2324 unionArrays[1][i].getIConst());
2325 break;
2326 case EbtUInt:
2327 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2328 unionArrays[1][i].getUConst());
2329 break;
2330 default:
2331 UNREACHABLE();
2332 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302333 }
2334 }
Olli Etuahof119a262016-08-19 15:54:22 +03002335 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302336 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302337
Olli Etuahof119a262016-08-19 15:54:22 +03002338 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302339 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002340 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302341 for (size_t i = 0; i < maxObjectSize; i++)
2342 {
2343 switch (basicType)
2344 {
Olli Etuahof119a262016-08-19 15:54:22 +03002345 case EbtFloat:
2346 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2347 unionArrays[1][i].getFConst());
2348 break;
2349 case EbtInt:
2350 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2351 unionArrays[1][i].getIConst());
2352 break;
2353 case EbtUInt:
2354 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2355 unionArrays[1][i].getUConst());
2356 break;
2357 default:
2358 UNREACHABLE();
2359 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302360 }
2361 }
Olli Etuahof119a262016-08-19 15:54:22 +03002362 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302363 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302364
Olli Etuahof119a262016-08-19 15:54:22 +03002365 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302366 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002367 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302368 for (size_t i = 0; i < maxObjectSize; i++)
2369 {
2370 switch (basicType)
2371 {
Olli Etuahof119a262016-08-19 15:54:22 +03002372 case EbtFloat:
2373 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2374 unionArrays[1][i].getFConst());
2375 break;
2376 case EbtInt:
2377 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2378 unionArrays[1][i].getIConst());
2379 break;
2380 case EbtUInt:
2381 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2382 unionArrays[1][i].getUConst());
2383 break;
2384 default:
2385 UNREACHABLE();
2386 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002387 }
2388 }
Olli Etuahof119a262016-08-19 15:54:22 +03002389 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302390 }
Olli Etuahof119a262016-08-19 15:54:22 +03002391 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302392 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002393 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302394 for (size_t i = 0; i < maxObjectSize; i++)
2395 {
2396 switch (basicType)
2397 {
Olli Etuahof119a262016-08-19 15:54:22 +03002398 case EbtFloat:
2399 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2400 unionArrays[1][i].getFConst());
2401 break;
2402 case EbtInt:
2403 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2404 unionArrays[1][i].getIConst());
2405 break;
2406 case EbtUInt:
2407 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2408 unionArrays[1][i].getUConst());
2409 break;
2410 default:
2411 UNREACHABLE();
2412 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302413 }
2414 }
2415 }
2416 break;
2417
Olli Etuahof119a262016-08-19 15:54:22 +03002418 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302419 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002420 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302421 for (size_t i = 0; i < maxObjectSize; i++)
2422 {
2423 switch (basicType)
2424 {
Olli Etuahof119a262016-08-19 15:54:22 +03002425 case EbtFloat:
2426 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2427 unionArrays[1][i].getFConst());
2428 break;
2429 case EbtInt:
2430 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2431 unionArrays[1][i].getIConst());
2432 break;
2433 case EbtUInt:
2434 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2435 unionArrays[1][i].getUConst());
2436 break;
2437 case EbtBool:
2438 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2439 unionArrays[1][i].getBConst());
2440 break;
2441 default:
2442 UNREACHABLE();
2443 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302444 }
2445 }
Olli Etuahof119a262016-08-19 15:54:22 +03002446 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302447 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302448
Olli Etuahof119a262016-08-19 15:54:22 +03002449 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302450 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002451 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302452 for (size_t i = 0; i < maxObjectSize; i++)
2453 {
2454 switch (basicType)
2455 {
Olli Etuahof119a262016-08-19 15:54:22 +03002456 case EbtFloat:
2457 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2458 unionArrays[1][i].getFConst());
2459 break;
2460 case EbtInt:
2461 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2462 unionArrays[1][i].getIConst());
2463 break;
2464 case EbtUInt:
2465 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2466 unionArrays[1][i].getUConst());
2467 break;
2468 case EbtBool:
2469 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2470 unionArrays[1][i].getBConst());
2471 break;
2472 default:
2473 UNREACHABLE();
2474 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302475 }
2476 }
Olli Etuahof119a262016-08-19 15:54:22 +03002477 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302478 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302479
Olli Etuahof119a262016-08-19 15:54:22 +03002480 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302481 {
Olli Etuahof119a262016-08-19 15:54:22 +03002482 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302483 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002484 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302485 for (size_t i = 0; i < maxObjectSize; i++)
2486 {
2487 float x = unionArrays[0][i].getFConst();
2488 float y = unionArrays[1][i].getFConst();
2489 distanceArray[i].setFConst(x - y);
2490 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002491 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002492 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302493 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302494
Olli Etuahof119a262016-08-19 15:54:22 +03002495 case EOpDot:
2496 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002497 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002498 resultArray->setFConst(
2499 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2500 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302501
Olli Etuahof119a262016-08-19 15:54:22 +03002502 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302503 {
Olli Etuahof119a262016-08-19 15:54:22 +03002504 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002505 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002506 float x0 = unionArrays[0][0].getFConst();
2507 float x1 = unionArrays[0][1].getFConst();
2508 float x2 = unionArrays[0][2].getFConst();
2509 float y0 = unionArrays[1][0].getFConst();
2510 float y1 = unionArrays[1][1].getFConst();
2511 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002512 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2513 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2514 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002515 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302516 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302517
Olli Etuahof119a262016-08-19 15:54:22 +03002518 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302519 {
Olli Etuahof119a262016-08-19 15:54:22 +03002520 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302521 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002522 // For the incident vector I and surface orientation N, returns the reflection
2523 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302524 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002525 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302526 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2527 for (size_t i = 0; i < maxObjectSize; i++)
2528 {
2529 float result = unionArrays[0][i].getFConst() -
2530 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002531 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302532 }
Olli Etuahof119a262016-08-19 15:54:22 +03002533 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302534 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302535
Olli Etuahof119a262016-08-19 15:54:22 +03002536 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302537 {
Olli Etuahof119a262016-08-19 15:54:22 +03002538 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2539 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302540 // Perform component-wise matrix multiplication.
2541 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002542 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302543 angle::Matrix<float> result =
2544 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2545 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002546 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302547 }
Arun Patole7fa33552015-06-10 15:15:18 +05302548
Olli Etuahof119a262016-08-19 15:54:22 +03002549 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302550 {
Olli Etuahof119a262016-08-19 15:54:22 +03002551 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302552 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2553 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002554 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302555 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002556 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2557 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302558 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002559 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302560 }
Arun Patole7fa33552015-06-10 15:15:18 +05302561
Olli Etuahof119a262016-08-19 15:54:22 +03002562 default:
2563 UNREACHABLE();
2564 // TODO: Add constant folding support for other built-in operations that take 2
2565 // parameters and not handled above.
2566 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302567 }
2568 }
2569 else if (paramsCount == 3)
2570 {
2571 //
2572 // Ternary built-in
2573 //
2574 switch (op)
2575 {
Olli Etuahof119a262016-08-19 15:54:22 +03002576 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302577 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002578 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302579 for (size_t i = 0; i < maxObjectSize; i++)
2580 {
2581 switch (basicType)
2582 {
Olli Etuahof119a262016-08-19 15:54:22 +03002583 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302584 {
Olli Etuahof119a262016-08-19 15:54:22 +03002585 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302586 float min = unionArrays[1][i].getFConst();
2587 float max = unionArrays[2][i].getFConst();
2588 // Results are undefined if min > max.
2589 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002590 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2591 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302592 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002593 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002594 break;
Arun Patole274f0702015-05-05 13:33:30 +05302595 }
Olli Etuahof119a262016-08-19 15:54:22 +03002596
2597 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302598 {
Olli Etuahof119a262016-08-19 15:54:22 +03002599 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302600 int min = unionArrays[1][i].getIConst();
2601 int max = unionArrays[2][i].getIConst();
2602 // Results are undefined if min > max.
2603 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002604 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2605 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302606 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002607 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002608 break;
Arun Patole274f0702015-05-05 13:33:30 +05302609 }
Olli Etuahof119a262016-08-19 15:54:22 +03002610 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302611 {
Olli Etuahof119a262016-08-19 15:54:22 +03002612 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302613 unsigned int min = unionArrays[1][i].getUConst();
2614 unsigned int max = unionArrays[2][i].getUConst();
2615 // Results are undefined if min > max.
2616 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002617 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2618 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302619 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002620 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002621 break;
Arun Patole274f0702015-05-05 13:33:30 +05302622 }
Olli Etuahof119a262016-08-19 15:54:22 +03002623 default:
2624 UNREACHABLE();
2625 break;
Arun Patole274f0702015-05-05 13:33:30 +05302626 }
2627 }
Olli Etuahof119a262016-08-19 15:54:22 +03002628 break;
Arun Patole274f0702015-05-05 13:33:30 +05302629 }
Arun Patole274f0702015-05-05 13:33:30 +05302630
Olli Etuahof119a262016-08-19 15:54:22 +03002631 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302632 {
Olli Etuahof119a262016-08-19 15:54:22 +03002633 ASSERT(basicType == EbtFloat);
2634 resultArray = new TConstantUnion[maxObjectSize];
2635 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302636 {
Olli Etuahof119a262016-08-19 15:54:22 +03002637 float x = unionArrays[0][i].getFConst();
2638 float y = unionArrays[1][i].getFConst();
2639 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2640 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302641 {
Olli Etuahof119a262016-08-19 15:54:22 +03002642 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2643 float a = unionArrays[2][i].getFConst();
2644 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2645 }
2646 else // 3rd parameter is EbtBool
2647 {
2648 ASSERT(type == EbtBool);
2649 // Selects which vector each returned component comes from.
2650 // For a component of a that is false, the corresponding component of x is
2651 // returned.
2652 // For a component of a that is true, the corresponding component of y is
2653 // returned.
2654 bool a = unionArrays[2][i].getBConst();
2655 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302656 }
2657 }
Olli Etuahof119a262016-08-19 15:54:22 +03002658 break;
Arun Patolebf790422015-05-18 17:53:04 +05302659 }
Arun Patolebf790422015-05-18 17:53:04 +05302660
Olli Etuahof119a262016-08-19 15:54:22 +03002661 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302662 {
Olli Etuahof119a262016-08-19 15:54:22 +03002663 ASSERT(basicType == EbtFloat);
2664 resultArray = new TConstantUnion[maxObjectSize];
2665 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302666 {
Olli Etuahof119a262016-08-19 15:54:22 +03002667 float edge0 = unionArrays[0][i].getFConst();
2668 float edge1 = unionArrays[1][i].getFConst();
2669 float x = unionArrays[2][i].getFConst();
2670 // Results are undefined if edge0 >= edge1.
2671 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302672 {
Olli Etuahof119a262016-08-19 15:54:22 +03002673 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2674 &resultArray[i]);
2675 }
2676 else
2677 {
2678 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2679 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2680 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2681 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302682 }
2683 }
Olli Etuahof119a262016-08-19 15:54:22 +03002684 break;
Arun Patolebf790422015-05-18 17:53:04 +05302685 }
Arun Patolebf790422015-05-18 17:53:04 +05302686
Olli Etuahof119a262016-08-19 15:54:22 +03002687 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302688 {
Olli Etuahof119a262016-08-19 15:54:22 +03002689 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302690 // genType faceforward(genType N, genType I, genType Nref) :
2691 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002692 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302693 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2694 for (size_t i = 0; i < maxObjectSize; i++)
2695 {
2696 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002697 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302698 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002699 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302700 }
Olli Etuahof119a262016-08-19 15:54:22 +03002701 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302702 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302703
Olli Etuahof119a262016-08-19 15:54:22 +03002704 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302705 {
Olli Etuahof119a262016-08-19 15:54:22 +03002706 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302707 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002708 // For the incident vector I and surface normal N, and the ratio of indices of
2709 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302710 // return the refraction vector. The result is computed by
2711 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2712 // if (k < 0.0)
2713 // return genType(0.0)
2714 // else
2715 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002716 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302717 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2718 for (size_t i = 0; i < maxObjectSize; i++)
2719 {
2720 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002721 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302722 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002723 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302724 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002725 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002726 (eta * dotProduct + sqrtf(k)) *
2727 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302728 }
Olli Etuahof119a262016-08-19 15:54:22 +03002729 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302730 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302731
Olli Etuahof119a262016-08-19 15:54:22 +03002732 default:
2733 UNREACHABLE();
2734 // TODO: Add constant folding support for other built-in operations that take 3
2735 // parameters and not handled above.
2736 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302737 }
2738 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002739 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302740}
2741
2742// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002743TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2744{
2745 if (hashFunction == NULL || name.empty())
2746 return name;
2747 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2748 TStringStream stream;
2749 stream << HASHED_NAME_PREFIX << std::hex << number;
2750 TString hashedName = stream.str();
2751 return hashedName;
2752}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002753
2754void TIntermTraverser::updateTree()
2755{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002756 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2757 {
2758 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2759 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002760 if (!insertion.insertionsAfter.empty())
2761 {
2762 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2763 insertion.insertionsAfter);
2764 ASSERT(inserted);
2765 UNUSED_ASSERTION_VARIABLE(inserted);
2766 }
2767 if (!insertion.insertionsBefore.empty())
2768 {
2769 bool inserted =
2770 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2771 ASSERT(inserted);
2772 UNUSED_ASSERTION_VARIABLE(inserted);
2773 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002774 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002775 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2776 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002777 const NodeUpdateEntry &replacement = mReplacements[ii];
2778 ASSERT(replacement.parent);
2779 bool replaced = replacement.parent->replaceChildNode(
2780 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002781 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002782 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002783
Olli Etuahocd94ef92015-04-16 19:18:10 +03002784 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002785 {
2786 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002787 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002788 // be replaced, we need to make sure we don't update the replaced
2789 // node; instead, we update the replacement node.
2790 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2791 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002792 NodeUpdateEntry &replacement2 = mReplacements[jj];
2793 if (replacement2.parent == replacement.original)
2794 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002795 }
2796 }
2797 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002798 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2799 {
2800 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2801 ASSERT(replacement.parent);
2802 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2803 replacement.original, replacement.replacements);
2804 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002805 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002806 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002807
Jamie Madill03d863c2016-07-27 18:15:53 -04002808 clearReplacementQueue();
2809}
2810
2811void TIntermTraverser::clearReplacementQueue()
2812{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002813 mReplacements.clear();
2814 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002815 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002816}
Jamie Madill1048e432016-07-23 18:51:28 -04002817
Jamie Madill03d863c2016-07-27 18:15:53 -04002818void TIntermTraverser::queueReplacement(TIntermNode *original,
2819 TIntermNode *replacement,
2820 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002821{
Jamie Madill03d863c2016-07-27 18:15:53 -04002822 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002823}
2824
Jamie Madill03d863c2016-07-27 18:15:53 -04002825void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2826 TIntermNode *original,
2827 TIntermNode *replacement,
2828 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002829{
Jamie Madill03d863c2016-07-27 18:15:53 -04002830 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2831 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002832}