blob: 478ae4c0843ff4c4badd016867e50368de1429b9 [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"
24
25namespace
26{
27
Arun Patole9dea48f2015-04-02 11:45:09 +053028const float kPi = 3.14159265358979323846f;
29const float kDegreesToRadiansMultiplier = kPi / 180.0f;
30const float kRadiansToDegreesMultiplier = 180.0f / kPi;
31
Jamie Madillb1a85f42014-08-19 15:23:24 -040032TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
33{
34 return left > right ? left : right;
35}
36
Arun Patole274f0702015-05-05 13:33:30 +053037TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
38{
39 TConstantUnion *constUnion = new TConstantUnion[size];
40 for (unsigned int i = 0; i < size; ++i)
41 constUnion[i] = constant;
42
43 return constUnion;
44}
45
Arun Patolebf790422015-05-18 17:53:04 +053046void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
47 TInfoSink &infoSink, TConstantUnion *result)
48{
49 std::stringstream constantFoldingErrorStream;
50 constantFoldingErrorStream << "'" << GetOperatorString(op)
51 << "' operation result is undefined for the values passed in";
52 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
53
54 switch (basicType)
55 {
56 case EbtFloat :
57 result->setFConst(0.0f);
58 break;
59 case EbtInt:
60 result->setIConst(0);
61 break;
62 case EbtUInt:
63 result->setUConst(0u);
64 break;
65 case EbtBool:
66 result->setBConst(false);
67 break;
68 default:
69 break;
70 }
71}
72
Olli Etuaho5c0e0232015-11-11 15:55:59 +020073float VectorLength(const TConstantUnion *paramArray, size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053074{
75 float result = 0.0f;
76 for (size_t i = 0; i < paramArraySize; i++)
77 {
78 float f = paramArray[i].getFConst();
79 result += f * f;
80 }
81 return sqrtf(result);
82}
83
Olli Etuaho5c0e0232015-11-11 15:55:59 +020084float VectorDotProduct(const TConstantUnion *paramArray1,
85 const TConstantUnion *paramArray2,
86 size_t paramArraySize)
Arun Patole1155ddd2015-06-05 18:04:36 +053087{
88 float result = 0.0f;
89 for (size_t i = 0; i < paramArraySize; i++)
90 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
91 return result;
92}
93
Olli Etuaho7c3848e2015-11-04 13:19:17 +020094TIntermTyped *CreateFoldedNode(TConstantUnion *constArray,
95 const TIntermTyped *originalNode,
96 TQualifier qualifier)
Olli Etuahob43846e2015-06-02 18:18:57 +030097{
98 if (constArray == nullptr)
99 {
100 return nullptr;
101 }
102 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200103 folded->getTypePointer()->setQualifier(qualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300104 folded->setLine(originalNode->getLine());
105 return folded;
106}
107
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200108angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray,
109 const unsigned int &rows,
110 const unsigned int &cols)
Arun Patole7fa33552015-06-10 15:15:18 +0530111{
112 std::vector<float> elements;
113 for (size_t i = 0; i < rows * cols; i++)
114 elements.push_back(paramArray[i].getFConst());
115 // Transpose is used since the Matrix constructor expects arguments in row-major order,
116 // whereas the paramArray is in column-major order.
117 return angle::Matrix<float>(elements, rows, cols).transpose();
118}
119
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200120angle::Matrix<float> GetMatrix(const TConstantUnion *paramArray, const unsigned int &size)
Arun Patole7fa33552015-06-10 15:15:18 +0530121{
122 std::vector<float> elements;
123 for (size_t i = 0; i < size * size; i++)
124 elements.push_back(paramArray[i].getFConst());
125 // Transpose is used since the Matrix constructor expects arguments in row-major order,
126 // whereas the paramArray is in column-major order.
127 return angle::Matrix<float>(elements, size).transpose();
128}
129
130void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
131{
132 // Transpose is used since the input Matrix is in row-major order,
133 // whereas the actual result should be in column-major order.
134 angle::Matrix<float> result = m.transpose();
135 std::vector<float> resultElements = result.elements();
136 for (size_t i = 0; i < resultElements.size(); i++)
137 resultArray[i].setFConst(resultElements[i]);
138}
139
Jamie Madillb1a85f42014-08-19 15:23:24 -0400140} // namespace anonymous
141
142
143////////////////////////////////////////////////////////////////
144//
145// Member functions of the nodes used for building the tree.
146//
147////////////////////////////////////////////////////////////////
148
Olli Etuahod2a67b92014-10-21 16:42:57 +0300149void TIntermTyped::setTypePreservePrecision(const TType &t)
150{
151 TPrecision precision = getPrecision();
152 mType = t;
153 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
154 mType.setPrecision(precision);
155}
156
Jamie Madillb1a85f42014-08-19 15:23:24 -0400157#define REPLACE_IF_IS(node, type, original, replacement) \
158 if (node == original) { \
159 node = static_cast<type *>(replacement); \
160 return true; \
161 }
162
163bool TIntermLoop::replaceChildNode(
164 TIntermNode *original, TIntermNode *replacement)
165{
Olli Etuaho3cbb27a2016-07-14 11:55:48 +0300166 ASSERT(original != nullptr); // This risks replacing multiple children.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400167 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
168 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
169 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
Olli Etuaho3fed4302015-11-02 12:26:02 +0200170 REPLACE_IF_IS(mBody, TIntermAggregate, original, replacement);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400171 return false;
172}
173
Jamie Madillb1a85f42014-08-19 15:23:24 -0400174bool TIntermBranch::replaceChildNode(
175 TIntermNode *original, TIntermNode *replacement)
176{
177 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
178 return false;
179}
180
Jamie Madillb1a85f42014-08-19 15:23:24 -0400181bool TIntermBinary::replaceChildNode(
182 TIntermNode *original, TIntermNode *replacement)
183{
184 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
185 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
186 return false;
187}
188
Jamie Madillb1a85f42014-08-19 15:23:24 -0400189bool TIntermUnary::replaceChildNode(
190 TIntermNode *original, TIntermNode *replacement)
191{
192 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
193 return false;
194}
195
Jamie Madillb1a85f42014-08-19 15:23:24 -0400196bool TIntermAggregate::replaceChildNode(
197 TIntermNode *original, TIntermNode *replacement)
198{
199 for (size_t ii = 0; ii < mSequence.size(); ++ii)
200 {
201 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
202 }
203 return false;
204}
205
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300206bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
207{
208 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
209 {
210 if (*it == original)
211 {
212 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300213 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300214 return true;
215 }
216 }
217 return false;
218}
219
Olli Etuahoa6f22092015-05-08 18:31:10 +0300220bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
221{
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300222 if (position > mSequence.size())
Olli Etuahoa6f22092015-05-08 18:31:10 +0300223 {
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300224 return false;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300225 }
Olli Etuaho5d91dda2015-06-18 15:47:46 +0300226 auto it = mSequence.begin() + position;
227 mSequence.insert(it, insertions.begin(), insertions.end());
228 return true;
Olli Etuahoa6f22092015-05-08 18:31:10 +0300229}
230
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200231bool TIntermAggregate::areChildrenConstQualified()
232{
233 for (TIntermNode *&child : mSequence)
234 {
235 TIntermTyped *typed = child->getAsTyped();
236 if (typed && typed->getQualifier() != EvqConst)
237 {
238 return false;
239 }
240 }
241 return true;
242}
243
Olli Etuahod2a67b92014-10-21 16:42:57 +0300244void TIntermAggregate::setPrecisionFromChildren()
245{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300246 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300247 if (getBasicType() == EbtBool)
248 {
249 mType.setPrecision(EbpUndefined);
250 return;
251 }
252
253 TPrecision precision = EbpUndefined;
254 TIntermSequence::iterator childIter = mSequence.begin();
255 while (childIter != mSequence.end())
256 {
257 TIntermTyped *typed = (*childIter)->getAsTyped();
258 if (typed)
259 precision = GetHigherPrecision(typed->getPrecision(), precision);
260 ++childIter;
261 }
262 mType.setPrecision(precision);
263}
264
265void TIntermAggregate::setBuiltInFunctionPrecision()
266{
267 // All built-ins returning bool should be handled as ops, not functions.
268 ASSERT(getBasicType() != EbtBool);
269
270 TPrecision precision = EbpUndefined;
271 TIntermSequence::iterator childIter = mSequence.begin();
272 while (childIter != mSequence.end())
273 {
274 TIntermTyped *typed = (*childIter)->getAsTyped();
275 // ESSL spec section 8: texture functions get their precision from the sampler.
276 if (typed && IsSampler(typed->getBasicType()))
277 {
278 precision = typed->getPrecision();
279 break;
280 }
281 ++childIter;
282 }
283 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
284 // All other functions that take a sampler are assumed to be texture functions.
Olli Etuaho59f9a642015-08-06 20:38:26 +0300285 if (mName.getString().find("textureSize") == 0)
Olli Etuahod2a67b92014-10-21 16:42:57 +0300286 mType.setPrecision(EbpHigh);
287 else
288 mType.setPrecision(precision);
289}
290
Jamie Madillb1a85f42014-08-19 15:23:24 -0400291bool TIntermSelection::replaceChildNode(
292 TIntermNode *original, TIntermNode *replacement)
293{
294 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
295 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
296 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
297 return false;
298}
299
Olli Etuahoa3a36662015-02-17 13:46:51 +0200300bool TIntermSwitch::replaceChildNode(
301 TIntermNode *original, TIntermNode *replacement)
302{
303 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
304 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
305 return false;
306}
307
308bool TIntermCase::replaceChildNode(
309 TIntermNode *original, TIntermNode *replacement)
310{
311 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
312 return false;
313}
314
Olli Etuahod7a25242015-08-18 13:49:45 +0300315TIntermTyped::TIntermTyped(const TIntermTyped &node) : TIntermNode(), mType(node.mType)
316{
317 // Copy constructor is disallowed for TIntermNode in order to disallow it for subclasses that
318 // don't explicitly allow it, so normal TIntermNode constructor is used to construct the copy.
319 // We need to manually copy any fields of TIntermNode besides handling fields in TIntermTyped.
320 mLine = node.mLine;
321}
322
Olli Etuahod4f4c112016-04-15 15:11:24 +0300323bool TIntermTyped::isConstructorWithOnlyConstantUnionParameters()
324{
325 TIntermAggregate *constructor = getAsAggregate();
326 if (!constructor || !constructor->isConstructor())
327 {
328 return false;
329 }
330 for (TIntermNode *&node : *constructor->getSequence())
331 {
332 if (!node->getAsConstantUnion())
333 return false;
334 }
335 return true;
336}
337
Olli Etuahod7a25242015-08-18 13:49:45 +0300338TIntermConstantUnion::TIntermConstantUnion(const TIntermConstantUnion &node) : TIntermTyped(node)
339{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200340 mUnionArrayPointer = node.mUnionArrayPointer;
Olli Etuahod7a25242015-08-18 13:49:45 +0300341}
342
343TIntermAggregate::TIntermAggregate(const TIntermAggregate &node)
344 : TIntermOperator(node),
345 mName(node.mName),
346 mUserDefined(node.mUserDefined),
347 mFunctionId(node.mFunctionId),
Olli Etuahod7a25242015-08-18 13:49:45 +0300348 mUseEmulatedFunction(node.mUseEmulatedFunction),
349 mGotPrecisionFromChildren(node.mGotPrecisionFromChildren)
350{
351 for (TIntermNode *child : node.mSequence)
352 {
353 TIntermTyped *typedChild = child->getAsTyped();
354 ASSERT(typedChild != nullptr);
355 TIntermTyped *childCopy = typedChild->deepCopy();
356 mSequence.push_back(childCopy);
357 }
358}
359
360TIntermBinary::TIntermBinary(const TIntermBinary &node)
361 : TIntermOperator(node), mAddIndexClamp(node.mAddIndexClamp)
362{
363 TIntermTyped *leftCopy = node.mLeft->deepCopy();
364 TIntermTyped *rightCopy = node.mRight->deepCopy();
365 ASSERT(leftCopy != nullptr && rightCopy != nullptr);
366 mLeft = leftCopy;
367 mRight = rightCopy;
368}
369
370TIntermUnary::TIntermUnary(const TIntermUnary &node)
371 : TIntermOperator(node), mUseEmulatedFunction(node.mUseEmulatedFunction)
372{
373 TIntermTyped *operandCopy = node.mOperand->deepCopy();
374 ASSERT(operandCopy != nullptr);
375 mOperand = operandCopy;
376}
377
378TIntermSelection::TIntermSelection(const TIntermSelection &node) : TIntermTyped(node)
379{
380 // Only supported for ternary nodes, not if statements.
381 TIntermTyped *trueTyped = node.mTrueBlock->getAsTyped();
382 TIntermTyped *falseTyped = node.mFalseBlock->getAsTyped();
383 ASSERT(trueTyped != nullptr);
384 ASSERT(falseTyped != nullptr);
385 TIntermTyped *conditionCopy = node.mCondition->deepCopy();
386 TIntermTyped *trueCopy = trueTyped->deepCopy();
387 TIntermTyped *falseCopy = falseTyped->deepCopy();
388 ASSERT(conditionCopy != nullptr && trueCopy != nullptr && falseCopy != nullptr);
389 mCondition = conditionCopy;
390 mTrueBlock = trueCopy;
391 mFalseBlock = falseCopy;
392}
393
Jamie Madillb1a85f42014-08-19 15:23:24 -0400394bool TIntermOperator::isAssignment() const
395{
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300396 return IsAssignment(mOp);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400397}
398
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300399bool TIntermOperator::isMultiplication() const
400{
401 switch (mOp)
402 {
403 case EOpMul:
404 case EOpMatrixTimesMatrix:
405 case EOpMatrixTimesVector:
406 case EOpMatrixTimesScalar:
407 case EOpVectorTimesMatrix:
408 case EOpVectorTimesScalar:
409 return true;
410 default:
411 return false;
412 }
413}
414
Jamie Madillb1a85f42014-08-19 15:23:24 -0400415//
416// returns true if the operator is for one of the constructors
417//
418bool TIntermOperator::isConstructor() const
419{
420 switch (mOp)
421 {
422 case EOpConstructVec2:
423 case EOpConstructVec3:
424 case EOpConstructVec4:
425 case EOpConstructMat2:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400426 case EOpConstructMat2x3:
427 case EOpConstructMat2x4:
428 case EOpConstructMat3x2:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400429 case EOpConstructMat3:
Alexis Hetu07e57df2015-06-16 16:55:52 -0400430 case EOpConstructMat3x4:
431 case EOpConstructMat4x2:
432 case EOpConstructMat4x3:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400433 case EOpConstructMat4:
434 case EOpConstructFloat:
435 case EOpConstructIVec2:
436 case EOpConstructIVec3:
437 case EOpConstructIVec4:
438 case EOpConstructInt:
439 case EOpConstructUVec2:
440 case EOpConstructUVec3:
441 case EOpConstructUVec4:
442 case EOpConstructUInt:
443 case EOpConstructBVec2:
444 case EOpConstructBVec3:
445 case EOpConstructBVec4:
446 case EOpConstructBool:
447 case EOpConstructStruct:
448 return true;
449 default:
450 return false;
451 }
452}
453
Olli Etuaho1dded802016-08-18 18:13:13 +0300454TOperator TIntermBinary::GetMulOpBasedOnOperands(const TType &left, const TType &right)
455{
456 if (left.isMatrix())
457 {
458 if (right.isMatrix())
459 {
460 return EOpMatrixTimesMatrix;
461 }
462 else
463 {
464 if (right.isVector())
465 {
466 return EOpMatrixTimesVector;
467 }
468 else
469 {
470 return EOpMatrixTimesScalar;
471 }
472 }
473 }
474 else
475 {
476 if (right.isMatrix())
477 {
478 if (left.isVector())
479 {
480 return EOpVectorTimesMatrix;
481 }
482 else
483 {
484 return EOpMatrixTimesScalar;
485 }
486 }
487 else
488 {
489 // Neither operand is a matrix.
490 if (left.isVector() == right.isVector())
491 {
492 // Leave as component product.
493 return EOpMul;
494 }
495 else
496 {
497 return EOpVectorTimesScalar;
498 }
499 }
500 }
501}
502
503TOperator TIntermBinary::GetMulAssignOpBasedOnOperands(const TType &left, const TType &right)
504{
505 if (left.isMatrix())
506 {
507 if (right.isMatrix())
508 {
509 return EOpMatrixTimesMatrixAssign;
510 }
511 else
512 {
513 // right should be scalar, but this may not be validated yet.
514 return EOpMatrixTimesScalarAssign;
515 }
516 }
517 else
518 {
519 if (right.isMatrix())
520 {
521 // Left should be a vector, but this may not be validated yet.
522 return EOpVectorTimesMatrixAssign;
523 }
524 else
525 {
526 // Neither operand is a matrix.
527 if (left.isVector() == right.isVector())
528 {
529 // Leave as component product.
530 return EOpMulAssign;
531 }
532 else
533 {
534 // left should be vector and right should be scalar, but this may not be validated
535 // yet.
536 return EOpVectorTimesScalarAssign;
537 }
538 }
539 }
540}
541
Jamie Madillb1a85f42014-08-19 15:23:24 -0400542//
543// Make sure the type of a unary operator is appropriate for its
544// combination of operation and operand type.
545//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200546void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400547{
548 switch (mOp)
549 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200550 case EOpFloatBitsToInt:
551 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200552 case EOpIntBitsToFloat:
553 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200554 case EOpPackSnorm2x16:
555 case EOpPackUnorm2x16:
556 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200557 case EOpUnpackSnorm2x16:
558 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200559 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530560 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200561 case EOpUnpackHalf2x16:
562 mType.setPrecision(EbpMedium);
563 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400564 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200565 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400566 }
567
Olli Etuahof6c694b2015-03-26 14:50:53 +0200568 if (funcReturnType != nullptr)
569 {
570 if (funcReturnType->getBasicType() == EbtBool)
571 {
572 // Bool types should not have precision.
573 setType(*funcReturnType);
574 }
575 else
576 {
577 // Precision of the node has been set based on the operand.
578 setTypePreservePrecision(*funcReturnType);
579 }
580 }
581
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200582 if (mOperand->getQualifier() == EvqConst)
583 mType.setQualifier(EvqConst);
584 else
585 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400586}
587
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300588TIntermBinary::TIntermBinary(TOperator op, TIntermTyped *left, TIntermTyped *right)
589 : TIntermOperator(op), mLeft(left), mRight(right), mAddIndexClamp(false)
590{
591 promote();
592}
593
Jamie Madillb1a85f42014-08-19 15:23:24 -0400594//
595// Establishes the type of the resultant operation, as well as
596// makes the operator the correct one for the operands.
597//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200598// For lots of operations it should already be established that the operand
599// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400600//
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300601void TIntermBinary::promote()
Jamie Madillb1a85f42014-08-19 15:23:24 -0400602{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200603 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400604
Olli Etuaho1dded802016-08-18 18:13:13 +0300605 ASSERT(!isMultiplication() ||
606 mOp == GetMulOpBasedOnOperands(mLeft->getType(), mRight->getType()));
607
Jamie Madillb1a85f42014-08-19 15:23:24 -0400608 // Base assumption: just make the type the same as the left
609 // operand. Then only deviations from this need be coded.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400610 setType(mLeft->getType());
611
612 // The result gets promoted to the highest precision.
613 TPrecision higherPrecision = GetHigherPrecision(
614 mLeft->getPrecision(), mRight->getPrecision());
615 getTypePointer()->setPrecision(higherPrecision);
616
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200617 TQualifier resultQualifier = EvqConst;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400618 // Binary operations results in temporary variables unless both
619 // operands are const.
620 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
621 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200622 resultQualifier = EvqTemporary;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400623 getTypePointer()->setQualifier(EvqTemporary);
624 }
625
626 const int nominalSize =
627 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
628
629 //
630 // All scalars or structs. Code after this test assumes this case is removed!
631 //
632 if (nominalSize == 1)
633 {
634 switch (mOp)
635 {
636 //
637 // Promote to conditional
638 //
639 case EOpEqual:
640 case EOpNotEqual:
641 case EOpLessThan:
642 case EOpGreaterThan:
643 case EOpLessThanEqual:
644 case EOpGreaterThanEqual:
645 setType(TType(EbtBool, EbpUndefined));
646 break;
647
648 //
649 // And and Or operate on conditionals
650 //
651 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200652 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400653 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200654 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400655 setType(TType(EbtBool, EbpUndefined));
656 break;
657
658 default:
659 break;
660 }
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300661 return;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400662 }
663
664 // If we reach here, at least one of the operands is vector or matrix.
665 // The other operand could be a scalar, vector, or matrix.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400666 TBasicType basicType = mLeft->getBasicType();
Olli Etuaho1dded802016-08-18 18:13:13 +0300667
Jamie Madillb1a85f42014-08-19 15:23:24 -0400668 switch (mOp)
669 {
Olli Etuaho1dded802016-08-18 18:13:13 +0300670 case EOpMul:
671 break;
672 case EOpMatrixTimesScalar:
673 if (mRight->isMatrix())
Jamie Madillb1a85f42014-08-19 15:23:24 -0400674 {
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200675 setType(TType(basicType, higherPrecision, resultQualifier,
676 static_cast<unsigned char>(mRight->getCols()),
677 static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400678 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300679 break;
680 case EOpMatrixTimesVector:
681 setType(TType(basicType, higherPrecision, resultQualifier,
682 static_cast<unsigned char>(mLeft->getRows()), 1));
683 break;
684 case EOpMatrixTimesMatrix:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200685 setType(TType(basicType, higherPrecision, resultQualifier,
686 static_cast<unsigned char>(mRight->getCols()),
687 static_cast<unsigned char>(mLeft->getRows())));
Olli Etuaho1dded802016-08-18 18:13:13 +0300688 break;
689 case EOpVectorTimesScalar:
Olli Etuahob1edc4f2015-11-02 17:20:03 +0200690 setType(TType(basicType, higherPrecision, resultQualifier,
Olli Etuaho1dded802016-08-18 18:13:13 +0300691 static_cast<unsigned char>(nominalSize), 1));
692 break;
693 case EOpVectorTimesMatrix:
694 setType(TType(basicType, higherPrecision, resultQualifier,
695 static_cast<unsigned char>(mRight->getCols()), 1));
696 break;
697 case EOpMulAssign:
698 case EOpVectorTimesScalarAssign:
699 case EOpVectorTimesMatrixAssign:
700 case EOpMatrixTimesScalarAssign:
701 case EOpMatrixTimesMatrixAssign:
702 ASSERT(mOp == GetMulAssignOpBasedOnOperands(mLeft->getType(), mRight->getType()));
703 break;
704 case EOpAssign:
705 case EOpInitialize:
Olli Etuaho1dded802016-08-18 18:13:13 +0300706 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
707 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
708 break;
709 case EOpAdd:
710 case EOpSub:
711 case EOpDiv:
712 case EOpIMod:
713 case EOpBitShiftLeft:
714 case EOpBitShiftRight:
715 case EOpBitwiseAnd:
716 case EOpBitwiseXor:
717 case EOpBitwiseOr:
718 case EOpAddAssign:
719 case EOpSubAssign:
720 case EOpDivAssign:
721 case EOpIModAssign:
722 case EOpBitShiftLeftAssign:
723 case EOpBitShiftRightAssign:
724 case EOpBitwiseAndAssign:
725 case EOpBitwiseXorAssign:
726 case EOpBitwiseOrAssign:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300727 {
728 const int secondarySize =
729 std::max(mLeft->getSecondarySize(), mRight->getSecondarySize());
730 setType(TType(basicType, higherPrecision, resultQualifier,
731 static_cast<unsigned char>(nominalSize),
732 static_cast<unsigned char>(secondarySize)));
733 ASSERT(!mLeft->isArray() && !mRight->isArray());
Olli Etuaho1dded802016-08-18 18:13:13 +0300734 break;
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300735 }
Olli Etuaho1dded802016-08-18 18:13:13 +0300736 case EOpEqual:
737 case EOpNotEqual:
738 case EOpLessThan:
739 case EOpGreaterThan:
740 case EOpLessThanEqual:
741 case EOpGreaterThanEqual:
742 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
743 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300744 setType(TType(EbtBool, EbpUndefined, resultQualifier));
Olli Etuaho1dded802016-08-18 18:13:13 +0300745 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400746
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300747 case EOpIndexDirect:
748 case EOpIndexIndirect:
749 case EOpIndexDirectInterfaceBlock:
750 case EOpIndexDirectStruct:
751 // TODO (oetuaho): These ops could be handled here as well (should be done closer to the
752 // top of the function).
753 UNREACHABLE();
754 break;
Olli Etuaho1dded802016-08-18 18:13:13 +0300755 default:
Olli Etuaho63e1ec52016-08-18 22:05:12 +0300756 UNREACHABLE();
757 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400758 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400759}
760
Olli Etuaho3fdec912016-08-18 15:08:06 +0300761TIntermTyped *TIntermBinary::fold(TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300762{
763 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
764 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
765 if (leftConstant == nullptr || rightConstant == nullptr)
766 {
767 return nullptr;
768 }
Olli Etuaho3fdec912016-08-18 15:08:06 +0300769 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, diagnostics);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200770
771 // Nodes may be constant folded without being qualified as constant.
772 TQualifier resultQualifier = EvqConst;
773 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
774 {
775 resultQualifier = EvqTemporary;
776 }
777 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300778}
779
Olli Etuaho95310b02015-06-02 17:43:38 +0300780TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
781{
782 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
783 if (operandConstant == nullptr)
784 {
785 return nullptr;
786 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530787
788 TConstantUnion *constArray = nullptr;
789 switch (mOp)
790 {
791 case EOpAny:
792 case EOpAll:
793 case EOpLength:
794 case EOpTranspose:
795 case EOpDeterminant:
796 case EOpInverse:
797 case EOpPackSnorm2x16:
798 case EOpUnpackSnorm2x16:
799 case EOpPackUnorm2x16:
800 case EOpUnpackUnorm2x16:
801 case EOpPackHalf2x16:
802 case EOpUnpackHalf2x16:
803 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
804 break;
805 default:
806 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
807 break;
808 }
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200809
810 // Nodes may be constant folded without being qualified as constant.
811 TQualifier resultQualifier = mOperand->getQualifier() == EvqConst ? EvqConst : EvqTemporary;
812 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuahob43846e2015-06-02 18:18:57 +0300813}
814
815TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
816{
817 // Make sure that all params are constant before actual constant folding.
818 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300819 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300820 if (param->getAsConstantUnion() == nullptr)
821 {
822 return nullptr;
823 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300824 }
Olli Etuaho1d122782015-11-06 15:35:17 +0200825 TConstantUnion *constArray = nullptr;
826 if (isConstructor())
827 constArray = TIntermConstantUnion::FoldAggregateConstructor(this, infoSink);
828 else
829 constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
Olli Etuaho7c3848e2015-11-04 13:19:17 +0200830
831 // Nodes may be constant folded without being qualified as constant.
832 TQualifier resultQualifier = areChildrenConstQualified() ? EvqConst : EvqTemporary;
833 return CreateFoldedNode(constArray, this, resultQualifier);
Olli Etuaho95310b02015-06-02 17:43:38 +0300834}
835
Jamie Madillb1a85f42014-08-19 15:23:24 -0400836//
837// The fold functions see if an operation on a constant can be done in place,
838// without generating run-time code.
839//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300840// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400841//
Olli Etuaho3fdec912016-08-18 15:08:06 +0300842TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op,
843 TIntermConstantUnion *rightNode,
844 TDiagnostics *diagnostics)
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300845{
Olli Etuaho5c0e0232015-11-11 15:55:59 +0200846 const TConstantUnion *leftArray = getUnionArrayPointer();
847 const TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300848
849 if (!leftArray)
850 return nullptr;
851 if (!rightArray)
852 return nullptr;
853
854 size_t objectSize = getType().getObjectSize();
855
856 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
857 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
858 {
859 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
860 }
861 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
862 {
863 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
864 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
865 objectSize = rightNode->getType().getObjectSize();
866 }
867
868 TConstantUnion *resultArray = nullptr;
869
870 switch(op)
871 {
872 case EOpAdd:
873 resultArray = new TConstantUnion[objectSize];
874 for (size_t i = 0; i < objectSize; i++)
875 resultArray[i] = leftArray[i] + rightArray[i];
876 break;
877 case EOpSub:
878 resultArray = new TConstantUnion[objectSize];
879 for (size_t i = 0; i < objectSize; i++)
880 resultArray[i] = leftArray[i] - rightArray[i];
881 break;
882
883 case EOpMul:
884 case EOpVectorTimesScalar:
885 case EOpMatrixTimesScalar:
886 resultArray = new TConstantUnion[objectSize];
887 for (size_t i = 0; i < objectSize; i++)
888 resultArray[i] = leftArray[i] * rightArray[i];
889 break;
890
891 case EOpMatrixTimesMatrix:
892 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300893 ASSERT(getType().getBasicType() == EbtFloat && rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300894
895 const int leftCols = getCols();
896 const int leftRows = getRows();
897 const int rightCols = rightNode->getType().getCols();
898 const int rightRows = rightNode->getType().getRows();
899 const int resultCols = rightCols;
900 const int resultRows = leftRows;
901
902 resultArray = new TConstantUnion[resultCols * resultRows];
903 for (int row = 0; row < resultRows; row++)
904 {
905 for (int column = 0; column < resultCols; column++)
906 {
907 resultArray[resultRows * column + row].setFConst(0.0f);
908 for (int i = 0; i < leftCols; i++)
909 {
910 resultArray[resultRows * column + row].setFConst(
911 resultArray[resultRows * column + row].getFConst() +
912 leftArray[i * leftRows + row].getFConst() *
913 rightArray[column * rightRows + i].getFConst());
914 }
915 }
916 }
917 }
918 break;
919
920 case EOpDiv:
921 case EOpIMod:
922 {
923 resultArray = new TConstantUnion[objectSize];
924 for (size_t i = 0; i < objectSize; i++)
925 {
926 switch (getType().getBasicType())
927 {
928 case EbtFloat:
929 if (rightArray[i] == 0.0f)
930 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300931 diagnostics->warning(
932 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300933 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
934 }
935 else
936 {
937 ASSERT(op == EOpDiv);
938 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
939 }
940 break;
941
942 case EbtInt:
943 if (rightArray[i] == 0)
944 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300945 diagnostics->warning(
946 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300947 resultArray[i].setIConst(INT_MAX);
948 }
949 else
950 {
951 if (op == EOpDiv)
952 {
953 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
954 }
955 else
956 {
957 ASSERT(op == EOpIMod);
958 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
959 }
960 }
961 break;
962
963 case EbtUInt:
964 if (rightArray[i] == 0)
965 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300966 diagnostics->warning(
967 getLine(), "Divide by zero error during constant folding", "/", "");
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300968 resultArray[i].setUConst(UINT_MAX);
969 }
970 else
971 {
972 if (op == EOpDiv)
973 {
974 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
975 }
976 else
977 {
978 ASSERT(op == EOpIMod);
979 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
980 }
981 }
982 break;
983
984 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +0300985 UNREACHABLE();
986 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300987 }
988 }
989 }
990 break;
991
992 case EOpMatrixTimesVector:
993 {
Olli Etuaho3fdec912016-08-18 15:08:06 +0300994 ASSERT(rightNode->getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300995
996 const int matrixCols = getCols();
997 const int matrixRows = getRows();
998
999 resultArray = new TConstantUnion[matrixRows];
1000
1001 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1002 {
1003 resultArray[matrixRow].setFConst(0.0f);
1004 for (int col = 0; col < matrixCols; col++)
1005 {
1006 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1007 leftArray[col * matrixRows + matrixRow].getFConst() *
1008 rightArray[col].getFConst());
1009 }
1010 }
1011 }
1012 break;
1013
1014 case EOpVectorTimesMatrix:
1015 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001016 ASSERT(getType().getBasicType() == EbtFloat);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001017
1018 const int matrixCols = rightNode->getType().getCols();
1019 const int matrixRows = rightNode->getType().getRows();
1020
1021 resultArray = new TConstantUnion[matrixCols];
1022
1023 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1024 {
1025 resultArray[matrixCol].setFConst(0.0f);
1026 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1027 {
1028 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1029 leftArray[matrixRow].getFConst() *
1030 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1031 }
1032 }
1033 }
1034 break;
1035
1036 case EOpLogicalAnd:
1037 {
1038 resultArray = new TConstantUnion[objectSize];
1039 for (size_t i = 0; i < objectSize; i++)
1040 {
1041 resultArray[i] = leftArray[i] && rightArray[i];
1042 }
1043 }
1044 break;
1045
1046 case EOpLogicalOr:
1047 {
1048 resultArray = new TConstantUnion[objectSize];
1049 for (size_t i = 0; i < objectSize; i++)
1050 {
1051 resultArray[i] = leftArray[i] || rightArray[i];
1052 }
1053 }
1054 break;
1055
1056 case EOpLogicalXor:
1057 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001058 ASSERT(getType().getBasicType() == EbtBool);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001059 resultArray = new TConstantUnion[objectSize];
1060 for (size_t i = 0; i < objectSize; i++)
1061 {
Olli Etuaho3fdec912016-08-18 15:08:06 +03001062 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001063 }
1064 }
1065 break;
1066
1067 case EOpBitwiseAnd:
1068 resultArray = new TConstantUnion[objectSize];
1069 for (size_t i = 0; i < objectSize; i++)
1070 resultArray[i] = leftArray[i] & rightArray[i];
1071 break;
1072 case EOpBitwiseXor:
1073 resultArray = new TConstantUnion[objectSize];
1074 for (size_t i = 0; i < objectSize; i++)
1075 resultArray[i] = leftArray[i] ^ rightArray[i];
1076 break;
1077 case EOpBitwiseOr:
1078 resultArray = new TConstantUnion[objectSize];
1079 for (size_t i = 0; i < objectSize; i++)
1080 resultArray[i] = leftArray[i] | rightArray[i];
1081 break;
1082 case EOpBitShiftLeft:
1083 resultArray = new TConstantUnion[objectSize];
1084 for (size_t i = 0; i < objectSize; i++)
1085 resultArray[i] = leftArray[i] << rightArray[i];
1086 break;
1087 case EOpBitShiftRight:
1088 resultArray = new TConstantUnion[objectSize];
1089 for (size_t i = 0; i < objectSize; i++)
1090 resultArray[i] = leftArray[i] >> rightArray[i];
1091 break;
1092
1093 case EOpLessThan:
1094 ASSERT(objectSize == 1);
1095 resultArray = new TConstantUnion[1];
1096 resultArray->setBConst(*leftArray < *rightArray);
1097 break;
1098
1099 case EOpGreaterThan:
1100 ASSERT(objectSize == 1);
1101 resultArray = new TConstantUnion[1];
1102 resultArray->setBConst(*leftArray > *rightArray);
1103 break;
1104
1105 case EOpLessThanEqual:
1106 ASSERT(objectSize == 1);
1107 resultArray = new TConstantUnion[1];
1108 resultArray->setBConst(!(*leftArray > *rightArray));
1109 break;
1110
1111 case EOpGreaterThanEqual:
1112 ASSERT(objectSize == 1);
1113 resultArray = new TConstantUnion[1];
1114 resultArray->setBConst(!(*leftArray < *rightArray));
1115 break;
1116
1117 case EOpEqual:
1118 case EOpNotEqual:
1119 {
1120 resultArray = new TConstantUnion[1];
1121 bool equal = true;
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001122 for (size_t i = 0; i < objectSize; i++)
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001123 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001124 if (leftArray[i] != rightArray[i])
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001125 {
Olli Etuaho40d9edf2015-11-12 17:30:34 +02001126 equal = false;
1127 break; // break out of for loop
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001128 }
1129 }
1130 if (op == EOpEqual)
1131 {
1132 resultArray->setBConst(equal);
1133 }
1134 else
1135 {
1136 resultArray->setBConst(!equal);
1137 }
1138 }
1139 break;
1140
1141 default:
Olli Etuaho3fdec912016-08-18 15:08:06 +03001142 UNREACHABLE();
1143 return nullptr;
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001144 }
1145 return resultArray;
1146}
1147
1148//
1149// The fold functions see if an operation on a constant can be done in place,
1150// without generating run-time code.
1151//
Olli Etuaho95310b02015-06-02 17:43:38 +03001152// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001153//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301154TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001155{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301156 //
1157 // Do operations where the return type has a different number of components compared to the operand type.
1158 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001159
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001160 const TConstantUnion *operandArray = getUnionArrayPointer();
Arun Patoleab2b9a22015-07-06 18:27:56 +05301161 if (!operandArray)
1162 return nullptr;
1163
1164 size_t objectSize = getType().getObjectSize();
1165 TConstantUnion *resultArray = nullptr;
1166 switch (op)
1167 {
1168 case EOpAny:
1169 if (getType().getBasicType() == EbtBool)
1170 {
1171 resultArray = new TConstantUnion();
1172 resultArray->setBConst(false);
1173 for (size_t i = 0; i < objectSize; i++)
1174 {
1175 if (operandArray[i].getBConst())
1176 {
1177 resultArray->setBConst(true);
1178 break;
1179 }
1180 }
1181 break;
1182 }
1183 else
1184 {
1185 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1186 return nullptr;
1187 }
1188
1189 case EOpAll:
1190 if (getType().getBasicType() == EbtBool)
1191 {
1192 resultArray = new TConstantUnion();
1193 resultArray->setBConst(true);
1194 for (size_t i = 0; i < objectSize; i++)
1195 {
1196 if (!operandArray[i].getBConst())
1197 {
1198 resultArray->setBConst(false);
1199 break;
1200 }
1201 }
1202 break;
1203 }
1204 else
1205 {
1206 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1207 return nullptr;
1208 }
1209
1210 case EOpLength:
1211 if (getType().getBasicType() == EbtFloat)
1212 {
1213 resultArray = new TConstantUnion();
1214 resultArray->setFConst(VectorLength(operandArray, objectSize));
1215 break;
1216 }
1217 else
1218 {
1219 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1220 return nullptr;
1221 }
1222
1223 case EOpTranspose:
1224 if (getType().getBasicType() == EbtFloat)
1225 {
1226 resultArray = new TConstantUnion[objectSize];
1227 angle::Matrix<float> result =
1228 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1229 SetUnionArrayFromMatrix(result, resultArray);
1230 break;
1231 }
1232 else
1233 {
1234 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1235 return nullptr;
1236 }
1237
1238 case EOpDeterminant:
1239 if (getType().getBasicType() == EbtFloat)
1240 {
1241 unsigned int size = getType().getNominalSize();
1242 ASSERT(size >= 2 && size <= 4);
1243 resultArray = new TConstantUnion();
1244 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1245 break;
1246 }
1247 else
1248 {
1249 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1250 return nullptr;
1251 }
1252
1253 case EOpInverse:
1254 if (getType().getBasicType() == EbtFloat)
1255 {
1256 unsigned int size = getType().getNominalSize();
1257 ASSERT(size >= 2 && size <= 4);
1258 resultArray = new TConstantUnion[objectSize];
1259 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1260 SetUnionArrayFromMatrix(result, resultArray);
1261 break;
1262 }
1263 else
1264 {
1265 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1266 return nullptr;
1267 }
1268
1269 case EOpPackSnorm2x16:
1270 if (getType().getBasicType() == EbtFloat)
1271 {
1272 ASSERT(getType().getNominalSize() == 2);
1273 resultArray = new TConstantUnion();
1274 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1275 break;
1276 }
1277 else
1278 {
1279 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1280 return nullptr;
1281 }
1282
1283 case EOpUnpackSnorm2x16:
1284 if (getType().getBasicType() == EbtUInt)
1285 {
1286 resultArray = new TConstantUnion[2];
1287 float f1, f2;
1288 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1289 resultArray[0].setFConst(f1);
1290 resultArray[1].setFConst(f2);
1291 break;
1292 }
1293 else
1294 {
1295 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1296 return nullptr;
1297 }
1298
1299 case EOpPackUnorm2x16:
1300 if (getType().getBasicType() == EbtFloat)
1301 {
1302 ASSERT(getType().getNominalSize() == 2);
1303 resultArray = new TConstantUnion();
1304 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1305 break;
1306 }
1307 else
1308 {
1309 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1310 return nullptr;
1311 }
1312
1313 case EOpUnpackUnorm2x16:
1314 if (getType().getBasicType() == EbtUInt)
1315 {
1316 resultArray = new TConstantUnion[2];
1317 float f1, f2;
1318 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1319 resultArray[0].setFConst(f1);
1320 resultArray[1].setFConst(f2);
1321 break;
1322 }
1323 else
1324 {
1325 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1326 return nullptr;
1327 }
1328
1329 case EOpPackHalf2x16:
1330 if (getType().getBasicType() == EbtFloat)
1331 {
1332 ASSERT(getType().getNominalSize() == 2);
1333 resultArray = new TConstantUnion();
1334 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1335 break;
1336 }
1337 else
1338 {
1339 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1340 return nullptr;
1341 }
1342
1343 case EOpUnpackHalf2x16:
1344 if (getType().getBasicType() == EbtUInt)
1345 {
1346 resultArray = new TConstantUnion[2];
1347 float f1, f2;
1348 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1349 resultArray[0].setFConst(f1);
1350 resultArray[1].setFConst(f2);
1351 break;
1352 }
1353 else
1354 {
1355 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1356 return nullptr;
1357 }
1358 break;
1359
1360 default:
1361 break;
1362 }
1363
1364 return resultArray;
1365}
1366
1367TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1368{
1369 //
1370 // Do unary operations where the return type is the same as operand type.
1371 //
1372
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001373 const TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001374 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301375 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001376
1377 size_t objectSize = getType().getObjectSize();
1378
Arun Patoleab2b9a22015-07-06 18:27:56 +05301379 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1380 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301381 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301382 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301383 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301384 case EOpNegative:
1385 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301386 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301387 case EbtFloat:
1388 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301389 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301390 case EbtInt:
1391 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301392 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301393 case EbtUInt:
1394 resultArray[i].setUConst(static_cast<unsigned int>(
1395 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301396 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301397 default:
1398 infoSink.info.message(
1399 EPrefixInternalError, getLine(),
1400 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301401 return nullptr;
1402 }
1403 break;
1404
Arun Patoleab2b9a22015-07-06 18:27:56 +05301405 case EOpPositive:
1406 switch (getType().getBasicType())
1407 {
1408 case EbtFloat:
1409 resultArray[i].setFConst(operandArray[i].getFConst());
1410 break;
1411 case EbtInt:
1412 resultArray[i].setIConst(operandArray[i].getIConst());
1413 break;
1414 case EbtUInt:
1415 resultArray[i].setUConst(static_cast<unsigned int>(
1416 static_cast<int>(operandArray[i].getUConst())));
1417 break;
1418 default:
1419 infoSink.info.message(
1420 EPrefixInternalError, getLine(),
1421 "Unary operation not folded into constant");
1422 return nullptr;
1423 }
1424 break;
1425
1426 case EOpLogicalNot:
1427 // this code is written for possible future use,
1428 // will not get executed currently
1429 switch (getType().getBasicType())
1430 {
1431 case EbtBool:
1432 resultArray[i].setBConst(!operandArray[i].getBConst());
1433 break;
1434 default:
1435 infoSink.info.message(
1436 EPrefixInternalError, getLine(),
1437 "Unary operation not folded into constant");
1438 return nullptr;
1439 }
1440 break;
1441
1442 case EOpBitwiseNot:
1443 switch (getType().getBasicType())
1444 {
1445 case EbtInt:
1446 resultArray[i].setIConst(~operandArray[i].getIConst());
1447 break;
1448 case EbtUInt:
1449 resultArray[i].setUConst(~operandArray[i].getUConst());
1450 break;
1451 default:
1452 infoSink.info.message(
1453 EPrefixInternalError, getLine(),
1454 "Unary operation not folded into constant");
1455 return nullptr;
1456 }
1457 break;
1458
1459 case EOpRadians:
1460 if (getType().getBasicType() == EbtFloat)
1461 {
1462 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1463 break;
1464 }
1465 infoSink.info.message(
1466 EPrefixInternalError, getLine(),
1467 "Unary operation not folded into constant");
1468 return nullptr;
1469
1470 case EOpDegrees:
1471 if (getType().getBasicType() == EbtFloat)
1472 {
1473 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1474 break;
1475 }
1476 infoSink.info.message(
1477 EPrefixInternalError, getLine(),
1478 "Unary operation not folded into constant");
1479 return nullptr;
1480
1481 case EOpSin:
1482 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1483 return nullptr;
1484 break;
1485
1486 case EOpCos:
1487 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1488 return nullptr;
1489 break;
1490
1491 case EOpTan:
1492 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1493 return nullptr;
1494 break;
1495
1496 case EOpAsin:
1497 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1498 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1499 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1500 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1501 return nullptr;
1502 break;
1503
1504 case EOpAcos:
1505 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1506 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1507 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1508 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1509 return nullptr;
1510 break;
1511
1512 case EOpAtan:
1513 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1514 return nullptr;
1515 break;
1516
1517 case EOpSinh:
1518 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1519 return nullptr;
1520 break;
1521
1522 case EOpCosh:
1523 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1524 return nullptr;
1525 break;
1526
1527 case EOpTanh:
1528 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1529 return nullptr;
1530 break;
1531
1532 case EOpAsinh:
1533 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1534 return nullptr;
1535 break;
1536
1537 case EOpAcosh:
1538 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1539 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1540 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1541 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1542 return nullptr;
1543 break;
1544
1545 case EOpAtanh:
1546 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1547 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1548 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1549 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1550 return nullptr;
1551 break;
1552
1553 case EOpAbs:
1554 switch (getType().getBasicType())
1555 {
1556 case EbtFloat:
1557 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1558 break;
1559 case EbtInt:
1560 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1561 break;
1562 default:
1563 infoSink.info.message(
1564 EPrefixInternalError, getLine(),
1565 "Unary operation not folded into constant");
1566 return nullptr;
1567 }
1568 break;
1569
1570 case EOpSign:
1571 switch (getType().getBasicType())
1572 {
1573 case EbtFloat:
1574 {
1575 float fConst = operandArray[i].getFConst();
1576 float fResult = 0.0f;
1577 if (fConst > 0.0f)
1578 fResult = 1.0f;
1579 else if (fConst < 0.0f)
1580 fResult = -1.0f;
1581 resultArray[i].setFConst(fResult);
1582 }
1583 break;
1584 case EbtInt:
1585 {
1586 int iConst = operandArray[i].getIConst();
1587 int iResult = 0;
1588 if (iConst > 0)
1589 iResult = 1;
1590 else if (iConst < 0)
1591 iResult = -1;
1592 resultArray[i].setIConst(iResult);
1593 }
1594 break;
1595 default:
1596 infoSink.info.message(
1597 EPrefixInternalError, getLine(),
1598 "Unary operation not folded into constant");
1599 return nullptr;
1600 }
1601 break;
1602
1603 case EOpFloor:
1604 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1605 return nullptr;
1606 break;
1607
1608 case EOpTrunc:
1609 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1610 return nullptr;
1611 break;
1612
1613 case EOpRound:
1614 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1615 return nullptr;
1616 break;
1617
1618 case EOpRoundEven:
1619 if (getType().getBasicType() == EbtFloat)
1620 {
1621 float x = operandArray[i].getFConst();
1622 float result;
1623 float fractPart = modff(x, &result);
1624 if (fabsf(fractPart) == 0.5f)
1625 result = 2.0f * roundf(x / 2.0f);
1626 else
1627 result = roundf(x);
1628 resultArray[i].setFConst(result);
1629 break;
1630 }
1631 infoSink.info.message(
1632 EPrefixInternalError, getLine(),
1633 "Unary operation not folded into constant");
1634 return nullptr;
1635
1636 case EOpCeil:
1637 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1638 return nullptr;
1639 break;
1640
1641 case EOpFract:
1642 if (getType().getBasicType() == EbtFloat)
1643 {
1644 float x = operandArray[i].getFConst();
1645 resultArray[i].setFConst(x - floorf(x));
1646 break;
1647 }
1648 infoSink.info.message(
1649 EPrefixInternalError, getLine(),
1650 "Unary operation not folded into constant");
1651 return nullptr;
1652
Arun Patole551279e2015-07-07 18:18:23 +05301653 case EOpIsNan:
1654 if (getType().getBasicType() == EbtFloat)
1655 {
1656 resultArray[i].setBConst(gl::isNaN(operandArray[0].getFConst()));
1657 break;
1658 }
1659 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1660 return nullptr;
1661
1662 case EOpIsInf:
1663 if (getType().getBasicType() == EbtFloat)
1664 {
1665 resultArray[i].setBConst(gl::isInf(operandArray[0].getFConst()));
1666 break;
1667 }
1668 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1669 return nullptr;
1670
1671 case EOpFloatBitsToInt:
1672 if (getType().getBasicType() == EbtFloat)
1673 {
1674 resultArray[i].setIConst(gl::bitCast<int32_t>(operandArray[0].getFConst()));
1675 break;
1676 }
1677 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1678 return nullptr;
1679
1680 case EOpFloatBitsToUint:
1681 if (getType().getBasicType() == EbtFloat)
1682 {
1683 resultArray[i].setUConst(gl::bitCast<uint32_t>(operandArray[0].getFConst()));
1684 break;
1685 }
1686 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1687 return nullptr;
1688
1689 case EOpIntBitsToFloat:
1690 if (getType().getBasicType() == EbtInt)
1691 {
1692 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getIConst()));
1693 break;
1694 }
1695 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1696 return nullptr;
1697
1698 case EOpUintBitsToFloat:
1699 if (getType().getBasicType() == EbtUInt)
1700 {
1701 resultArray[i].setFConst(gl::bitCast<float>(operandArray[0].getUConst()));
1702 break;
1703 }
1704 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1705 return nullptr;
1706
Arun Patoleab2b9a22015-07-06 18:27:56 +05301707 case EOpExp:
1708 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1709 return nullptr;
1710 break;
1711
1712 case EOpLog:
1713 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1714 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1715 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1716 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1717 return nullptr;
1718 break;
1719
1720 case EOpExp2:
1721 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1722 return nullptr;
1723 break;
1724
1725 case EOpLog2:
1726 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1727 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1728 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1729 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1730 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1731 return nullptr;
1732 else
1733 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1734 break;
1735
1736 case EOpSqrt:
1737 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1738 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1739 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1740 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1741 return nullptr;
1742 break;
1743
1744 case EOpInverseSqrt:
1745 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1746 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1747 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1748 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1749 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1750 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1751 return nullptr;
1752 else
1753 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1754 break;
1755
1756 case EOpVectorLogicalNot:
1757 if (getType().getBasicType() == EbtBool)
1758 {
1759 resultArray[i].setBConst(!operandArray[i].getBConst());
1760 break;
1761 }
1762 infoSink.info.message(
1763 EPrefixInternalError, getLine(),
1764 "Unary operation not folded into constant");
1765 return nullptr;
1766
1767 case EOpNormalize:
1768 if (getType().getBasicType() == EbtFloat)
1769 {
1770 float x = operandArray[i].getFConst();
1771 float length = VectorLength(operandArray, objectSize);
1772 if (length)
1773 resultArray[i].setFConst(x / length);
1774 else
1775 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1776 &resultArray[i]);
1777 break;
1778 }
1779 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1780 return nullptr;
1781
Arun Patole0c5409f2015-07-08 15:17:53 +05301782 case EOpDFdx:
1783 case EOpDFdy:
1784 case EOpFwidth:
1785 if (getType().getBasicType() == EbtFloat)
1786 {
1787 // Derivatives of constant arguments should be 0.
1788 resultArray[i].setFConst(0.0f);
1789 break;
1790 }
1791 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1792 return nullptr;
1793
Arun Patole1155ddd2015-06-05 18:04:36 +05301794 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301795 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301796 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301797 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001798
Arun Patoleab2b9a22015-07-06 18:27:56 +05301799 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001800}
1801
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001802bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1803 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301804{
1805 ASSERT(builtinFunc);
1806
1807 if (getType().getBasicType() == EbtFloat)
1808 {
1809 result->setFConst(builtinFunc(parameter.getFConst()));
1810 return true;
1811 }
1812
1813 infoSink.info.message(
1814 EPrefixInternalError, getLine(),
1815 "Unary operation not folded into constant");
1816 return false;
1817}
1818
Jamie Madillb1a85f42014-08-19 15:23:24 -04001819// static
Olli Etuaho1d122782015-11-06 15:35:17 +02001820TConstantUnion *TIntermConstantUnion::FoldAggregateConstructor(TIntermAggregate *aggregate,
1821 TInfoSink &infoSink)
1822{
1823 ASSERT(aggregate->getSequence()->size() > 0u);
1824 size_t resultSize = aggregate->getType().getObjectSize();
1825 TConstantUnion *resultArray = new TConstantUnion[resultSize];
1826 TBasicType basicType = aggregate->getBasicType();
1827
1828 size_t resultIndex = 0u;
1829
1830 if (aggregate->getSequence()->size() == 1u)
1831 {
1832 TIntermNode *argument = aggregate->getSequence()->front();
1833 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1834 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1835 // Check the special case of constructing a matrix diagonal from a single scalar,
1836 // or a vector from a single scalar.
1837 if (argumentConstant->getType().getObjectSize() == 1u)
1838 {
1839 if (aggregate->isMatrix())
1840 {
1841 int resultCols = aggregate->getType().getCols();
1842 int resultRows = aggregate->getType().getRows();
1843 for (int col = 0; col < resultCols; ++col)
1844 {
1845 for (int row = 0; row < resultRows; ++row)
1846 {
1847 if (col == row)
1848 {
1849 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1850 }
1851 else
1852 {
1853 resultArray[resultIndex].setFConst(0.0f);
1854 }
1855 ++resultIndex;
1856 }
1857 }
1858 }
1859 else
1860 {
1861 while (resultIndex < resultSize)
1862 {
1863 resultArray[resultIndex].cast(basicType, argumentUnionArray[0]);
1864 ++resultIndex;
1865 }
1866 }
1867 ASSERT(resultIndex == resultSize);
1868 return resultArray;
1869 }
1870 else if (aggregate->isMatrix() && argumentConstant->isMatrix())
1871 {
1872 // The special case of constructing a matrix from a matrix.
1873 int argumentCols = argumentConstant->getType().getCols();
1874 int argumentRows = argumentConstant->getType().getRows();
1875 int resultCols = aggregate->getType().getCols();
1876 int resultRows = aggregate->getType().getRows();
1877 for (int col = 0; col < resultCols; ++col)
1878 {
1879 for (int row = 0; row < resultRows; ++row)
1880 {
1881 if (col < argumentCols && row < argumentRows)
1882 {
1883 resultArray[resultIndex].cast(basicType,
1884 argumentUnionArray[col * argumentRows + row]);
1885 }
1886 else if (col == row)
1887 {
1888 resultArray[resultIndex].setFConst(1.0f);
1889 }
1890 else
1891 {
1892 resultArray[resultIndex].setFConst(0.0f);
1893 }
1894 ++resultIndex;
1895 }
1896 }
1897 ASSERT(resultIndex == resultSize);
1898 return resultArray;
1899 }
1900 }
1901
1902 for (TIntermNode *&argument : *aggregate->getSequence())
1903 {
1904 TIntermConstantUnion *argumentConstant = argument->getAsConstantUnion();
1905 size_t argumentSize = argumentConstant->getType().getObjectSize();
1906 const TConstantUnion *argumentUnionArray = argumentConstant->getUnionArrayPointer();
1907 for (size_t i = 0u; i < argumentSize; ++i)
1908 {
1909 if (resultIndex >= resultSize)
1910 break;
1911 resultArray[resultIndex].cast(basicType, argumentUnionArray[i]);
1912 ++resultIndex;
1913 }
1914 }
1915 ASSERT(resultIndex == resultSize);
1916 return resultArray;
1917}
1918
1919// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001920TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301921{
Olli Etuahob43846e2015-06-02 18:18:57 +03001922 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301923 TIntermSequence *sequence = aggregate->getSequence();
Cooper Partin4d61f7e2015-08-12 10:56:50 -07001924 unsigned int paramsCount = static_cast<unsigned int>(sequence->size());
Olli Etuaho5c0e0232015-11-11 15:55:59 +02001925 std::vector<const TConstantUnion *> unionArrays(paramsCount);
Arun Patole274f0702015-05-05 13:33:30 +05301926 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001927 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301928 TBasicType basicType = EbtVoid;
1929 TSourceLoc loc;
1930 for (unsigned int i = 0; i < paramsCount; i++)
1931 {
1932 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001933 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301934
1935 if (i == 0)
1936 {
1937 basicType = paramConstant->getType().getBasicType();
1938 loc = paramConstant->getLine();
1939 }
1940 unionArrays[i] = paramConstant->getUnionArrayPointer();
1941 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001942 if (objectSizes[i] > maxObjectSize)
1943 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301944 }
1945
Arun Patole7fa33552015-06-10 15:15:18 +05301946 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1947 {
1948 for (unsigned int i = 0; i < paramsCount; i++)
1949 if (objectSizes[i] != maxObjectSize)
1950 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1951 }
Arun Patole274f0702015-05-05 13:33:30 +05301952
Olli Etuahob43846e2015-06-02 18:18:57 +03001953 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301954 if (paramsCount == 2)
1955 {
1956 //
1957 // Binary built-in
1958 //
1959 switch (op)
1960 {
Arun Patolebf790422015-05-18 17:53:04 +05301961 case EOpAtan:
1962 {
1963 if (basicType == EbtFloat)
1964 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001965 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301966 for (size_t i = 0; i < maxObjectSize; i++)
1967 {
1968 float y = unionArrays[0][i].getFConst();
1969 float x = unionArrays[1][i].getFConst();
1970 // Results are undefined if x and y are both 0.
1971 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001972 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301973 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001974 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301975 }
1976 }
1977 else
1978 UNREACHABLE();
1979 }
1980 break;
1981
1982 case EOpPow:
1983 {
1984 if (basicType == EbtFloat)
1985 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001986 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301987 for (size_t i = 0; i < maxObjectSize; i++)
1988 {
1989 float x = unionArrays[0][i].getFConst();
1990 float y = unionArrays[1][i].getFConst();
1991 // Results are undefined if x < 0.
1992 // Results are undefined if x = 0 and y <= 0.
1993 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001994 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301995 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001996 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301997 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001998 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05301999 }
2000 }
2001 else
2002 UNREACHABLE();
2003 }
2004 break;
2005
2006 case EOpMod:
2007 {
2008 if (basicType == EbtFloat)
2009 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002010 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302011 for (size_t i = 0; i < maxObjectSize; i++)
2012 {
2013 float x = unionArrays[0][i].getFConst();
2014 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002015 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05302016 }
2017 }
2018 else
2019 UNREACHABLE();
2020 }
2021 break;
2022
Arun Patole274f0702015-05-05 13:33:30 +05302023 case EOpMin:
2024 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002025 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302026 for (size_t i = 0; i < maxObjectSize; i++)
2027 {
2028 switch (basicType)
2029 {
2030 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002031 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302032 break;
2033 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002034 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302035 break;
2036 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002037 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302038 break;
2039 default:
2040 UNREACHABLE();
2041 break;
2042 }
2043 }
2044 }
2045 break;
2046
2047 case EOpMax:
2048 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002049 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302050 for (size_t i = 0; i < maxObjectSize; i++)
2051 {
2052 switch (basicType)
2053 {
2054 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002055 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302056 break;
2057 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002058 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302059 break;
2060 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002061 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05302062 break;
2063 default:
2064 UNREACHABLE();
2065 break;
2066 }
2067 }
2068 }
2069 break;
2070
Arun Patolebf790422015-05-18 17:53:04 +05302071 case EOpStep:
2072 {
2073 if (basicType == EbtFloat)
2074 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002075 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302076 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03002077 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05302078 }
2079 else
2080 UNREACHABLE();
2081 }
2082 break;
2083
Arun Patole9d0b1f92015-05-20 14:27:17 +05302084 case EOpLessThan:
2085 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002086 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302087 for (size_t i = 0; i < maxObjectSize; i++)
2088 {
2089 switch (basicType)
2090 {
2091 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002092 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302093 break;
2094 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002095 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302096 break;
2097 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002098 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302099 break;
2100 default:
2101 UNREACHABLE();
2102 break;
2103 }
2104 }
2105 }
2106 break;
2107
2108 case EOpLessThanEqual:
2109 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002110 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302111 for (size_t i = 0; i < maxObjectSize; i++)
2112 {
2113 switch (basicType)
2114 {
2115 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002116 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302117 break;
2118 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002119 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302120 break;
2121 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002122 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302123 break;
2124 default:
2125 UNREACHABLE();
2126 break;
2127 }
2128 }
2129 }
2130 break;
2131
2132 case EOpGreaterThan:
2133 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002134 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302135 for (size_t i = 0; i < maxObjectSize; i++)
2136 {
2137 switch (basicType)
2138 {
2139 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002140 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302141 break;
2142 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002143 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302144 break;
2145 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002146 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302147 break;
2148 default:
2149 UNREACHABLE();
2150 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002151 }
2152 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302153 }
2154 break;
2155
2156 case EOpGreaterThanEqual:
2157 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002158 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302159 for (size_t i = 0; i < maxObjectSize; i++)
2160 {
2161 switch (basicType)
2162 {
2163 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002164 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302165 break;
2166 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002167 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302168 break;
2169 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002170 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302171 break;
2172 default:
2173 UNREACHABLE();
2174 break;
2175 }
2176 }
2177 }
2178 break;
2179
2180 case EOpVectorEqual:
2181 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002182 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302183 for (size_t i = 0; i < maxObjectSize; i++)
2184 {
2185 switch (basicType)
2186 {
2187 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002188 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302189 break;
2190 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002191 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302192 break;
2193 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002194 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302195 break;
2196 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002197 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302198 break;
2199 default:
2200 UNREACHABLE();
2201 break;
2202 }
2203 }
2204 }
2205 break;
2206
2207 case EOpVectorNotEqual:
2208 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002209 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302210 for (size_t i = 0; i < maxObjectSize; i++)
2211 {
2212 switch (basicType)
2213 {
2214 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002215 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302216 break;
2217 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002218 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302219 break;
2220 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002221 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302222 break;
2223 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002224 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302225 break;
2226 default:
2227 UNREACHABLE();
2228 break;
2229 }
2230 }
2231 }
2232 break;
2233
Arun Patole1155ddd2015-06-05 18:04:36 +05302234 case EOpDistance:
2235 if (basicType == EbtFloat)
2236 {
2237 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002238 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302239 for (size_t i = 0; i < maxObjectSize; i++)
2240 {
2241 float x = unionArrays[0][i].getFConst();
2242 float y = unionArrays[1][i].getFConst();
2243 distanceArray[i].setFConst(x - y);
2244 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002245 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302246 }
2247 else
2248 UNREACHABLE();
2249 break;
2250
2251 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002252
Arun Patole1155ddd2015-06-05 18:04:36 +05302253 if (basicType == EbtFloat)
2254 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002255 resultArray = new TConstantUnion();
2256 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302257 }
2258 else
2259 UNREACHABLE();
2260 break;
2261
2262 case EOpCross:
2263 if (basicType == EbtFloat && maxObjectSize == 3)
2264 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002265 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302266 float x0 = unionArrays[0][0].getFConst();
2267 float x1 = unionArrays[0][1].getFConst();
2268 float x2 = unionArrays[0][2].getFConst();
2269 float y0 = unionArrays[1][0].getFConst();
2270 float y1 = unionArrays[1][1].getFConst();
2271 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002272 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2273 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2274 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302275 }
2276 else
2277 UNREACHABLE();
2278 break;
2279
2280 case EOpReflect:
2281 if (basicType == EbtFloat)
2282 {
2283 // genType reflect (genType I, genType N) :
2284 // For the incident vector I and surface orientation N, returns the reflection direction:
2285 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002286 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302287 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2288 for (size_t i = 0; i < maxObjectSize; i++)
2289 {
2290 float result = unionArrays[0][i].getFConst() -
2291 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002292 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302293 }
2294 }
2295 else
2296 UNREACHABLE();
2297 break;
2298
Arun Patole7fa33552015-06-10 15:15:18 +05302299 case EOpMul:
2300 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2301 (*sequence)[1]->getAsTyped()->isMatrix())
2302 {
2303 // Perform component-wise matrix multiplication.
2304 resultArray = new TConstantUnion[maxObjectSize];
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002305 int size = (*sequence)[0]->getAsTyped()->getNominalSize();
Arun Patole7fa33552015-06-10 15:15:18 +05302306 angle::Matrix<float> result =
2307 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2308 SetUnionArrayFromMatrix(result, resultArray);
2309 }
2310 else
2311 UNREACHABLE();
2312 break;
2313
2314 case EOpOuterProduct:
2315 if (basicType == EbtFloat)
2316 {
2317 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2318 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2319 resultArray = new TConstantUnion[numRows * numCols];
2320 angle::Matrix<float> result =
Cooper Partin4d61f7e2015-08-12 10:56:50 -07002321 GetMatrix(unionArrays[0], 1, static_cast<int>(numCols))
2322 .outerProduct(GetMatrix(unionArrays[1], static_cast<int>(numRows), 1));
Arun Patole7fa33552015-06-10 15:15:18 +05302323 SetUnionArrayFromMatrix(result, resultArray);
2324 }
2325 else
2326 UNREACHABLE();
2327 break;
2328
Arun Patole274f0702015-05-05 13:33:30 +05302329 default:
2330 UNREACHABLE();
2331 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2332 return nullptr;
2333 }
2334 }
2335 else if (paramsCount == 3)
2336 {
2337 //
2338 // Ternary built-in
2339 //
2340 switch (op)
2341 {
2342 case EOpClamp:
2343 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002344 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302345 for (size_t i = 0; i < maxObjectSize; i++)
2346 {
2347 switch (basicType)
2348 {
2349 case EbtFloat:
2350 {
2351 float x = unionArrays[0][i].getFConst();
2352 float min = unionArrays[1][i].getFConst();
2353 float max = unionArrays[2][i].getFConst();
2354 // Results are undefined if min > max.
2355 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002356 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302357 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002358 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302359 }
2360 break;
2361 case EbtInt:
2362 {
2363 int x = unionArrays[0][i].getIConst();
2364 int min = unionArrays[1][i].getIConst();
2365 int max = unionArrays[2][i].getIConst();
2366 // Results are undefined if min > max.
2367 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002368 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302369 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002370 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302371 }
2372 break;
2373 case EbtUInt:
2374 {
2375 unsigned int x = unionArrays[0][i].getUConst();
2376 unsigned int min = unionArrays[1][i].getUConst();
2377 unsigned int max = unionArrays[2][i].getUConst();
2378 // Results are undefined if min > max.
2379 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002380 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302381 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002382 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302383 }
2384 break;
2385 default:
2386 UNREACHABLE();
2387 break;
2388 }
2389 }
2390 }
2391 break;
2392
Arun Patolebf790422015-05-18 17:53:04 +05302393 case EOpMix:
2394 {
2395 if (basicType == EbtFloat)
2396 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002397 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302398 for (size_t i = 0; i < maxObjectSize; i++)
2399 {
2400 float x = unionArrays[0][i].getFConst();
2401 float y = unionArrays[1][i].getFConst();
2402 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2403 if (type == EbtFloat)
2404 {
2405 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2406 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002407 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302408 }
2409 else // 3rd parameter is EbtBool
2410 {
2411 ASSERT(type == EbtBool);
2412 // Selects which vector each returned component comes from.
2413 // For a component of a that is false, the corresponding component of x is returned.
2414 // For a component of a that is true, the corresponding component of y is returned.
2415 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002416 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302417 }
2418 }
2419 }
2420 else
2421 UNREACHABLE();
2422 }
2423 break;
2424
2425 case EOpSmoothStep:
2426 {
2427 if (basicType == EbtFloat)
2428 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002429 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302430 for (size_t i = 0; i < maxObjectSize; i++)
2431 {
2432 float edge0 = unionArrays[0][i].getFConst();
2433 float edge1 = unionArrays[1][i].getFConst();
2434 float x = unionArrays[2][i].getFConst();
2435 // Results are undefined if edge0 >= edge1.
2436 if (edge0 >= edge1)
2437 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002438 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302439 }
2440 else
2441 {
2442 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2443 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2444 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002445 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302446 }
2447 }
2448 }
2449 else
2450 UNREACHABLE();
2451 }
2452 break;
2453
Arun Patole1155ddd2015-06-05 18:04:36 +05302454 case EOpFaceForward:
2455 if (basicType == EbtFloat)
2456 {
2457 // genType faceforward(genType N, genType I, genType Nref) :
2458 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002459 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302460 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2461 for (size_t i = 0; i < maxObjectSize; i++)
2462 {
2463 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002464 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302465 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002466 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302467 }
2468 }
2469 else
2470 UNREACHABLE();
2471 break;
2472
2473 case EOpRefract:
2474 if (basicType == EbtFloat)
2475 {
2476 // genType refract(genType I, genType N, float eta) :
2477 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2478 // return the refraction vector. The result is computed by
2479 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2480 // if (k < 0.0)
2481 // return genType(0.0)
2482 // else
2483 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002484 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302485 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2486 for (size_t i = 0; i < maxObjectSize; i++)
2487 {
2488 float eta = unionArrays[2][i].getFConst();
2489 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2490 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002491 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302492 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002493 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302494 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2495 }
2496 }
2497 else
2498 UNREACHABLE();
2499 break;
2500
Arun Patole274f0702015-05-05 13:33:30 +05302501 default:
2502 UNREACHABLE();
2503 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2504 return nullptr;
2505 }
2506 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002507 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302508}
2509
2510// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002511TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2512{
2513 if (hashFunction == NULL || name.empty())
2514 return name;
2515 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2516 TStringStream stream;
2517 stream << HASHED_NAME_PREFIX << std::hex << number;
2518 TString hashedName = stream.str();
2519 return hashedName;
2520}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002521
2522void TIntermTraverser::updateTree()
2523{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002524 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2525 {
2526 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2527 ASSERT(insertion.parent);
Olli Etuaho5d91dda2015-06-18 15:47:46 +03002528 if (!insertion.insertionsAfter.empty())
2529 {
2530 bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
2531 insertion.insertionsAfter);
2532 ASSERT(inserted);
2533 UNUSED_ASSERTION_VARIABLE(inserted);
2534 }
2535 if (!insertion.insertionsBefore.empty())
2536 {
2537 bool inserted =
2538 insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
2539 ASSERT(inserted);
2540 UNUSED_ASSERTION_VARIABLE(inserted);
2541 }
Olli Etuahoa6f22092015-05-08 18:31:10 +03002542 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002543 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2544 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002545 const NodeUpdateEntry &replacement = mReplacements[ii];
2546 ASSERT(replacement.parent);
2547 bool replaced = replacement.parent->replaceChildNode(
2548 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002549 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002550 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002551
Olli Etuahocd94ef92015-04-16 19:18:10 +03002552 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002553 {
2554 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002555 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002556 // be replaced, we need to make sure we don't update the replaced
2557 // node; instead, we update the replacement node.
2558 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2559 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002560 NodeUpdateEntry &replacement2 = mReplacements[jj];
2561 if (replacement2.parent == replacement.original)
2562 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002563 }
2564 }
2565 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002566 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2567 {
2568 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2569 ASSERT(replacement.parent);
2570 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2571 replacement.original, replacement.replacements);
2572 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002573 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002574 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002575
Jamie Madill03d863c2016-07-27 18:15:53 -04002576 clearReplacementQueue();
2577}
2578
2579void TIntermTraverser::clearReplacementQueue()
2580{
Olli Etuahod4f303e2015-05-20 17:09:06 +03002581 mReplacements.clear();
2582 mMultiReplacements.clear();
Jamie Madill03d863c2016-07-27 18:15:53 -04002583 mInsertions.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002584}
Jamie Madill1048e432016-07-23 18:51:28 -04002585
Jamie Madill03d863c2016-07-27 18:15:53 -04002586void TIntermTraverser::queueReplacement(TIntermNode *original,
2587 TIntermNode *replacement,
2588 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002589{
Jamie Madill03d863c2016-07-27 18:15:53 -04002590 queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
Jamie Madill1048e432016-07-23 18:51:28 -04002591}
2592
Jamie Madill03d863c2016-07-27 18:15:53 -04002593void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
2594 TIntermNode *original,
2595 TIntermNode *replacement,
2596 OriginalNode originalStatus)
Jamie Madill1048e432016-07-23 18:51:28 -04002597{
Jamie Madill03d863c2016-07-27 18:15:53 -04002598 bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
2599 mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
Jamie Madill1048e432016-07-23 18:51:28 -04002600}