blob: b00022a4682457bc72ee15be8c47127759a9290b [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
Arun Patolebf790422015-05-18 17:53:04 +053047void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
48 TInfoSink &infoSink, TConstantUnion *result)
49{
50 std::stringstream constantFoldingErrorStream;
51 constantFoldingErrorStream << "'" << GetOperatorString(op)
52 << "' operation result is undefined for the values passed in";
53 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
54
55 switch (basicType)
56 {
57 case EbtFloat :
58 result->setFConst(0.0f);
59 break;
60 case EbtInt:
61 result->setIConst(0);
62 break;
63 case EbtUInt:
64 result->setUConst(0u);
65 break;
66 case EbtBool:
67 result->setBConst(false);
68 break;
69 default:
70 break;
71 }
72}
73
Olli Etuaho5c0e0232015-11-11 15:55:59 +020074float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053075{
76 float result = 0.0f;
77 for (size_t i = 0; i < paramArraySize; i++)
78 {
79 float f = paramArray[i].getFConst();
80 result += f * f;
81 }
82 return sqrtf(result);
83}
84
Olli Etuaho5c0e0232015-11-11 15:55:59 +020085float VectorDotProduct(const TConstantUnion *paramArray1,
86 const TConstantUnion *paramArray2,
87 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053088{
89 float result = 0.0f;
90 for (size_t i = 0; i < paramArraySize; i++)
91 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
92 return result;
93}
94
Olli Etuaho7c3848e2015-11-04 13:19:17 +020095TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
96 const TIntermTyped *originalNode,
97 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +030098{
99 if (constArray == nullptr)
100 {
101 return nullptr;
102 }
103 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200104 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300105 folded->setLine(originalNode->getLine());
106 return folded;
107}
108
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200109angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
110 const unsigned int &rows,
111 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530112{
113 std::vector<float> elements;
114 for (size_t i = 0; i < rows * cols; i++)
115 elements.push_back(paramArray[i].getFConst());
116 // Transpose is used since the Matrix constructor expects arguments in row-major order,
Olli Etuahod5da5052016-08-29 13:16:55 +0300117 // whereas the paramArray is in column-major order. Rows/cols parameters are also flipped below
118 // so that the created matrix will have the expected dimensions after the transpose.
119 return angle::Matrix<float>(elements, cols, rows).transpose();
Arun Patole7fa33552015-06-10 15:15:18 +0530120}
121
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200122angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530123{
124 std::vector<float> elements;
125 for (size_t i = 0; i < size * size; i++)
126 elements.push_back(paramArray[i].getFConst());
127 // Transpose is used since the Matrix constructor expects arguments in row-major order,
128 // whereas the paramArray is in column-major order.
129 return angle::Matrix<float>(elements, size).transpose();
130}
131
132void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
133{
134 // Transpose is used since the input Matrix is in row-major order,
135 // whereas the actual result should be in column-major order.
136 angle::Matrix<float> result = m.transpose();
137 std::vector<float> resultElements = result.elements();
138 for (size_t i = 0; i < resultElements.size(); i++)
139 resultArray[i].setFConst(resultElements[i]);
140}
141
Jamie Madillb1a85f42014-08-19 15:23:24 -0400142} // namespace anonymous
143
144
145////////////////////////////////////////////////////////////////
146//
147// Member functions of the nodes used for building the tree.
148//
149////////////////////////////////////////////////////////////////
150
Olli Etuahod2a67b92014-10-21 16:42:57 +0300151void TIntermTyped::setTypePreservePrecision(const TType &t)
152{
153 TPrecision precision = getPrecision();
154 mType = t;
155 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
156 mType.setPrecision(precision);
157}
158
Jamie Madillb1a85f42014-08-19 15:23:24 -0400159#define REPLACE_IF_IS(node, type, original, replacement) \
160 if (node == original) { \
161 node = static_cast<type *>(replacement); \
162 return true; \
163 }
164
165bool TIntermLoop::replaceChildNode(
166 TIntermNode *original, TIntermNode *replacement)
167{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300168 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400169 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
170 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
171 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200172 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400173 return false;
174}
175
Jamie Madillb1a85f42014-08-19 15:23:24 -0400176bool TIntermBranch::replaceChildNode(
177 TIntermNode *original, TIntermNode *replacement)
178{
179 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
180 return false;
181}
182
Jamie Madillb1a85f42014-08-19 15:23:24 -0400183bool TIntermBinary::replaceChildNode(
184 TIntermNode *original, TIntermNode *replacement)
185{
186 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
187 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
188 return false;
189}
190
Jamie Madillb1a85f42014-08-19 15:23:24 -0400191bool TIntermUnary::replaceChildNode(
192 TIntermNode *original, TIntermNode *replacement)
193{
194 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
195 return false;
196}
197
Jamie Madillb1a85f42014-08-19 15:23:24 -0400198bool TIntermAggregate::replaceChildNode(
199 TIntermNode *original, TIntermNode *replacement)
200{
201 for (size_t ii = 0; ii < mSequence.size(); ++ii)
202 {
203 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
204 }
205 return false;
206}
207
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300208bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
209{
210 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
211 {
212 if (*it == original)
213 {
214 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300215 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300216 return true;
217 }
218 }
219 return false;
220}
221
Olli Etuahoa6f22092015-05-08 18:31:10 +0300222bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
223{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300224 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300225 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300226 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300227 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300228 auto it = mSequence.begin() + position;
229 mSequence.insert(it, insertions.begin(), insertions.end());
230 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300231}
232
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200233bool TIntermAggregate::areChildrenConstQualified()
234{
235 for (TIntermNode *&child : mSequence)
236 {
237 TIntermTyped *typed = child->getAsTyped();
238 if (typed && typed->getQualifier() != EvqConst)
239 {
240 return false;
241 }
242 }
243 return true;
244}
245
Olli Etuahod2a67b92014-10-21 16:42:57 +0300246void TIntermAggregate::setPrecisionFromChildren()
247{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300248 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300249 if (getBasicType() == EbtBool)
250 {
251 mType.setPrecision(EbpUndefined);
252 return;
253 }
254
255 TPrecision precision = EbpUndefined;
256 TIntermSequence::iterator childIter = mSequence.begin();
257 while (childIter != mSequence.end())
258 {
259 TIntermTyped *typed = (*childIter)->getAsTyped();
260 if (typed)
261 precision = GetHigherPrecision(typed->getPrecision(), precision);
262 ++childIter;
263 }
264 mType.setPrecision(precision);
265}
266
267void TIntermAggregate::setBuiltInFunctionPrecision()
268{
269 // All built-ins returning bool should be handled as ops, not functions.
270 ASSERT(getBasicType() != EbtBool);
271
272 TPrecision precision = EbpUndefined;
273 TIntermSequence::iterator childIter = mSequence.begin();
274 while (childIter != mSequence.end())
275 {
276 TIntermTyped *typed = (*childIter)->getAsTyped();
277 // ESSL spec section 8: texture functions get their precision from the sampler.
278 if (typed && IsSampler(typed->getBasicType()))
279 {
280 precision = typed->getPrecision();
281 break;
282 }
283 ++childIter;
284 }
285 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
286 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300287 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300288 mType.setPrecision(EbpHigh);
289 else
290 mType.setPrecision(precision);
291}
292
Jamie Madillb1a85f42014-08-19 15:23:24 -0400293bool TIntermSelection::replaceChildNode(
294 TIntermNode *original, TIntermNode *replacement)
295{
296 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
297 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
298 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
299 return false;
300}
301
Olli Etuahoa3a36662015-02-17 13:46:51 +0200302bool TIntermSwitch::replaceChildNode(
303 TIntermNode *original, TIntermNode *replacement)
304{
305 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
306 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
307 return false;
308}
309
310bool TIntermCase::replaceChildNode(
311 TIntermNode *original, TIntermNode *replacement)
312{
313 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
314 return false;
315}
316
Olli Etuahod7a25242015-08-18 13:49:45 +0300317TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
318{
319 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
320 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
321 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
322 mLine = node.mLine;
323}
324
Olli Etuahod4f4c112016-04-15 15:11:24 +0300325bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
326{
327 TIntermAggregate *constructor = getAsAggregate();
328 if (!constructor || !constructor->isConstructor())
329 {
330 return false;
331 }
332 for (TIntermNode *&node : *constructor->getSequence())
333 {
334 if (!node->getAsConstantUnion())
335 return false;
336 }
337 return true;
338}
339
Corentin Wallez509e4562016-08-25 14:55:44 -0400340// static
341TIntermTyped *TIntermTyped::CreateIndexNode(int index)
342{
343 TConstantUnion *u = new TConstantUnion[1];
344 u[0].setIConst(index);
345
346 TType type(EbtInt, EbpUndefined, EvqConst, 1);
347 TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
348 return node;
349}
350
351// static
352TIntermTyped *TIntermTyped::CreateZero(const TType &type)
353{
354 TType constType(type);
355 constType.setQualifier(EvqConst);
356
357 if (!type.isArray() && type.getBasicType() != EbtStruct)
358 {
359 ASSERT(type.isScalar() || type.isVector() || type.isMatrix());
360
361 size_t size = constType.getObjectSize();
362 TConstantUnion *u = new TConstantUnion[size];
363 for (size_t i = 0; i < size; ++i)
364 {
365 switch (type.getBasicType())
366 {
367 case EbtFloat:
368 u[i].setFConst(0.0f);
369 break;
370 case EbtInt:
371 u[i].setIConst(0);
372 break;
373 case EbtUInt:
374 u[i].setUConst(0u);
375 break;
376 case EbtBool:
377 u[i].setBConst(false);
378 break;
379 default:
380 UNREACHABLE();
381 return nullptr;
382 }
383 }
384
385 TIntermConstantUnion *node = new TIntermConstantUnion(u, constType);
386 return node;
387 }
388
389 TIntermAggregate *constructor = new TIntermAggregate(sh::TypeToConstructorOperator(type));
390 constructor->setType(constType);
391
392 if (type.isArray())
393 {
394 TType elementType(type);
395 elementType.clearArrayness();
396
397 size_t arraySize = type.getArraySize();
398 for (size_t i = 0; i < arraySize; ++i)
399 {
400 constructor->getSequence()->push_back(CreateZero(elementType));
401 }
402 }
403 else
404 {
405 ASSERT(type.getBasicType() == EbtStruct);
406
407 TStructure *structure = type.getStruct();
408 for (const auto &field : structure->fields())
409 {
410 constructor->getSequence()->push_back(CreateZero(*field->type()));
411 }
412 }
413
414 return constructor;
415}
416
Olli Etuahod7a25242015-08-18 13:49:45 +0300417TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
418{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200419 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300420}
421
422TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
423 : TIntermOperator(node),
424 mName(node.mName),
425 mUserDefined(node.mUserDefined),
426 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300427 mUseEmulatedFunction(node.mUseEmulatedFunction),
428 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
429{
430 for (TIntermNode *child : node.mSequence)
431 {
432 TIntermTyped *typedChild = child->getAsTyped();
433 ASSERT(typedChild != nullptr);
434 TIntermTyped *childCopy = typedChild->deepCopy();
435 mSequence.push_back(childCopy);
436 }
437}
438
439TIntermBinary::TIntermBinary(const TIntermBinary &node)
440 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
441{
442 TIntermTyped *leftCopy = node.mLeft->deepCopy();
443 TIntermTyped *rightCopy = node.mRight->deepCopy();
444 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
445 mLeft = leftCopy;
446 mRight = rightCopy;
447}
448
449TIntermUnary::TIntermUnary(const TIntermUnary &node)
450 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
451{
452 TIntermTyped *operandCopy = node.mOperand->deepCopy();
453 ASSERT(operandCopy != nullptr);
454 mOperand = operandCopy;
455}
456
457TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
458{
459 // Only supported for ternary nodes, not if statements.
460 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
461 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
462 ASSERT(trueTyped != nullptr);
463 ASSERT(falseTyped != nullptr);
464 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
465 TIntermTyped *trueCopy = trueTyped->deepCopy();
466 TIntermTyped *falseCopy = falseTyped->deepCopy();
467 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
468 mCondition = conditionCopy;
469 mTrueBlock = trueCopy;
470 mFalseBlock = falseCopy;
471}
472
Jamie Madillb1a85f42014-08-19 15:23:24 -0400473bool TIntermOperator::isAssignment() const
474{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300475 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400476}
477
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300478bool TIntermOperator::isMultiplication() const
479{
480 switch (mOp)
481 {
482 case EOpMul:
483 case EOpMatrixTimesMatrix:
484 case EOpMatrixTimesVector:
485 case EOpMatrixTimesScalar:
486 case EOpVectorTimesMatrix:
487 case EOpVectorTimesScalar:
488 return true;
489 default:
490 return false;
491 }
492}
493
Jamie Madillb1a85f42014-08-19 15:23:24 -0400494//
495// returns true if the operator is for one of the constructors
496//
497bool TIntermOperator::isConstructor() const
498{
499 switch (mOp)
500 {
501 case EOpConstructVec2:
502 case EOpConstructVec3:
503 case EOpConstructVec4:
504 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400505 case EOpConstructMat2x3:
506 case EOpConstructMat2x4:
507 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400508 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400509 case EOpConstructMat3x4:
510 case EOpConstructMat4x2:
511 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400512 case EOpConstructMat4:
513 case EOpConstructFloat:
514 case EOpConstructIVec2:
515 case EOpConstructIVec3:
516 case EOpConstructIVec4:
517 case EOpConstructInt:
518 case EOpConstructUVec2:
519 case EOpConstructUVec3:
520 case EOpConstructUVec4:
521 case EOpConstructUInt:
522 case EOpConstructBVec2:
523 case EOpConstructBVec3:
524 case EOpConstructBVec4:
525 case EOpConstructBool:
526 case EOpConstructStruct:
527 return true;
528 default:
529 return false;
530 }
531}
532
Olli Etuaho1dded802016-08-18 18:13:13 +0300533TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
534{
535 if (left.isMatrix())
536 {
537 if (right.isMatrix())
538 {
539 return EOpMatrixTimesMatrix;
540 }
541 else
542 {
543 if (right.isVector())
544 {
545 return EOpMatrixTimesVector;
546 }
547 else
548 {
549 return EOpMatrixTimesScalar;
550 }
551 }
552 }
553 else
554 {
555 if (right.isMatrix())
556 {
557 if (left.isVector())
558 {
559 return EOpVectorTimesMatrix;
560 }
561 else
562 {
563 return EOpMatrixTimesScalar;
564 }
565 }
566 else
567 {
568 // Neither operand is a matrix.
569 if (left.isVector() == right.isVector())
570 {
571 // Leave as component product.
572 return EOpMul;
573 }
574 else
575 {
576 return EOpVectorTimesScalar;
577 }
578 }
579 }
580}
581
582TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
583{
584 if (left.isMatrix())
585 {
586 if (right.isMatrix())
587 {
588 return EOpMatrixTimesMatrixAssign;
589 }
590 else
591 {
592 // right should be scalar, but this may not be validated yet.
593 return EOpMatrixTimesScalarAssign;
594 }
595 }
596 else
597 {
598 if (right.isMatrix())
599 {
600 // Left should be a vector, but this may not be validated yet.
601 return EOpVectorTimesMatrixAssign;
602 }
603 else
604 {
605 // Neither operand is a matrix.
606 if (left.isVector() == right.isVector())
607 {
608 // Leave as component product.
609 return EOpMulAssign;
610 }
611 else
612 {
613 // left should be vector and right should be scalar, but this may not be validated
614 // yet.
615 return EOpVectorTimesScalarAssign;
616 }
617 }
618 }
619}
620
Jamie Madillb1a85f42014-08-19 15:23:24 -0400621//
622// Make sure the type of a unary operator is appropriate for its
623// combination of operation and operand type.
624//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200625void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400626{
627 switch (mOp)
628 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200629 case EOpFloatBitsToInt:
630 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200631 case EOpIntBitsToFloat:
632 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200633 case EOpPackSnorm2x16:
634 case EOpPackUnorm2x16:
635 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200636 case EOpUnpackSnorm2x16:
637 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200638 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530639 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200640 case EOpUnpackHalf2x16:
641 mType.setPrecision(EbpMedium);
642 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400643 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200644 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400645 }
646
Olli Etuahof6c694b2015-03-26 14:50:53 +0200647 if (funcReturnType != nullptr)
648 {
649 if (funcReturnType->getBasicType() == EbtBool)
650 {
651 // Bool types should not have precision.
652 setType(*funcReturnType);
653 }
654 else
655 {
656 // Precision of the node has been set based on the operand.
657 setTypePreservePrecision(*funcReturnType);
658 }
659 }
660
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200661 if (mOperand->getQualifier() == EvqConst)
662 mType.setQualifier(EvqConst);
663 else
664 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400665}
666
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300667TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
668 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
669{
670 promote();
671}
672
Jamie Madillb1a85f42014-08-19 15:23:24 -0400673//
674// Establishes the type of the resultant operation, as well as
675// makes the operator the correct one for the operands.
676//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200677// For lots of operations it should already be established that the operand
678// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400679//
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300680void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400681{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200682 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400683
Olli Etuaho1dded802016-08-18 18:13:13 +0300684 ASSERT(!isMultiplication() ||
685 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
686
Jamie Madillb1a85f42014-08-19 15:23:24 -0400687 // Base assumption: just make the type the same as the left
688 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400689 setType(mLeft->getType());
690
691 // The result gets promoted to the highest precision.
692 TPrecision higherPrecision = GetHigherPrecision(
693 mLeft->getPrecision(), mRight->getPrecision());
694 getTypePointer()->setPrecision(higherPrecision);
695
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200696 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400697 // Binary operations results in temporary variables unless both
698 // operands are const.
699 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
700 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200701 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400702 getTypePointer()->setQualifier(EvqTemporary);
703 }
704
705 const int nominalSize =
706 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
707
708 //
709 // All scalars or structs. Code after this test assumes this case is removed!
710 //
711 if (nominalSize == 1)
712 {
713 switch (mOp)
714 {
715 //
716 // Promote to conditional
717 //
718 case EOpEqual:
719 case EOpNotEqual:
720 case EOpLessThan:
721 case EOpGreaterThan:
722 case EOpLessThanEqual:
723 case EOpGreaterThanEqual:
724 setType(TType(EbtBool, EbpUndefined));
725 break;
726
727 //
728 // And and Or operate on conditionals
729 //
730 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200731 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400732 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200733 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400734 setType(TType(EbtBool, EbpUndefined));
735 break;
736
737 default:
738 break;
739 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300740 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400741 }
742
743 // If we reach here, at least one of the operands is vector or matrix.
744 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400745 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300746
Jamie Madillb1a85f42014-08-19 15:23:24 -0400747 switch (mOp)
748 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300749 case EOpMul:
750 break;
751 case EOpMatrixTimesScalar:
752 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400753 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200754 setType(TType(basicType, higherPrecision, resultQualifier,
755 static_cast<unsigned char>(mRight->getCols()),
756 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400757 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300758 break;
759 case EOpMatrixTimesVector:
760 setType(TType(basicType, higherPrecision, resultQualifier,
761 static_cast<unsigned char>(mLeft->getRows()), 1));
762 break;
763 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200764 setType(TType(basicType, higherPrecision, resultQualifier,
765 static_cast<unsigned char>(mRight->getCols()),
766 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300767 break;
768 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200769 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300770 static_cast<unsigned char>(nominalSize), 1));
771 break;
772 case EOpVectorTimesMatrix:
773 setType(TType(basicType, higherPrecision, resultQualifier,
774 static_cast<unsigned char>(mRight->getCols()), 1));
775 break;
776 case EOpMulAssign:
777 case EOpVectorTimesScalarAssign:
778 case EOpVectorTimesMatrixAssign:
779 case EOpMatrixTimesScalarAssign:
780 case EOpMatrixTimesMatrixAssign:
781 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
782 break;
783 case EOpAssign:
784 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300785 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
786 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
787 break;
788 case EOpAdd:
789 case EOpSub:
790 case EOpDiv:
791 case EOpIMod:
792 case EOpBitShiftLeft:
793 case EOpBitShiftRight:
794 case EOpBitwiseAnd:
795 case EOpBitwiseXor:
796 case EOpBitwiseOr:
797 case EOpAddAssign:
798 case EOpSubAssign:
799 case EOpDivAssign:
800 case EOpIModAssign:
801 case EOpBitShiftLeftAssign:
802 case EOpBitShiftRightAssign:
803 case EOpBitwiseAndAssign:
804 case EOpBitwiseXorAssign:
805 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300806 {
807 const int secondarySize =
808 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
809 setType(TType(basicType, higherPrecision, resultQualifier,
810 static_cast<unsigned char>(nominalSize),
811 static_cast<unsigned char>(secondarySize)));
812 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300813 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300814 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300815 case EOpEqual:
816 case EOpNotEqual:
817 case EOpLessThan:
818 case EOpGreaterThan:
819 case EOpLessThanEqual:
820 case EOpGreaterThanEqual:
821 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
822 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300823 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300824 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400825
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300826 case EOpIndexDirect:
827 case EOpIndexIndirect:
828 case EOpIndexDirectInterfaceBlock:
829 case EOpIndexDirectStruct:
830 // TODO (oetuaho): These ops could be handled here as well (should be done closer to the
831 // top of the function).
832 UNREACHABLE();
833 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300834 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300835 UNREACHABLE();
836 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400837 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400838}
839
Olli Etuaho3fdec912016-08-18 15:08:06 +0300840TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300841{
842 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
843 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
844 if (leftConstant == nullptr || rightConstant == nullptr)
845 {
846 return nullptr;
847 }
Olli Etuaho3fdec912016-08-18 15:08:06 +0300848 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200849
850 // Nodes may be constant folded without being qualified as constant.
851 TQualifier resultQualifier = EvqConst;
852 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
853 {
854 resultQualifier = EvqTemporary;
855 }
856 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300857}
858
Olli Etuaho95310b02015-06-02 17:43:38 +0300859TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
860{
861 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
862 if (operandConstant == nullptr)
863 {
864 return nullptr;
865 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530866
867 TConstantUnion *constArray = nullptr;
868 switch (mOp)
869 {
870 case EOpAny:
871 case EOpAll:
872 case EOpLength:
873 case EOpTranspose:
874 case EOpDeterminant:
875 case EOpInverse:
876 case EOpPackSnorm2x16:
877 case EOpUnpackSnorm2x16:
878 case EOpPackUnorm2x16:
879 case EOpUnpackUnorm2x16:
880 case EOpPackHalf2x16:
881 case EOpUnpackHalf2x16:
882 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
883 break;
884 default:
885 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
886 break;
887 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200888
889 // Nodes may be constant folded without being qualified as constant.
890 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
891 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300892}
893
894TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
895{
896 // Make sure that all params are constant before actual constant folding.
897 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300898 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300899 if (param->getAsConstantUnion() == nullptr)
900 {
901 return nullptr;
902 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300903 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200904 TConstantUnion *constArray = nullptr;
905 if (isConstructor())
906 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
907 else
908 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200909
910 // Nodes may be constant folded without being qualified as constant.
911 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
912 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300913}
914
Jamie Madillb1a85f42014-08-19 15:23:24 -0400915//
916// The fold functions see if an operation on a constant can be done in place,
917// without generating run-time code.
918//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300919// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400920//
Olli Etuaho3fdec912016-08-18 15:08:06 +0300921TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
922 TIntermConstantUnion *rightNode,
923 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300924{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200925 const TConstantUnion *leftArray = getUnionArrayPointer();
926 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300927
928 if (!leftArray)
929 return nullptr;
930 if (!rightArray)
931 return nullptr;
932
933 size_t objectSize = getType().getObjectSize();
934
935 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
936 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
937 {
938 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
939 }
940 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
941 {
942 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
943 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
944 objectSize = rightNode->getType().getObjectSize();
945 }
946
947 TConstantUnion *resultArray = nullptr;
948
949 switch(op)
950 {
951 case EOpAdd:
952 resultArray = new TConstantUnion[objectSize];
953 for (size_t i = 0; i < objectSize; i++)
954 resultArray[i] = leftArray[i] + rightArray[i];
955 break;
956 case EOpSub:
957 resultArray = new TConstantUnion[objectSize];
958 for (size_t i = 0; i < objectSize; i++)
959 resultArray[i] = leftArray[i] - rightArray[i];
960 break;
961
962 case EOpMul:
963 case EOpVectorTimesScalar:
964 case EOpMatrixTimesScalar:
965 resultArray = new TConstantUnion[objectSize];
966 for (size_t i = 0; i < objectSize; i++)
967 resultArray[i] = leftArray[i] * rightArray[i];
968 break;
969
970 case EOpMatrixTimesMatrix:
971 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300972 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300973
974 const int leftCols = getCols();
975 const int leftRows = getRows();
976 const int rightCols = rightNode->getType().getCols();
977 const int rightRows = rightNode->getType().getRows();
978 const int resultCols = rightCols;
979 const int resultRows = leftRows;
980
981 resultArray = new TConstantUnion[resultCols * resultRows];
982 for (int row = 0; row < resultRows; row++)
983 {
984 for (int column = 0; column < resultCols; column++)
985 {
986 resultArray[resultRows * column + row].setFConst(0.0f);
987 for (int i = 0; i < leftCols; i++)
988 {
989 resultArray[resultRows * column + row].setFConst(
990 resultArray[resultRows * column + row].getFConst() +
991 leftArray[i * leftRows + row].getFConst() *
992 rightArray[column * rightRows + i].getFConst());
993 }
994 }
995 }
996 }
997 break;
998
999 case EOpDiv:
1000 case EOpIMod:
1001 {
1002 resultArray = new TConstantUnion[objectSize];
1003 for (size_t i = 0; i < objectSize; i++)
1004 {
1005 switch (getType().getBasicType())
1006 {
1007 case EbtFloat:
1008 if (rightArray[i] == 0.0f)
1009 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001010 diagnostics->warning(
1011 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001012 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
1013 }
1014 else
1015 {
1016 ASSERT(op == EOpDiv);
1017 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
1018 }
1019 break;
1020
1021 case EbtInt:
1022 if (rightArray[i] == 0)
1023 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001024 diagnostics->warning(
1025 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001026 resultArray[i].setIConst(INT_MAX);
1027 }
1028 else
1029 {
1030 if (op == EOpDiv)
1031 {
1032 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
1033 }
1034 else
1035 {
1036 ASSERT(op == EOpIMod);
1037 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
1038 }
1039 }
1040 break;
1041
1042 case EbtUInt:
1043 if (rightArray[i] == 0)
1044 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001045 diagnostics->warning(
1046 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001047 resultArray[i].setUConst(UINT_MAX);
1048 }
1049 else
1050 {
1051 if (op == EOpDiv)
1052 {
1053 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
1054 }
1055 else
1056 {
1057 ASSERT(op == EOpIMod);
1058 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1059 }
1060 }
1061 break;
1062
1063 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001064 UNREACHABLE();
1065 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001066 }
1067 }
1068 }
1069 break;
1070
1071 case EOpMatrixTimesVector:
1072 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001073 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001074
1075 const int matrixCols = getCols();
1076 const int matrixRows = getRows();
1077
1078 resultArray = new TConstantUnion[matrixRows];
1079
1080 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1081 {
1082 resultArray[matrixRow].setFConst(0.0f);
1083 for (int col = 0; col < matrixCols; col++)
1084 {
1085 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1086 leftArray[col * matrixRows + matrixRow].getFConst() *
1087 rightArray[col].getFConst());
1088 }
1089 }
1090 }
1091 break;
1092
1093 case EOpVectorTimesMatrix:
1094 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001095 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001096
1097 const int matrixCols = rightNode->getType().getCols();
1098 const int matrixRows = rightNode->getType().getRows();
1099
1100 resultArray = new TConstantUnion[matrixCols];
1101
1102 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1103 {
1104 resultArray[matrixCol].setFConst(0.0f);
1105 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1106 {
1107 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1108 leftArray[matrixRow].getFConst() *
1109 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1110 }
1111 }
1112 }
1113 break;
1114
1115 case EOpLogicalAnd:
1116 {
1117 resultArray = new TConstantUnion[objectSize];
1118 for (size_t i = 0; i < objectSize; i++)
1119 {
1120 resultArray[i] = leftArray[i] && rightArray[i];
1121 }
1122 }
1123 break;
1124
1125 case EOpLogicalOr:
1126 {
1127 resultArray = new TConstantUnion[objectSize];
1128 for (size_t i = 0; i < objectSize; i++)
1129 {
1130 resultArray[i] = leftArray[i] || rightArray[i];
1131 }
1132 }
1133 break;
1134
1135 case EOpLogicalXor:
1136 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001137 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001138 resultArray = new TConstantUnion[objectSize];
1139 for (size_t i = 0; i < objectSize; i++)
1140 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001141 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001142 }
1143 }
1144 break;
1145
1146 case EOpBitwiseAnd:
1147 resultArray = new TConstantUnion[objectSize];
1148 for (size_t i = 0; i < objectSize; i++)
1149 resultArray[i] = leftArray[i] & rightArray[i];
1150 break;
1151 case EOpBitwiseXor:
1152 resultArray = new TConstantUnion[objectSize];
1153 for (size_t i = 0; i < objectSize; i++)
1154 resultArray[i] = leftArray[i] ^ rightArray[i];
1155 break;
1156 case EOpBitwiseOr:
1157 resultArray = new TConstantUnion[objectSize];
1158 for (size_t i = 0; i < objectSize; i++)
1159 resultArray[i] = leftArray[i] | rightArray[i];
1160 break;
1161 case EOpBitShiftLeft:
1162 resultArray = new TConstantUnion[objectSize];
1163 for (size_t i = 0; i < objectSize; i++)
1164 resultArray[i] = leftArray[i] << rightArray[i];
1165 break;
1166 case EOpBitShiftRight:
1167 resultArray = new TConstantUnion[objectSize];
1168 for (size_t i = 0; i < objectSize; i++)
1169 resultArray[i] = leftArray[i] >> rightArray[i];
1170 break;
1171
1172 case EOpLessThan:
1173 ASSERT(objectSize == 1);
1174 resultArray = new TConstantUnion[1];
1175 resultArray->setBConst(*leftArray < *rightArray);
1176 break;
1177
1178 case EOpGreaterThan:
1179 ASSERT(objectSize == 1);
1180 resultArray = new TConstantUnion[1];
1181 resultArray->setBConst(*leftArray > *rightArray);
1182 break;
1183
1184 case EOpLessThanEqual:
1185 ASSERT(objectSize == 1);
1186 resultArray = new TConstantUnion[1];
1187 resultArray->setBConst(!(*leftArray > *rightArray));
1188 break;
1189
1190 case EOpGreaterThanEqual:
1191 ASSERT(objectSize == 1);
1192 resultArray = new TConstantUnion[1];
1193 resultArray->setBConst(!(*leftArray < *rightArray));
1194 break;
1195
1196 case EOpEqual:
1197 case EOpNotEqual:
1198 {
1199 resultArray = new TConstantUnion[1];
1200 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001201 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001202 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001203 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001204 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001205 equal = false;
1206 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001207 }
1208 }
1209 if (op == EOpEqual)
1210 {
1211 resultArray->setBConst(equal);
1212 }
1213 else
1214 {
1215 resultArray->setBConst(!equal);
1216 }
1217 }
1218 break;
1219
1220 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001221 UNREACHABLE();
1222 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001223 }
1224 return resultArray;
1225}
1226
1227//
1228// The fold functions see if an operation on a constant can be done in place,
1229// without generating run-time code.
1230//
Olli Etuaho95310b02015-06-02 17:43:38 +03001231// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001232//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301233TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001234{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301235 //
1236 // Do operations where the return type has a different number of components compared to the operand type.
1237 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001238
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001239 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301240 if (!operandArray)
1241 return nullptr;
1242
1243 size_t objectSize = getType().getObjectSize();
1244 TConstantUnion *resultArray = nullptr;
1245 switch (op)
1246 {
1247 case EOpAny:
1248 if (getType().getBasicType() == EbtBool)
1249 {
1250 resultArray = new TConstantUnion();
1251 resultArray->setBConst(false);
1252 for (size_t i = 0; i < objectSize; i++)
1253 {
1254 if (operandArray[i].getBConst())
1255 {
1256 resultArray->setBConst(true);
1257 break;
1258 }
1259 }
1260 break;
1261 }
1262 else
1263 {
1264 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1265 return nullptr;
1266 }
1267
1268 case EOpAll:
1269 if (getType().getBasicType() == EbtBool)
1270 {
1271 resultArray = new TConstantUnion();
1272 resultArray->setBConst(true);
1273 for (size_t i = 0; i < objectSize; i++)
1274 {
1275 if (!operandArray[i].getBConst())
1276 {
1277 resultArray->setBConst(false);
1278 break;
1279 }
1280 }
1281 break;
1282 }
1283 else
1284 {
1285 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1286 return nullptr;
1287 }
1288
1289 case EOpLength:
1290 if (getType().getBasicType() == EbtFloat)
1291 {
1292 resultArray = new TConstantUnion();
1293 resultArray->setFConst(VectorLength(operandArray, objectSize));
1294 break;
1295 }
1296 else
1297 {
1298 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1299 return nullptr;
1300 }
1301
1302 case EOpTranspose:
1303 if (getType().getBasicType() == EbtFloat)
1304 {
1305 resultArray = new TConstantUnion[objectSize];
1306 angle::Matrix<float> result =
Olli Etuahod5da5052016-08-29 13:16:55 +03001307 GetMatrix(operandArray, getType().getRows(), getType().getCols()).transpose();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301308 SetUnionArrayFromMatrix(result, resultArray);
1309 break;
1310 }
1311 else
1312 {
1313 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1314 return nullptr;
1315 }
1316
1317 case EOpDeterminant:
1318 if (getType().getBasicType() == EbtFloat)
1319 {
1320 unsigned int size = getType().getNominalSize();
1321 ASSERT(size >= 2 && size <= 4);
1322 resultArray = new TConstantUnion();
1323 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1324 break;
1325 }
1326 else
1327 {
1328 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1329 return nullptr;
1330 }
1331
1332 case EOpInverse:
1333 if (getType().getBasicType() == EbtFloat)
1334 {
1335 unsigned int size = getType().getNominalSize();
1336 ASSERT(size >= 2 && size <= 4);
1337 resultArray = new TConstantUnion[objectSize];
1338 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1339 SetUnionArrayFromMatrix(result, resultArray);
1340 break;
1341 }
1342 else
1343 {
1344 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1345 return nullptr;
1346 }
1347
1348 case EOpPackSnorm2x16:
1349 if (getType().getBasicType() == EbtFloat)
1350 {
1351 ASSERT(getType().getNominalSize() == 2);
1352 resultArray = new TConstantUnion();
1353 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1354 break;
1355 }
1356 else
1357 {
1358 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1359 return nullptr;
1360 }
1361
1362 case EOpUnpackSnorm2x16:
1363 if (getType().getBasicType() == EbtUInt)
1364 {
1365 resultArray = new TConstantUnion[2];
1366 float f1, f2;
1367 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1368 resultArray[0].setFConst(f1);
1369 resultArray[1].setFConst(f2);
1370 break;
1371 }
1372 else
1373 {
1374 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1375 return nullptr;
1376 }
1377
1378 case EOpPackUnorm2x16:
1379 if (getType().getBasicType() == EbtFloat)
1380 {
1381 ASSERT(getType().getNominalSize() == 2);
1382 resultArray = new TConstantUnion();
1383 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1384 break;
1385 }
1386 else
1387 {
1388 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1389 return nullptr;
1390 }
1391
1392 case EOpUnpackUnorm2x16:
1393 if (getType().getBasicType() == EbtUInt)
1394 {
1395 resultArray = new TConstantUnion[2];
1396 float f1, f2;
1397 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1398 resultArray[0].setFConst(f1);
1399 resultArray[1].setFConst(f2);
1400 break;
1401 }
1402 else
1403 {
1404 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1405 return nullptr;
1406 }
1407
1408 case EOpPackHalf2x16:
1409 if (getType().getBasicType() == EbtFloat)
1410 {
1411 ASSERT(getType().getNominalSize() == 2);
1412 resultArray = new TConstantUnion();
1413 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1414 break;
1415 }
1416 else
1417 {
1418 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1419 return nullptr;
1420 }
1421
1422 case EOpUnpackHalf2x16:
1423 if (getType().getBasicType() == EbtUInt)
1424 {
1425 resultArray = new TConstantUnion[2];
1426 float f1, f2;
1427 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1428 resultArray[0].setFConst(f1);
1429 resultArray[1].setFConst(f2);
1430 break;
1431 }
1432 else
1433 {
1434 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1435 return nullptr;
1436 }
1437 break;
1438
1439 default:
1440 break;
1441 }
1442
1443 return resultArray;
1444}
1445
1446TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1447{
1448 //
1449 // Do unary operations where the return type is the same as operand type.
1450 //
1451
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001452 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001453 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301454 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001455
1456 size_t objectSize = getType().getObjectSize();
1457
Arun Patoleab2b9a22015-07-06 18:27:56 +05301458 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1459 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301460 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301461 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301462 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301463 case EOpNegative:
1464 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301465 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301466 case EbtFloat:
1467 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301468 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301469 case EbtInt:
1470 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301471 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301472 case EbtUInt:
1473 resultArray[i].setUConst(static_cast<unsigned int>(
1474 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301475 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301476 default:
1477 infoSink.info.message(
1478 EPrefixInternalError, getLine(),
1479 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301480 return nullptr;
1481 }
1482 break;
1483
Arun Patoleab2b9a22015-07-06 18:27:56 +05301484 case EOpPositive:
1485 switch (getType().getBasicType())
1486 {
1487 case EbtFloat:
1488 resultArray[i].setFConst(operandArray[i].getFConst());
1489 break;
1490 case EbtInt:
1491 resultArray[i].setIConst(operandArray[i].getIConst());
1492 break;
1493 case EbtUInt:
1494 resultArray[i].setUConst(static_cast<unsigned int>(
1495 static_cast<int>(operandArray[i].getUConst())));
1496 break;
1497 default:
1498 infoSink.info.message(
1499 EPrefixInternalError, getLine(),
1500 "Unary operation not folded into constant");
1501 return nullptr;
1502 }
1503 break;
1504
1505 case EOpLogicalNot:
1506 // this code is written for possible future use,
1507 // will not get executed currently
1508 switch (getType().getBasicType())
1509 {
1510 case EbtBool:
1511 resultArray[i].setBConst(!operandArray[i].getBConst());
1512 break;
1513 default:
1514 infoSink.info.message(
1515 EPrefixInternalError, getLine(),
1516 "Unary operation not folded into constant");
1517 return nullptr;
1518 }
1519 break;
1520
1521 case EOpBitwiseNot:
1522 switch (getType().getBasicType())
1523 {
1524 case EbtInt:
1525 resultArray[i].setIConst(~operandArray[i].getIConst());
1526 break;
1527 case EbtUInt:
1528 resultArray[i].setUConst(~operandArray[i].getUConst());
1529 break;
1530 default:
1531 infoSink.info.message(
1532 EPrefixInternalError, getLine(),
1533 "Unary operation not folded into constant");
1534 return nullptr;
1535 }
1536 break;
1537
1538 case EOpRadians:
1539 if (getType().getBasicType() == EbtFloat)
1540 {
1541 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1542 break;
1543 }
1544 infoSink.info.message(
1545 EPrefixInternalError, getLine(),
1546 "Unary operation not folded into constant");
1547 return nullptr;
1548
1549 case EOpDegrees:
1550 if (getType().getBasicType() == EbtFloat)
1551 {
1552 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1553 break;
1554 }
1555 infoSink.info.message(
1556 EPrefixInternalError, getLine(),
1557 "Unary operation not folded into constant");
1558 return nullptr;
1559
1560 case EOpSin:
1561 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1562 return nullptr;
1563 break;
1564
1565 case EOpCos:
1566 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1567 return nullptr;
1568 break;
1569
1570 case EOpTan:
1571 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1572 return nullptr;
1573 break;
1574
1575 case EOpAsin:
1576 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1577 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1578 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1579 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1580 return nullptr;
1581 break;
1582
1583 case EOpAcos:
1584 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1585 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1586 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1587 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1588 return nullptr;
1589 break;
1590
1591 case EOpAtan:
1592 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1593 return nullptr;
1594 break;
1595
1596 case EOpSinh:
1597 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1598 return nullptr;
1599 break;
1600
1601 case EOpCosh:
1602 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1603 return nullptr;
1604 break;
1605
1606 case EOpTanh:
1607 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1608 return nullptr;
1609 break;
1610
1611 case EOpAsinh:
1612 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1613 return nullptr;
1614 break;
1615
1616 case EOpAcosh:
1617 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1618 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1619 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1620 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1621 return nullptr;
1622 break;
1623
1624 case EOpAtanh:
1625 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1626 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1627 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1628 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1629 return nullptr;
1630 break;
1631
1632 case EOpAbs:
1633 switch (getType().getBasicType())
1634 {
1635 case EbtFloat:
1636 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1637 break;
1638 case EbtInt:
1639 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1640 break;
1641 default:
1642 infoSink.info.message(
1643 EPrefixInternalError, getLine(),
1644 "Unary operation not folded into constant");
1645 return nullptr;
1646 }
1647 break;
1648
1649 case EOpSign:
1650 switch (getType().getBasicType())
1651 {
1652 case EbtFloat:
1653 {
1654 float fConst = operandArray[i].getFConst();
1655 float fResult = 0.0f;
1656 if (fConst > 0.0f)
1657 fResult = 1.0f;
1658 else if (fConst < 0.0f)
1659 fResult = -1.0f;
1660 resultArray[i].setFConst(fResult);
1661 }
1662 break;
1663 case EbtInt:
1664 {
1665 int iConst = operandArray[i].getIConst();
1666 int iResult = 0;
1667 if (iConst > 0)
1668 iResult = 1;
1669 else if (iConst < 0)
1670 iResult = -1;
1671 resultArray[i].setIConst(iResult);
1672 }
1673 break;
1674 default:
1675 infoSink.info.message(
1676 EPrefixInternalError, getLine(),
1677 "Unary operation not folded into constant");
1678 return nullptr;
1679 }
1680 break;
1681
1682 case EOpFloor:
1683 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1684 return nullptr;
1685 break;
1686
1687 case EOpTrunc:
1688 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1689 return nullptr;
1690 break;
1691
1692 case EOpRound:
1693 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1694 return nullptr;
1695 break;
1696
1697 case EOpRoundEven:
1698 if (getType().getBasicType() == EbtFloat)
1699 {
1700 float x = operandArray[i].getFConst();
1701 float result;
1702 float fractPart = modff(x, &result);
1703 if (fabsf(fractPart) == 0.5f)
1704 result = 2.0f * roundf(x / 2.0f);
1705 else
1706 result = roundf(x);
1707 resultArray[i].setFConst(result);
1708 break;
1709 }
1710 infoSink.info.message(
1711 EPrefixInternalError, getLine(),
1712 "Unary operation not folded into constant");
1713 return nullptr;
1714
1715 case EOpCeil:
1716 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1717 return nullptr;
1718 break;
1719
1720 case EOpFract:
1721 if (getType().getBasicType() == EbtFloat)
1722 {
1723 float x = operandArray[i].getFConst();
1724 resultArray[i].setFConst(x - floorf(x));
1725 break;
1726 }
1727 infoSink.info.message(
1728 EPrefixInternalError, getLine(),
1729 "Unary operation not folded into constant");
1730 return nullptr;
1731
Arun Patole551279e2015-07-07 18:18:23 +05301732 case EOpIsNan:
1733 if (getType().getBasicType() == EbtFloat)
1734 {
1735 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1736 break;
1737 }
1738 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1739 return nullptr;
1740
1741 case EOpIsInf:
1742 if (getType().getBasicType() == EbtFloat)
1743 {
1744 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1745 break;
1746 }
1747 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1748 return nullptr;
1749
1750 case EOpFloatBitsToInt:
1751 if (getType().getBasicType() == EbtFloat)
1752 {
1753 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1754 break;
1755 }
1756 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1757 return nullptr;
1758
1759 case EOpFloatBitsToUint:
1760 if (getType().getBasicType() == EbtFloat)
1761 {
1762 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1763 break;
1764 }
1765 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1766 return nullptr;
1767
1768 case EOpIntBitsToFloat:
1769 if (getType().getBasicType() == EbtInt)
1770 {
1771 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1772 break;
1773 }
1774 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1775 return nullptr;
1776
1777 case EOpUintBitsToFloat:
1778 if (getType().getBasicType() == EbtUInt)
1779 {
1780 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1781 break;
1782 }
1783 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1784 return nullptr;
1785
Arun Patoleab2b9a22015-07-06 18:27:56 +05301786 case EOpExp:
1787 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1788 return nullptr;
1789 break;
1790
1791 case EOpLog:
1792 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1793 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1794 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1795 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1796 return nullptr;
1797 break;
1798
1799 case EOpExp2:
1800 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1801 return nullptr;
1802 break;
1803
1804 case EOpLog2:
1805 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1806 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1807 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1808 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1809 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1810 return nullptr;
1811 else
1812 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1813 break;
1814
1815 case EOpSqrt:
1816 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1817 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1818 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1819 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1820 return nullptr;
1821 break;
1822
1823 case EOpInverseSqrt:
1824 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1825 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1826 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1827 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1828 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1829 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1830 return nullptr;
1831 else
1832 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1833 break;
1834
1835 case EOpVectorLogicalNot:
1836 if (getType().getBasicType() == EbtBool)
1837 {
1838 resultArray[i].setBConst(!operandArray[i].getBConst());
1839 break;
1840 }
1841 infoSink.info.message(
1842 EPrefixInternalError, getLine(),
1843 "Unary operation not folded into constant");
1844 return nullptr;
1845
1846 case EOpNormalize:
1847 if (getType().getBasicType() == EbtFloat)
1848 {
1849 float x = operandArray[i].getFConst();
1850 float length = VectorLength(operandArray, objectSize);
1851 if (length)
1852 resultArray[i].setFConst(x / length);
1853 else
1854 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1855 &resultArray[i]);
1856 break;
1857 }
1858 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1859 return nullptr;
1860
Arun Patole0c5409f2015-07-08 15:17:53 +05301861 case EOpDFdx:
1862 case EOpDFdy:
1863 case EOpFwidth:
1864 if (getType().getBasicType() == EbtFloat)
1865 {
1866 // Derivatives of constant arguments should be 0.
1867 resultArray[i].setFConst(0.0f);
1868 break;
1869 }
1870 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1871 return nullptr;
1872
Arun Patole1155ddd2015-06-05 18:04:36 +05301873 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301874 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301875 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301876 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001877
Arun Patoleab2b9a22015-07-06 18:27:56 +05301878 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001879}
1880
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001881bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1882 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301883{
1884 ASSERT(builtinFunc);
1885
1886 if (getType().getBasicType() == EbtFloat)
1887 {
1888 result->setFConst(builtinFunc(parameter.getFConst()));
1889 return true;
1890 }
1891
1892 infoSink.info.message(
1893 EPrefixInternalError, getLine(),
1894 "Unary operation not folded into constant");
1895 return false;
1896}
1897
Jamie Madillb1a85f42014-08-19 15:23:24 -04001898// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001899TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1900 TInfoSink &infoSink)
1901{
1902 ASSERT(aggregate->getSequence()->size() > 0u);
1903 size_t resultSize = aggregate->getType().getObjectSize();
1904 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1905 TBasicType basicType = aggregate->getBasicType();
1906
1907 size_t resultIndex = 0u;
1908
1909 if (aggregate->getSequence()->size() == 1u)
1910 {
1911 TIntermNode *argument = aggregate->getSequence()->front();
1912 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1913 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1914 // Check the special case of constructing a matrix diagonal from a single scalar,
1915 // or a vector from a single scalar.
1916 if (argumentConstant->getType().getObjectSize() == 1u)
1917 {
1918 if (aggregate->isMatrix())
1919 {
1920 int resultCols = aggregate->getType().getCols();
1921 int resultRows = aggregate->getType().getRows();
1922 for (int col = 0; col < resultCols; ++col)
1923 {
1924 for (int row = 0; row < resultRows; ++row)
1925 {
1926 if (col == row)
1927 {
1928 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1929 }
1930 else
1931 {
1932 resultArray[resultIndex].setFConst(0.0f);
1933 }
1934 ++resultIndex;
1935 }
1936 }
1937 }
1938 else
1939 {
1940 while (resultIndex < resultSize)
1941 {
1942 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1943 ++resultIndex;
1944 }
1945 }
1946 ASSERT(resultIndex == resultSize);
1947 return resultArray;
1948 }
1949 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1950 {
1951 // The special case of constructing a matrix from a matrix.
1952 int argumentCols = argumentConstant->getType().getCols();
1953 int argumentRows = argumentConstant->getType().getRows();
1954 int resultCols = aggregate->getType().getCols();
1955 int resultRows = aggregate->getType().getRows();
1956 for (int col = 0; col < resultCols; ++col)
1957 {
1958 for (int row = 0; row < resultRows; ++row)
1959 {
1960 if (col < argumentCols && row < argumentRows)
1961 {
1962 resultArray[resultIndex].cast(basicType,
1963 argumentUnionArray[col * argumentRows + row]);
1964 }
1965 else if (col == row)
1966 {
1967 resultArray[resultIndex].setFConst(1.0f);
1968 }
1969 else
1970 {
1971 resultArray[resultIndex].setFConst(0.0f);
1972 }
1973 ++resultIndex;
1974 }
1975 }
1976 ASSERT(resultIndex == resultSize);
1977 return resultArray;
1978 }
1979 }
1980
1981 for (TIntermNode *&argument : *aggregate->getSequence())
1982 {
1983 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1984 size_t argumentSize = argumentConstant->getType().getObjectSize();
1985 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1986 for (size_t i = 0u; i < argumentSize; ++i)
1987 {
1988 if (resultIndex >= resultSize)
1989 break;
1990 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1991 ++resultIndex;
1992 }
1993 }
1994 ASSERT(resultIndex == resultSize);
1995 return resultArray;
1996}
1997
1998// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001999TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05302000{
Olli Etuahob43846e2015-06-02 18:18:57 +03002001 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05302002 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002003 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02002004 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05302005 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03002006 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05302007 TBasicType basicType = EbtVoid;
2008 TSourceLoc loc;
2009 for (unsigned int i = 0; i < paramsCount; i++)
2010 {
2011 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03002012 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05302013
2014 if (i == 0)
2015 {
2016 basicType = paramConstant->getType().getBasicType();
2017 loc = paramConstant->getLine();
2018 }
2019 unionArrays[i] = paramConstant->getUnionArrayPointer();
2020 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03002021 if (objectSizes[i] > maxObjectSize)
2022 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05302023 }
2024
Olli Etuahod5da5052016-08-29 13:16:55 +03002025 if (!(*sequence)[0]->getAsTyped()->isMatrix() && aggregate->getOp() != EOpOuterProduct)
Arun Patole7fa33552015-06-10 15:15:18 +05302026 {
2027 for (unsigned int i = 0; i < paramsCount; i++)
2028 if (objectSizes[i] != maxObjectSize)
2029 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
2030 }
Arun Patole274f0702015-05-05 13:33:30 +05302031
Olli Etuahob43846e2015-06-02 18:18:57 +03002032 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05302033 if (paramsCount == 2)
2034 {
2035 //
2036 // Binary built-in
2037 //
2038 switch (op)
2039 {
Arun Patolebf790422015-05-18 17:53:04 +05302040 case EOpAtan:
2041 {
2042 if (basicType == EbtFloat)
2043 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002044 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302045 for (size_t i = 0; i < maxObjectSize; i++)
2046 {
2047 float y = unionArrays[0][i].getFConst();
2048 float x = unionArrays[1][i].getFConst();
2049 // Results are undefined if x and y are both 0.
2050 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002051 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302052 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002053 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05302054 }
2055 }
2056 else
2057 UNREACHABLE();
2058 }
2059 break;
2060
2061 case EOpPow:
2062 {
2063 if (basicType == EbtFloat)
2064 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002065 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302066 for (size_t i = 0; i < maxObjectSize; i++)
2067 {
2068 float x = unionArrays[0][i].getFConst();
2069 float y = unionArrays[1][i].getFConst();
2070 // Results are undefined if x < 0.
2071 // Results are undefined if x = 0 and y <= 0.
2072 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002073 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302074 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002075 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302076 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002077 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05302078 }
2079 }
2080 else
2081 UNREACHABLE();
2082 }
2083 break;
2084
2085 case EOpMod:
2086 {
2087 if (basicType == EbtFloat)
2088 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002089 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302090 for (size_t i = 0; i < maxObjectSize; i++)
2091 {
2092 float x = unionArrays[0][i].getFConst();
2093 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002094 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302095 }
2096 }
2097 else
2098 UNREACHABLE();
2099 }
2100 break;
2101
Arun Patole274f0702015-05-05 13:33:30 +05302102 case EOpMin:
2103 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002104 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302105 for (size_t i = 0; i < maxObjectSize; i++)
2106 {
2107 switch (basicType)
2108 {
2109 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002110 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302111 break;
2112 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002113 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302114 break;
2115 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002116 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302117 break;
2118 default:
2119 UNREACHABLE();
2120 break;
2121 }
2122 }
2123 }
2124 break;
2125
2126 case EOpMax:
2127 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002128 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302129 for (size_t i = 0; i < maxObjectSize; i++)
2130 {
2131 switch (basicType)
2132 {
2133 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002134 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302135 break;
2136 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002137 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302138 break;
2139 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002140 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302141 break;
2142 default:
2143 UNREACHABLE();
2144 break;
2145 }
2146 }
2147 }
2148 break;
2149
Arun Patolebf790422015-05-18 17:53:04 +05302150 case EOpStep:
2151 {
2152 if (basicType == EbtFloat)
2153 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002154 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302155 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002156 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302157 }
2158 else
2159 UNREACHABLE();
2160 }
2161 break;
2162
Arun Patole9d0b1f92015-05-20 14:27:17 +05302163 case EOpLessThan:
2164 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002165 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302166 for (size_t i = 0; i < maxObjectSize; i++)
2167 {
2168 switch (basicType)
2169 {
2170 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002171 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302172 break;
2173 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002174 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302175 break;
2176 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002177 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302178 break;
2179 default:
2180 UNREACHABLE();
2181 break;
2182 }
2183 }
2184 }
2185 break;
2186
2187 case EOpLessThanEqual:
2188 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002189 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302190 for (size_t i = 0; i < maxObjectSize; i++)
2191 {
2192 switch (basicType)
2193 {
2194 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002195 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302196 break;
2197 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002198 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302199 break;
2200 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002201 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302202 break;
2203 default:
2204 UNREACHABLE();
2205 break;
2206 }
2207 }
2208 }
2209 break;
2210
2211 case EOpGreaterThan:
2212 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002213 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302214 for (size_t i = 0; i < maxObjectSize; i++)
2215 {
2216 switch (basicType)
2217 {
2218 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002219 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302220 break;
2221 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002222 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302223 break;
2224 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002225 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302226 break;
2227 default:
2228 UNREACHABLE();
2229 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002230 }
2231 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302232 }
2233 break;
2234
2235 case EOpGreaterThanEqual:
2236 {
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 {
2242 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002243 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302244 break;
2245 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002246 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302247 break;
2248 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002249 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302250 break;
2251 default:
2252 UNREACHABLE();
2253 break;
2254 }
2255 }
2256 }
2257 break;
2258
2259 case EOpVectorEqual:
2260 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002261 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302262 for (size_t i = 0; i < maxObjectSize; i++)
2263 {
2264 switch (basicType)
2265 {
2266 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002267 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302268 break;
2269 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002270 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302271 break;
2272 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002273 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302274 break;
2275 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002276 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302277 break;
2278 default:
2279 UNREACHABLE();
2280 break;
2281 }
2282 }
2283 }
2284 break;
2285
2286 case EOpVectorNotEqual:
2287 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002288 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302289 for (size_t i = 0; i < maxObjectSize; i++)
2290 {
2291 switch (basicType)
2292 {
2293 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002294 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302295 break;
2296 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002297 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302298 break;
2299 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002300 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302301 break;
2302 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002303 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302304 break;
2305 default:
2306 UNREACHABLE();
2307 break;
2308 }
2309 }
2310 }
2311 break;
2312
Arun Patole1155ddd2015-06-05 18:04:36 +05302313 case EOpDistance:
2314 if (basicType == EbtFloat)
2315 {
2316 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002317 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302318 for (size_t i = 0; i < maxObjectSize; i++)
2319 {
2320 float x = unionArrays[0][i].getFConst();
2321 float y = unionArrays[1][i].getFConst();
2322 distanceArray[i].setFConst(x - y);
2323 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002324 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302325 }
2326 else
2327 UNREACHABLE();
2328 break;
2329
2330 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002331
Arun Patole1155ddd2015-06-05 18:04:36 +05302332 if (basicType == EbtFloat)
2333 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002334 resultArray = new TConstantUnion();
2335 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302336 }
2337 else
2338 UNREACHABLE();
2339 break;
2340
2341 case EOpCross:
2342 if (basicType == EbtFloat && maxObjectSize == 3)
2343 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002344 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302345 float x0 = unionArrays[0][0].getFConst();
2346 float x1 = unionArrays[0][1].getFConst();
2347 float x2 = unionArrays[0][2].getFConst();
2348 float y0 = unionArrays[1][0].getFConst();
2349 float y1 = unionArrays[1][1].getFConst();
2350 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002351 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2352 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2353 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302354 }
2355 else
2356 UNREACHABLE();
2357 break;
2358
2359 case EOpReflect:
2360 if (basicType == EbtFloat)
2361 {
2362 // genType reflect (genType I, genType N) :
2363 // For the incident vector I and surface orientation N, returns the reflection direction:
2364 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002365 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302366 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2367 for (size_t i = 0; i < maxObjectSize; i++)
2368 {
2369 float result = unionArrays[0][i].getFConst() -
2370 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002371 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302372 }
2373 }
2374 else
2375 UNREACHABLE();
2376 break;
2377
Arun Patole7fa33552015-06-10 15:15:18 +05302378 case EOpMul:
2379 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2380 (*sequence)[1]->getAsTyped()->isMatrix())
2381 {
2382 // Perform component-wise matrix multiplication.
2383 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002384 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302385 angle::Matrix<float> result =
2386 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2387 SetUnionArrayFromMatrix(result, resultArray);
2388 }
2389 else
2390 UNREACHABLE();
2391 break;
2392
2393 case EOpOuterProduct:
2394 if (basicType == EbtFloat)
2395 {
2396 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2397 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2398 resultArray = new TConstantUnion[numRows * numCols];
2399 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);
2403 }
2404 else
2405 UNREACHABLE();
2406 break;
2407
Arun Patole274f0702015-05-05 13:33:30 +05302408 default:
2409 UNREACHABLE();
2410 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2411 return nullptr;
2412 }
2413 }
2414 else if (paramsCount == 3)
2415 {
2416 //
2417 // Ternary built-in
2418 //
2419 switch (op)
2420 {
2421 case EOpClamp:
2422 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002423 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302424 for (size_t i = 0; i < maxObjectSize; i++)
2425 {
2426 switch (basicType)
2427 {
2428 case EbtFloat:
2429 {
2430 float x = unionArrays[0][i].getFConst();
2431 float min = unionArrays[1][i].getFConst();
2432 float max = unionArrays[2][i].getFConst();
2433 // Results are undefined if min > max.
2434 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002435 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &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));
Arun Patole274f0702015-05-05 13:33:30 +05302438 }
2439 break;
2440 case EbtInt:
2441 {
2442 int x = unionArrays[0][i].getIConst();
2443 int min = unionArrays[1][i].getIConst();
2444 int max = unionArrays[2][i].getIConst();
2445 // Results are undefined if min > max.
2446 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002447 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302448 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002449 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302450 }
2451 break;
2452 case EbtUInt:
2453 {
2454 unsigned int x = unionArrays[0][i].getUConst();
2455 unsigned int min = unionArrays[1][i].getUConst();
2456 unsigned int max = unionArrays[2][i].getUConst();
2457 // Results are undefined if min > max.
2458 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002459 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302460 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002461 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302462 }
2463 break;
2464 default:
2465 UNREACHABLE();
2466 break;
2467 }
2468 }
2469 }
2470 break;
2471
Arun Patolebf790422015-05-18 17:53:04 +05302472 case EOpMix:
2473 {
2474 if (basicType == EbtFloat)
2475 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002476 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302477 for (size_t i = 0; i < maxObjectSize; i++)
2478 {
2479 float x = unionArrays[0][i].getFConst();
2480 float y = unionArrays[1][i].getFConst();
2481 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2482 if (type == EbtFloat)
2483 {
2484 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2485 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002486 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302487 }
2488 else // 3rd parameter is EbtBool
2489 {
2490 ASSERT(type == EbtBool);
2491 // Selects which vector each returned component comes from.
2492 // For a component of a that is false, the corresponding component of x is returned.
2493 // For a component of a that is true, the corresponding component of y is returned.
2494 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002495 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302496 }
2497 }
2498 }
2499 else
2500 UNREACHABLE();
2501 }
2502 break;
2503
2504 case EOpSmoothStep:
2505 {
2506 if (basicType == EbtFloat)
2507 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002508 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302509 for (size_t i = 0; i < maxObjectSize; i++)
2510 {
2511 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)
2516 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002517 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302518 }
2519 else
2520 {
2521 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2522 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2523 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002524 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302525 }
2526 }
2527 }
2528 else
2529 UNREACHABLE();
2530 }
2531 break;
2532
Arun Patole1155ddd2015-06-05 18:04:36 +05302533 case EOpFaceForward:
2534 if (basicType == EbtFloat)
2535 {
2536 // genType faceforward(genType N, genType I, genType Nref) :
2537 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002538 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302539 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2540 for (size_t i = 0; i < maxObjectSize; i++)
2541 {
2542 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002543 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302544 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002545 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302546 }
2547 }
2548 else
2549 UNREACHABLE();
2550 break;
2551
2552 case EOpRefract:
2553 if (basicType == EbtFloat)
2554 {
2555 // genType refract(genType I, genType N, float eta) :
2556 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2557 // return the refraction vector. The result is computed by
2558 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2559 // if (k < 0.0)
2560 // return genType(0.0)
2561 // else
2562 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002563 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302564 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2565 for (size_t i = 0; i < maxObjectSize; i++)
2566 {
2567 float eta = unionArrays[2][i].getFConst();
2568 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2569 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002570 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302571 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002572 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302573 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2574 }
2575 }
2576 else
2577 UNREACHABLE();
2578 break;
2579
Arun Patole274f0702015-05-05 13:33:30 +05302580 default:
2581 UNREACHABLE();
2582 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2583 return nullptr;
2584 }
2585 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002586 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302587}
2588
2589// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002590TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2591{
2592 if (hashFunction == NULL || name.empty())
2593 return name;
2594 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2595 TStringStream stream;
2596 stream << HASHED_NAME_PREFIX << std::hex << number;
2597 TString hashedName = stream.str();
2598 return hashedName;
2599}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002600
2601void TIntermTraverser::updateTree()
2602{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002603 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2604 {
2605 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2606 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002607 if (!insertion.insertionsAfter.empty())
2608 {
2609 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2610 insertion.insertionsAfter);
2611 ASSERT(inserted);
2612 UNUSED_ASSERTION_VARIABLE(inserted);
2613 }
2614 if (!insertion.insertionsBefore.empty())
2615 {
2616 bool inserted =
2617 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2618 ASSERT(inserted);
2619 UNUSED_ASSERTION_VARIABLE(inserted);
2620 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002621 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002622 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2623 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002624 const NodeUpdateEntry &replacement = mReplacements[ii];
2625 ASSERT(replacement.parent);
2626 bool replaced = replacement.parent->replaceChildNode(
2627 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002628 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002629 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002630
Olli Etuahocd94ef92015-04-16 19:18:10 +03002631 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002632 {
2633 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002634 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002635 // be replaced, we need to make sure we don't update the replaced
2636 // node; instead, we update the replacement node.
2637 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2638 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002639 NodeUpdateEntry &replacement2 = mReplacements[jj];
2640 if (replacement2.parent == replacement.original)
2641 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002642 }
2643 }
2644 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002645 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2646 {
2647 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2648 ASSERT(replacement.parent);
2649 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2650 replacement.original, replacement.replacements);
2651 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002652 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002653 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002654
Jamie Madill03d863c2016-07-27 18:15:53 -04002655 clearReplacementQueue();
2656}
2657
2658void TIntermTraverser::clearReplacementQueue()
2659{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002660 mReplacements.clear();
2661 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002662 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002663}
Jamie Madill1048e432016-07-23 18:51:28 -04002664
Jamie Madill03d863c2016-07-27 18:15:53 -04002665void TIntermTraverser::queueReplacement(TIntermNode *original,
2666 TIntermNode *replacement,
2667 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002668{
Jamie Madill03d863c2016-07-27 18:15:53 -04002669 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002670}
2671
Jamie Madill03d863c2016-07-27 18:15:53 -04002672void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2673 TIntermNode *original,
2674 TIntermNode *replacement,
2675 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002676{
Jamie Madill03d863c2016-07-27 18:15:53 -04002677 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2678 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002679}