blob: 9b124a49d64c7136cde358503d1deffd1416b0c1 [file] [log] [blame]
Jamie Madillb1a85f42014-08-19 15:23:24 -04001//
2// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7//
8// Build the intermediate representation.
9//
10
11#include <float.h>
12#include <limits.h>
Arun Patole9dea48f2015-04-02 11:45:09 +053013#include <math.h>
Arun Patole97dc22e2015-04-06 17:35:38 +053014#include <stdlib.h>
Jamie Madillb1a85f42014-08-19 15:23:24 -040015#include <algorithm>
Arun Patole274f0702015-05-05 13:33:30 +053016#include <vector>
Jamie Madillb1a85f42014-08-19 15:23:24 -040017
Arun Patole274f0702015-05-05 13:33:30 +053018#include "common/mathutil.h"
Arun Patole7fa33552015-06-10 15:15:18 +053019#include "common/matrix_utils.h"
Olli Etuaho3fdec912016-08-18 15:08:06 +030020#include "compiler/translator/Diagnostics.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040021#include "compiler/translator/HashNames.h"
22#include "compiler/translator/IntermNode.h"
23#include "compiler/translator/SymbolTable.h"
Corentin Wallez509e4562016-08-25 14:55:44 -040024#include "compiler/translator/util.h"
Jamie Madillb1a85f42014-08-19 15:23:24 -040025
26namespace
27{
28
Arun Patole9dea48f2015-04-02 11:45:09 +053029const float kPi = 3.14159265358979323846f;
30const float kDegreesToRadiansMultiplier = kPi / 180.0f;
31const float kRadiansToDegreesMultiplier = 180.0f / kPi;
32
Jamie Madillb1a85f42014-08-19 15:23:24 -040033TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
34{
35 return left > right ? left : right;
36}
37
Arun Patole274f0702015-05-05 13:33:30 +053038TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
39{
40 TConstantUnion *constUnion = new TConstantUnion[size];
41 for (unsigned int i = 0; i < size; ++i)
42 constUnion[i] = constant;
43
44 return constUnion;
45}
46
Olli Etuahof119a262016-08-19 15:54:22 +030047void UndefinedConstantFoldingError(const TSourceLoc &loc,
48 TOperator op,
49 TBasicType basicType,
50 TDiagnostics *diagnostics,
51 TConstantUnion *result)
Arun Patolebf790422015-05-18 17:53:04 +053052{
Olli Etuahof119a262016-08-19 15:54:22 +030053 diagnostics->warning(loc, "operation result is undefined for the values passed in",
54 GetOperatorString(op), "");
Arun Patolebf790422015-05-18 17:53:04 +053055
56 switch (basicType)
57 {
58 case EbtFloat :
59 result->setFConst(0.0f);
60 break;
61 case EbtInt:
62 result->setIConst(0);
63 break;
64 case EbtUInt:
65 result->setUConst(0u);
66 break;
67 case EbtBool:
68 result->setBConst(false);
69 break;
70 default:
71 break;
72 }
73}
74
Olli Etuaho5c0e0232015-11-11 15:55:59 +020075float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053076{
77 float result = 0.0f;
78 for (size_t i = 0; i < paramArraySize; i++)
79 {
80 float f = paramArray[i].getFConst();
81 result += f * f;
82 }
83 return sqrtf(result);
84}
85
Olli Etuaho5c0e0232015-11-11 15:55:59 +020086float VectorDotProduct(const TConstantUnion *paramArray1,
87 const TConstantUnion *paramArray2,
88 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053089{
90 float result = 0.0f;
91 for (size_t i = 0; i < paramArraySize; i++)
92 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
93 return result;
94}
95
Olli Etuaho3272a6d2016-08-29 17:54:50 +030096TIntermTyped *CreateFoldedNode(const TConstantUnion *constArray,
Olli Etuaho7c3848e2015-11-04 13:19:17 +020097 const TIntermTyped *originalNode,
98 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +030099{
100 if (constArray == nullptr)
101 {
102 return nullptr;
103 }
104 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200105 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300106 folded->setLine(originalNode->getLine());
107 return folded;
108}
109
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200110angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
111 const unsigned int &rows,
112 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530113{
114 std::vector<float> elements;
115 for (size_t i = 0; i < rows * cols; i++)
116 elements.push_back(paramArray[i].getFConst());
117 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300118 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
119 // so that the created matrix will have the expected dimensions after the transpose.
120 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530121}
122
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200123angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530124{
125 std::vector<float> elements;
126 for (size_t i = 0; i < size * size; i++)
127 elements.push_back(paramArray[i].getFConst());
128 // Transpose is used since the Matrix constructor expects arguments in row-major order,
129 // whereas the paramArray is in column-major order.
130 return angle::Matrix<float>(elements, size).transpose();
131}
132
133void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
134{
135 // Transpose is used since the input Matrix is in row-major order,
136 // whereas the actual result should be in column-major order.
137 angle::Matrix<float> result = m.transpose();
138 std::vector<float> resultElements = result.elements();
139 for (size_t i = 0; i < resultElements.size(); i++)
140 resultArray[i].setFConst(resultElements[i]);
141}
142
Jamie Madillb1a85f42014-08-19 15:23:24 -0400143} // namespace anonymous
144
145
146////////////////////////////////////////////////////////////////
147//
148// Member functions of the nodes used for building the tree.
149//
150////////////////////////////////////////////////////////////////
151
Olli Etuahod2a67b92014-10-21 16:42:57 +0300152void TIntermTyped::setTypePreservePrecision(const TType &t)
153{
154 TPrecision precision = getPrecision();
155 mType = t;
156 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
157 mType.setPrecision(precision);
158}
159
Jamie Madillb1a85f42014-08-19 15:23:24 -0400160#define REPLACE_IF_IS(node, type, original, replacement) \
161 if (node == original) { \
162 node = static_cast<type *>(replacement); \
163 return true; \
164 }
165
166bool TIntermLoop::replaceChildNode(
167 TIntermNode *original, TIntermNode *replacement)
168{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300169 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400170 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
171 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
172 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200173 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174 return false;
175}
176
Jamie Madillb1a85f42014-08-19 15:23:24 -0400177bool TIntermBranch::replaceChildNode(
178 TIntermNode *original, TIntermNode *replacement)
179{
180 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
181 return false;
182}
183
Jamie Madillb1a85f42014-08-19 15:23:24 -0400184bool TIntermBinary::replaceChildNode(
185 TIntermNode *original, TIntermNode *replacement)
186{
187 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
188 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
189 return false;
190}
191
Jamie Madillb1a85f42014-08-19 15:23:24 -0400192bool TIntermUnary::replaceChildNode(
193 TIntermNode *original, TIntermNode *replacement)
194{
Olli Etuahoa2234302016-08-31 12:05:39 +0300195 ASSERT(original->getAsTyped()->getType() == replacement->getAsTyped()->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400196 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
197 return false;
198}
199
Jamie Madillb1a85f42014-08-19 15:23:24 -0400200bool TIntermAggregate::replaceChildNode(
201 TIntermNode *original, TIntermNode *replacement)
202{
203 for (size_t ii = 0; ii < mSequence.size(); ++ii)
204 {
205 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
206 }
207 return false;
208}
209
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300210bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
211{
212 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
213 {
214 if (*it == original)
215 {
216 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300217 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300218 return true;
219 }
220 }
221 return false;
222}
223
Olli Etuahoa6f22092015-05-08 18:31:10 +0300224bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
225{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300226 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300227 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300228 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300229 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300230 auto it = mSequence.begin() + position;
231 mSequence.insert(it, insertions.begin(), insertions.end());
232 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300233}
234
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200235bool TIntermAggregate::areChildrenConstQualified()
236{
237 for (TIntermNode *&child : mSequence)
238 {
239 TIntermTyped *typed = child->getAsTyped();
240 if (typed && typed->getQualifier() != EvqConst)
241 {
242 return false;
243 }
244 }
245 return true;
246}
247
Olli Etuahod2a67b92014-10-21 16:42:57 +0300248void TIntermAggregate::setPrecisionFromChildren()
249{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300250 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300251 if (getBasicType() == EbtBool)
252 {
253 mType.setPrecision(EbpUndefined);
254 return;
255 }
256
257 TPrecision precision = EbpUndefined;
258 TIntermSequence::iterator childIter = mSequence.begin();
259 while (childIter != mSequence.end())
260 {
261 TIntermTyped *typed = (*childIter)->getAsTyped();
262 if (typed)
263 precision = GetHigherPrecision(typed->getPrecision(), precision);
264 ++childIter;
265 }
266 mType.setPrecision(precision);
267}
268
269void TIntermAggregate::setBuiltInFunctionPrecision()
270{
271 // All built-ins returning bool should be handled as ops, not functions.
272 ASSERT(getBasicType() != EbtBool);
273
274 TPrecision precision = EbpUndefined;
275 TIntermSequence::iterator childIter = mSequence.begin();
276 while (childIter != mSequence.end())
277 {
278 TIntermTyped *typed = (*childIter)->getAsTyped();
279 // ESSL spec section 8: texture functions get their precision from the sampler.
280 if (typed && IsSampler(typed->getBasicType()))
281 {
282 precision = typed->getPrecision();
283 break;
284 }
285 ++childIter;
286 }
287 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
288 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300289 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300290 mType.setPrecision(EbpHigh);
291 else
292 mType.setPrecision(precision);
293}
294
Jamie Madillb1a85f42014-08-19 15:23:24 -0400295bool TIntermSelection::replaceChildNode(
296 TIntermNode *original, TIntermNode *replacement)
297{
298 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
299 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
300 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
301 return false;
302}
303
Olli Etuahoa3a36662015-02-17 13:46:51 +0200304bool TIntermSwitch::replaceChildNode(
305 TIntermNode *original, TIntermNode *replacement)
306{
307 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
308 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
309 return false;
310}
311
312bool TIntermCase::replaceChildNode(
313 TIntermNode *original, TIntermNode *replacement)
314{
315 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
316 return false;
317}
318
Olli Etuahod7a25242015-08-18 13:49:45 +0300319TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
320{
321 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
322 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
323 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
324 mLine = node.mLine;
325}
326
Olli Etuahod4f4c112016-04-15 15:11:24 +0300327bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
328{
329 TIntermAggregate *constructor = getAsAggregate();
330 if (!constructor || !constructor->isConstructor())
331 {
332 return false;
333 }
334 for (TIntermNode *&node : *constructor->getSequence())
335 {
336 if (!node->getAsConstantUnion())
337 return false;
338 }
339 return true;
340}
341
Corentin Wallez509e4562016-08-25 14:55:44 -0400342// static
343TIntermTyped *TIntermTyped::CreateIndexNode(int index)
344{
345 TConstantUnion *u = new TConstantUnion[1];
346 u[0].setIConst(index);
347
348 TType type(EbtInt, EbpUndefined, EvqConst, 1);
349 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
350 return node;
351}
352
353// static
354TIntermTyped *TIntermTyped::CreateZero(const TType &type)
355{
356 TType constType(type);
357 constType.setQualifier(EvqConst);
358
359 if (!type.isArray() && type.getBasicType() != EbtStruct)
360 {
361 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
362
363 size_t size = constType.getObjectSize();
364 TConstantUnion *u = new TConstantUnion[size];
365 for (size_t i = 0; i < size; ++i)
366 {
367 switch (type.getBasicType())
368 {
369 case EbtFloat:
370 u[i].setFConst(0.0f);
371 break;
372 case EbtInt:
373 u[i].setIConst(0);
374 break;
375 case EbtUInt:
376 u[i].setUConst(0u);
377 break;
378 case EbtBool:
379 u[i].setBConst(false);
380 break;
381 default:
382 UNREACHABLE();
383 return nullptr;
384 }
385 }
386
387 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
388 return node;
389 }
390
391 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
392 constructor->setType(constType);
393
394 if (type.isArray())
395 {
396 TType elementType(type);
397 elementType.clearArrayness();
398
399 size_t arraySize = type.getArraySize();
400 for (size_t i = 0; i < arraySize; ++i)
401 {
402 constructor->getSequence()->push_back(CreateZero(elementType));
403 }
404 }
405 else
406 {
407 ASSERT(type.getBasicType() == EbtStruct);
408
409 TStructure *structure = type.getStruct();
410 for (const auto &field : structure->fields())
411 {
412 constructor->getSequence()->push_back(CreateZero(*field->type()));
413 }
414 }
415
416 return constructor;
417}
418
Olli Etuahod7a25242015-08-18 13:49:45 +0300419TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
420{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200421 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300422}
423
424TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
425 : TIntermOperator(node),
426 mName(node.mName),
427 mUserDefined(node.mUserDefined),
428 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300429 mUseEmulatedFunction(node.mUseEmulatedFunction),
430 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
431{
432 for (TIntermNode *child : node.mSequence)
433 {
434 TIntermTyped *typedChild = child->getAsTyped();
435 ASSERT(typedChild != nullptr);
436 TIntermTyped *childCopy = typedChild->deepCopy();
437 mSequence.push_back(childCopy);
438 }
439}
440
441TIntermBinary::TIntermBinary(const TIntermBinary &node)
442 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
443{
444 TIntermTyped *leftCopy = node.mLeft->deepCopy();
445 TIntermTyped *rightCopy = node.mRight->deepCopy();
446 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
447 mLeft = leftCopy;
448 mRight = rightCopy;
449}
450
451TIntermUnary::TIntermUnary(const TIntermUnary &node)
452 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
453{
454 TIntermTyped *operandCopy = node.mOperand->deepCopy();
455 ASSERT(operandCopy != nullptr);
456 mOperand = operandCopy;
457}
458
459TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
460{
461 // Only supported for ternary nodes, not if statements.
462 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
463 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
464 ASSERT(trueTyped != nullptr);
465 ASSERT(falseTyped != nullptr);
466 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
467 TIntermTyped *trueCopy = trueTyped->deepCopy();
468 TIntermTyped *falseCopy = falseTyped->deepCopy();
469 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
470 mCondition = conditionCopy;
471 mTrueBlock = trueCopy;
472 mFalseBlock = falseCopy;
473}
474
Jamie Madillb1a85f42014-08-19 15:23:24 -0400475bool TIntermOperator::isAssignment() const
476{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300477 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400478}
479
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300480bool TIntermOperator::isMultiplication() const
481{
482 switch (mOp)
483 {
484 case EOpMul:
485 case EOpMatrixTimesMatrix:
486 case EOpMatrixTimesVector:
487 case EOpMatrixTimesScalar:
488 case EOpVectorTimesMatrix:
489 case EOpVectorTimesScalar:
490 return true;
491 default:
492 return false;
493 }
494}
495
Jamie Madillb1a85f42014-08-19 15:23:24 -0400496//
497// returns true if the operator is for one of the constructors
498//
499bool TIntermOperator::isConstructor() const
500{
501 switch (mOp)
502 {
503 case EOpConstructVec2:
504 case EOpConstructVec3:
505 case EOpConstructVec4:
506 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400507 case EOpConstructMat2x3:
508 case EOpConstructMat2x4:
509 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400510 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400511 case EOpConstructMat3x4:
512 case EOpConstructMat4x2:
513 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400514 case EOpConstructMat4:
515 case EOpConstructFloat:
516 case EOpConstructIVec2:
517 case EOpConstructIVec3:
518 case EOpConstructIVec4:
519 case EOpConstructInt:
520 case EOpConstructUVec2:
521 case EOpConstructUVec3:
522 case EOpConstructUVec4:
523 case EOpConstructUInt:
524 case EOpConstructBVec2:
525 case EOpConstructBVec3:
526 case EOpConstructBVec4:
527 case EOpConstructBool:
528 case EOpConstructStruct:
529 return true;
530 default:
531 return false;
532 }
533}
534
Olli Etuaho1dded802016-08-18 18:13:13 +0300535TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
536{
537 if (left.isMatrix())
538 {
539 if (right.isMatrix())
540 {
541 return EOpMatrixTimesMatrix;
542 }
543 else
544 {
545 if (right.isVector())
546 {
547 return EOpMatrixTimesVector;
548 }
549 else
550 {
551 return EOpMatrixTimesScalar;
552 }
553 }
554 }
555 else
556 {
557 if (right.isMatrix())
558 {
559 if (left.isVector())
560 {
561 return EOpVectorTimesMatrix;
562 }
563 else
564 {
565 return EOpMatrixTimesScalar;
566 }
567 }
568 else
569 {
570 // Neither operand is a matrix.
571 if (left.isVector() == right.isVector())
572 {
573 // Leave as component product.
574 return EOpMul;
575 }
576 else
577 {
578 return EOpVectorTimesScalar;
579 }
580 }
581 }
582}
583
584TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
585{
586 if (left.isMatrix())
587 {
588 if (right.isMatrix())
589 {
590 return EOpMatrixTimesMatrixAssign;
591 }
592 else
593 {
594 // right should be scalar, but this may not be validated yet.
595 return EOpMatrixTimesScalarAssign;
596 }
597 }
598 else
599 {
600 if (right.isMatrix())
601 {
602 // Left should be a vector, but this may not be validated yet.
603 return EOpVectorTimesMatrixAssign;
604 }
605 else
606 {
607 // Neither operand is a matrix.
608 if (left.isVector() == right.isVector())
609 {
610 // Leave as component product.
611 return EOpMulAssign;
612 }
613 else
614 {
615 // left should be vector and right should be scalar, but this may not be validated
616 // yet.
617 return EOpVectorTimesScalarAssign;
618 }
619 }
620 }
621}
622
Jamie Madillb1a85f42014-08-19 15:23:24 -0400623//
624// Make sure the type of a unary operator is appropriate for its
625// combination of operation and operand type.
626//
Olli Etuahoa2234302016-08-31 12:05:39 +0300627void TIntermUnary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400628{
Olli Etuahoa2234302016-08-31 12:05:39 +0300629 TQualifier resultQualifier = EvqTemporary;
630 if (mOperand->getQualifier() == EvqConst)
631 resultQualifier = EvqConst;
632
633 unsigned char operandPrimarySize =
634 static_cast<unsigned char>(mOperand->getType().getNominalSize());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400635 switch (mOp)
636 {
Olli Etuahoa2234302016-08-31 12:05:39 +0300637 case EOpFloatBitsToInt:
638 setType(TType(EbtInt, EbpHigh, resultQualifier, operandPrimarySize));
639 break;
640 case EOpFloatBitsToUint:
641 setType(TType(EbtUInt, EbpHigh, resultQualifier, operandPrimarySize));
642 break;
643 case EOpIntBitsToFloat:
644 case EOpUintBitsToFloat:
645 setType(TType(EbtFloat, EbpHigh, resultQualifier, operandPrimarySize));
646 break;
647 case EOpPackSnorm2x16:
648 case EOpPackUnorm2x16:
649 case EOpPackHalf2x16:
650 setType(TType(EbtUInt, EbpHigh, resultQualifier));
651 break;
652 case EOpUnpackSnorm2x16:
653 case EOpUnpackUnorm2x16:
654 setType(TType(EbtFloat, EbpHigh, resultQualifier, 2));
655 break;
656 case EOpUnpackHalf2x16:
657 setType(TType(EbtFloat, EbpMedium, resultQualifier, 2));
658 break;
659 case EOpAny:
660 case EOpAll:
661 setType(TType(EbtBool, EbpUndefined, resultQualifier));
662 break;
663 case EOpLength:
664 case EOpDeterminant:
665 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier));
666 break;
667 case EOpTranspose:
668 setType(TType(EbtFloat, mOperand->getType().getPrecision(), resultQualifier,
669 static_cast<unsigned char>(mOperand->getType().getRows()),
670 static_cast<unsigned char>(mOperand->getType().getCols())));
671 break;
672 case EOpIsInf:
673 case EOpIsNan:
674 setType(TType(EbtBool, EbpUndefined, resultQualifier, operandPrimarySize));
675 break;
676 default:
677 setType(mOperand->getType());
678 mType.setQualifier(resultQualifier);
679 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400680 }
Olli Etuahoa2234302016-08-31 12:05:39 +0300681}
Jamie Madillb1a85f42014-08-19 15:23:24 -0400682
Olli Etuahoa2234302016-08-31 12:05:39 +0300683TIntermUnary::TIntermUnary(TOperator op, TIntermTyped *operand)
684 : TIntermOperator(op), mOperand(operand), mUseEmulatedFunction(false)
685{
686 promote();
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687}
688
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300689TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
690 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
691{
692 promote();
693}
694
Jamie Madillb1a85f42014-08-19 15:23:24 -0400695//
696// Establishes the type of the resultant operation, as well as
697// makes the operator the correct one for the operands.
698//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200699// For lots of operations it should already be established that the operand
700// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400701//
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300702void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400703{
Olli Etuaho1dded802016-08-18 18:13:13 +0300704 ASSERT(!isMultiplication() ||
705 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
706
Jamie Madillb1a85f42014-08-19 15:23:24 -0400707 // Base assumption: just make the type the same as the left
708 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400709 setType(mLeft->getType());
710
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200711 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400712 // Binary operations results in temporary variables unless both
713 // operands are const.
714 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
715 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200716 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400717 getTypePointer()->setQualifier(EvqTemporary);
718 }
719
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300720 // Handle indexing ops.
721 switch (mOp)
722 {
723 case EOpIndexDirect:
724 case EOpIndexIndirect:
725 if (mLeft->isArray())
726 {
727 mType.clearArrayness();
728 }
729 else if (mLeft->isMatrix())
730 {
731 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
732 static_cast<unsigned char>(mLeft->getRows())));
733 }
734 else if (mLeft->isVector())
735 {
736 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier));
737 }
738 else
739 {
740 UNREACHABLE();
741 }
742 return;
743 case EOpIndexDirectStruct:
744 {
745 const TFieldList &fields = mLeft->getType().getStruct()->fields();
746 const int i = mRight->getAsConstantUnion()->getIConst(0);
747 setType(*fields[i]->type());
748 getTypePointer()->setQualifier(resultQualifier);
749 return;
750 }
751 case EOpIndexDirectInterfaceBlock:
752 {
753 const TFieldList &fields = mLeft->getType().getInterfaceBlock()->fields();
754 const int i = mRight->getAsConstantUnion()->getIConst(0);
755 setType(*fields[i]->type());
756 getTypePointer()->setQualifier(resultQualifier);
757 return;
758 }
759 case EOpVectorSwizzle:
760 {
761 auto numFields = mRight->getAsAggregate()->getSequence()->size();
762 setType(TType(mLeft->getBasicType(), mLeft->getPrecision(), resultQualifier,
763 static_cast<unsigned char>(numFields)));
764 return;
765 }
766 default:
767 break;
768 }
769
770 ASSERT(mLeft->isArray() == mRight->isArray());
771
772 // The result gets promoted to the highest precision.
773 TPrecision higherPrecision = GetHigherPrecision(mLeft->getPrecision(), mRight->getPrecision());
774 getTypePointer()->setPrecision(higherPrecision);
775
Jamie Madillb1a85f42014-08-19 15:23:24 -0400776 const int nominalSize =
777 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
778
779 //
780 // All scalars or structs. Code after this test assumes this case is removed!
781 //
782 if (nominalSize == 1)
783 {
784 switch (mOp)
785 {
786 //
787 // Promote to conditional
788 //
789 case EOpEqual:
790 case EOpNotEqual:
791 case EOpLessThan:
792 case EOpGreaterThan:
793 case EOpLessThanEqual:
794 case EOpGreaterThanEqual:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300795 setType(TType(EbtBool, EbpUndefined, resultQualifier));
796 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400797
798 //
799 // And and Or operate on conditionals
800 //
801 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200802 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400803 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200804 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Olli Etuahoc9550582016-08-29 17:56:22 +0300805 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400806 break;
807
808 default:
809 break;
810 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300811 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400812 }
813
814 // If we reach here, at least one of the operands is vector or matrix.
815 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400816 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300817
Jamie Madillb1a85f42014-08-19 15:23:24 -0400818 switch (mOp)
819 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300820 case EOpMul:
821 break;
822 case EOpMatrixTimesScalar:
823 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400824 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200825 setType(TType(basicType, higherPrecision, resultQualifier,
826 static_cast<unsigned char>(mRight->getCols()),
827 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400828 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300829 break;
830 case EOpMatrixTimesVector:
831 setType(TType(basicType, higherPrecision, resultQualifier,
832 static_cast<unsigned char>(mLeft->getRows()), 1));
833 break;
834 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200835 setType(TType(basicType, higherPrecision, resultQualifier,
836 static_cast<unsigned char>(mRight->getCols()),
837 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300838 break;
839 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200840 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300841 static_cast<unsigned char>(nominalSize), 1));
842 break;
843 case EOpVectorTimesMatrix:
844 setType(TType(basicType, higherPrecision, resultQualifier,
845 static_cast<unsigned char>(mRight->getCols()), 1));
846 break;
847 case EOpMulAssign:
848 case EOpVectorTimesScalarAssign:
849 case EOpVectorTimesMatrixAssign:
850 case EOpMatrixTimesScalarAssign:
851 case EOpMatrixTimesMatrixAssign:
852 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
853 break;
854 case EOpAssign:
855 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300856 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
857 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
858 break;
859 case EOpAdd:
860 case EOpSub:
861 case EOpDiv:
862 case EOpIMod:
863 case EOpBitShiftLeft:
864 case EOpBitShiftRight:
865 case EOpBitwiseAnd:
866 case EOpBitwiseXor:
867 case EOpBitwiseOr:
868 case EOpAddAssign:
869 case EOpSubAssign:
870 case EOpDivAssign:
871 case EOpIModAssign:
872 case EOpBitShiftLeftAssign:
873 case EOpBitShiftRightAssign:
874 case EOpBitwiseAndAssign:
875 case EOpBitwiseXorAssign:
876 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300877 {
878 const int secondarySize =
879 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
880 setType(TType(basicType, higherPrecision, resultQualifier,
881 static_cast<unsigned char>(nominalSize),
882 static_cast<unsigned char>(secondarySize)));
883 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300884 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300885 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300886 case EOpEqual:
887 case EOpNotEqual:
888 case EOpLessThan:
889 case EOpGreaterThan:
890 case EOpLessThanEqual:
891 case EOpGreaterThanEqual:
892 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
893 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300894 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300895 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400896
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300897 case EOpIndexDirect:
898 case EOpIndexIndirect:
899 case EOpIndexDirectInterfaceBlock:
900 case EOpIndexDirectStruct:
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300901 case EOpVectorSwizzle:
902 // These ops should be already fully handled.
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300903 UNREACHABLE();
904 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300905 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300906 UNREACHABLE();
907 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400908 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400909}
910
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300911const TConstantUnion *TIntermConstantUnion::foldIndexing(int index)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300912{
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300913 if (isArray())
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300914 {
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300915 ASSERT(index < static_cast<int>(getType().getArraySize()));
916 TType arrayElementType = getType();
917 arrayElementType.clearArrayness();
918 size_t arrayElementSize = arrayElementType.getObjectSize();
919 return &mUnionArrayPointer[arrayElementSize * index];
920 }
921 else if (isMatrix())
922 {
923 ASSERT(index < getType().getCols());
924 int size = getType().getRows();
925 return &mUnionArrayPointer[size * index];
926 }
927 else if (isVector())
928 {
929 ASSERT(index < getType().getNominalSize());
930 return &mUnionArrayPointer[index];
931 }
932 else
933 {
934 UNREACHABLE();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300935 return nullptr;
936 }
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300937}
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200938
Olli Etuaho3272a6d2016-08-29 17:54:50 +0300939TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
940{
941 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
942 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
943 switch (mOp)
944 {
945 case EOpIndexDirect:
946 {
947 if (leftConstant == nullptr || rightConstant == nullptr)
948 {
949 return nullptr;
950 }
951 int index = rightConstant->getIConst(0);
952
953 const TConstantUnion *constArray = leftConstant->foldIndexing(index);
954 return CreateFoldedNode(constArray, this, mType.getQualifier());
955 }
956 case EOpIndexDirectStruct:
957 {
958 if (leftConstant == nullptr || rightConstant == nullptr)
959 {
960 return nullptr;
961 }
962 const TFieldList &fields = mLeft->getType().getStruct()->fields();
963 size_t index = static_cast<size_t>(rightConstant->getIConst(0));
964
965 size_t previousFieldsSize = 0;
966 for (size_t i = 0; i < index; ++i)
967 {
968 previousFieldsSize += fields[i]->type()->getObjectSize();
969 }
970
971 const TConstantUnion *constArray = leftConstant->getUnionArrayPointer();
972 return CreateFoldedNode(constArray + previousFieldsSize, this, mType.getQualifier());
973 }
974 case EOpIndexIndirect:
975 case EOpIndexDirectInterfaceBlock:
976 // Can never be constant folded.
977 return nullptr;
978 case EOpVectorSwizzle:
979 {
980 if (leftConstant == nullptr)
981 {
982 return nullptr;
983 }
984 TIntermAggregate *fieldsAgg = mRight->getAsAggregate();
985 TIntermSequence *fieldsSequence = fieldsAgg->getSequence();
986 size_t numFields = fieldsSequence->size();
987
988 TConstantUnion *constArray = new TConstantUnion[numFields];
989 for (size_t i = 0; i < numFields; i++)
990 {
991 int fieldOffset = fieldsSequence->at(i)->getAsConstantUnion()->getIConst(0);
992 constArray[i] = *leftConstant->foldIndexing(fieldOffset);
993 }
994 return CreateFoldedNode(constArray, this, mType.getQualifier());
995 }
996 default:
997 {
998 if (leftConstant == nullptr || rightConstant == nullptr)
999 {
1000 return nullptr;
1001 }
1002 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
1003
1004 // Nodes may be constant folded without being qualified as constant.
1005 return CreateFoldedNode(constArray, this, mType.getQualifier());
1006 }
1007 }
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001008}
1009
Olli Etuahof119a262016-08-19 15:54:22 +03001010TIntermTyped *TIntermUnary::fold(TDiagnostics *diagnostics)
Olli Etuaho95310b02015-06-02 17:43:38 +03001011{
1012 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
1013 if (operandConstant == nullptr)
1014 {
1015 return nullptr;
1016 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301017
1018 TConstantUnion *constArray = nullptr;
1019 switch (mOp)
1020 {
1021 case EOpAny:
1022 case EOpAll:
1023 case EOpLength:
1024 case EOpTranspose:
1025 case EOpDeterminant:
1026 case EOpInverse:
1027 case EOpPackSnorm2x16:
1028 case EOpUnpackSnorm2x16:
1029 case EOpPackUnorm2x16:
1030 case EOpUnpackUnorm2x16:
1031 case EOpPackHalf2x16:
1032 case EOpUnpackHalf2x16:
Olli Etuahof119a262016-08-19 15:54:22 +03001033 constArray = operandConstant->foldUnaryNonComponentWise(mOp);
1034 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301035 default:
Olli Etuahof119a262016-08-19 15:54:22 +03001036 constArray = operandConstant->foldUnaryComponentWise(mOp, diagnostics);
1037 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301038 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001039
1040 // Nodes may be constant folded without being qualified as constant.
Olli Etuahoc9550582016-08-29 17:56:22 +03001041 return CreateFoldedNode(constArray, this, mType.getQualifier());
Olli Etuahob43846e2015-06-02 18:18:57 +03001042}
1043
Olli Etuahof119a262016-08-19 15:54:22 +03001044TIntermTyped *TIntermAggregate::fold(TDiagnostics *diagnostics)
Olli Etuahob43846e2015-06-02 18:18:57 +03001045{
1046 // Make sure that all params are constant before actual constant folding.
1047 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +03001048 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001049 if (param->getAsConstantUnion() == nullptr)
1050 {
1051 return nullptr;
1052 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001053 }
Olli Etuaho1d122782015-11-06 15:35:17 +02001054 TConstantUnion *constArray = nullptr;
1055 if (isConstructor())
Olli Etuahof119a262016-08-19 15:54:22 +03001056 constArray = TIntermConstantUnion::FoldAggregateConstructor(this);
Olli Etuaho1d122782015-11-06 15:35:17 +02001057 else
Olli Etuahof119a262016-08-19 15:54:22 +03001058 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +02001059
1060 // Nodes may be constant folded without being qualified as constant.
1061 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
1062 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +03001063}
1064
Jamie Madillb1a85f42014-08-19 15:23:24 -04001065//
1066// The fold functions see if an operation on a constant can be done in place,
1067// without generating run-time code.
1068//
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001069// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001070//
Olli Etuaho3fdec912016-08-18 15:08:06 +03001071TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
1072 TIntermConstantUnion *rightNode,
1073 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001074{
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001075 const TConstantUnion *leftArray = getUnionArrayPointer();
1076 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001077
Olli Etuahof119a262016-08-19 15:54:22 +03001078 ASSERT(leftArray && rightArray);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001079
1080 size_t objectSize = getType().getObjectSize();
1081
1082 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
1083 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
1084 {
1085 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
1086 }
1087 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
1088 {
1089 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
1090 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
1091 objectSize = rightNode->getType().getObjectSize();
1092 }
1093
1094 TConstantUnion *resultArray = nullptr;
1095
1096 switch(op)
1097 {
1098 case EOpAdd:
1099 resultArray = new TConstantUnion[objectSize];
1100 for (size_t i = 0; i < objectSize; i++)
1101 resultArray[i] = leftArray[i] + rightArray[i];
1102 break;
1103 case EOpSub:
1104 resultArray = new TConstantUnion[objectSize];
1105 for (size_t i = 0; i < objectSize; i++)
1106 resultArray[i] = leftArray[i] - rightArray[i];
1107 break;
1108
1109 case EOpMul:
1110 case EOpVectorTimesScalar:
1111 case EOpMatrixTimesScalar:
1112 resultArray = new TConstantUnion[objectSize];
1113 for (size_t i = 0; i < objectSize; i++)
1114 resultArray[i] = leftArray[i] * rightArray[i];
1115 break;
1116
1117 case EOpMatrixTimesMatrix:
1118 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001119 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001120
1121 const int leftCols = getCols();
1122 const int leftRows = getRows();
1123 const int rightCols = rightNode->getType().getCols();
1124 const int rightRows = rightNode->getType().getRows();
1125 const int resultCols = rightCols;
1126 const int resultRows = leftRows;
1127
1128 resultArray = new TConstantUnion[resultCols * resultRows];
1129 for (int row = 0; row < resultRows; row++)
1130 {
1131 for (int column = 0; column < resultCols; column++)
1132 {
1133 resultArray[resultRows * column + row].setFConst(0.0f);
1134 for (int i = 0; i < leftCols; i++)
1135 {
1136 resultArray[resultRows * column + row].setFConst(
1137 resultArray[resultRows * column + row].getFConst() +
1138 leftArray[i * leftRows + row].getFConst() *
1139 rightArray[column * rightRows + i].getFConst());
1140 }
1141 }
1142 }
1143 }
1144 break;
1145
1146 case EOpDiv:
1147 case EOpIMod:
1148 {
1149 resultArray = new TConstantUnion[objectSize];
1150 for (size_t i = 0; i < objectSize; i++)
1151 {
1152 switch (getType().getBasicType())
1153 {
1154 case EbtFloat:
1155 if (rightArray[i] == 0.0f)
1156 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001157 diagnostics->warning(
1158 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001159 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1160 }
1161 else
1162 {
1163 ASSERT(op == EOpDiv);
1164 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1165 }
1166 break;
1167
1168 case EbtInt:
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].setIConst(INT_MAX);
1174 }
1175 else
1176 {
1177 if (op == EOpDiv)
1178 {
1179 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1180 }
1181 else
1182 {
1183 ASSERT(op == EOpIMod);
1184 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1185 }
1186 }
1187 break;
1188
1189 case EbtUInt:
1190 if (rightArray[i] == 0)
1191 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001192 diagnostics->warning(
1193 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001194 resultArray[i].setUConst(UINT_MAX);
1195 }
1196 else
1197 {
1198 if (op == EOpDiv)
1199 {
1200 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1201 }
1202 else
1203 {
1204 ASSERT(op == EOpIMod);
1205 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1206 }
1207 }
1208 break;
1209
1210 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001211 UNREACHABLE();
1212 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001213 }
1214 }
1215 }
1216 break;
1217
1218 case EOpMatrixTimesVector:
1219 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001220 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001221
1222 const int matrixCols = getCols();
1223 const int matrixRows = getRows();
1224
1225 resultArray = new TConstantUnion[matrixRows];
1226
1227 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1228 {
1229 resultArray[matrixRow].setFConst(0.0f);
1230 for (int col = 0; col < matrixCols; col++)
1231 {
1232 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1233 leftArray[col * matrixRows + matrixRow].getFConst() *
1234 rightArray[col].getFConst());
1235 }
1236 }
1237 }
1238 break;
1239
1240 case EOpVectorTimesMatrix:
1241 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001242 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001243
1244 const int matrixCols = rightNode->getType().getCols();
1245 const int matrixRows = rightNode->getType().getRows();
1246
1247 resultArray = new TConstantUnion[matrixCols];
1248
1249 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1250 {
1251 resultArray[matrixCol].setFConst(0.0f);
1252 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1253 {
1254 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1255 leftArray[matrixRow].getFConst() *
1256 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1257 }
1258 }
1259 }
1260 break;
1261
1262 case EOpLogicalAnd:
1263 {
1264 resultArray = new TConstantUnion[objectSize];
1265 for (size_t i = 0; i < objectSize; i++)
1266 {
1267 resultArray[i] = leftArray[i] && rightArray[i];
1268 }
1269 }
1270 break;
1271
1272 case EOpLogicalOr:
1273 {
1274 resultArray = new TConstantUnion[objectSize];
1275 for (size_t i = 0; i < objectSize; i++)
1276 {
1277 resultArray[i] = leftArray[i] || rightArray[i];
1278 }
1279 }
1280 break;
1281
1282 case EOpLogicalXor:
1283 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001284 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001285 resultArray = new TConstantUnion[objectSize];
1286 for (size_t i = 0; i < objectSize; i++)
1287 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001288 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001289 }
1290 }
1291 break;
1292
1293 case EOpBitwiseAnd:
1294 resultArray = new TConstantUnion[objectSize];
1295 for (size_t i = 0; i < objectSize; i++)
1296 resultArray[i] = leftArray[i] & rightArray[i];
1297 break;
1298 case EOpBitwiseXor:
1299 resultArray = new TConstantUnion[objectSize];
1300 for (size_t i = 0; i < objectSize; i++)
1301 resultArray[i] = leftArray[i] ^ rightArray[i];
1302 break;
1303 case EOpBitwiseOr:
1304 resultArray = new TConstantUnion[objectSize];
1305 for (size_t i = 0; i < objectSize; i++)
1306 resultArray[i] = leftArray[i] | rightArray[i];
1307 break;
1308 case EOpBitShiftLeft:
1309 resultArray = new TConstantUnion[objectSize];
1310 for (size_t i = 0; i < objectSize; i++)
1311 resultArray[i] = leftArray[i] << rightArray[i];
1312 break;
1313 case EOpBitShiftRight:
1314 resultArray = new TConstantUnion[objectSize];
1315 for (size_t i = 0; i < objectSize; i++)
1316 resultArray[i] = leftArray[i] >> rightArray[i];
1317 break;
1318
1319 case EOpLessThan:
1320 ASSERT(objectSize == 1);
1321 resultArray = new TConstantUnion[1];
1322 resultArray->setBConst(*leftArray < *rightArray);
1323 break;
1324
1325 case EOpGreaterThan:
1326 ASSERT(objectSize == 1);
1327 resultArray = new TConstantUnion[1];
1328 resultArray->setBConst(*leftArray > *rightArray);
1329 break;
1330
1331 case EOpLessThanEqual:
1332 ASSERT(objectSize == 1);
1333 resultArray = new TConstantUnion[1];
1334 resultArray->setBConst(!(*leftArray > *rightArray));
1335 break;
1336
1337 case EOpGreaterThanEqual:
1338 ASSERT(objectSize == 1);
1339 resultArray = new TConstantUnion[1];
1340 resultArray->setBConst(!(*leftArray < *rightArray));
1341 break;
1342
1343 case EOpEqual:
1344 case EOpNotEqual:
1345 {
1346 resultArray = new TConstantUnion[1];
1347 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001348 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001349 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001350 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001351 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001352 equal = false;
1353 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001354 }
1355 }
1356 if (op == EOpEqual)
1357 {
1358 resultArray->setBConst(equal);
1359 }
1360 else
1361 {
1362 resultArray->setBConst(!equal);
1363 }
1364 }
1365 break;
1366
1367 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001368 UNREACHABLE();
1369 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001370 }
1371 return resultArray;
1372}
1373
Olli Etuahof119a262016-08-19 15:54:22 +03001374// The fold functions do operations on a constant at GLSL compile time, without generating run-time
1375// code. Returns the constant value to keep using. Nullptr should not be returned.
1376TConstantUnion *TIntermConstantUnion::foldUnaryNonComponentWise(TOperator op)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001377{
Olli Etuahof119a262016-08-19 15:54:22 +03001378 // Do operations where the return type may have a different number of components compared to the
1379 // operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001380
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001381 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001382 ASSERT(operandArray);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301383
1384 size_t objectSize = getType().getObjectSize();
1385 TConstantUnion *resultArray = nullptr;
1386 switch (op)
1387 {
Olli Etuahof119a262016-08-19 15:54:22 +03001388 case EOpAny:
1389 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301390 resultArray = new TConstantUnion();
1391 resultArray->setBConst(false);
1392 for (size_t i = 0; i < objectSize; i++)
1393 {
1394 if (operandArray[i].getBConst())
1395 {
1396 resultArray->setBConst(true);
1397 break;
1398 }
1399 }
1400 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301401
Olli Etuahof119a262016-08-19 15:54:22 +03001402 case EOpAll:
1403 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301404 resultArray = new TConstantUnion();
1405 resultArray->setBConst(true);
1406 for (size_t i = 0; i < objectSize; i++)
1407 {
1408 if (!operandArray[i].getBConst())
1409 {
1410 resultArray->setBConst(false);
1411 break;
1412 }
1413 }
1414 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301415
Olli Etuahof119a262016-08-19 15:54:22 +03001416 case EOpLength:
1417 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301418 resultArray = new TConstantUnion();
1419 resultArray->setFConst(VectorLength(operandArray, objectSize));
1420 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301421
Olli Etuahof119a262016-08-19 15:54:22 +03001422 case EOpTranspose:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301423 {
Olli Etuahof119a262016-08-19 15:54:22 +03001424 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301425 resultArray = new TConstantUnion[objectSize];
1426 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001427 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301428 SetUnionArrayFromMatrix(result, resultArray);
1429 break;
1430 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301431
Olli Etuahof119a262016-08-19 15:54:22 +03001432 case EOpDeterminant:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301433 {
Olli Etuahof119a262016-08-19 15:54:22 +03001434 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301435 unsigned int size = getType().getNominalSize();
1436 ASSERT(size >= 2 && size <= 4);
1437 resultArray = new TConstantUnion();
1438 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1439 break;
1440 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301441
Olli Etuahof119a262016-08-19 15:54:22 +03001442 case EOpInverse:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301443 {
Olli Etuahof119a262016-08-19 15:54:22 +03001444 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301445 unsigned int size = getType().getNominalSize();
1446 ASSERT(size >= 2 && size <= 4);
Olli Etuahof119a262016-08-19 15:54:22 +03001447 resultArray = new TConstantUnion[objectSize];
Arun Patoleab2b9a22015-07-06 18:27:56 +05301448 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1449 SetUnionArrayFromMatrix(result, resultArray);
1450 break;
1451 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301452
Olli Etuahof119a262016-08-19 15:54:22 +03001453 case EOpPackSnorm2x16:
1454 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301455 ASSERT(getType().getNominalSize() == 2);
1456 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001457 resultArray->setUConst(
1458 gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301459 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301460
Olli Etuahof119a262016-08-19 15:54:22 +03001461 case EOpUnpackSnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301462 {
Olli Etuahof119a262016-08-19 15:54:22 +03001463 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301464 resultArray = new TConstantUnion[2];
1465 float f1, f2;
1466 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1467 resultArray[0].setFConst(f1);
1468 resultArray[1].setFConst(f2);
1469 break;
1470 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301471
Olli Etuahof119a262016-08-19 15:54:22 +03001472 case EOpPackUnorm2x16:
1473 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301474 ASSERT(getType().getNominalSize() == 2);
1475 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001476 resultArray->setUConst(
1477 gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301478 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301479
Olli Etuahof119a262016-08-19 15:54:22 +03001480 case EOpUnpackUnorm2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301481 {
Olli Etuahof119a262016-08-19 15:54:22 +03001482 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301483 resultArray = new TConstantUnion[2];
1484 float f1, f2;
1485 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1486 resultArray[0].setFConst(f1);
1487 resultArray[1].setFConst(f2);
1488 break;
1489 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301490
Olli Etuahof119a262016-08-19 15:54:22 +03001491 case EOpPackHalf2x16:
1492 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301493 ASSERT(getType().getNominalSize() == 2);
1494 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03001495 resultArray->setUConst(
1496 gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
Arun Patoleab2b9a22015-07-06 18:27:56 +05301497 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301498
Olli Etuahof119a262016-08-19 15:54:22 +03001499 case EOpUnpackHalf2x16:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301500 {
Olli Etuahof119a262016-08-19 15:54:22 +03001501 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301502 resultArray = new TConstantUnion[2];
1503 float f1, f2;
1504 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1505 resultArray[0].setFConst(f1);
1506 resultArray[1].setFConst(f2);
1507 break;
1508 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301509
Olli Etuahof119a262016-08-19 15:54:22 +03001510 default:
1511 UNREACHABLE();
1512 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301513 }
1514
1515 return resultArray;
1516}
1517
Olli Etuahof119a262016-08-19 15:54:22 +03001518TConstantUnion *TIntermConstantUnion::foldUnaryComponentWise(TOperator op,
1519 TDiagnostics *diagnostics)
Arun Patoleab2b9a22015-07-06 18:27:56 +05301520{
Olli Etuahof119a262016-08-19 15:54:22 +03001521 // Do unary operations where each component of the result is computed based on the corresponding
1522 // component of the operand. Also folds normalize, though the divisor in that case takes all
1523 // components into account.
Arun Patoleab2b9a22015-07-06 18:27:56 +05301524
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001525 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuahof119a262016-08-19 15:54:22 +03001526 ASSERT(operandArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -04001527
1528 size_t objectSize = getType().getObjectSize();
1529
Arun Patoleab2b9a22015-07-06 18:27:56 +05301530 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1531 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301532 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301533 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301534 {
Olli Etuahof119a262016-08-19 15:54:22 +03001535 case EOpNegative:
1536 switch (getType().getBasicType())
1537 {
1538 case EbtFloat:
1539 resultArray[i].setFConst(-operandArray[i].getFConst());
1540 break;
1541 case EbtInt:
1542 resultArray[i].setIConst(-operandArray[i].getIConst());
1543 break;
1544 case EbtUInt:
1545 resultArray[i].setUConst(static_cast<unsigned int>(
1546 -static_cast<int>(operandArray[i].getUConst())));
1547 break;
1548 default:
1549 UNREACHABLE();
1550 return nullptr;
1551 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301552 break;
Arun Patolecdfa8f52015-06-30 17:48:25 +05301553
Olli Etuahof119a262016-08-19 15:54:22 +03001554 case EOpPositive:
1555 switch (getType().getBasicType())
1556 {
1557 case EbtFloat:
1558 resultArray[i].setFConst(operandArray[i].getFConst());
1559 break;
1560 case EbtInt:
1561 resultArray[i].setIConst(operandArray[i].getIConst());
1562 break;
1563 case EbtUInt:
1564 resultArray[i].setUConst(static_cast<unsigned int>(
1565 static_cast<int>(operandArray[i].getUConst())));
1566 break;
1567 default:
1568 UNREACHABLE();
1569 return nullptr;
1570 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301571 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301572
Olli Etuahof119a262016-08-19 15:54:22 +03001573 case EOpLogicalNot:
1574 switch (getType().getBasicType())
1575 {
1576 case EbtBool:
1577 resultArray[i].setBConst(!operandArray[i].getBConst());
1578 break;
1579 default:
1580 UNREACHABLE();
1581 return nullptr;
1582 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301583 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301584
Olli Etuahof119a262016-08-19 15:54:22 +03001585 case EOpBitwiseNot:
1586 switch (getType().getBasicType())
1587 {
1588 case EbtInt:
1589 resultArray[i].setIConst(~operandArray[i].getIConst());
1590 break;
1591 case EbtUInt:
1592 resultArray[i].setUConst(~operandArray[i].getUConst());
1593 break;
1594 default:
1595 UNREACHABLE();
1596 return nullptr;
1597 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301598 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301599
Olli Etuahof119a262016-08-19 15:54:22 +03001600 case EOpRadians:
1601 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301602 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1603 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301604
Olli Etuahof119a262016-08-19 15:54:22 +03001605 case EOpDegrees:
1606 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301607 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1608 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301609
Olli Etuahof119a262016-08-19 15:54:22 +03001610 case EOpSin:
1611 foldFloatTypeUnary(operandArray[i], &sinf, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301612 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301613
Olli Etuahof119a262016-08-19 15:54:22 +03001614 case EOpCos:
1615 foldFloatTypeUnary(operandArray[i], &cosf, &resultArray[i]);
1616 break;
1617
1618 case EOpTan:
1619 foldFloatTypeUnary(operandArray[i], &tanf, &resultArray[i]);
1620 break;
1621
1622 case EOpAsin:
1623 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to
1624 // 0.
1625 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1626 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1627 diagnostics, &resultArray[i]);
1628 else
1629 foldFloatTypeUnary(operandArray[i], &asinf, &resultArray[i]);
1630 break;
1631
1632 case EOpAcos:
1633 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to
1634 // 0.
1635 if (fabsf(operandArray[i].getFConst()) > 1.0f)
1636 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1637 diagnostics, &resultArray[i]);
1638 else
1639 foldFloatTypeUnary(operandArray[i], &acosf, &resultArray[i]);
1640 break;
1641
1642 case EOpAtan:
1643 foldFloatTypeUnary(operandArray[i], &atanf, &resultArray[i]);
1644 break;
1645
1646 case EOpSinh:
1647 foldFloatTypeUnary(operandArray[i], &sinhf, &resultArray[i]);
1648 break;
1649
1650 case EOpCosh:
1651 foldFloatTypeUnary(operandArray[i], &coshf, &resultArray[i]);
1652 break;
1653
1654 case EOpTanh:
1655 foldFloatTypeUnary(operandArray[i], &tanhf, &resultArray[i]);
1656 break;
1657
1658 case EOpAsinh:
1659 foldFloatTypeUnary(operandArray[i], &asinhf, &resultArray[i]);
1660 break;
1661
1662 case EOpAcosh:
1663 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1664 if (operandArray[i].getFConst() < 1.0f)
1665 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1666 diagnostics, &resultArray[i]);
1667 else
1668 foldFloatTypeUnary(operandArray[i], &acoshf, &resultArray[i]);
1669 break;
1670
1671 case EOpAtanh:
1672 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to
1673 // 0.
1674 if (fabsf(operandArray[i].getFConst()) >= 1.0f)
1675 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1676 diagnostics, &resultArray[i]);
1677 else
1678 foldFloatTypeUnary(operandArray[i], &atanhf, &resultArray[i]);
1679 break;
1680
1681 case EOpAbs:
1682 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301683 {
Olli Etuahof119a262016-08-19 15:54:22 +03001684 case EbtFloat:
1685 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1686 break;
1687 case EbtInt:
1688 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1689 break;
1690 default:
1691 UNREACHABLE();
1692 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301693 }
1694 break;
Olli Etuahof119a262016-08-19 15:54:22 +03001695
1696 case EOpSign:
1697 switch (getType().getBasicType())
Arun Patoleab2b9a22015-07-06 18:27:56 +05301698 {
Olli Etuahof119a262016-08-19 15:54:22 +03001699 case EbtFloat:
1700 {
1701 float fConst = operandArray[i].getFConst();
1702 float fResult = 0.0f;
1703 if (fConst > 0.0f)
1704 fResult = 1.0f;
1705 else if (fConst < 0.0f)
1706 fResult = -1.0f;
1707 resultArray[i].setFConst(fResult);
1708 break;
1709 }
1710 case EbtInt:
1711 {
1712 int iConst = operandArray[i].getIConst();
1713 int iResult = 0;
1714 if (iConst > 0)
1715 iResult = 1;
1716 else if (iConst < 0)
1717 iResult = -1;
1718 resultArray[i].setIConst(iResult);
1719 break;
1720 }
1721 default:
1722 UNREACHABLE();
1723 return nullptr;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301724 }
1725 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301726
Olli Etuahof119a262016-08-19 15:54:22 +03001727 case EOpFloor:
1728 foldFloatTypeUnary(operandArray[i], &floorf, &resultArray[i]);
1729 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301730
Olli Etuahof119a262016-08-19 15:54:22 +03001731 case EOpTrunc:
1732 foldFloatTypeUnary(operandArray[i], &truncf, &resultArray[i]);
1733 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301734
Olli Etuahof119a262016-08-19 15:54:22 +03001735 case EOpRound:
1736 foldFloatTypeUnary(operandArray[i], &roundf, &resultArray[i]);
1737 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301738
Olli Etuahof119a262016-08-19 15:54:22 +03001739 case EOpRoundEven:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301740 {
Olli Etuahof119a262016-08-19 15:54:22 +03001741 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301742 float x = operandArray[i].getFConst();
1743 float result;
1744 float fractPart = modff(x, &result);
1745 if (fabsf(fractPart) == 0.5f)
1746 result = 2.0f * roundf(x / 2.0f);
1747 else
1748 result = roundf(x);
1749 resultArray[i].setFConst(result);
1750 break;
1751 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301752
Olli Etuahof119a262016-08-19 15:54:22 +03001753 case EOpCeil:
1754 foldFloatTypeUnary(operandArray[i], &ceilf, &resultArray[i]);
1755 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301756
Olli Etuahof119a262016-08-19 15:54:22 +03001757 case EOpFract:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301758 {
Olli Etuahof119a262016-08-19 15:54:22 +03001759 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301760 float x = operandArray[i].getFConst();
1761 resultArray[i].setFConst(x - floorf(x));
1762 break;
1763 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301764
Olli Etuahof119a262016-08-19 15:54:22 +03001765 case EOpIsNan:
1766 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301767 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1768 break;
Arun Patole551279e2015-07-07 18:18:23 +05301769
Olli Etuahof119a262016-08-19 15:54:22 +03001770 case EOpIsInf:
1771 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301772 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1773 break;
Arun Patole551279e2015-07-07 18:18:23 +05301774
Olli Etuahof119a262016-08-19 15:54:22 +03001775 case EOpFloatBitsToInt:
1776 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301777 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1778 break;
Arun Patole551279e2015-07-07 18:18:23 +05301779
Olli Etuahof119a262016-08-19 15:54:22 +03001780 case EOpFloatBitsToUint:
1781 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole551279e2015-07-07 18:18:23 +05301782 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1783 break;
Arun Patole551279e2015-07-07 18:18:23 +05301784
Olli Etuahof119a262016-08-19 15:54:22 +03001785 case EOpIntBitsToFloat:
1786 ASSERT(getType().getBasicType() == EbtInt);
Arun Patole551279e2015-07-07 18:18:23 +05301787 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1788 break;
Arun Patole551279e2015-07-07 18:18:23 +05301789
Olli Etuahof119a262016-08-19 15:54:22 +03001790 case EOpUintBitsToFloat:
1791 ASSERT(getType().getBasicType() == EbtUInt);
Arun Patole551279e2015-07-07 18:18:23 +05301792 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1793 break;
Arun Patole551279e2015-07-07 18:18:23 +05301794
Olli Etuahof119a262016-08-19 15:54:22 +03001795 case EOpExp:
1796 foldFloatTypeUnary(operandArray[i], &expf, &resultArray[i]);
1797 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301798
Olli Etuahof119a262016-08-19 15:54:22 +03001799 case EOpLog:
1800 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1801 if (operandArray[i].getFConst() <= 0.0f)
1802 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1803 diagnostics, &resultArray[i]);
1804 else
1805 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1806 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301807
Olli Etuahof119a262016-08-19 15:54:22 +03001808 case EOpExp2:
1809 foldFloatTypeUnary(operandArray[i], &exp2f, &resultArray[i]);
1810 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301811
Olli Etuahof119a262016-08-19 15:54:22 +03001812 case EOpLog2:
1813 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1814 // And log2f is not available on some plarforms like old android, so just using
1815 // log(x)/log(2) here.
1816 if (operandArray[i].getFConst() <= 0.0f)
1817 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1818 diagnostics, &resultArray[i]);
1819 else
1820 {
1821 foldFloatTypeUnary(operandArray[i], &logf, &resultArray[i]);
1822 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1823 }
1824 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301825
Olli Etuahof119a262016-08-19 15:54:22 +03001826 case EOpSqrt:
1827 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1828 if (operandArray[i].getFConst() < 0.0f)
1829 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1830 diagnostics, &resultArray[i]);
1831 else
1832 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1833 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301834
Olli Etuahof119a262016-08-19 15:54:22 +03001835 case EOpInverseSqrt:
1836 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1837 // so getting the square root first using builtin function sqrt() and then taking
1838 // its inverse.
1839 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set
1840 // result to 0.
1841 if (operandArray[i].getFConst() <= 0.0f)
1842 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1843 diagnostics, &resultArray[i]);
1844 else
1845 {
1846 foldFloatTypeUnary(operandArray[i], &sqrtf, &resultArray[i]);
1847 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1848 }
1849 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301850
Olli Etuahof119a262016-08-19 15:54:22 +03001851 case EOpVectorLogicalNot:
1852 ASSERT(getType().getBasicType() == EbtBool);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301853 resultArray[i].setBConst(!operandArray[i].getBConst());
1854 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301855
Olli Etuahof119a262016-08-19 15:54:22 +03001856 case EOpNormalize:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301857 {
Olli Etuahof119a262016-08-19 15:54:22 +03001858 ASSERT(getType().getBasicType() == EbtFloat);
1859 float x = operandArray[i].getFConst();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301860 float length = VectorLength(operandArray, objectSize);
1861 if (length)
1862 resultArray[i].setFConst(x / length);
1863 else
Olli Etuahof119a262016-08-19 15:54:22 +03001864 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(),
1865 diagnostics, &resultArray[i]);
Arun Patoleab2b9a22015-07-06 18:27:56 +05301866 break;
1867 }
Arun Patoleab2b9a22015-07-06 18:27:56 +05301868
Olli Etuahof119a262016-08-19 15:54:22 +03001869 case EOpDFdx:
1870 case EOpDFdy:
1871 case EOpFwidth:
1872 ASSERT(getType().getBasicType() == EbtFloat);
Arun Patole0c5409f2015-07-08 15:17:53 +05301873 // Derivatives of constant arguments should be 0.
1874 resultArray[i].setFConst(0.0f);
1875 break;
Arun Patole0c5409f2015-07-08 15:17:53 +05301876
Olli Etuahof119a262016-08-19 15:54:22 +03001877 default:
1878 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301879 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301880 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001881
Arun Patoleab2b9a22015-07-06 18:27:56 +05301882 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001883}
1884
Olli Etuahof119a262016-08-19 15:54:22 +03001885void TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter,
1886 FloatTypeUnaryFunc builtinFunc,
1887 TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301888{
1889 ASSERT(builtinFunc);
1890
Olli Etuahof119a262016-08-19 15:54:22 +03001891 ASSERT(getType().getBasicType() == EbtFloat);
1892 result->setFConst(builtinFunc(parameter.getFConst()));
Arun Patole9dea48f2015-04-02 11:45:09 +05301893}
1894
Jamie Madillb1a85f42014-08-19 15:23:24 -04001895// static
Olli Etuahof119a262016-08-19 15:54:22 +03001896TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate)
Olli Etuaho1d122782015-11-06 15:35:17 +02001897{
1898 ASSERT(aggregate->getSequence()->size() > 0u);
1899 size_t resultSize = aggregate->getType().getObjectSize();
1900 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1901 TBasicType basicType = aggregate->getBasicType();
1902
1903 size_t resultIndex = 0u;
1904
1905 if (aggregate->getSequence()->size() == 1u)
1906 {
1907 TIntermNode *argument = aggregate->getSequence()->front();
1908 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1909 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1910 // Check the special case of constructing a matrix diagonal from a single scalar,
1911 // or a vector from a single scalar.
1912 if (argumentConstant->getType().getObjectSize() == 1u)
1913 {
1914 if (aggregate->isMatrix())
1915 {
1916 int resultCols = aggregate->getType().getCols();
1917 int resultRows = aggregate->getType().getRows();
1918 for (int col = 0; col < resultCols; ++col)
1919 {
1920 for (int row = 0; row < resultRows; ++row)
1921 {
1922 if (col == row)
1923 {
1924 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1925 }
1926 else
1927 {
1928 resultArray[resultIndex].setFConst(0.0f);
1929 }
1930 ++resultIndex;
1931 }
1932 }
1933 }
1934 else
1935 {
1936 while (resultIndex < resultSize)
1937 {
1938 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1939 ++resultIndex;
1940 }
1941 }
1942 ASSERT(resultIndex == resultSize);
1943 return resultArray;
1944 }
1945 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1946 {
1947 // The special case of constructing a matrix from a matrix.
1948 int argumentCols = argumentConstant->getType().getCols();
1949 int argumentRows = argumentConstant->getType().getRows();
1950 int resultCols = aggregate->getType().getCols();
1951 int resultRows = aggregate->getType().getRows();
1952 for (int col = 0; col < resultCols; ++col)
1953 {
1954 for (int row = 0; row < resultRows; ++row)
1955 {
1956 if (col < argumentCols && row < argumentRows)
1957 {
1958 resultArray[resultIndex].cast(basicType,
1959 argumentUnionArray[col * argumentRows + row]);
1960 }
1961 else if (col == row)
1962 {
1963 resultArray[resultIndex].setFConst(1.0f);
1964 }
1965 else
1966 {
1967 resultArray[resultIndex].setFConst(0.0f);
1968 }
1969 ++resultIndex;
1970 }
1971 }
1972 ASSERT(resultIndex == resultSize);
1973 return resultArray;
1974 }
1975 }
1976
1977 for (TIntermNode *&argument : *aggregate->getSequence())
1978 {
1979 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1980 size_t argumentSize = argumentConstant->getType().getObjectSize();
1981 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1982 for (size_t i = 0u; i < argumentSize; ++i)
1983 {
1984 if (resultIndex >= resultSize)
1985 break;
1986 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1987 ++resultIndex;
1988 }
1989 }
1990 ASSERT(resultIndex == resultSize);
1991 return resultArray;
1992}
1993
1994// static
Olli Etuahof119a262016-08-19 15:54:22 +03001995TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate,
1996 TDiagnostics *diagnostics)
Arun Patole274f0702015-05-05 13:33:30 +05301997{
Olli Etuahob43846e2015-06-02 18:18:57 +03001998 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301999 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002000 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002001 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302002 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002003 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302004 TBasicType basicType = EbtVoid;
2005 TSourceLoc loc;
2006 for (unsigned int i = 0; i < paramsCount; i++)
2007 {
2008 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002009 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302010
2011 if (i == 0)
2012 {
2013 basicType = paramConstant->getType().getBasicType();
2014 loc = paramConstant->getLine();
2015 }
2016 unionArrays[i] = paramConstant->getUnionArrayPointer();
2017 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002018 if (objectSizes[i] > maxObjectSize)
2019 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302020 }
2021
Olli Etuahod5da5052016-08-29 13:16:55 +03002022 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302023 {
2024 for (unsigned int i = 0; i < paramsCount; i++)
2025 if (objectSizes[i] != maxObjectSize)
2026 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2027 }
Arun Patole274f0702015-05-05 13:33:30 +05302028
Olli Etuahob43846e2015-06-02 18:18:57 +03002029 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302030 if (paramsCount == 2)
2031 {
2032 //
2033 // Binary built-in
2034 //
2035 switch (op)
2036 {
Olli Etuahof119a262016-08-19 15:54:22 +03002037 case EOpAtan:
Arun Patolebf790422015-05-18 17:53:04 +05302038 {
Olli Etuahof119a262016-08-19 15:54:22 +03002039 ASSERT(basicType == EbtFloat);
2040 resultArray = new TConstantUnion[maxObjectSize];
2041 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302042 {
Olli Etuahof119a262016-08-19 15:54:22 +03002043 float y = unionArrays[0][i].getFConst();
2044 float x = unionArrays[1][i].getFConst();
2045 // Results are undefined if x and y are both 0.
2046 if (x == 0.0f && y == 0.0f)
2047 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2048 &resultArray[i]);
2049 else
2050 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302051 }
Olli Etuahof119a262016-08-19 15:54:22 +03002052 break;
Arun Patolebf790422015-05-18 17:53:04 +05302053 }
Arun Patolebf790422015-05-18 17:53:04 +05302054
Olli Etuahof119a262016-08-19 15:54:22 +03002055 case EOpPow:
Arun Patolebf790422015-05-18 17:53:04 +05302056 {
Olli Etuahof119a262016-08-19 15:54:22 +03002057 ASSERT(basicType == EbtFloat);
2058 resultArray = new TConstantUnion[maxObjectSize];
2059 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302060 {
Olli Etuahof119a262016-08-19 15:54:22 +03002061 float x = unionArrays[0][i].getFConst();
2062 float y = unionArrays[1][i].getFConst();
2063 // Results are undefined if x < 0.
2064 // Results are undefined if x = 0 and y <= 0.
2065 if (x < 0.0f)
2066 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2067 &resultArray[i]);
2068 else if (x == 0.0f && y <= 0.0f)
2069 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2070 &resultArray[i]);
2071 else
2072 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302073 }
Olli Etuahof119a262016-08-19 15:54:22 +03002074 break;
Arun Patolebf790422015-05-18 17:53:04 +05302075 }
Arun Patolebf790422015-05-18 17:53:04 +05302076
Olli Etuahof119a262016-08-19 15:54:22 +03002077 case EOpMod:
Arun Patolebf790422015-05-18 17:53:04 +05302078 {
Olli Etuahof119a262016-08-19 15:54:22 +03002079 ASSERT(basicType == EbtFloat);
2080 resultArray = new TConstantUnion[maxObjectSize];
2081 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302082 {
Olli Etuahof119a262016-08-19 15:54:22 +03002083 float x = unionArrays[0][i].getFConst();
2084 float y = unionArrays[1][i].getFConst();
2085 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302086 }
Olli Etuahof119a262016-08-19 15:54:22 +03002087 break;
Arun Patolebf790422015-05-18 17:53:04 +05302088 }
Arun Patolebf790422015-05-18 17:53:04 +05302089
Olli Etuahof119a262016-08-19 15:54:22 +03002090 case EOpMin:
Arun Patole274f0702015-05-05 13:33:30 +05302091 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002092 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302093 for (size_t i = 0; i < maxObjectSize; i++)
2094 {
2095 switch (basicType)
2096 {
Olli Etuahof119a262016-08-19 15:54:22 +03002097 case EbtFloat:
2098 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(),
2099 unionArrays[1][i].getFConst()));
2100 break;
2101 case EbtInt:
2102 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(),
2103 unionArrays[1][i].getIConst()));
2104 break;
2105 case EbtUInt:
2106 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(),
2107 unionArrays[1][i].getUConst()));
2108 break;
2109 default:
2110 UNREACHABLE();
2111 break;
Arun Patole274f0702015-05-05 13:33:30 +05302112 }
2113 }
Olli Etuahof119a262016-08-19 15:54:22 +03002114 break;
Arun Patole274f0702015-05-05 13:33:30 +05302115 }
Arun Patole274f0702015-05-05 13:33:30 +05302116
Olli Etuahof119a262016-08-19 15:54:22 +03002117 case EOpMax:
Arun Patole274f0702015-05-05 13:33:30 +05302118 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002119 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302120 for (size_t i = 0; i < maxObjectSize; i++)
2121 {
2122 switch (basicType)
2123 {
Olli Etuahof119a262016-08-19 15:54:22 +03002124 case EbtFloat:
2125 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(),
2126 unionArrays[1][i].getFConst()));
2127 break;
2128 case EbtInt:
2129 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(),
2130 unionArrays[1][i].getIConst()));
2131 break;
2132 case EbtUInt:
2133 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(),
2134 unionArrays[1][i].getUConst()));
2135 break;
2136 default:
2137 UNREACHABLE();
2138 break;
Arun Patole274f0702015-05-05 13:33:30 +05302139 }
2140 }
Olli Etuahof119a262016-08-19 15:54:22 +03002141 break;
Arun Patole274f0702015-05-05 13:33:30 +05302142 }
Arun Patole274f0702015-05-05 13:33:30 +05302143
Olli Etuahof119a262016-08-19 15:54:22 +03002144 case EOpStep:
Arun Patolebf790422015-05-18 17:53:04 +05302145 {
Olli Etuahof119a262016-08-19 15:54:22 +03002146 ASSERT(basicType == EbtFloat);
2147 resultArray = new TConstantUnion[maxObjectSize];
2148 for (size_t i = 0; i < maxObjectSize; i++)
2149 resultArray[i].setFConst(
2150 unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f
2151 : 1.0f);
2152 break;
Arun Patolebf790422015-05-18 17:53:04 +05302153 }
Arun Patolebf790422015-05-18 17:53:04 +05302154
Olli Etuahof119a262016-08-19 15:54:22 +03002155 case EOpLessThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302156 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002157 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302158 for (size_t i = 0; i < maxObjectSize; i++)
2159 {
2160 switch (basicType)
2161 {
Olli Etuahof119a262016-08-19 15:54:22 +03002162 case EbtFloat:
2163 resultArray[i].setBConst(unionArrays[0][i].getFConst() <
2164 unionArrays[1][i].getFConst());
2165 break;
2166 case EbtInt:
2167 resultArray[i].setBConst(unionArrays[0][i].getIConst() <
2168 unionArrays[1][i].getIConst());
2169 break;
2170 case EbtUInt:
2171 resultArray[i].setBConst(unionArrays[0][i].getUConst() <
2172 unionArrays[1][i].getUConst());
2173 break;
2174 default:
2175 UNREACHABLE();
2176 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302177 }
2178 }
Olli Etuahof119a262016-08-19 15:54:22 +03002179 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302180 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302181
Olli Etuahof119a262016-08-19 15:54:22 +03002182 case EOpLessThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302183 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002184 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302185 for (size_t i = 0; i < maxObjectSize; i++)
2186 {
2187 switch (basicType)
2188 {
Olli Etuahof119a262016-08-19 15:54:22 +03002189 case EbtFloat:
2190 resultArray[i].setBConst(unionArrays[0][i].getFConst() <=
2191 unionArrays[1][i].getFConst());
2192 break;
2193 case EbtInt:
2194 resultArray[i].setBConst(unionArrays[0][i].getIConst() <=
2195 unionArrays[1][i].getIConst());
2196 break;
2197 case EbtUInt:
2198 resultArray[i].setBConst(unionArrays[0][i].getUConst() <=
2199 unionArrays[1][i].getUConst());
2200 break;
2201 default:
2202 UNREACHABLE();
2203 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302204 }
2205 }
Olli Etuahof119a262016-08-19 15:54:22 +03002206 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302207 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302208
Olli Etuahof119a262016-08-19 15:54:22 +03002209 case EOpGreaterThan:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302210 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002211 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302212 for (size_t i = 0; i < maxObjectSize; i++)
2213 {
2214 switch (basicType)
2215 {
Olli Etuahof119a262016-08-19 15:54:22 +03002216 case EbtFloat:
2217 resultArray[i].setBConst(unionArrays[0][i].getFConst() >
2218 unionArrays[1][i].getFConst());
2219 break;
2220 case EbtInt:
2221 resultArray[i].setBConst(unionArrays[0][i].getIConst() >
2222 unionArrays[1][i].getIConst());
2223 break;
2224 case EbtUInt:
2225 resultArray[i].setBConst(unionArrays[0][i].getUConst() >
2226 unionArrays[1][i].getUConst());
2227 break;
2228 default:
2229 UNREACHABLE();
2230 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002231 }
2232 }
Olli Etuahof119a262016-08-19 15:54:22 +03002233 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302234 }
Olli Etuahof119a262016-08-19 15:54:22 +03002235 case EOpGreaterThanEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302236 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002237 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302238 for (size_t i = 0; i < maxObjectSize; i++)
2239 {
2240 switch (basicType)
2241 {
Olli Etuahof119a262016-08-19 15:54:22 +03002242 case EbtFloat:
2243 resultArray[i].setBConst(unionArrays[0][i].getFConst() >=
2244 unionArrays[1][i].getFConst());
2245 break;
2246 case EbtInt:
2247 resultArray[i].setBConst(unionArrays[0][i].getIConst() >=
2248 unionArrays[1][i].getIConst());
2249 break;
2250 case EbtUInt:
2251 resultArray[i].setBConst(unionArrays[0][i].getUConst() >=
2252 unionArrays[1][i].getUConst());
2253 break;
2254 default:
2255 UNREACHABLE();
2256 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302257 }
2258 }
2259 }
2260 break;
2261
Olli Etuahof119a262016-08-19 15:54:22 +03002262 case EOpVectorEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302263 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002264 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302265 for (size_t i = 0; i < maxObjectSize; i++)
2266 {
2267 switch (basicType)
2268 {
Olli Etuahof119a262016-08-19 15:54:22 +03002269 case EbtFloat:
2270 resultArray[i].setBConst(unionArrays[0][i].getFConst() ==
2271 unionArrays[1][i].getFConst());
2272 break;
2273 case EbtInt:
2274 resultArray[i].setBConst(unionArrays[0][i].getIConst() ==
2275 unionArrays[1][i].getIConst());
2276 break;
2277 case EbtUInt:
2278 resultArray[i].setBConst(unionArrays[0][i].getUConst() ==
2279 unionArrays[1][i].getUConst());
2280 break;
2281 case EbtBool:
2282 resultArray[i].setBConst(unionArrays[0][i].getBConst() ==
2283 unionArrays[1][i].getBConst());
2284 break;
2285 default:
2286 UNREACHABLE();
2287 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302288 }
2289 }
Olli Etuahof119a262016-08-19 15:54:22 +03002290 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302291 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302292
Olli Etuahof119a262016-08-19 15:54:22 +03002293 case EOpVectorNotEqual:
Arun Patole9d0b1f92015-05-20 14:27:17 +05302294 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002295 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302296 for (size_t i = 0; i < maxObjectSize; i++)
2297 {
2298 switch (basicType)
2299 {
Olli Etuahof119a262016-08-19 15:54:22 +03002300 case EbtFloat:
2301 resultArray[i].setBConst(unionArrays[0][i].getFConst() !=
2302 unionArrays[1][i].getFConst());
2303 break;
2304 case EbtInt:
2305 resultArray[i].setBConst(unionArrays[0][i].getIConst() !=
2306 unionArrays[1][i].getIConst());
2307 break;
2308 case EbtUInt:
2309 resultArray[i].setBConst(unionArrays[0][i].getUConst() !=
2310 unionArrays[1][i].getUConst());
2311 break;
2312 case EbtBool:
2313 resultArray[i].setBConst(unionArrays[0][i].getBConst() !=
2314 unionArrays[1][i].getBConst());
2315 break;
2316 default:
2317 UNREACHABLE();
2318 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302319 }
2320 }
Olli Etuahof119a262016-08-19 15:54:22 +03002321 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05302322 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302323
Olli Etuahof119a262016-08-19 15:54:22 +03002324 case EOpDistance:
Arun Patole1155ddd2015-06-05 18:04:36 +05302325 {
Olli Etuahof119a262016-08-19 15:54:22 +03002326 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302327 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002328 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302329 for (size_t i = 0; i < maxObjectSize; i++)
2330 {
2331 float x = unionArrays[0][i].getFConst();
2332 float y = unionArrays[1][i].getFConst();
2333 distanceArray[i].setFConst(x - y);
2334 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002335 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Olli Etuahof119a262016-08-19 15:54:22 +03002336 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302337 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302338
Olli Etuahof119a262016-08-19 15:54:22 +03002339 case EOpDot:
2340 ASSERT(basicType == EbtFloat);
Olli Etuahob43846e2015-06-02 18:18:57 +03002341 resultArray = new TConstantUnion();
Olli Etuahof119a262016-08-19 15:54:22 +03002342 resultArray->setFConst(
2343 VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
2344 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302345
Olli Etuahof119a262016-08-19 15:54:22 +03002346 case EOpCross:
Arun Patole1155ddd2015-06-05 18:04:36 +05302347 {
Olli Etuahof119a262016-08-19 15:54:22 +03002348 ASSERT(basicType == EbtFloat && maxObjectSize == 3);
Olli Etuahob43846e2015-06-02 18:18:57 +03002349 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002350 float x0 = unionArrays[0][0].getFConst();
2351 float x1 = unionArrays[0][1].getFConst();
2352 float x2 = unionArrays[0][2].getFConst();
2353 float y0 = unionArrays[1][0].getFConst();
2354 float y1 = unionArrays[1][1].getFConst();
2355 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002356 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2357 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2358 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Olli Etuahof119a262016-08-19 15:54:22 +03002359 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302360 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302361
Olli Etuahof119a262016-08-19 15:54:22 +03002362 case EOpReflect:
Arun Patole1155ddd2015-06-05 18:04:36 +05302363 {
Olli Etuahof119a262016-08-19 15:54:22 +03002364 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302365 // genType reflect (genType I, genType N) :
Olli Etuahof119a262016-08-19 15:54:22 +03002366 // For the incident vector I and surface orientation N, returns the reflection
2367 // direction:
Arun Patole1155ddd2015-06-05 18:04:36 +05302368 // I - 2 * dot(N, I) * N.
Olli Etuahof119a262016-08-19 15:54:22 +03002369 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302370 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2371 for (size_t i = 0; i < maxObjectSize; i++)
2372 {
2373 float result = unionArrays[0][i].getFConst() -
2374 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002375 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302376 }
Olli Etuahof119a262016-08-19 15:54:22 +03002377 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302378 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302379
Olli Etuahof119a262016-08-19 15:54:22 +03002380 case EOpMul:
Arun Patole7fa33552015-06-10 15:15:18 +05302381 {
Olli Etuahof119a262016-08-19 15:54:22 +03002382 ASSERT(basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2383 (*sequence)[1]->getAsTyped()->isMatrix());
Arun Patole7fa33552015-06-10 15:15:18 +05302384 // Perform component-wise matrix multiplication.
2385 resultArray = new TConstantUnion[maxObjectSize];
Olli Etuahof119a262016-08-19 15:54:22 +03002386 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302387 angle::Matrix<float> result =
2388 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2389 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002390 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302391 }
Arun Patole7fa33552015-06-10 15:15:18 +05302392
Olli Etuahof119a262016-08-19 15:54:22 +03002393 case EOpOuterProduct:
Arun Patole7fa33552015-06-10 15:15:18 +05302394 {
Olli Etuahof119a262016-08-19 15:54:22 +03002395 ASSERT(basicType == EbtFloat);
Arun Patole7fa33552015-06-10 15:15:18 +05302396 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2397 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
Olli Etuahof119a262016-08-19 15:54:22 +03002398 resultArray = new TConstantUnion[numRows * numCols];
Arun Patole7fa33552015-06-10 15:15:18 +05302399 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03002400 GetMatrix(unionArrays[0], static_cast<int>(numRows), 1)
2401 .outerProduct(GetMatrix(unionArrays[1], 1, static_cast<int>(numCols)));
Arun Patole7fa33552015-06-10 15:15:18 +05302402 SetUnionArrayFromMatrix(result, resultArray);
Olli Etuahof119a262016-08-19 15:54:22 +03002403 break;
Arun Patole7fa33552015-06-10 15:15:18 +05302404 }
Arun Patole7fa33552015-06-10 15:15:18 +05302405
Olli Etuahof119a262016-08-19 15:54:22 +03002406 default:
2407 UNREACHABLE();
2408 // TODO: Add constant folding support for other built-in operations that take 2
2409 // parameters and not handled above.
2410 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302411 }
2412 }
2413 else if (paramsCount == 3)
2414 {
2415 //
2416 // Ternary built-in
2417 //
2418 switch (op)
2419 {
Olli Etuahof119a262016-08-19 15:54:22 +03002420 case EOpClamp:
Arun Patole274f0702015-05-05 13:33:30 +05302421 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002422 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302423 for (size_t i = 0; i < maxObjectSize; i++)
2424 {
2425 switch (basicType)
2426 {
Olli Etuahof119a262016-08-19 15:54:22 +03002427 case EbtFloat:
Arun Patole274f0702015-05-05 13:33:30 +05302428 {
Olli Etuahof119a262016-08-19 15:54:22 +03002429 float x = unionArrays[0][i].getFConst();
Arun Patole274f0702015-05-05 13:33:30 +05302430 float min = unionArrays[1][i].getFConst();
2431 float max = unionArrays[2][i].getFConst();
2432 // Results are undefined if min > max.
2433 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002434 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2435 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302436 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002437 resultArray[i].setFConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002438 break;
Arun Patole274f0702015-05-05 13:33:30 +05302439 }
Olli Etuahof119a262016-08-19 15:54:22 +03002440
2441 case EbtInt:
Arun Patole274f0702015-05-05 13:33:30 +05302442 {
Olli Etuahof119a262016-08-19 15:54:22 +03002443 int x = unionArrays[0][i].getIConst();
Arun Patole274f0702015-05-05 13:33:30 +05302444 int min = unionArrays[1][i].getIConst();
2445 int max = unionArrays[2][i].getIConst();
2446 // Results are undefined if min > max.
2447 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002448 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2449 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302450 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002451 resultArray[i].setIConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002452 break;
Arun Patole274f0702015-05-05 13:33:30 +05302453 }
Olli Etuahof119a262016-08-19 15:54:22 +03002454 case EbtUInt:
Arun Patole274f0702015-05-05 13:33:30 +05302455 {
Olli Etuahof119a262016-08-19 15:54:22 +03002456 unsigned int x = unionArrays[0][i].getUConst();
Arun Patole274f0702015-05-05 13:33:30 +05302457 unsigned int min = unionArrays[1][i].getUConst();
2458 unsigned int max = unionArrays[2][i].getUConst();
2459 // Results are undefined if min > max.
2460 if (min > max)
Olli Etuahof119a262016-08-19 15:54:22 +03002461 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2462 &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302463 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002464 resultArray[i].setUConst(gl::clamp(x, min, max));
Olli Etuahof119a262016-08-19 15:54:22 +03002465 break;
Arun Patole274f0702015-05-05 13:33:30 +05302466 }
Olli Etuahof119a262016-08-19 15:54:22 +03002467 default:
2468 UNREACHABLE();
2469 break;
Arun Patole274f0702015-05-05 13:33:30 +05302470 }
2471 }
Olli Etuahof119a262016-08-19 15:54:22 +03002472 break;
Arun Patole274f0702015-05-05 13:33:30 +05302473 }
Arun Patole274f0702015-05-05 13:33:30 +05302474
Olli Etuahof119a262016-08-19 15:54:22 +03002475 case EOpMix:
Arun Patolebf790422015-05-18 17:53:04 +05302476 {
Olli Etuahof119a262016-08-19 15:54:22 +03002477 ASSERT(basicType == EbtFloat);
2478 resultArray = new TConstantUnion[maxObjectSize];
2479 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302480 {
Olli Etuahof119a262016-08-19 15:54:22 +03002481 float x = unionArrays[0][i].getFConst();
2482 float y = unionArrays[1][i].getFConst();
2483 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2484 if (type == EbtFloat)
Arun Patolebf790422015-05-18 17:53:04 +05302485 {
Olli Etuahof119a262016-08-19 15:54:22 +03002486 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2487 float a = unionArrays[2][i].getFConst();
2488 resultArray[i].setFConst(x * (1.0f - a) + y * a);
2489 }
2490 else // 3rd parameter is EbtBool
2491 {
2492 ASSERT(type == EbtBool);
2493 // Selects which vector each returned component comes from.
2494 // For a component of a that is false, the corresponding component of x is
2495 // returned.
2496 // For a component of a that is true, the corresponding component of y is
2497 // returned.
2498 bool a = unionArrays[2][i].getBConst();
2499 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302500 }
2501 }
Olli Etuahof119a262016-08-19 15:54:22 +03002502 break;
Arun Patolebf790422015-05-18 17:53:04 +05302503 }
Arun Patolebf790422015-05-18 17:53:04 +05302504
Olli Etuahof119a262016-08-19 15:54:22 +03002505 case EOpSmoothStep:
Arun Patolebf790422015-05-18 17:53:04 +05302506 {
Olli Etuahof119a262016-08-19 15:54:22 +03002507 ASSERT(basicType == EbtFloat);
2508 resultArray = new TConstantUnion[maxObjectSize];
2509 for (size_t i = 0; i < maxObjectSize; i++)
Arun Patolebf790422015-05-18 17:53:04 +05302510 {
Olli Etuahof119a262016-08-19 15:54:22 +03002511 float edge0 = unionArrays[0][i].getFConst();
2512 float edge1 = unionArrays[1][i].getFConst();
2513 float x = unionArrays[2][i].getFConst();
2514 // Results are undefined if edge0 >= edge1.
2515 if (edge0 >= edge1)
Arun Patolebf790422015-05-18 17:53:04 +05302516 {
Olli Etuahof119a262016-08-19 15:54:22 +03002517 UndefinedConstantFoldingError(loc, op, basicType, diagnostics,
2518 &resultArray[i]);
2519 }
2520 else
2521 {
2522 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2523 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2524 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
2525 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302526 }
2527 }
Olli Etuahof119a262016-08-19 15:54:22 +03002528 break;
Arun Patolebf790422015-05-18 17:53:04 +05302529 }
Arun Patolebf790422015-05-18 17:53:04 +05302530
Olli Etuahof119a262016-08-19 15:54:22 +03002531 case EOpFaceForward:
Arun Patole1155ddd2015-06-05 18:04:36 +05302532 {
Olli Etuahof119a262016-08-19 15:54:22 +03002533 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302534 // genType faceforward(genType N, genType I, genType Nref) :
2535 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahof119a262016-08-19 15:54:22 +03002536 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302537 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2538 for (size_t i = 0; i < maxObjectSize; i++)
2539 {
2540 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002541 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302542 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002543 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302544 }
Olli Etuahof119a262016-08-19 15:54:22 +03002545 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302546 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302547
Olli Etuahof119a262016-08-19 15:54:22 +03002548 case EOpRefract:
Arun Patole1155ddd2015-06-05 18:04:36 +05302549 {
Olli Etuahof119a262016-08-19 15:54:22 +03002550 ASSERT(basicType == EbtFloat);
Arun Patole1155ddd2015-06-05 18:04:36 +05302551 // genType refract(genType I, genType N, float eta) :
Olli Etuahof119a262016-08-19 15:54:22 +03002552 // For the incident vector I and surface normal N, and the ratio of indices of
2553 // refraction eta,
Arun Patole1155ddd2015-06-05 18:04:36 +05302554 // return the refraction vector. The result is computed by
2555 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2556 // if (k < 0.0)
2557 // return genType(0.0)
2558 // else
2559 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahof119a262016-08-19 15:54:22 +03002560 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302561 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2562 for (size_t i = 0; i < maxObjectSize; i++)
2563 {
2564 float eta = unionArrays[2][i].getFConst();
Olli Etuahof119a262016-08-19 15:54:22 +03002565 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
Arun Patole1155ddd2015-06-05 18:04:36 +05302566 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002567 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302568 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002569 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Olli Etuahof119a262016-08-19 15:54:22 +03002570 (eta * dotProduct + sqrtf(k)) *
2571 unionArrays[1][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302572 }
Olli Etuahof119a262016-08-19 15:54:22 +03002573 break;
Arun Patole1155ddd2015-06-05 18:04:36 +05302574 }
Arun Patole1155ddd2015-06-05 18:04:36 +05302575
Olli Etuahof119a262016-08-19 15:54:22 +03002576 default:
2577 UNREACHABLE();
2578 // TODO: Add constant folding support for other built-in operations that take 3
2579 // parameters and not handled above.
2580 return nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302581 }
2582 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002583 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302584}
2585
2586// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002587TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2588{
2589 if (hashFunction == NULL || name.empty())
2590 return name;
2591 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2592 TStringStream stream;
2593 stream << HASHED_NAME_PREFIX << std::hex << number;
2594 TString hashedName = stream.str();
2595 return hashedName;
2596}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002597
2598void TIntermTraverser::updateTree()
2599{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002600 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2601 {
2602 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2603 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002604 if (!insertion.insertionsAfter.empty())
2605 {
2606 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2607 insertion.insertionsAfter);
2608 ASSERT(inserted);
2609 UNUSED_ASSERTION_VARIABLE(inserted);
2610 }
2611 if (!insertion.insertionsBefore.empty())
2612 {
2613 bool inserted =
2614 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2615 ASSERT(inserted);
2616 UNUSED_ASSERTION_VARIABLE(inserted);
2617 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002618 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002619 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2620 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002621 const NodeUpdateEntry &replacement = mReplacements[ii];
2622 ASSERT(replacement.parent);
2623 bool replaced = replacement.parent->replaceChildNode(
2624 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002625 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002626 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002627
Olli Etuahocd94ef92015-04-16 19:18:10 +03002628 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002629 {
2630 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002631 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002632 // be replaced, we need to make sure we don't update the replaced
2633 // node; instead, we update the replacement node.
2634 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2635 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002636 NodeUpdateEntry &replacement2 = mReplacements[jj];
2637 if (replacement2.parent == replacement.original)
2638 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002639 }
2640 }
2641 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002642 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2643 {
2644 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2645 ASSERT(replacement.parent);
2646 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2647 replacement.original, replacement.replacements);
2648 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002649 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002650 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002651
Jamie Madill03d863c2016-07-27 18:15:53 -04002652 clearReplacementQueue();
2653}
2654
2655void TIntermTraverser::clearReplacementQueue()
2656{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002657 mReplacements.clear();
2658 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002659 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002660}
Jamie Madill1048e432016-07-23 18:51:28 -04002661
Jamie Madill03d863c2016-07-27 18:15:53 -04002662void TIntermTraverser::queueReplacement(TIntermNode *original,
2663 TIntermNode *replacement,
2664 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002665{
Jamie Madill03d863c2016-07-27 18:15:53 -04002666 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002667}
2668
Jamie Madill03d863c2016-07-27 18:15:53 -04002669void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2670 TIntermNode *original,
2671 TIntermNode *replacement,
2672 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002673{
Jamie Madill03d863c2016-07-27 18:15:53 -04002674 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2675 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002676}