blob: 1c0e5e54ff87710f689e8139e57d9d137d73ca12 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/HashNames.h"
22#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
26namespace
27{
28
Arun Patole9dea48f2015-04-02 11:45:09 +053029const float kPi = 3.14159265358979323846f;
30const float kDegreesToRadiansMultiplier = kPi / 180.0f;
31const float kRadiansToDegreesMultiplier = 180.0f / kPi;
32
Jamie Madillb1a85f42014-08-19 15:23:24 -040033TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
34{
35 return left > right ? left : right;
36}
37
Arun Patole274f0702015-05-05 13:33:30 +053038TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
39{
40 TConstantUnion *constUnion = new TConstantUnion[size];
41 for (unsigned int i = 0; i < size; ++i)
42 constUnion[i] = constant;
43
44 return constUnion;
45}
46
Olli Etuahof119a262016-08-19 15:54:22 +030047void UndefinedConstantFoldingError(const TSourceLoc &loc,
48 TOperator op,
49 TBasicType basicType,
50 TDiagnostics *diagnostics,
51 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053052{
Olli Etuahof119a262016-08-19 15:54:22 +030053 diagnostics->warning(loc, "operation result is undefined for the values passed in",
54 GetOperatorString(op), "");
Arun Patolebf790422015-05-18 17:53:04 +053055
56 switch (basicType)
57 {
58 case EbtFloat :
59 result->setFConst(0.0f);
60 break;
61 case EbtInt:
62 result->setIConst(0);
63 break;
64 case EbtUInt:
65 result->setUConst(0u);
66 break;
67 case EbtBool:
68 result->setBConst(false);
69 break;
70 default:
71 break;
72 }
73}
74
Olli Etuaho5c0e0232015-11-11 15:55:59 +020075float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053076{
77 float result = 0.0f;
78 for (size_t i = 0; i < paramArraySize; i++)
79 {
80 float f = paramArray[i].getFConst();
81 result += f * f;
82 }
83 return sqrtf(result);
84}
85
Olli Etuaho5c0e0232015-11-11 15:55:59 +020086float VectorDotProduct(const TConstantUnion *paramArray1,
87 const TConstantUnion *paramArray2,
88 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053089{
90 float result = 0.0f;
91 for (size_t i = 0; i < paramArraySize; i++)
92 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
93 return result;
94}
95
Olli Etuaho3272a6d2016-08-29 17:54:50 +030096TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020097 const TIntermTyped *originalNode,
98 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +030099{
100 if (constArray == nullptr)
101 {
102 return nullptr;
103 }
104 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200105 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300106 folded->setLine(originalNode->getLine());
107 return folded;
108}
109
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200110angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
111 const unsigned int &rows,
112 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530113{
114 std::vector<float> elements;
115 for (size_t i = 0; i < rows * cols; i++)
116 elements.push_back(paramArray[i].getFConst());
117 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300118 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
119 // so that the created matrix will have the expected dimensions after the transpose.
120 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530121}
122
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200123angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530124{
125 std::vector<float> elements;
126 for (size_t i = 0; i < size * size; i++)
127 elements.push_back(paramArray[i].getFConst());
128 // Transpose is used since the Matrix constructor expects arguments in row-major order,
129 // whereas the paramArray is in column-major order.
130 return angle::Matrix<float>(elements, size).transpose();
131}
132
133void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
134{
135 // Transpose is used since the input Matrix is in row-major order,
136 // whereas the actual result should be in column-major order.
137 angle::Matrix<float> result = m.transpose();
138 std::vector<float> resultElements = result.elements();
139 for (size_t i = 0; i < resultElements.size(); i++)
140 resultArray[i].setFConst(resultElements[i]);
141}
142
Jamie Madillb1a85f42014-08-19 15:23:24 -0400143} // namespace anonymous
144
145
146////////////////////////////////////////////////////////////////
147//
148// Member functions of the nodes used for building the tree.
149//
150////////////////////////////////////////////////////////////////
151
Olli Etuahod2a67b92014-10-21 16:42:57 +0300152void TIntermTyped::setTypePreservePrecision(const TType &t)
153{
154 TPrecision precision = getPrecision();
155 mType = t;
156 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
157 mType.setPrecision(precision);
158}
159
Jamie Madillb1a85f42014-08-19 15:23:24 -0400160#define REPLACE_IF_IS(node, type, original, replacement) \
161 if (node == original) { \
162 node = static_cast<type *>(replacement); \
163 return true; \
164 }
165
166bool TIntermLoop::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300169 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
171 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
172 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200173 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174 return false;
175}
176
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177bool TIntermBranch::replaceChildNode(
178 TIntermNode *original, TIntermNode *replacement)
179{
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182}
183
Jamie Madillb1a85f42014-08-19 15:23:24 -0400184bool TIntermBinary::replaceChildNode(
185 TIntermNode *original, TIntermNode *replacement)
186{
187 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
188 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
189 return false;
190}
191
Jamie Madillb1a85f42014-08-19 15:23:24 -0400192bool TIntermUnary::replaceChildNode(
193 TIntermNode *original, TIntermNode *replacement)
194{
195 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
196 return false;
197}
198
Jamie Madillb1a85f42014-08-19 15:23:24 -0400199bool TIntermAggregate::replaceChildNode(
200 TIntermNode *original, TIntermNode *replacement)
201{
202 for (size_t ii = 0; ii < mSequence.size(); ++ii)
203 {
204 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
205 }
206 return false;
207}
208
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300209bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
210{
211 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
212 {
213 if (*it == original)
214 {
215 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300216 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300217 return true;
218 }
219 }
220 return false;
221}
222
Olli Etuahoa6f22092015-05-08 18:31:10 +0300223bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
224{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300225 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300226 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300227 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300228 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300229 auto it = mSequence.begin() + position;
230 mSequence.insert(it, insertions.begin(), insertions.end());
231 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300232}
233
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200234bool TIntermAggregate::areChildrenConstQualified()
235{
236 for (TIntermNode *&child : mSequence)
237 {
238 TIntermTyped *typed = child->getAsTyped();
239 if (typed && typed->getQualifier() != EvqConst)
240 {
241 return false;
242 }
243 }
244 return true;
245}
246
Olli Etuahod2a67b92014-10-21 16:42:57 +0300247void TIntermAggregate::setPrecisionFromChildren()
248{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300249 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300250 if (getBasicType() == EbtBool)
251 {
252 mType.setPrecision(EbpUndefined);
253 return;
254 }
255
256 TPrecision precision = EbpUndefined;
257 TIntermSequence::iterator childIter = mSequence.begin();
258 while (childIter != mSequence.end())
259 {
260 TIntermTyped *typed = (*childIter)->getAsTyped();
261 if (typed)
262 precision = GetHigherPrecision(typed->getPrecision(), precision);
263 ++childIter;
264 }
265 mType.setPrecision(precision);
266}
267
268void TIntermAggregate::setBuiltInFunctionPrecision()
269{
270 // All built-ins returning bool should be handled as ops, not functions.
271 ASSERT(getBasicType() != EbtBool);
272
273 TPrecision precision = EbpUndefined;
274 TIntermSequence::iterator childIter = mSequence.begin();
275 while (childIter != mSequence.end())
276 {
277 TIntermTyped *typed = (*childIter)->getAsTyped();
278 // ESSL spec section 8: texture functions get their precision from the sampler.
279 if (typed && IsSampler(typed->getBasicType()))
280 {
281 precision = typed->getPrecision();
282 break;
283 }
284 ++childIter;
285 }
286 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
287 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300288 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300289 mType.setPrecision(EbpHigh);
290 else
291 mType.setPrecision(precision);
292}
293
Jamie Madillb1a85f42014-08-19 15:23:24 -0400294bool TIntermSelection::replaceChildNode(
295 TIntermNode *original, TIntermNode *replacement)
296{
297 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
298 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
299 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
300 return false;
301}
302
Olli Etuahoa3a36662015-02-17 13:46:51 +0200303bool TIntermSwitch::replaceChildNode(
304 TIntermNode *original, TIntermNode *replacement)
305{
306 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
307 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
308 return false;
309}
310
311bool TIntermCase::replaceChildNode(
312 TIntermNode *original, TIntermNode *replacement)
313{
314 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
315 return false;
316}
317
Olli Etuahod7a25242015-08-18 13:49:45 +0300318TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
319{
320 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
321 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
322 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
323 mLine = node.mLine;
324}
325
Olli Etuahod4f4c112016-04-15 15:11:24 +0300326bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
327{
328 TIntermAggregate *constructor = getAsAggregate();
329 if (!constructor || !constructor->isConstructor())
330 {
331 return false;
332 }
333 for (TIntermNode *&node : *constructor->getSequence())
334 {
335 if (!node->getAsConstantUnion())
336 return false;
337 }
338 return true;
339}
340
Corentin Wallez509e4562016-08-25 14:55:44 -0400341// static
342TIntermTyped *TIntermTyped::CreateIndexNode(int index)
343{
344 TConstantUnion *u = new TConstantUnion[1];
345 u[0].setIConst(index);
346
347 TType type(EbtInt, EbpUndefined, EvqConst, 1);
348 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
349 return node;
350}
351
352// static
353TIntermTyped *TIntermTyped::CreateZero(const TType &type)
354{
355 TType constType(type);
356 constType.setQualifier(EvqConst);
357
358 if (!type.isArray() && type.getBasicType() != EbtStruct)
359 {
360 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
361
362 size_t size = constType.getObjectSize();
363 TConstantUnion *u = new TConstantUnion[size];
364 for (size_t i = 0; i < size; ++i)
365 {
366 switch (type.getBasicType())
367 {
368 case EbtFloat:
369 u[i].setFConst(0.0f);
370 break;
371 case EbtInt:
372 u[i].setIConst(0);
373 break;
374 case EbtUInt:
375 u[i].setUConst(0u);
376 break;
377 case EbtBool:
378 u[i].setBConst(false);
379 break;
380 default:
381 UNREACHABLE();
382 return nullptr;
383 }
384 }
385
386 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
387 return node;
388 }
389
390 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
391 constructor->setType(constType);
392
393 if (type.isArray())
394 {
395 TType elementType(type);
396 elementType.clearArrayness();
397
398 size_t arraySize = type.getArraySize();
399 for (size_t i = 0; i < arraySize; ++i)
400 {
401 constructor->getSequence()->push_back(CreateZero(elementType));
402 }
403 }
404 else
405 {
406 ASSERT(type.getBasicType() == EbtStruct);
407
408 TStructure *structure = type.getStruct();
409 for (const auto &field : structure->fields())
410 {
411 constructor->getSequence()->push_back(CreateZero(*field->type()));
412 }
413 }
414
415 return constructor;
416}
417
Olli Etuahod7a25242015-08-18 13:49:45 +0300418TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
419{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200420 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300421}
422
423TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
424 : TIntermOperator(node),
425 mName(node.mName),
426 mUserDefined(node.mUserDefined),
427 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300428 mUseEmulatedFunction(node.mUseEmulatedFunction),
429 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
430{
431 for (TIntermNode *child : node.mSequence)
432 {
433 TIntermTyped *typedChild = child->getAsTyped();
434 ASSERT(typedChild != nullptr);
435 TIntermTyped *childCopy = typedChild->deepCopy();
436 mSequence.push_back(childCopy);
437 }
438}
439
440TIntermBinary::TIntermBinary(const TIntermBinary &node)
441 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
442{
443 TIntermTyped *leftCopy = node.mLeft->deepCopy();
444 TIntermTyped *rightCopy = node.mRight->deepCopy();
445 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
446 mLeft = leftCopy;
447 mRight = rightCopy;
448}
449
450TIntermUnary::TIntermUnary(const TIntermUnary &node)
451 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
452{
453 TIntermTyped *operandCopy = node.mOperand->deepCopy();
454 ASSERT(operandCopy != nullptr);
455 mOperand = operandCopy;
456}
457
458TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
459{
460 // Only supported for ternary nodes, not if statements.
461 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
462 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
463 ASSERT(trueTyped != nullptr);
464 ASSERT(falseTyped != nullptr);
465 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
466 TIntermTyped *trueCopy = trueTyped->deepCopy();
467 TIntermTyped *falseCopy = falseTyped->deepCopy();
468 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
469 mCondition = conditionCopy;
470 mTrueBlock = trueCopy;
471 mFalseBlock = falseCopy;
472}
473
Jamie Madillb1a85f42014-08-19 15:23:24 -0400474bool TIntermOperator::isAssignment() const
475{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300476 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400477}
478
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300479bool TIntermOperator::isMultiplication() const
480{
481 switch (mOp)
482 {
483 case EOpMul:
484 case EOpMatrixTimesMatrix:
485 case EOpMatrixTimesVector:
486 case EOpMatrixTimesScalar:
487 case EOpVectorTimesMatrix:
488 case EOpVectorTimesScalar:
489 return true;
490 default:
491 return false;
492 }
493}
494
Jamie Madillb1a85f42014-08-19 15:23:24 -0400495//
496// returns true if the operator is for one of the constructors
497//
498bool TIntermOperator::isConstructor() const
499{
500 switch (mOp)
501 {
502 case EOpConstructVec2:
503 case EOpConstructVec3:
504 case EOpConstructVec4:
505 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400506 case EOpConstructMat2x3:
507 case EOpConstructMat2x4:
508 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400509 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400510 case EOpConstructMat3x4:
511 case EOpConstructMat4x2:
512 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400513 case EOpConstructMat4:
514 case EOpConstructFloat:
515 case EOpConstructIVec2:
516 case EOpConstructIVec3:
517 case EOpConstructIVec4:
518 case EOpConstructInt:
519 case EOpConstructUVec2:
520 case EOpConstructUVec3:
521 case EOpConstructUVec4:
522 case EOpConstructUInt:
523 case EOpConstructBVec2:
524 case EOpConstructBVec3:
525 case EOpConstructBVec4:
526 case EOpConstructBool:
527 case EOpConstructStruct:
528 return true;
529 default:
530 return false;
531 }
532}
533
Olli Etuaho1dded802016-08-18 18:13:13 +0300534TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
535{
536 if (left.isMatrix())
537 {
538 if (right.isMatrix())
539 {
540 return EOpMatrixTimesMatrix;
541 }
542 else
543 {
544 if (right.isVector())
545 {
546 return EOpMatrixTimesVector;
547 }
548 else
549 {
550 return EOpMatrixTimesScalar;
551 }
552 }
553 }
554 else
555 {
556 if (right.isMatrix())
557 {
558 if (left.isVector())
559 {
560 return EOpVectorTimesMatrix;
561 }
562 else
563 {
564 return EOpMatrixTimesScalar;
565 }
566 }
567 else
568 {
569 // Neither operand is a matrix.
570 if (left.isVector() == right.isVector())
571 {
572 // Leave as component product.
573 return EOpMul;
574 }
575 else
576 {
577 return EOpVectorTimesScalar;
578 }
579 }
580 }
581}
582
583TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
584{
585 if (left.isMatrix())
586 {
587 if (right.isMatrix())
588 {
589 return EOpMatrixTimesMatrixAssign;
590 }
591 else
592 {
593 // right should be scalar, but this may not be validated yet.
594 return EOpMatrixTimesScalarAssign;
595 }
596 }
597 else
598 {
599 if (right.isMatrix())
600 {
601 // Left should be a vector, but this may not be validated yet.
602 return EOpVectorTimesMatrixAssign;
603 }
604 else
605 {
606 // Neither operand is a matrix.
607 if (left.isVector() == right.isVector())
608 {
609 // Leave as component product.
610 return EOpMulAssign;
611 }
612 else
613 {
614 // left should be vector and right should be scalar, but this may not be validated
615 // yet.
616 return EOpVectorTimesScalarAssign;
617 }
618 }
619 }
620}
621
Jamie Madillb1a85f42014-08-19 15:23:24 -0400622//
623// Make sure the type of a unary operator is appropriate for its
624// combination of operation and operand type.
625//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200626void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400627{
628 switch (mOp)
629 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200630 case EOpFloatBitsToInt:
631 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200632 case EOpIntBitsToFloat:
633 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200634 case EOpPackSnorm2x16:
635 case EOpPackUnorm2x16:
636 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200637 case EOpUnpackSnorm2x16:
638 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200639 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530640 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200641 case EOpUnpackHalf2x16:
642 mType.setPrecision(EbpMedium);
643 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400644 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200645 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400646 }
647
Olli Etuahof6c694b2015-03-26 14:50:53 +0200648 if (funcReturnType != nullptr)
649 {
650 if (funcReturnType->getBasicType() == EbtBool)
651 {
652 // Bool types should not have precision.
653 setType(*funcReturnType);
654 }
655 else
656 {
657 // Precision of the node has been set based on the operand.
658 setTypePreservePrecision(*funcReturnType);
659 }
660 }
661
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200662 if (mOperand->getQualifier() == EvqConst)
663 mType.setQualifier(EvqConst);
664 else
665 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400666}
667
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300668TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
669 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
670{
671 promote();
672}
673
Jamie Madillb1a85f42014-08-19 15:23:24 -0400674//
675// Establishes the type of the resultant operation, as well as
676// makes the operator the correct one for the operands.
677//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200678// For lots of operations it should already be established that the operand
679// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400680//
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300681void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400682{
Olli Etuaho1dded802016-08-18 18:13:13 +0300683 ASSERT(!isMultiplication() ||
684 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
685
Jamie Madillb1a85f42014-08-19 15:23:24 -0400686 // Base assumption: just make the type the same as the left
687 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400688 setType(mLeft->getType());
689
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200690 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400691 // Binary operations results in temporary variables unless both
692 // operands are const.
693 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
694 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200695 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400696 getTypePointer()->setQualifier(EvqTemporary);
697 }
698
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300699 // Handle indexing ops.
700 switch (mOp)
701 {
702 case EOpIndexDirect:
703 case EOpIndexIndirect:
704 if (mLeft->isArray())
705 {
706 mType.clearArrayness();
707 }
708 else if (mLeft->isMatrix())
709 {
710 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
711 static_cast<unsigned char>(mLeft->getRows())));
712 }
713 else if (mLeft->isVector())
714 {
715 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
716 }
717 else
718 {
719 UNREACHABLE();
720 }
721 return;
722 case EOpIndexDirectStruct:
723 {
724 const TFieldList &fields = mLeft->getType().getStruct()->fields();
725 const int i = mRight->getAsConstantUnion()->getIConst(0);
726 setType(*fields[i]->type());
727 getTypePointer()->setQualifier(resultQualifier);
728 return;
729 }
730 case EOpIndexDirectInterfaceBlock:
731 {
732 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
733 const int i = mRight->getAsConstantUnion()->getIConst(0);
734 setType(*fields[i]->type());
735 getTypePointer()->setQualifier(resultQualifier);
736 return;
737 }
738 case EOpVectorSwizzle:
739 {
740 auto numFields = mRight->getAsAggregate()->getSequence()->size();
741 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
742 static_cast<unsigned char>(numFields)));
743 return;
744 }
745 default:
746 break;
747 }
748
749 ASSERT(mLeft->isArray() == mRight->isArray());
750
751 // The result gets promoted to the highest precision.
752 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
753 getTypePointer()->setPrecision(higherPrecision);
754
Jamie Madillb1a85f42014-08-19 15:23:24 -0400755 const int nominalSize =
756 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
757
758 //
759 // All scalars or structs. Code after this test assumes this case is removed!
760 //
761 if (nominalSize == 1)
762 {
763 switch (mOp)
764 {
765 //
766 // Promote to conditional
767 //
768 case EOpEqual:
769 case EOpNotEqual:
770 case EOpLessThan:
771 case EOpGreaterThan:
772 case EOpLessThanEqual:
773 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300774 setType(TType(EbtBool, EbpUndefined, resultQualifier));
775 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776
777 //
778 // And and Or operate on conditionals
779 //
780 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200781 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400782 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200783 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300784 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400785 break;
786
787 default:
788 break;
789 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300790 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400791 }
792
793 // If we reach here, at least one of the operands is vector or matrix.
794 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400795 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300796
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797 switch (mOp)
798 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300799 case EOpMul:
800 break;
801 case EOpMatrixTimesScalar:
802 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400803 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200804 setType(TType(basicType, higherPrecision, resultQualifier,
805 static_cast<unsigned char>(mRight->getCols()),
806 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400807 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300808 break;
809 case EOpMatrixTimesVector:
810 setType(TType(basicType, higherPrecision, resultQualifier,
811 static_cast<unsigned char>(mLeft->getRows()), 1));
812 break;
813 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200814 setType(TType(basicType, higherPrecision, resultQualifier,
815 static_cast<unsigned char>(mRight->getCols()),
816 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300817 break;
818 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200819 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300820 static_cast<unsigned char>(nominalSize), 1));
821 break;
822 case EOpVectorTimesMatrix:
823 setType(TType(basicType, higherPrecision, resultQualifier,
824 static_cast<unsigned char>(mRight->getCols()), 1));
825 break;
826 case EOpMulAssign:
827 case EOpVectorTimesScalarAssign:
828 case EOpVectorTimesMatrixAssign:
829 case EOpMatrixTimesScalarAssign:
830 case EOpMatrixTimesMatrixAssign:
831 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
832 break;
833 case EOpAssign:
834 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300835 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
836 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
837 break;
838 case EOpAdd:
839 case EOpSub:
840 case EOpDiv:
841 case EOpIMod:
842 case EOpBitShiftLeft:
843 case EOpBitShiftRight:
844 case EOpBitwiseAnd:
845 case EOpBitwiseXor:
846 case EOpBitwiseOr:
847 case EOpAddAssign:
848 case EOpSubAssign:
849 case EOpDivAssign:
850 case EOpIModAssign:
851 case EOpBitShiftLeftAssign:
852 case EOpBitShiftRightAssign:
853 case EOpBitwiseAndAssign:
854 case EOpBitwiseXorAssign:
855 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300856 {
857 const int secondarySize =
858 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
859 setType(TType(basicType, higherPrecision, resultQualifier,
860 static_cast<unsigned char>(nominalSize),
861 static_cast<unsigned char>(secondarySize)));
862 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300863 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300864 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300865 case EOpEqual:
866 case EOpNotEqual:
867 case EOpLessThan:
868 case EOpGreaterThan:
869 case EOpLessThanEqual:
870 case EOpGreaterThanEqual:
871 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
872 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300873 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300874 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400875
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300876 case EOpIndexDirect:
877 case EOpIndexIndirect:
878 case EOpIndexDirectInterfaceBlock:
879 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300880 case EOpVectorSwizzle:
881 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300882 UNREACHABLE();
883 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300884 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300885 UNREACHABLE();
886 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400887 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400888}
889
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300890const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300891{
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300892 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300893 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300894 ASSERT(index < static_cast<int>(getType().getArraySize()));
895 TType arrayElementType = getType();
896 arrayElementType.clearArrayness();
897 size_t arrayElementSize = arrayElementType.getObjectSize();
898 return &mUnionArrayPointer[arrayElementSize * index];
899 }
900 else if (isMatrix())
901 {
902 ASSERT(index < getType().getCols());
903 int size = getType().getRows();
904 return &mUnionArrayPointer[size * index];
905 }
906 else if (isVector())
907 {
908 ASSERT(index < getType().getNominalSize());
909 return &mUnionArrayPointer[index];
910 }
911 else
912 {
913 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300914 return nullptr;
915 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300916}
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200917
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300918TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
919{
920 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
921 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
922 switch (mOp)
923 {
924 case EOpIndexDirect:
925 {
926 if (leftConstant == nullptr || rightConstant == nullptr)
927 {
928 return nullptr;
929 }
930 int index = rightConstant->getIConst(0);
931
932 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
933 return CreateFoldedNode(constArray, this, mType.getQualifier());
934 }
935 case EOpIndexDirectStruct:
936 {
937 if (leftConstant == nullptr || rightConstant == nullptr)
938 {
939 return nullptr;
940 }
941 const TFieldList &fields = mLeft->getType().getStruct()->fields();
942 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
943
944 size_t previousFieldsSize = 0;
945 for (size_t i = 0; i < index; ++i)
946 {
947 previousFieldsSize += fields[i]->type()->getObjectSize();
948 }
949
950 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
951 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
952 }
953 case EOpIndexIndirect:
954 case EOpIndexDirectInterfaceBlock:
955 // Can never be constant folded.
956 return nullptr;
957 case EOpVectorSwizzle:
958 {
959 if (leftConstant == nullptr)
960 {
961 return nullptr;
962 }
963 TIntermAggregate *fieldsAgg = mRight->getAsAggregate();
964 TIntermSequence *fieldsSequence = fieldsAgg->getSequence();
965 size_t numFields = fieldsSequence->size();
966
967 TConstantUnion *constArray = new TConstantUnion[numFields];
968 for (size_t i = 0; i < numFields; i++)
969 {
970 int fieldOffset = fieldsSequence->at(i)->getAsConstantUnion()->getIConst(0);
971 constArray[i] = *leftConstant->foldIndexing(fieldOffset);
972 }
973 return CreateFoldedNode(constArray, this, mType.getQualifier());
974 }
975 default:
976 {
977 if (leftConstant == nullptr || rightConstant == nullptr)
978 {
979 return nullptr;
980 }
981 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
982
983 // Nodes may be constant folded without being qualified as constant.
984 return CreateFoldedNode(constArray, this, mType.getQualifier());
985 }
986 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300987}
988
Olli Etuahof119a262016-08-19 15:54:22 +0300989TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +0300990{
991 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
992 if (operandConstant == nullptr)
993 {
994 return nullptr;
995 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530996
997 TConstantUnion *constArray = nullptr;
998 switch (mOp)
999 {
1000 case EOpAny:
1001 case EOpAll:
1002 case EOpLength:
1003 case EOpTranspose:
1004 case EOpDeterminant:
1005 case EOpInverse:
1006 case EOpPackSnorm2x16:
1007 case EOpUnpackSnorm2x16:
1008 case EOpPackUnorm2x16:
1009 case EOpUnpackUnorm2x16:
1010 case EOpPackHalf2x16:
1011 case EOpUnpackHalf2x16:
Olli Etuahof119a262016-08-19 15:54:22 +03001012 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1013 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301014 default:
Olli Etuahof119a262016-08-19 15:54:22 +03001015 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1016 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301017 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001018
1019 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001020 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001021}
1022
Olli Etuahof119a262016-08-19 15:54:22 +03001023TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001024{
1025 // Make sure that all params are constant before actual constant folding.
1026 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001027 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001028 if (param->getAsConstantUnion() == nullptr)
1029 {
1030 return nullptr;
1031 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001032 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001033 TConstantUnion *constArray = nullptr;
1034 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001035 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001036 else
Olli Etuahof119a262016-08-19 15:54:22 +03001037 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001038
1039 // Nodes may be constant folded without being qualified as constant.
1040 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1041 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001042}
1043
Jamie Madillb1a85f42014-08-19 15:23:24 -04001044//
1045// The fold functions see if an operation on a constant can be done in place,
1046// without generating run-time code.
1047//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001048// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001049//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001050TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1051 TIntermConstantUnion *rightNode,
1052 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001053{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001054 const TConstantUnion *leftArray = getUnionArrayPointer();
1055 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001056
Olli Etuahof119a262016-08-19 15:54:22 +03001057 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001058
1059 size_t objectSize = getType().getObjectSize();
1060
1061 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1062 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1063 {
1064 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1065 }
1066 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1067 {
1068 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1069 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1070 objectSize = rightNode->getType().getObjectSize();
1071 }
1072
1073 TConstantUnion *resultArray = nullptr;
1074
1075 switch(op)
1076 {
1077 case EOpAdd:
1078 resultArray = new TConstantUnion[objectSize];
1079 for (size_t i = 0; i < objectSize; i++)
1080 resultArray[i] = leftArray[i] + rightArray[i];
1081 break;
1082 case EOpSub:
1083 resultArray = new TConstantUnion[objectSize];
1084 for (size_t i = 0; i < objectSize; i++)
1085 resultArray[i] = leftArray[i] - rightArray[i];
1086 break;
1087
1088 case EOpMul:
1089 case EOpVectorTimesScalar:
1090 case EOpMatrixTimesScalar:
1091 resultArray = new TConstantUnion[objectSize];
1092 for (size_t i = 0; i < objectSize; i++)
1093 resultArray[i] = leftArray[i] * rightArray[i];
1094 break;
1095
1096 case EOpMatrixTimesMatrix:
1097 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001098 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001099
1100 const int leftCols = getCols();
1101 const int leftRows = getRows();
1102 const int rightCols = rightNode->getType().getCols();
1103 const int rightRows = rightNode->getType().getRows();
1104 const int resultCols = rightCols;
1105 const int resultRows = leftRows;
1106
1107 resultArray = new TConstantUnion[resultCols * resultRows];
1108 for (int row = 0; row < resultRows; row++)
1109 {
1110 for (int column = 0; column < resultCols; column++)
1111 {
1112 resultArray[resultRows * column + row].setFConst(0.0f);
1113 for (int i = 0; i < leftCols; i++)
1114 {
1115 resultArray[resultRows * column + row].setFConst(
1116 resultArray[resultRows * column + row].getFConst() +
1117 leftArray[i * leftRows + row].getFConst() *
1118 rightArray[column * rightRows + i].getFConst());
1119 }
1120 }
1121 }
1122 }
1123 break;
1124
1125 case EOpDiv:
1126 case EOpIMod:
1127 {
1128 resultArray = new TConstantUnion[objectSize];
1129 for (size_t i = 0; i < objectSize; i++)
1130 {
1131 switch (getType().getBasicType())
1132 {
1133 case EbtFloat:
1134 if (rightArray[i] == 0.0f)
1135 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001136 diagnostics->warning(
1137 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001138 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1139 }
1140 else
1141 {
1142 ASSERT(op == EOpDiv);
1143 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1144 }
1145 break;
1146
1147 case EbtInt:
1148 if (rightArray[i] == 0)
1149 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001150 diagnostics->warning(
1151 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001152 resultArray[i].setIConst(INT_MAX);
1153 }
1154 else
1155 {
1156 if (op == EOpDiv)
1157 {
1158 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1159 }
1160 else
1161 {
1162 ASSERT(op == EOpIMod);
1163 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1164 }
1165 }
1166 break;
1167
1168 case EbtUInt:
1169 if (rightArray[i] == 0)
1170 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001171 diagnostics->warning(
1172 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001173 resultArray[i].setUConst(UINT_MAX);
1174 }
1175 else
1176 {
1177 if (op == EOpDiv)
1178 {
1179 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1180 }
1181 else
1182 {
1183 ASSERT(op == EOpIMod);
1184 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1185 }
1186 }
1187 break;
1188
1189 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001190 UNREACHABLE();
1191 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001192 }
1193 }
1194 }
1195 break;
1196
1197 case EOpMatrixTimesVector:
1198 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001199 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001200
1201 const int matrixCols = getCols();
1202 const int matrixRows = getRows();
1203
1204 resultArray = new TConstantUnion[matrixRows];
1205
1206 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1207 {
1208 resultArray[matrixRow].setFConst(0.0f);
1209 for (int col = 0; col < matrixCols; col++)
1210 {
1211 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1212 leftArray[col * matrixRows + matrixRow].getFConst() *
1213 rightArray[col].getFConst());
1214 }
1215 }
1216 }
1217 break;
1218
1219 case EOpVectorTimesMatrix:
1220 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001221 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001222
1223 const int matrixCols = rightNode->getType().getCols();
1224 const int matrixRows = rightNode->getType().getRows();
1225
1226 resultArray = new TConstantUnion[matrixCols];
1227
1228 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1229 {
1230 resultArray[matrixCol].setFConst(0.0f);
1231 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1232 {
1233 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1234 leftArray[matrixRow].getFConst() *
1235 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1236 }
1237 }
1238 }
1239 break;
1240
1241 case EOpLogicalAnd:
1242 {
1243 resultArray = new TConstantUnion[objectSize];
1244 for (size_t i = 0; i < objectSize; i++)
1245 {
1246 resultArray[i] = leftArray[i] && rightArray[i];
1247 }
1248 }
1249 break;
1250
1251 case EOpLogicalOr:
1252 {
1253 resultArray = new TConstantUnion[objectSize];
1254 for (size_t i = 0; i < objectSize; i++)
1255 {
1256 resultArray[i] = leftArray[i] || rightArray[i];
1257 }
1258 }
1259 break;
1260
1261 case EOpLogicalXor:
1262 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001263 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001264 resultArray = new TConstantUnion[objectSize];
1265 for (size_t i = 0; i < objectSize; i++)
1266 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001267 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001268 }
1269 }
1270 break;
1271
1272 case EOpBitwiseAnd:
1273 resultArray = new TConstantUnion[objectSize];
1274 for (size_t i = 0; i < objectSize; i++)
1275 resultArray[i] = leftArray[i] & rightArray[i];
1276 break;
1277 case EOpBitwiseXor:
1278 resultArray = new TConstantUnion[objectSize];
1279 for (size_t i = 0; i < objectSize; i++)
1280 resultArray[i] = leftArray[i] ^ rightArray[i];
1281 break;
1282 case EOpBitwiseOr:
1283 resultArray = new TConstantUnion[objectSize];
1284 for (size_t i = 0; i < objectSize; i++)
1285 resultArray[i] = leftArray[i] | rightArray[i];
1286 break;
1287 case EOpBitShiftLeft:
1288 resultArray = new TConstantUnion[objectSize];
1289 for (size_t i = 0; i < objectSize; i++)
1290 resultArray[i] = leftArray[i] << rightArray[i];
1291 break;
1292 case EOpBitShiftRight:
1293 resultArray = new TConstantUnion[objectSize];
1294 for (size_t i = 0; i < objectSize; i++)
1295 resultArray[i] = leftArray[i] >> rightArray[i];
1296 break;
1297
1298 case EOpLessThan:
1299 ASSERT(objectSize == 1);
1300 resultArray = new TConstantUnion[1];
1301 resultArray->setBConst(*leftArray < *rightArray);
1302 break;
1303
1304 case EOpGreaterThan:
1305 ASSERT(objectSize == 1);
1306 resultArray = new TConstantUnion[1];
1307 resultArray->setBConst(*leftArray > *rightArray);
1308 break;
1309
1310 case EOpLessThanEqual:
1311 ASSERT(objectSize == 1);
1312 resultArray = new TConstantUnion[1];
1313 resultArray->setBConst(!(*leftArray > *rightArray));
1314 break;
1315
1316 case EOpGreaterThanEqual:
1317 ASSERT(objectSize == 1);
1318 resultArray = new TConstantUnion[1];
1319 resultArray->setBConst(!(*leftArray < *rightArray));
1320 break;
1321
1322 case EOpEqual:
1323 case EOpNotEqual:
1324 {
1325 resultArray = new TConstantUnion[1];
1326 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001327 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001328 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001329 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001330 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001331 equal = false;
1332 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001333 }
1334 }
1335 if (op == EOpEqual)
1336 {
1337 resultArray->setBConst(equal);
1338 }
1339 else
1340 {
1341 resultArray->setBConst(!equal);
1342 }
1343 }
1344 break;
1345
1346 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001347 UNREACHABLE();
1348 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001349 }
1350 return resultArray;
1351}
1352
Olli Etuahof119a262016-08-19 15:54:22 +03001353// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1354// code. Returns the constant value to keep using. Nullptr should not be returned.
1355TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001356{
Olli Etuahof119a262016-08-19 15:54:22 +03001357 // Do operations where the return type may have a different number of components compared to the
1358 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001359
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001360 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001361 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301362
1363 size_t objectSize = getType().getObjectSize();
1364 TConstantUnion *resultArray = nullptr;
1365 switch (op)
1366 {
Olli Etuahof119a262016-08-19 15:54:22 +03001367 case EOpAny:
1368 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301369 resultArray = new TConstantUnion();
1370 resultArray->setBConst(false);
1371 for (size_t i = 0; i < objectSize; i++)
1372 {
1373 if (operandArray[i].getBConst())
1374 {
1375 resultArray->setBConst(true);
1376 break;
1377 }
1378 }
1379 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301380
Olli Etuahof119a262016-08-19 15:54:22 +03001381 case EOpAll:
1382 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301383 resultArray = new TConstantUnion();
1384 resultArray->setBConst(true);
1385 for (size_t i = 0; i < objectSize; i++)
1386 {
1387 if (!operandArray[i].getBConst())
1388 {
1389 resultArray->setBConst(false);
1390 break;
1391 }
1392 }
1393 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301394
Olli Etuahof119a262016-08-19 15:54:22 +03001395 case EOpLength:
1396 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301397 resultArray = new TConstantUnion();
1398 resultArray->setFConst(VectorLength(operandArray, objectSize));
1399 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301400
Olli Etuahof119a262016-08-19 15:54:22 +03001401 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301402 {
Olli Etuahof119a262016-08-19 15:54:22 +03001403 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301404 resultArray = new TConstantUnion[objectSize];
1405 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001406 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301407 SetUnionArrayFromMatrix(result, resultArray);
1408 break;
1409 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301410
Olli Etuahof119a262016-08-19 15:54:22 +03001411 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301412 {
Olli Etuahof119a262016-08-19 15:54:22 +03001413 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301414 unsigned int size = getType().getNominalSize();
1415 ASSERT(size >= 2 && size <= 4);
1416 resultArray = new TConstantUnion();
1417 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1418 break;
1419 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301420
Olli Etuahof119a262016-08-19 15:54:22 +03001421 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301422 {
Olli Etuahof119a262016-08-19 15:54:22 +03001423 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301424 unsigned int size = getType().getNominalSize();
1425 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001426 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301427 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1428 SetUnionArrayFromMatrix(result, resultArray);
1429 break;
1430 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301431
Olli Etuahof119a262016-08-19 15:54:22 +03001432 case EOpPackSnorm2x16:
1433 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301434 ASSERT(getType().getNominalSize() == 2);
1435 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001436 resultArray->setUConst(
1437 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301438 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301439
Olli Etuahof119a262016-08-19 15:54:22 +03001440 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301441 {
Olli Etuahof119a262016-08-19 15:54:22 +03001442 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301443 resultArray = new TConstantUnion[2];
1444 float f1, f2;
1445 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1446 resultArray[0].setFConst(f1);
1447 resultArray[1].setFConst(f2);
1448 break;
1449 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301450
Olli Etuahof119a262016-08-19 15:54:22 +03001451 case EOpPackUnorm2x16:
1452 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301453 ASSERT(getType().getNominalSize() == 2);
1454 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001455 resultArray->setUConst(
1456 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301457 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301458
Olli Etuahof119a262016-08-19 15:54:22 +03001459 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301460 {
Olli Etuahof119a262016-08-19 15:54:22 +03001461 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301462 resultArray = new TConstantUnion[2];
1463 float f1, f2;
1464 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1465 resultArray[0].setFConst(f1);
1466 resultArray[1].setFConst(f2);
1467 break;
1468 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301469
Olli Etuahof119a262016-08-19 15:54:22 +03001470 case EOpPackHalf2x16:
1471 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301472 ASSERT(getType().getNominalSize() == 2);
1473 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001474 resultArray->setUConst(
1475 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301476 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301477
Olli Etuahof119a262016-08-19 15:54:22 +03001478 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301479 {
Olli Etuahof119a262016-08-19 15:54:22 +03001480 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301481 resultArray = new TConstantUnion[2];
1482 float f1, f2;
1483 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1484 resultArray[0].setFConst(f1);
1485 resultArray[1].setFConst(f2);
1486 break;
1487 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301488
Olli Etuahof119a262016-08-19 15:54:22 +03001489 default:
1490 UNREACHABLE();
1491 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301492 }
1493
1494 return resultArray;
1495}
1496
Olli Etuahof119a262016-08-19 15:54:22 +03001497TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1498 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301499{
Olli Etuahof119a262016-08-19 15:54:22 +03001500 // Do unary operations where each component of the result is computed based on the corresponding
1501 // component of the operand. Also folds normalize, though the divisor in that case takes all
1502 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301503
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001504 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001505 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001506
1507 size_t objectSize = getType().getObjectSize();
1508
Arun Patoleab2b9a22015-07-06 18:27:56 +05301509 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1510 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301511 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301512 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301513 {
Olli Etuahof119a262016-08-19 15:54:22 +03001514 case EOpNegative:
1515 switch (getType().getBasicType())
1516 {
1517 case EbtFloat:
1518 resultArray[i].setFConst(-operandArray[i].getFConst());
1519 break;
1520 case EbtInt:
1521 resultArray[i].setIConst(-operandArray[i].getIConst());
1522 break;
1523 case EbtUInt:
1524 resultArray[i].setUConst(static_cast<unsigned int>(
1525 -static_cast<int>(operandArray[i].getUConst())));
1526 break;
1527 default:
1528 UNREACHABLE();
1529 return nullptr;
1530 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301531 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301532
Olli Etuahof119a262016-08-19 15:54:22 +03001533 case EOpPositive:
1534 switch (getType().getBasicType())
1535 {
1536 case EbtFloat:
1537 resultArray[i].setFConst(operandArray[i].getFConst());
1538 break;
1539 case EbtInt:
1540 resultArray[i].setIConst(operandArray[i].getIConst());
1541 break;
1542 case EbtUInt:
1543 resultArray[i].setUConst(static_cast<unsigned int>(
1544 static_cast<int>(operandArray[i].getUConst())));
1545 break;
1546 default:
1547 UNREACHABLE();
1548 return nullptr;
1549 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301550 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301551
Olli Etuahof119a262016-08-19 15:54:22 +03001552 case EOpLogicalNot:
1553 switch (getType().getBasicType())
1554 {
1555 case EbtBool:
1556 resultArray[i].setBConst(!operandArray[i].getBConst());
1557 break;
1558 default:
1559 UNREACHABLE();
1560 return nullptr;
1561 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301562 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301563
Olli Etuahof119a262016-08-19 15:54:22 +03001564 case EOpBitwiseNot:
1565 switch (getType().getBasicType())
1566 {
1567 case EbtInt:
1568 resultArray[i].setIConst(~operandArray[i].getIConst());
1569 break;
1570 case EbtUInt:
1571 resultArray[i].setUConst(~operandArray[i].getUConst());
1572 break;
1573 default:
1574 UNREACHABLE();
1575 return nullptr;
1576 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301577 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301578
Olli Etuahof119a262016-08-19 15:54:22 +03001579 case EOpRadians:
1580 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301581 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1582 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301583
Olli Etuahof119a262016-08-19 15:54:22 +03001584 case EOpDegrees:
1585 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301586 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1587 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301588
Olli Etuahof119a262016-08-19 15:54:22 +03001589 case EOpSin:
1590 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301591 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301592
Olli Etuahof119a262016-08-19 15:54:22 +03001593 case EOpCos:
1594 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1595 break;
1596
1597 case EOpTan:
1598 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1599 break;
1600
1601 case EOpAsin:
1602 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1603 // 0.
1604 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1605 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1606 diagnostics, &resultArray[i]);
1607 else
1608 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1609 break;
1610
1611 case EOpAcos:
1612 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1613 // 0.
1614 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1615 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1616 diagnostics, &resultArray[i]);
1617 else
1618 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1619 break;
1620
1621 case EOpAtan:
1622 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1623 break;
1624
1625 case EOpSinh:
1626 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1627 break;
1628
1629 case EOpCosh:
1630 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1631 break;
1632
1633 case EOpTanh:
1634 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1635 break;
1636
1637 case EOpAsinh:
1638 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1639 break;
1640
1641 case EOpAcosh:
1642 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1643 if (operandArray[i].getFConst() < 1.0f)
1644 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1645 diagnostics, &resultArray[i]);
1646 else
1647 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1648 break;
1649
1650 case EOpAtanh:
1651 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1652 // 0.
1653 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1654 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1655 diagnostics, &resultArray[i]);
1656 else
1657 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1658 break;
1659
1660 case EOpAbs:
1661 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301662 {
Olli Etuahof119a262016-08-19 15:54:22 +03001663 case EbtFloat:
1664 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1665 break;
1666 case EbtInt:
1667 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1668 break;
1669 default:
1670 UNREACHABLE();
1671 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301672 }
1673 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001674
1675 case EOpSign:
1676 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301677 {
Olli Etuahof119a262016-08-19 15:54:22 +03001678 case EbtFloat:
1679 {
1680 float fConst = operandArray[i].getFConst();
1681 float fResult = 0.0f;
1682 if (fConst > 0.0f)
1683 fResult = 1.0f;
1684 else if (fConst < 0.0f)
1685 fResult = -1.0f;
1686 resultArray[i].setFConst(fResult);
1687 break;
1688 }
1689 case EbtInt:
1690 {
1691 int iConst = operandArray[i].getIConst();
1692 int iResult = 0;
1693 if (iConst > 0)
1694 iResult = 1;
1695 else if (iConst < 0)
1696 iResult = -1;
1697 resultArray[i].setIConst(iResult);
1698 break;
1699 }
1700 default:
1701 UNREACHABLE();
1702 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301703 }
1704 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301705
Olli Etuahof119a262016-08-19 15:54:22 +03001706 case EOpFloor:
1707 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1708 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301709
Olli Etuahof119a262016-08-19 15:54:22 +03001710 case EOpTrunc:
1711 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1712 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301713
Olli Etuahof119a262016-08-19 15:54:22 +03001714 case EOpRound:
1715 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1716 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301717
Olli Etuahof119a262016-08-19 15:54:22 +03001718 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301719 {
Olli Etuahof119a262016-08-19 15:54:22 +03001720 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301721 float x = operandArray[i].getFConst();
1722 float result;
1723 float fractPart = modff(x, &result);
1724 if (fabsf(fractPart) == 0.5f)
1725 result = 2.0f * roundf(x / 2.0f);
1726 else
1727 result = roundf(x);
1728 resultArray[i].setFConst(result);
1729 break;
1730 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301731
Olli Etuahof119a262016-08-19 15:54:22 +03001732 case EOpCeil:
1733 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
1734 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301735
Olli Etuahof119a262016-08-19 15:54:22 +03001736 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301737 {
Olli Etuahof119a262016-08-19 15:54:22 +03001738 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301739 float x = operandArray[i].getFConst();
1740 resultArray[i].setFConst(x - floorf(x));
1741 break;
1742 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301743
Olli Etuahof119a262016-08-19 15:54:22 +03001744 case EOpIsNan:
1745 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301746 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1747 break;
Arun Patole551279e2015-07-07 18:18:23 +05301748
Olli Etuahof119a262016-08-19 15:54:22 +03001749 case EOpIsInf:
1750 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301751 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1752 break;
Arun Patole551279e2015-07-07 18:18:23 +05301753
Olli Etuahof119a262016-08-19 15:54:22 +03001754 case EOpFloatBitsToInt:
1755 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301756 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1757 break;
Arun Patole551279e2015-07-07 18:18:23 +05301758
Olli Etuahof119a262016-08-19 15:54:22 +03001759 case EOpFloatBitsToUint:
1760 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301761 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1762 break;
Arun Patole551279e2015-07-07 18:18:23 +05301763
Olli Etuahof119a262016-08-19 15:54:22 +03001764 case EOpIntBitsToFloat:
1765 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05301766 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1767 break;
Arun Patole551279e2015-07-07 18:18:23 +05301768
Olli Etuahof119a262016-08-19 15:54:22 +03001769 case EOpUintBitsToFloat:
1770 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05301771 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1772 break;
Arun Patole551279e2015-07-07 18:18:23 +05301773
Olli Etuahof119a262016-08-19 15:54:22 +03001774 case EOpExp:
1775 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
1776 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301777
Olli Etuahof119a262016-08-19 15:54:22 +03001778 case EOpLog:
1779 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1780 if (operandArray[i].getFConst() <= 0.0f)
1781 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1782 diagnostics, &resultArray[i]);
1783 else
1784 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1785 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786
Olli Etuahof119a262016-08-19 15:54:22 +03001787 case EOpExp2:
1788 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
1789 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301790
Olli Etuahof119a262016-08-19 15:54:22 +03001791 case EOpLog2:
1792 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1793 // And log2f is not available on some plarforms like old android, so just using
1794 // log(x)/log(2) here.
1795 if (operandArray[i].getFConst() <= 0.0f)
1796 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1797 diagnostics, &resultArray[i]);
1798 else
1799 {
1800 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1801 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1802 }
1803 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301804
Olli Etuahof119a262016-08-19 15:54:22 +03001805 case EOpSqrt:
1806 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1807 if (operandArray[i].getFConst() < 0.0f)
1808 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1809 diagnostics, &resultArray[i]);
1810 else
1811 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1812 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301813
Olli Etuahof119a262016-08-19 15:54:22 +03001814 case EOpInverseSqrt:
1815 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1816 // so getting the square root first using builtin function sqrt() and then taking
1817 // its inverse.
1818 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
1819 // result to 0.
1820 if (operandArray[i].getFConst() <= 0.0f)
1821 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1822 diagnostics, &resultArray[i]);
1823 else
1824 {
1825 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1826 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1827 }
1828 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301829
Olli Etuahof119a262016-08-19 15:54:22 +03001830 case EOpVectorLogicalNot:
1831 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301832 resultArray[i].setBConst(!operandArray[i].getBConst());
1833 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301834
Olli Etuahof119a262016-08-19 15:54:22 +03001835 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301836 {
Olli Etuahof119a262016-08-19 15:54:22 +03001837 ASSERT(getType().getBasicType() == EbtFloat);
1838 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301839 float length = VectorLength(operandArray, objectSize);
1840 if (length)
1841 resultArray[i].setFConst(x / length);
1842 else
Olli Etuahof119a262016-08-19 15:54:22 +03001843 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1844 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301845 break;
1846 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301847
Olli Etuahof119a262016-08-19 15:54:22 +03001848 case EOpDFdx:
1849 case EOpDFdy:
1850 case EOpFwidth:
1851 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05301852 // Derivatives of constant arguments should be 0.
1853 resultArray[i].setFConst(0.0f);
1854 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05301855
Olli Etuahof119a262016-08-19 15:54:22 +03001856 default:
1857 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301858 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301859 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001860
Arun Patoleab2b9a22015-07-06 18:27:56 +05301861 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001862}
1863
Olli Etuahof119a262016-08-19 15:54:22 +03001864void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
1865 FloatTypeUnaryFunc builtinFunc,
1866 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301867{
1868 ASSERT(builtinFunc);
1869
Olli Etuahof119a262016-08-19 15:54:22 +03001870 ASSERT(getType().getBasicType() == EbtFloat);
1871 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05301872}
1873
Jamie Madillb1a85f42014-08-19 15:23:24 -04001874// static
Olli Etuahof119a262016-08-19 15:54:22 +03001875TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02001876{
1877 ASSERT(aggregate->getSequence()->size() > 0u);
1878 size_t resultSize = aggregate->getType().getObjectSize();
1879 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1880 TBasicType basicType = aggregate->getBasicType();
1881
1882 size_t resultIndex = 0u;
1883
1884 if (aggregate->getSequence()->size() == 1u)
1885 {
1886 TIntermNode *argument = aggregate->getSequence()->front();
1887 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1888 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1889 // Check the special case of constructing a matrix diagonal from a single scalar,
1890 // or a vector from a single scalar.
1891 if (argumentConstant->getType().getObjectSize() == 1u)
1892 {
1893 if (aggregate->isMatrix())
1894 {
1895 int resultCols = aggregate->getType().getCols();
1896 int resultRows = aggregate->getType().getRows();
1897 for (int col = 0; col < resultCols; ++col)
1898 {
1899 for (int row = 0; row < resultRows; ++row)
1900 {
1901 if (col == row)
1902 {
1903 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1904 }
1905 else
1906 {
1907 resultArray[resultIndex].setFConst(0.0f);
1908 }
1909 ++resultIndex;
1910 }
1911 }
1912 }
1913 else
1914 {
1915 while (resultIndex < resultSize)
1916 {
1917 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1918 ++resultIndex;
1919 }
1920 }
1921 ASSERT(resultIndex == resultSize);
1922 return resultArray;
1923 }
1924 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1925 {
1926 // The special case of constructing a matrix from a matrix.
1927 int argumentCols = argumentConstant->getType().getCols();
1928 int argumentRows = argumentConstant->getType().getRows();
1929 int resultCols = aggregate->getType().getCols();
1930 int resultRows = aggregate->getType().getRows();
1931 for (int col = 0; col < resultCols; ++col)
1932 {
1933 for (int row = 0; row < resultRows; ++row)
1934 {
1935 if (col < argumentCols && row < argumentRows)
1936 {
1937 resultArray[resultIndex].cast(basicType,
1938 argumentUnionArray[col * argumentRows + row]);
1939 }
1940 else if (col == row)
1941 {
1942 resultArray[resultIndex].setFConst(1.0f);
1943 }
1944 else
1945 {
1946 resultArray[resultIndex].setFConst(0.0f);
1947 }
1948 ++resultIndex;
1949 }
1950 }
1951 ASSERT(resultIndex == resultSize);
1952 return resultArray;
1953 }
1954 }
1955
1956 for (TIntermNode *&argument : *aggregate->getSequence())
1957 {
1958 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1959 size_t argumentSize = argumentConstant->getType().getObjectSize();
1960 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1961 for (size_t i = 0u; i < argumentSize; ++i)
1962 {
1963 if (resultIndex >= resultSize)
1964 break;
1965 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1966 ++resultIndex;
1967 }
1968 }
1969 ASSERT(resultIndex == resultSize);
1970 return resultArray;
1971}
1972
1973// static
Olli Etuahof119a262016-08-19 15:54:22 +03001974TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
1975 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05301976{
Olli Etuahob43846e2015-06-02 18:18:57 +03001977 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301978 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001979 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001980 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05301981 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001982 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301983 TBasicType basicType = EbtVoid;
1984 TSourceLoc loc;
1985 for (unsigned int i = 0; i < paramsCount; i++)
1986 {
1987 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001988 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301989
1990 if (i == 0)
1991 {
1992 basicType = paramConstant->getType().getBasicType();
1993 loc = paramConstant->getLine();
1994 }
1995 unionArrays[i] = paramConstant->getUnionArrayPointer();
1996 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001997 if (objectSizes[i] > maxObjectSize)
1998 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301999 }
2000
Olli Etuahod5da5052016-08-29 13:16:55 +03002001 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302002 {
2003 for (unsigned int i = 0; i < paramsCount; i++)
2004 if (objectSizes[i] != maxObjectSize)
2005 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2006 }
Arun Patole274f0702015-05-05 13:33:30 +05302007
Olli Etuahob43846e2015-06-02 18:18:57 +03002008 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302009 if (paramsCount == 2)
2010 {
2011 //
2012 // Binary built-in
2013 //
2014 switch (op)
2015 {
Olli Etuahof119a262016-08-19 15:54:22 +03002016 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302017 {
Olli Etuahof119a262016-08-19 15:54:22 +03002018 ASSERT(basicType == EbtFloat);
2019 resultArray = new TConstantUnion[maxObjectSize];
2020 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302021 {
Olli Etuahof119a262016-08-19 15:54:22 +03002022 float y = unionArrays[0][i].getFConst();
2023 float x = unionArrays[1][i].getFConst();
2024 // Results are undefined if x and y are both 0.
2025 if (x == 0.0f && y == 0.0f)
2026 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2027 &resultArray[i]);
2028 else
2029 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302030 }
Olli Etuahof119a262016-08-19 15:54:22 +03002031 break;
Arun Patolebf790422015-05-18 17:53:04 +05302032 }
Arun Patolebf790422015-05-18 17:53:04 +05302033
Olli Etuahof119a262016-08-19 15:54:22 +03002034 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302035 {
Olli Etuahof119a262016-08-19 15:54:22 +03002036 ASSERT(basicType == EbtFloat);
2037 resultArray = new TConstantUnion[maxObjectSize];
2038 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302039 {
Olli Etuahof119a262016-08-19 15:54:22 +03002040 float x = unionArrays[0][i].getFConst();
2041 float y = unionArrays[1][i].getFConst();
2042 // Results are undefined if x < 0.
2043 // Results are undefined if x = 0 and y <= 0.
2044 if (x < 0.0f)
2045 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2046 &resultArray[i]);
2047 else if (x == 0.0f && y <= 0.0f)
2048 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2049 &resultArray[i]);
2050 else
2051 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302052 }
Olli Etuahof119a262016-08-19 15:54:22 +03002053 break;
Arun Patolebf790422015-05-18 17:53:04 +05302054 }
Arun Patolebf790422015-05-18 17:53:04 +05302055
Olli Etuahof119a262016-08-19 15:54:22 +03002056 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302057 {
Olli Etuahof119a262016-08-19 15:54:22 +03002058 ASSERT(basicType == EbtFloat);
2059 resultArray = new TConstantUnion[maxObjectSize];
2060 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302061 {
Olli Etuahof119a262016-08-19 15:54:22 +03002062 float x = unionArrays[0][i].getFConst();
2063 float y = unionArrays[1][i].getFConst();
2064 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302065 }
Olli Etuahof119a262016-08-19 15:54:22 +03002066 break;
Arun Patolebf790422015-05-18 17:53:04 +05302067 }
Arun Patolebf790422015-05-18 17:53:04 +05302068
Olli Etuahof119a262016-08-19 15:54:22 +03002069 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302070 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002071 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302072 for (size_t i = 0; i < maxObjectSize; i++)
2073 {
2074 switch (basicType)
2075 {
Olli Etuahof119a262016-08-19 15:54:22 +03002076 case EbtFloat:
2077 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2078 unionArrays[1][i].getFConst()));
2079 break;
2080 case EbtInt:
2081 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2082 unionArrays[1][i].getIConst()));
2083 break;
2084 case EbtUInt:
2085 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2086 unionArrays[1][i].getUConst()));
2087 break;
2088 default:
2089 UNREACHABLE();
2090 break;
Arun Patole274f0702015-05-05 13:33:30 +05302091 }
2092 }
Olli Etuahof119a262016-08-19 15:54:22 +03002093 break;
Arun Patole274f0702015-05-05 13:33:30 +05302094 }
Arun Patole274f0702015-05-05 13:33:30 +05302095
Olli Etuahof119a262016-08-19 15:54:22 +03002096 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302097 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002098 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302099 for (size_t i = 0; i < maxObjectSize; i++)
2100 {
2101 switch (basicType)
2102 {
Olli Etuahof119a262016-08-19 15:54:22 +03002103 case EbtFloat:
2104 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2105 unionArrays[1][i].getFConst()));
2106 break;
2107 case EbtInt:
2108 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2109 unionArrays[1][i].getIConst()));
2110 break;
2111 case EbtUInt:
2112 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2113 unionArrays[1][i].getUConst()));
2114 break;
2115 default:
2116 UNREACHABLE();
2117 break;
Arun Patole274f0702015-05-05 13:33:30 +05302118 }
2119 }
Olli Etuahof119a262016-08-19 15:54:22 +03002120 break;
Arun Patole274f0702015-05-05 13:33:30 +05302121 }
Arun Patole274f0702015-05-05 13:33:30 +05302122
Olli Etuahof119a262016-08-19 15:54:22 +03002123 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302124 {
Olli Etuahof119a262016-08-19 15:54:22 +03002125 ASSERT(basicType == EbtFloat);
2126 resultArray = new TConstantUnion[maxObjectSize];
2127 for (size_t i = 0; i < maxObjectSize; i++)
2128 resultArray[i].setFConst(
2129 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2130 : 1.0f);
2131 break;
Arun Patolebf790422015-05-18 17:53:04 +05302132 }
Arun Patolebf790422015-05-18 17:53:04 +05302133
Olli Etuahof119a262016-08-19 15:54:22 +03002134 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302135 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002136 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302137 for (size_t i = 0; i < maxObjectSize; i++)
2138 {
2139 switch (basicType)
2140 {
Olli Etuahof119a262016-08-19 15:54:22 +03002141 case EbtFloat:
2142 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2143 unionArrays[1][i].getFConst());
2144 break;
2145 case EbtInt:
2146 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2147 unionArrays[1][i].getIConst());
2148 break;
2149 case EbtUInt:
2150 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2151 unionArrays[1][i].getUConst());
2152 break;
2153 default:
2154 UNREACHABLE();
2155 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302156 }
2157 }
Olli Etuahof119a262016-08-19 15:54:22 +03002158 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302159 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302160
Olli Etuahof119a262016-08-19 15:54:22 +03002161 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302162 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002163 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302164 for (size_t i = 0; i < maxObjectSize; i++)
2165 {
2166 switch (basicType)
2167 {
Olli Etuahof119a262016-08-19 15:54:22 +03002168 case EbtFloat:
2169 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2170 unionArrays[1][i].getFConst());
2171 break;
2172 case EbtInt:
2173 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2174 unionArrays[1][i].getIConst());
2175 break;
2176 case EbtUInt:
2177 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2178 unionArrays[1][i].getUConst());
2179 break;
2180 default:
2181 UNREACHABLE();
2182 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302183 }
2184 }
Olli Etuahof119a262016-08-19 15:54:22 +03002185 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302186 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302187
Olli Etuahof119a262016-08-19 15:54:22 +03002188 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302189 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002190 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302191 for (size_t i = 0; i < maxObjectSize; i++)
2192 {
2193 switch (basicType)
2194 {
Olli Etuahof119a262016-08-19 15:54:22 +03002195 case EbtFloat:
2196 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2197 unionArrays[1][i].getFConst());
2198 break;
2199 case EbtInt:
2200 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2201 unionArrays[1][i].getIConst());
2202 break;
2203 case EbtUInt:
2204 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2205 unionArrays[1][i].getUConst());
2206 break;
2207 default:
2208 UNREACHABLE();
2209 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002210 }
2211 }
Olli Etuahof119a262016-08-19 15:54:22 +03002212 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302213 }
Olli Etuahof119a262016-08-19 15:54:22 +03002214 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302215 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002216 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302217 for (size_t i = 0; i < maxObjectSize; i++)
2218 {
2219 switch (basicType)
2220 {
Olli Etuahof119a262016-08-19 15:54:22 +03002221 case EbtFloat:
2222 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2223 unionArrays[1][i].getFConst());
2224 break;
2225 case EbtInt:
2226 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2227 unionArrays[1][i].getIConst());
2228 break;
2229 case EbtUInt:
2230 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2231 unionArrays[1][i].getUConst());
2232 break;
2233 default:
2234 UNREACHABLE();
2235 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302236 }
2237 }
2238 }
2239 break;
2240
Olli Etuahof119a262016-08-19 15:54:22 +03002241 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302242 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002243 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 for (size_t i = 0; i < maxObjectSize; i++)
2245 {
2246 switch (basicType)
2247 {
Olli Etuahof119a262016-08-19 15:54:22 +03002248 case EbtFloat:
2249 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2250 unionArrays[1][i].getFConst());
2251 break;
2252 case EbtInt:
2253 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2254 unionArrays[1][i].getIConst());
2255 break;
2256 case EbtUInt:
2257 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2258 unionArrays[1][i].getUConst());
2259 break;
2260 case EbtBool:
2261 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2262 unionArrays[1][i].getBConst());
2263 break;
2264 default:
2265 UNREACHABLE();
2266 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302267 }
2268 }
Olli Etuahof119a262016-08-19 15:54:22 +03002269 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302270 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302271
Olli Etuahof119a262016-08-19 15:54:22 +03002272 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302273 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002274 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302275 for (size_t i = 0; i < maxObjectSize; i++)
2276 {
2277 switch (basicType)
2278 {
Olli Etuahof119a262016-08-19 15:54:22 +03002279 case EbtFloat:
2280 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2281 unionArrays[1][i].getFConst());
2282 break;
2283 case EbtInt:
2284 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2285 unionArrays[1][i].getIConst());
2286 break;
2287 case EbtUInt:
2288 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2289 unionArrays[1][i].getUConst());
2290 break;
2291 case EbtBool:
2292 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2293 unionArrays[1][i].getBConst());
2294 break;
2295 default:
2296 UNREACHABLE();
2297 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302298 }
2299 }
Olli Etuahof119a262016-08-19 15:54:22 +03002300 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302301 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302302
Olli Etuahof119a262016-08-19 15:54:22 +03002303 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302304 {
Olli Etuahof119a262016-08-19 15:54:22 +03002305 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302306 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002307 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302308 for (size_t i = 0; i < maxObjectSize; i++)
2309 {
2310 float x = unionArrays[0][i].getFConst();
2311 float y = unionArrays[1][i].getFConst();
2312 distanceArray[i].setFConst(x - y);
2313 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002314 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002315 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302316 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302317
Olli Etuahof119a262016-08-19 15:54:22 +03002318 case EOpDot:
2319 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002320 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002321 resultArray->setFConst(
2322 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2323 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302324
Olli Etuahof119a262016-08-19 15:54:22 +03002325 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302326 {
Olli Etuahof119a262016-08-19 15:54:22 +03002327 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002328 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002329 float x0 = unionArrays[0][0].getFConst();
2330 float x1 = unionArrays[0][1].getFConst();
2331 float x2 = unionArrays[0][2].getFConst();
2332 float y0 = unionArrays[1][0].getFConst();
2333 float y1 = unionArrays[1][1].getFConst();
2334 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002335 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2336 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2337 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002338 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302339 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302340
Olli Etuahof119a262016-08-19 15:54:22 +03002341 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302342 {
Olli Etuahof119a262016-08-19 15:54:22 +03002343 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302344 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002345 // For the incident vector I and surface orientation N, returns the reflection
2346 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302347 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002348 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302349 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2350 for (size_t i = 0; i < maxObjectSize; i++)
2351 {
2352 float result = unionArrays[0][i].getFConst() -
2353 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002354 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302355 }
Olli Etuahof119a262016-08-19 15:54:22 +03002356 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302357 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302358
Olli Etuahof119a262016-08-19 15:54:22 +03002359 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302360 {
Olli Etuahof119a262016-08-19 15:54:22 +03002361 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2362 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302363 // Perform component-wise matrix multiplication.
2364 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002365 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302366 angle::Matrix<float> result =
2367 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2368 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002369 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302370 }
Arun Patole7fa33552015-06-10 15:15:18 +05302371
Olli Etuahof119a262016-08-19 15:54:22 +03002372 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302373 {
Olli Etuahof119a262016-08-19 15:54:22 +03002374 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302375 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2376 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002377 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302378 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002379 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2380 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302381 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002382 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302383 }
Arun Patole7fa33552015-06-10 15:15:18 +05302384
Olli Etuahof119a262016-08-19 15:54:22 +03002385 default:
2386 UNREACHABLE();
2387 // TODO: Add constant folding support for other built-in operations that take 2
2388 // parameters and not handled above.
2389 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302390 }
2391 }
2392 else if (paramsCount == 3)
2393 {
2394 //
2395 // Ternary built-in
2396 //
2397 switch (op)
2398 {
Olli Etuahof119a262016-08-19 15:54:22 +03002399 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302400 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002401 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302402 for (size_t i = 0; i < maxObjectSize; i++)
2403 {
2404 switch (basicType)
2405 {
Olli Etuahof119a262016-08-19 15:54:22 +03002406 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302407 {
Olli Etuahof119a262016-08-19 15:54:22 +03002408 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302409 float min = unionArrays[1][i].getFConst();
2410 float max = unionArrays[2][i].getFConst();
2411 // Results are undefined if min > max.
2412 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002413 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2414 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302415 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002416 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002417 break;
Arun Patole274f0702015-05-05 13:33:30 +05302418 }
Olli Etuahof119a262016-08-19 15:54:22 +03002419
2420 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302421 {
Olli Etuahof119a262016-08-19 15:54:22 +03002422 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302423 int min = unionArrays[1][i].getIConst();
2424 int max = unionArrays[2][i].getIConst();
2425 // Results are undefined if min > max.
2426 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002427 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2428 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302429 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002430 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002431 break;
Arun Patole274f0702015-05-05 13:33:30 +05302432 }
Olli Etuahof119a262016-08-19 15:54:22 +03002433 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302434 {
Olli Etuahof119a262016-08-19 15:54:22 +03002435 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302436 unsigned int min = unionArrays[1][i].getUConst();
2437 unsigned int max = unionArrays[2][i].getUConst();
2438 // Results are undefined if min > max.
2439 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002440 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2441 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302442 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002443 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002444 break;
Arun Patole274f0702015-05-05 13:33:30 +05302445 }
Olli Etuahof119a262016-08-19 15:54:22 +03002446 default:
2447 UNREACHABLE();
2448 break;
Arun Patole274f0702015-05-05 13:33:30 +05302449 }
2450 }
Olli Etuahof119a262016-08-19 15:54:22 +03002451 break;
Arun Patole274f0702015-05-05 13:33:30 +05302452 }
Arun Patole274f0702015-05-05 13:33:30 +05302453
Olli Etuahof119a262016-08-19 15:54:22 +03002454 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302455 {
Olli Etuahof119a262016-08-19 15:54:22 +03002456 ASSERT(basicType == EbtFloat);
2457 resultArray = new TConstantUnion[maxObjectSize];
2458 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302459 {
Olli Etuahof119a262016-08-19 15:54:22 +03002460 float x = unionArrays[0][i].getFConst();
2461 float y = unionArrays[1][i].getFConst();
2462 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2463 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302464 {
Olli Etuahof119a262016-08-19 15:54:22 +03002465 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2466 float a = unionArrays[2][i].getFConst();
2467 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2468 }
2469 else // 3rd parameter is EbtBool
2470 {
2471 ASSERT(type == EbtBool);
2472 // Selects which vector each returned component comes from.
2473 // For a component of a that is false, the corresponding component of x is
2474 // returned.
2475 // For a component of a that is true, the corresponding component of y is
2476 // returned.
2477 bool a = unionArrays[2][i].getBConst();
2478 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302479 }
2480 }
Olli Etuahof119a262016-08-19 15:54:22 +03002481 break;
Arun Patolebf790422015-05-18 17:53:04 +05302482 }
Arun Patolebf790422015-05-18 17:53:04 +05302483
Olli Etuahof119a262016-08-19 15:54:22 +03002484 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302485 {
Olli Etuahof119a262016-08-19 15:54:22 +03002486 ASSERT(basicType == EbtFloat);
2487 resultArray = new TConstantUnion[maxObjectSize];
2488 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302489 {
Olli Etuahof119a262016-08-19 15:54:22 +03002490 float edge0 = unionArrays[0][i].getFConst();
2491 float edge1 = unionArrays[1][i].getFConst();
2492 float x = unionArrays[2][i].getFConst();
2493 // Results are undefined if edge0 >= edge1.
2494 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302495 {
Olli Etuahof119a262016-08-19 15:54:22 +03002496 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2497 &resultArray[i]);
2498 }
2499 else
2500 {
2501 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2502 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2503 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2504 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302505 }
2506 }
Olli Etuahof119a262016-08-19 15:54:22 +03002507 break;
Arun Patolebf790422015-05-18 17:53:04 +05302508 }
Arun Patolebf790422015-05-18 17:53:04 +05302509
Olli Etuahof119a262016-08-19 15:54:22 +03002510 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302511 {
Olli Etuahof119a262016-08-19 15:54:22 +03002512 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302513 // genType faceforward(genType N, genType I, genType Nref) :
2514 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002515 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302516 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2517 for (size_t i = 0; i < maxObjectSize; i++)
2518 {
2519 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002520 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302521 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002522 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302523 }
Olli Etuahof119a262016-08-19 15:54:22 +03002524 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302525 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302526
Olli Etuahof119a262016-08-19 15:54:22 +03002527 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302528 {
Olli Etuahof119a262016-08-19 15:54:22 +03002529 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302530 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002531 // For the incident vector I and surface normal N, and the ratio of indices of
2532 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302533 // return the refraction vector. The result is computed by
2534 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2535 // if (k < 0.0)
2536 // return genType(0.0)
2537 // else
2538 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002539 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302540 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2541 for (size_t i = 0; i < maxObjectSize; i++)
2542 {
2543 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002544 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302545 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002546 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302547 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002548 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002549 (eta * dotProduct + sqrtf(k)) *
2550 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302551 }
Olli Etuahof119a262016-08-19 15:54:22 +03002552 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302553 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302554
Olli Etuahof119a262016-08-19 15:54:22 +03002555 default:
2556 UNREACHABLE();
2557 // TODO: Add constant folding support for other built-in operations that take 3
2558 // parameters and not handled above.
2559 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302560 }
2561 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002562 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302563}
2564
2565// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002566TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2567{
2568 if (hashFunction == NULL || name.empty())
2569 return name;
2570 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2571 TStringStream stream;
2572 stream << HASHED_NAME_PREFIX << std::hex << number;
2573 TString hashedName = stream.str();
2574 return hashedName;
2575}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002576
2577void TIntermTraverser::updateTree()
2578{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002579 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2580 {
2581 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2582 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002583 if (!insertion.insertionsAfter.empty())
2584 {
2585 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2586 insertion.insertionsAfter);
2587 ASSERT(inserted);
2588 UNUSED_ASSERTION_VARIABLE(inserted);
2589 }
2590 if (!insertion.insertionsBefore.empty())
2591 {
2592 bool inserted =
2593 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2594 ASSERT(inserted);
2595 UNUSED_ASSERTION_VARIABLE(inserted);
2596 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002597 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002598 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2599 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002600 const NodeUpdateEntry &replacement = mReplacements[ii];
2601 ASSERT(replacement.parent);
2602 bool replaced = replacement.parent->replaceChildNode(
2603 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002604 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002605 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002606
Olli Etuahocd94ef92015-04-16 19:18:10 +03002607 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002608 {
2609 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002610 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002611 // be replaced, we need to make sure we don't update the replaced
2612 // node; instead, we update the replacement node.
2613 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2614 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002615 NodeUpdateEntry &replacement2 = mReplacements[jj];
2616 if (replacement2.parent == replacement.original)
2617 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002618 }
2619 }
2620 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002621 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2622 {
2623 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2624 ASSERT(replacement.parent);
2625 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2626 replacement.original, replacement.replacements);
2627 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002628 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002629 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002630
Jamie Madill03d863c2016-07-27 18:15:53 -04002631 clearReplacementQueue();
2632}
2633
2634void TIntermTraverser::clearReplacementQueue()
2635{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002636 mReplacements.clear();
2637 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002638 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002639}
Jamie Madill1048e432016-07-23 18:51:28 -04002640
Jamie Madill03d863c2016-07-27 18:15:53 -04002641void TIntermTraverser::queueReplacement(TIntermNode *original,
2642 TIntermNode *replacement,
2643 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002644{
Jamie Madill03d863c2016-07-27 18:15:53 -04002645 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002646}
2647
Jamie Madill03d863c2016-07-27 18:15:53 -04002648void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2649 TIntermNode *original,
2650 TIntermNode *replacement,
2651 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002652{
Jamie Madill03d863c2016-07-27 18:15:53 -04002653 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2654 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002655}