blob: 6c0e9072a3e80bf1fd71c28858c162321f8f8679 [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"
Jamie Madillb1a85f42014-08-19 15:23:24 -040020#include "compiler/translator/HashNames.h"
21#include "compiler/translator/IntermNode.h"
22#include "compiler/translator/SymbolTable.h"
23
24namespace
25{
26
Arun Patole9dea48f2015-04-02 11:45:09 +053027const float kPi = 3.14159265358979323846f;
28const float kDegreesToRadiansMultiplier = kPi / 180.0f;
29const float kRadiansToDegreesMultiplier = 180.0f / kPi;
30
Jamie Madillb1a85f42014-08-19 15:23:24 -040031TPrecision GetHigherPrecision(TPrecision left, TPrecision right)
32{
33 return left > right ? left : right;
34}
35
36bool ValidateMultiplication(TOperator op, const TType &left, const TType &right)
37{
38 switch (op)
39 {
40 case EOpMul:
41 case EOpMulAssign:
42 return left.getNominalSize() == right.getNominalSize() &&
43 left.getSecondarySize() == right.getSecondarySize();
44 case EOpVectorTimesScalar:
45 case EOpVectorTimesScalarAssign:
46 return true;
47 case EOpVectorTimesMatrix:
48 return left.getNominalSize() == right.getRows();
49 case EOpVectorTimesMatrixAssign:
50 return left.getNominalSize() == right.getRows() &&
51 left.getNominalSize() == right.getCols();
52 case EOpMatrixTimesVector:
53 return left.getCols() == right.getNominalSize();
54 case EOpMatrixTimesScalar:
55 case EOpMatrixTimesScalarAssign:
56 return true;
57 case EOpMatrixTimesMatrix:
58 return left.getCols() == right.getRows();
59 case EOpMatrixTimesMatrixAssign:
60 return left.getCols() == right.getCols() &&
61 left.getRows() == right.getRows();
62
63 default:
64 UNREACHABLE();
65 return false;
66 }
67}
68
69bool CompareStructure(const TType& leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040070 const TConstantUnion *rightUnionArray,
71 const TConstantUnion *leftUnionArray);
Jamie Madillb1a85f42014-08-19 15:23:24 -040072
73bool CompareStruct(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -040074 const TConstantUnion *rightUnionArray,
75 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -040076{
77 const TFieldList &fields = leftNodeType.getStruct()->fields();
78
79 size_t structSize = fields.size();
80 size_t index = 0;
81
82 for (size_t j = 0; j < structSize; j++)
83 {
84 size_t size = fields[j]->type()->getObjectSize();
85 for (size_t i = 0; i < size; i++)
86 {
87 if (fields[j]->type()->getBasicType() == EbtStruct)
88 {
89 if (!CompareStructure(*fields[j]->type(),
90 &rightUnionArray[index],
91 &leftUnionArray[index]))
92 {
93 return false;
94 }
95 }
96 else
97 {
98 if (leftUnionArray[index] != rightUnionArray[index])
99 return false;
100 index++;
101 }
102 }
103 }
104 return true;
105}
106
107bool CompareStructure(const TType &leftNodeType,
Jamie Madillb11e2482015-05-04 14:21:22 -0400108 const TConstantUnion *rightUnionArray,
109 const TConstantUnion *leftUnionArray)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400110{
111 if (leftNodeType.isArray())
112 {
113 TType typeWithoutArrayness = leftNodeType;
114 typeWithoutArrayness.clearArrayness();
115
116 size_t arraySize = leftNodeType.getArraySize();
117
118 for (size_t i = 0; i < arraySize; ++i)
119 {
120 size_t offset = typeWithoutArrayness.getObjectSize() * i;
121 if (!CompareStruct(typeWithoutArrayness,
122 &rightUnionArray[offset],
123 &leftUnionArray[offset]))
124 {
125 return false;
126 }
127 }
128 }
129 else
130 {
131 return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray);
132 }
133 return true;
134}
135
Arun Patole274f0702015-05-05 13:33:30 +0530136TConstantUnion *Vectorize(const TConstantUnion &constant, size_t size)
137{
138 TConstantUnion *constUnion = new TConstantUnion[size];
139 for (unsigned int i = 0; i < size; ++i)
140 constUnion[i] = constant;
141
142 return constUnion;
143}
144
Arun Patolebf790422015-05-18 17:53:04 +0530145void UndefinedConstantFoldingError(const TSourceLoc &loc, TOperator op, TBasicType basicType,
146 TInfoSink &infoSink, TConstantUnion *result)
147{
148 std::stringstream constantFoldingErrorStream;
149 constantFoldingErrorStream << "'" << GetOperatorString(op)
150 << "' operation result is undefined for the values passed in";
151 infoSink.info.message(EPrefixWarning, loc, constantFoldingErrorStream.str().c_str());
152
153 switch (basicType)
154 {
155 case EbtFloat :
156 result->setFConst(0.0f);
157 break;
158 case EbtInt:
159 result->setIConst(0);
160 break;
161 case EbtUInt:
162 result->setUConst(0u);
163 break;
164 case EbtBool:
165 result->setBConst(false);
166 break;
167 default:
168 break;
169 }
170}
171
Arun Patole1155ddd2015-06-05 18:04:36 +0530172float VectorLength(TConstantUnion *paramArray, size_t paramArraySize)
173{
174 float result = 0.0f;
175 for (size_t i = 0; i < paramArraySize; i++)
176 {
177 float f = paramArray[i].getFConst();
178 result += f * f;
179 }
180 return sqrtf(result);
181}
182
183float VectorDotProduct(TConstantUnion *paramArray1, TConstantUnion *paramArray2, size_t paramArraySize)
184{
185 float result = 0.0f;
186 for (size_t i = 0; i < paramArraySize; i++)
187 result += paramArray1[i].getFConst() * paramArray2[i].getFConst();
188 return result;
189}
190
Olli Etuahob43846e2015-06-02 18:18:57 +0300191TIntermTyped *CreateFoldedNode(TConstantUnion *constArray, const TIntermTyped *originalNode)
192{
193 if (constArray == nullptr)
194 {
195 return nullptr;
196 }
197 TIntermTyped *folded = new TIntermConstantUnion(constArray, originalNode->getType());
198 folded->getTypePointer()->setQualifier(EvqConst);
199 folded->setLine(originalNode->getLine());
200 return folded;
201}
202
Arun Patole7fa33552015-06-10 15:15:18 +0530203angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &rows, const unsigned int &cols)
204{
205 std::vector<float> elements;
206 for (size_t i = 0; i < rows * cols; i++)
207 elements.push_back(paramArray[i].getFConst());
208 // Transpose is used since the Matrix constructor expects arguments in row-major order,
209 // whereas the paramArray is in column-major order.
210 return angle::Matrix<float>(elements, rows, cols).transpose();
211}
212
213angle::Matrix<float> GetMatrix(TConstantUnion *paramArray, const unsigned int &size)
214{
215 std::vector<float> elements;
216 for (size_t i = 0; i < size * size; i++)
217 elements.push_back(paramArray[i].getFConst());
218 // Transpose is used since the Matrix constructor expects arguments in row-major order,
219 // whereas the paramArray is in column-major order.
220 return angle::Matrix<float>(elements, size).transpose();
221}
222
223void SetUnionArrayFromMatrix(const angle::Matrix<float> &m, TConstantUnion *resultArray)
224{
225 // Transpose is used since the input Matrix is in row-major order,
226 // whereas the actual result should be in column-major order.
227 angle::Matrix<float> result = m.transpose();
228 std::vector<float> resultElements = result.elements();
229 for (size_t i = 0; i < resultElements.size(); i++)
230 resultArray[i].setFConst(resultElements[i]);
231}
232
Jamie Madillb1a85f42014-08-19 15:23:24 -0400233} // namespace anonymous
234
235
236////////////////////////////////////////////////////////////////
237//
238// Member functions of the nodes used for building the tree.
239//
240////////////////////////////////////////////////////////////////
241
Olli Etuahod2a67b92014-10-21 16:42:57 +0300242void TIntermTyped::setTypePreservePrecision(const TType &t)
243{
244 TPrecision precision = getPrecision();
245 mType = t;
246 ASSERT(mType.getBasicType() != EbtBool || precision == EbpUndefined);
247 mType.setPrecision(precision);
248}
249
Jamie Madillb1a85f42014-08-19 15:23:24 -0400250#define REPLACE_IF_IS(node, type, original, replacement) \
251 if (node == original) { \
252 node = static_cast<type *>(replacement); \
253 return true; \
254 }
255
256bool TIntermLoop::replaceChildNode(
257 TIntermNode *original, TIntermNode *replacement)
258{
259 REPLACE_IF_IS(mInit, TIntermNode, original, replacement);
260 REPLACE_IF_IS(mCond, TIntermTyped, original, replacement);
261 REPLACE_IF_IS(mExpr, TIntermTyped, original, replacement);
262 REPLACE_IF_IS(mBody, TIntermNode, original, replacement);
263 return false;
264}
265
Jamie Madillb1a85f42014-08-19 15:23:24 -0400266bool TIntermBranch::replaceChildNode(
267 TIntermNode *original, TIntermNode *replacement)
268{
269 REPLACE_IF_IS(mExpression, TIntermTyped, original, replacement);
270 return false;
271}
272
Jamie Madillb1a85f42014-08-19 15:23:24 -0400273bool TIntermBinary::replaceChildNode(
274 TIntermNode *original, TIntermNode *replacement)
275{
276 REPLACE_IF_IS(mLeft, TIntermTyped, original, replacement);
277 REPLACE_IF_IS(mRight, TIntermTyped, original, replacement);
278 return false;
279}
280
Jamie Madillb1a85f42014-08-19 15:23:24 -0400281bool TIntermUnary::replaceChildNode(
282 TIntermNode *original, TIntermNode *replacement)
283{
284 REPLACE_IF_IS(mOperand, TIntermTyped, original, replacement);
285 return false;
286}
287
Jamie Madillb1a85f42014-08-19 15:23:24 -0400288bool TIntermAggregate::replaceChildNode(
289 TIntermNode *original, TIntermNode *replacement)
290{
291 for (size_t ii = 0; ii < mSequence.size(); ++ii)
292 {
293 REPLACE_IF_IS(mSequence[ii], TIntermNode, original, replacement);
294 }
295 return false;
296}
297
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300298bool TIntermAggregate::replaceChildNodeWithMultiple(TIntermNode *original, TIntermSequence replacements)
299{
300 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
301 {
302 if (*it == original)
303 {
304 it = mSequence.erase(it);
Olli Etuaho8fee0ab2015-04-23 14:52:46 +0300305 mSequence.insert(it, replacements.begin(), replacements.end());
Olli Etuahofc0e2bc2015-04-16 13:39:56 +0300306 return true;
307 }
308 }
309 return false;
310}
311
Olli Etuahoa6f22092015-05-08 18:31:10 +0300312bool TIntermAggregate::insertChildNodes(TIntermSequence::size_type position, TIntermSequence insertions)
313{
314 TIntermSequence::size_type itPosition = 0;
315 for (auto it = mSequence.begin(); it < mSequence.end(); ++it)
316 {
317 if (itPosition == position)
318 {
319 mSequence.insert(it, insertions.begin(), insertions.end());
320 return true;
321 }
322 ++itPosition;
323 }
324 return false;
325}
326
Olli Etuahod2a67b92014-10-21 16:42:57 +0300327void TIntermAggregate::setPrecisionFromChildren()
328{
Olli Etuahoa4aa4e32015-06-04 15:54:30 +0300329 mGotPrecisionFromChildren = true;
Olli Etuahod2a67b92014-10-21 16:42:57 +0300330 if (getBasicType() == EbtBool)
331 {
332 mType.setPrecision(EbpUndefined);
333 return;
334 }
335
336 TPrecision precision = EbpUndefined;
337 TIntermSequence::iterator childIter = mSequence.begin();
338 while (childIter != mSequence.end())
339 {
340 TIntermTyped *typed = (*childIter)->getAsTyped();
341 if (typed)
342 precision = GetHigherPrecision(typed->getPrecision(), precision);
343 ++childIter;
344 }
345 mType.setPrecision(precision);
346}
347
348void TIntermAggregate::setBuiltInFunctionPrecision()
349{
350 // All built-ins returning bool should be handled as ops, not functions.
351 ASSERT(getBasicType() != EbtBool);
352
353 TPrecision precision = EbpUndefined;
354 TIntermSequence::iterator childIter = mSequence.begin();
355 while (childIter != mSequence.end())
356 {
357 TIntermTyped *typed = (*childIter)->getAsTyped();
358 // ESSL spec section 8: texture functions get their precision from the sampler.
359 if (typed && IsSampler(typed->getBasicType()))
360 {
361 precision = typed->getPrecision();
362 break;
363 }
364 ++childIter;
365 }
366 // ESSL 3.0 spec section 8: textureSize always gets highp precision.
367 // All other functions that take a sampler are assumed to be texture functions.
368 if (mName.find("textureSize") == 0)
369 mType.setPrecision(EbpHigh);
370 else
371 mType.setPrecision(precision);
372}
373
Jamie Madillb1a85f42014-08-19 15:23:24 -0400374bool TIntermSelection::replaceChildNode(
375 TIntermNode *original, TIntermNode *replacement)
376{
377 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
378 REPLACE_IF_IS(mTrueBlock, TIntermNode, original, replacement);
379 REPLACE_IF_IS(mFalseBlock, TIntermNode, original, replacement);
380 return false;
381}
382
Olli Etuahoa3a36662015-02-17 13:46:51 +0200383bool TIntermSwitch::replaceChildNode(
384 TIntermNode *original, TIntermNode *replacement)
385{
386 REPLACE_IF_IS(mInit, TIntermTyped, original, replacement);
387 REPLACE_IF_IS(mStatementList, TIntermAggregate, original, replacement);
388 return false;
389}
390
391bool TIntermCase::replaceChildNode(
392 TIntermNode *original, TIntermNode *replacement)
393{
394 REPLACE_IF_IS(mCondition, TIntermTyped, original, replacement);
395 return false;
396}
397
Jamie Madillb1a85f42014-08-19 15:23:24 -0400398//
399// Say whether or not an operation node changes the value of a variable.
400//
401bool TIntermOperator::isAssignment() const
402{
403 switch (mOp)
404 {
405 case EOpPostIncrement:
406 case EOpPostDecrement:
407 case EOpPreIncrement:
408 case EOpPreDecrement:
409 case EOpAssign:
410 case EOpAddAssign:
411 case EOpSubAssign:
412 case EOpMulAssign:
413 case EOpVectorTimesMatrixAssign:
414 case EOpVectorTimesScalarAssign:
415 case EOpMatrixTimesScalarAssign:
416 case EOpMatrixTimesMatrixAssign:
417 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200418 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200419 case EOpBitShiftLeftAssign:
420 case EOpBitShiftRightAssign:
421 case EOpBitwiseAndAssign:
422 case EOpBitwiseXorAssign:
423 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400424 return true;
425 default:
426 return false;
427 }
428}
429
Olli Etuaho8f76bcc2015-06-02 13:54:20 +0300430bool TIntermOperator::isMultiplication() const
431{
432 switch (mOp)
433 {
434 case EOpMul:
435 case EOpMatrixTimesMatrix:
436 case EOpMatrixTimesVector:
437 case EOpMatrixTimesScalar:
438 case EOpVectorTimesMatrix:
439 case EOpVectorTimesScalar:
440 return true;
441 default:
442 return false;
443 }
444}
445
Jamie Madillb1a85f42014-08-19 15:23:24 -0400446//
447// returns true if the operator is for one of the constructors
448//
449bool TIntermOperator::isConstructor() const
450{
451 switch (mOp)
452 {
453 case EOpConstructVec2:
454 case EOpConstructVec3:
455 case EOpConstructVec4:
456 case EOpConstructMat2:
457 case EOpConstructMat3:
458 case EOpConstructMat4:
459 case EOpConstructFloat:
460 case EOpConstructIVec2:
461 case EOpConstructIVec3:
462 case EOpConstructIVec4:
463 case EOpConstructInt:
464 case EOpConstructUVec2:
465 case EOpConstructUVec3:
466 case EOpConstructUVec4:
467 case EOpConstructUInt:
468 case EOpConstructBVec2:
469 case EOpConstructBVec3:
470 case EOpConstructBVec4:
471 case EOpConstructBool:
472 case EOpConstructStruct:
473 return true;
474 default:
475 return false;
476 }
477}
478
479//
480// Make sure the type of a unary operator is appropriate for its
481// combination of operation and operand type.
482//
Olli Etuahof6c694b2015-03-26 14:50:53 +0200483void TIntermUnary::promote(const TType *funcReturnType)
Jamie Madillb1a85f42014-08-19 15:23:24 -0400484{
485 switch (mOp)
486 {
Olli Etuahodca3e792015-03-26 13:24:04 +0200487 case EOpFloatBitsToInt:
488 case EOpFloatBitsToUint:
Olli Etuahoe8d2c072015-01-08 16:33:54 +0200489 case EOpIntBitsToFloat:
490 case EOpUintBitsToFloat:
Olli Etuahodca3e792015-03-26 13:24:04 +0200491 case EOpPackSnorm2x16:
492 case EOpPackUnorm2x16:
493 case EOpPackHalf2x16:
Olli Etuaho7700ff62015-01-15 12:16:29 +0200494 case EOpUnpackSnorm2x16:
495 case EOpUnpackUnorm2x16:
Olli Etuahodca3e792015-03-26 13:24:04 +0200496 mType.setPrecision(EbpHigh);
Arun Patole6b19d762015-02-19 09:40:39 +0530497 break;
Olli Etuahodca3e792015-03-26 13:24:04 +0200498 case EOpUnpackHalf2x16:
499 mType.setPrecision(EbpMedium);
500 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400501 default:
Olli Etuahodca3e792015-03-26 13:24:04 +0200502 setType(mOperand->getType());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400503 }
504
Olli Etuahof6c694b2015-03-26 14:50:53 +0200505 if (funcReturnType != nullptr)
506 {
507 if (funcReturnType->getBasicType() == EbtBool)
508 {
509 // Bool types should not have precision.
510 setType(*funcReturnType);
511 }
512 else
513 {
514 // Precision of the node has been set based on the operand.
515 setTypePreservePrecision(*funcReturnType);
516 }
517 }
518
Jamie Madillb1a85f42014-08-19 15:23:24 -0400519 mType.setQualifier(EvqTemporary);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400520}
521
522//
523// Establishes the type of the resultant operation, as well as
524// makes the operator the correct one for the operands.
525//
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200526// For lots of operations it should already be established that the operand
527// combination is valid, but returns false if operator can't work on operands.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400528//
529bool TIntermBinary::promote(TInfoSink &infoSink)
530{
Olli Etuahoe79904c2015-03-18 16:56:42 +0200531 ASSERT(mLeft->isArray() == mRight->isArray());
Jamie Madillb1a85f42014-08-19 15:23:24 -0400532
Jamie Madillb1a85f42014-08-19 15:23:24 -0400533 //
534 // Base assumption: just make the type the same as the left
535 // operand. Then only deviations from this need be coded.
536 //
537 setType(mLeft->getType());
538
539 // The result gets promoted to the highest precision.
540 TPrecision higherPrecision = GetHigherPrecision(
541 mLeft->getPrecision(), mRight->getPrecision());
542 getTypePointer()->setPrecision(higherPrecision);
543
544 // Binary operations results in temporary variables unless both
545 // operands are const.
546 if (mLeft->getQualifier() != EvqConst || mRight->getQualifier() != EvqConst)
547 {
548 getTypePointer()->setQualifier(EvqTemporary);
549 }
550
551 const int nominalSize =
552 std::max(mLeft->getNominalSize(), mRight->getNominalSize());
553
554 //
555 // All scalars or structs. Code after this test assumes this case is removed!
556 //
557 if (nominalSize == 1)
558 {
559 switch (mOp)
560 {
561 //
562 // Promote to conditional
563 //
564 case EOpEqual:
565 case EOpNotEqual:
566 case EOpLessThan:
567 case EOpGreaterThan:
568 case EOpLessThanEqual:
569 case EOpGreaterThanEqual:
570 setType(TType(EbtBool, EbpUndefined));
571 break;
572
573 //
574 // And and Or operate on conditionals
575 //
576 case EOpLogicalAnd:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200577 case EOpLogicalXor:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400578 case EOpLogicalOr:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200579 ASSERT(mLeft->getBasicType() == EbtBool && mRight->getBasicType() == EbtBool);
Jamie Madillb1a85f42014-08-19 15:23:24 -0400580 setType(TType(EbtBool, EbpUndefined));
581 break;
582
583 default:
584 break;
585 }
586 return true;
587 }
588
589 // If we reach here, at least one of the operands is vector or matrix.
590 // The other operand could be a scalar, vector, or matrix.
591 // Can these two operands be combined?
592 //
593 TBasicType basicType = mLeft->getBasicType();
594 switch (mOp)
595 {
596 case EOpMul:
597 if (!mLeft->isMatrix() && mRight->isMatrix())
598 {
599 if (mLeft->isVector())
600 {
601 mOp = EOpVectorTimesMatrix;
602 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700603 static_cast<unsigned char>(mRight->getCols()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400604 }
605 else
606 {
607 mOp = EOpMatrixTimesScalar;
608 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700609 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mRight->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400610 }
611 }
612 else if (mLeft->isMatrix() && !mRight->isMatrix())
613 {
614 if (mRight->isVector())
615 {
616 mOp = EOpMatrixTimesVector;
617 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700618 static_cast<unsigned char>(mLeft->getRows()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400619 }
620 else
621 {
622 mOp = EOpMatrixTimesScalar;
623 }
624 }
625 else if (mLeft->isMatrix() && mRight->isMatrix())
626 {
627 mOp = EOpMatrixTimesMatrix;
628 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700629 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400630 }
631 else if (!mLeft->isMatrix() && !mRight->isMatrix())
632 {
633 if (mLeft->isVector() && mRight->isVector())
634 {
635 // leave as component product
636 }
637 else if (mLeft->isVector() || mRight->isVector())
638 {
639 mOp = EOpVectorTimesScalar;
640 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700641 static_cast<unsigned char>(nominalSize), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400642 }
643 }
644 else
645 {
646 infoSink.info.message(EPrefixInternalError, getLine(),
647 "Missing elses");
648 return false;
649 }
650
651 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
652 {
653 return false;
654 }
655 break;
656
657 case EOpMulAssign:
658 if (!mLeft->isMatrix() && mRight->isMatrix())
659 {
660 if (mLeft->isVector())
661 {
662 mOp = EOpVectorTimesMatrixAssign;
663 }
664 else
665 {
666 return false;
667 }
668 }
669 else if (mLeft->isMatrix() && !mRight->isMatrix())
670 {
671 if (mRight->isVector())
672 {
673 return false;
674 }
675 else
676 {
677 mOp = EOpMatrixTimesScalarAssign;
678 }
679 }
680 else if (mLeft->isMatrix() && mRight->isMatrix())
681 {
682 mOp = EOpMatrixTimesMatrixAssign;
683 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700684 static_cast<unsigned char>(mRight->getCols()), static_cast<unsigned char>(mLeft->getRows())));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400685 }
686 else if (!mLeft->isMatrix() && !mRight->isMatrix())
687 {
688 if (mLeft->isVector() && mRight->isVector())
689 {
690 // leave as component product
691 }
692 else if (mLeft->isVector() || mRight->isVector())
693 {
694 if (!mLeft->isVector())
695 return false;
696 mOp = EOpVectorTimesScalarAssign;
697 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700698 static_cast<unsigned char>(mLeft->getNominalSize()), 1));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400699 }
700 }
701 else
702 {
703 infoSink.info.message(EPrefixInternalError, getLine(),
704 "Missing elses");
705 return false;
706 }
707
708 if (!ValidateMultiplication(mOp, mLeft->getType(), mRight->getType()))
709 {
710 return false;
711 }
712 break;
713
714 case EOpAssign:
715 case EOpInitialize:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200716 // No more additional checks are needed.
717 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
718 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
719 break;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400720 case EOpAdd:
721 case EOpSub:
722 case EOpDiv:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200723 case EOpIMod:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200724 case EOpBitShiftLeft:
725 case EOpBitShiftRight:
726 case EOpBitwiseAnd:
727 case EOpBitwiseXor:
728 case EOpBitwiseOr:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400729 case EOpAddAssign:
730 case EOpSubAssign:
731 case EOpDivAssign:
Olli Etuahoff805cc2015-02-13 10:59:34 +0200732 case EOpIModAssign:
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200733 case EOpBitShiftLeftAssign:
734 case EOpBitShiftRightAssign:
735 case EOpBitwiseAndAssign:
736 case EOpBitwiseXorAssign:
737 case EOpBitwiseOrAssign:
Jamie Madillb1a85f42014-08-19 15:23:24 -0400738 if ((mLeft->isMatrix() && mRight->isVector()) ||
739 (mLeft->isVector() && mRight->isMatrix()))
740 {
741 return false;
742 }
743
744 // Are the sizes compatible?
745 if (mLeft->getNominalSize() != mRight->getNominalSize() ||
746 mLeft->getSecondarySize() != mRight->getSecondarySize())
747 {
Olli Etuaho6c850472014-12-02 16:23:17 +0200748 // If the nominal sizes of operands do not match:
749 // One of them must be a scalar.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400750 if (!mLeft->isScalar() && !mRight->isScalar())
751 return false;
752
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200753 // In the case of compound assignment other than multiply-assign,
754 // the right side needs to be a scalar. Otherwise a vector/matrix
755 // would be assigned to a scalar. A scalar can't be shifted by a
756 // vector either.
Olli Etuaho6c850472014-12-02 16:23:17 +0200757 if (!mRight->isScalar() &&
Olli Etuaho31b5fc62015-01-16 12:13:36 +0200758 (isAssignment() ||
759 mOp == EOpBitShiftLeft ||
760 mOp == EOpBitShiftRight))
Olli Etuaho6c850472014-12-02 16:23:17 +0200761 return false;
Jamie Madillb1a85f42014-08-19 15:23:24 -0400762 }
763
764 {
765 const int secondarySize = std::max(
766 mLeft->getSecondarySize(), mRight->getSecondarySize());
767 setType(TType(basicType, higherPrecision, EvqTemporary,
Minmin Gong794e0002015-04-07 18:31:54 -0700768 static_cast<unsigned char>(nominalSize), static_cast<unsigned char>(secondarySize)));
Olli Etuahoe79904c2015-03-18 16:56:42 +0200769 if (mLeft->isArray())
770 {
771 ASSERT(mLeft->getArraySize() == mRight->getArraySize());
772 mType.setArraySize(mLeft->getArraySize());
773 }
Jamie Madillb1a85f42014-08-19 15:23:24 -0400774 }
775 break;
776
777 case EOpEqual:
778 case EOpNotEqual:
779 case EOpLessThan:
780 case EOpGreaterThan:
781 case EOpLessThanEqual:
782 case EOpGreaterThanEqual:
Olli Etuaho47fd36a2015-03-19 14:22:24 +0200783 ASSERT((mLeft->getNominalSize() == mRight->getNominalSize()) &&
784 (mLeft->getSecondarySize() == mRight->getSecondarySize()));
Jamie Madillb1a85f42014-08-19 15:23:24 -0400785 setType(TType(EbtBool, EbpUndefined));
786 break;
787
788 default:
789 return false;
790 }
791 return true;
792}
793
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300794TIntermTyped *TIntermBinary::fold(TInfoSink &infoSink)
795{
796 TIntermConstantUnion *leftConstant = mLeft->getAsConstantUnion();
797 TIntermConstantUnion *rightConstant = mRight->getAsConstantUnion();
798 if (leftConstant == nullptr || rightConstant == nullptr)
799 {
800 return nullptr;
801 }
802 TConstantUnion *constArray = leftConstant->foldBinary(mOp, rightConstant, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300803 return CreateFoldedNode(constArray, this);
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300804}
805
Olli Etuaho95310b02015-06-02 17:43:38 +0300806TIntermTyped *TIntermUnary::fold(TInfoSink &infoSink)
807{
808 TIntermConstantUnion *operandConstant = mOperand->getAsConstantUnion();
809 if (operandConstant == nullptr)
810 {
811 return nullptr;
812 }
Arun Patoleab2b9a22015-07-06 18:27:56 +0530813
814 TConstantUnion *constArray = nullptr;
815 switch (mOp)
816 {
817 case EOpAny:
818 case EOpAll:
819 case EOpLength:
820 case EOpTranspose:
821 case EOpDeterminant:
822 case EOpInverse:
823 case EOpPackSnorm2x16:
824 case EOpUnpackSnorm2x16:
825 case EOpPackUnorm2x16:
826 case EOpUnpackUnorm2x16:
827 case EOpPackHalf2x16:
828 case EOpUnpackHalf2x16:
829 constArray = operandConstant->foldUnaryWithDifferentReturnType(mOp, infoSink);
830 break;
831 default:
832 constArray = operandConstant->foldUnaryWithSameReturnType(mOp, infoSink);
833 break;
834 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300835 return CreateFoldedNode(constArray, this);
836}
837
838TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
839{
840 // Make sure that all params are constant before actual constant folding.
841 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300842 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300843 if (param->getAsConstantUnion() == nullptr)
844 {
845 return nullptr;
846 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300847 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300848 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
849 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300850}
851
Jamie Madillb1a85f42014-08-19 15:23:24 -0400852//
853// The fold functions see if an operation on a constant can be done in place,
854// without generating run-time code.
855//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300856// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400857//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300858TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
859{
860 TConstantUnion *leftArray = getUnionArrayPointer();
861 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
862
863 if (!leftArray)
864 return nullptr;
865 if (!rightArray)
866 return nullptr;
867
868 size_t objectSize = getType().getObjectSize();
869
870 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
871 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
872 {
873 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
874 }
875 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
876 {
877 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
878 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
879 objectSize = rightNode->getType().getObjectSize();
880 }
881
882 TConstantUnion *resultArray = nullptr;
883
884 switch(op)
885 {
886 case EOpAdd:
887 resultArray = new TConstantUnion[objectSize];
888 for (size_t i = 0; i < objectSize; i++)
889 resultArray[i] = leftArray[i] + rightArray[i];
890 break;
891 case EOpSub:
892 resultArray = new TConstantUnion[objectSize];
893 for (size_t i = 0; i < objectSize; i++)
894 resultArray[i] = leftArray[i] - rightArray[i];
895 break;
896
897 case EOpMul:
898 case EOpVectorTimesScalar:
899 case EOpMatrixTimesScalar:
900 resultArray = new TConstantUnion[objectSize];
901 for (size_t i = 0; i < objectSize; i++)
902 resultArray[i] = leftArray[i] * rightArray[i];
903 break;
904
905 case EOpMatrixTimesMatrix:
906 {
907 if (getType().getBasicType() != EbtFloat ||
908 rightNode->getBasicType() != EbtFloat)
909 {
910 infoSink.info.message(
911 EPrefixInternalError, getLine(),
912 "Constant Folding cannot be done for matrix multiply");
913 return nullptr;
914 }
915
916 const int leftCols = getCols();
917 const int leftRows = getRows();
918 const int rightCols = rightNode->getType().getCols();
919 const int rightRows = rightNode->getType().getRows();
920 const int resultCols = rightCols;
921 const int resultRows = leftRows;
922
923 resultArray = new TConstantUnion[resultCols * resultRows];
924 for (int row = 0; row < resultRows; row++)
925 {
926 for (int column = 0; column < resultCols; column++)
927 {
928 resultArray[resultRows * column + row].setFConst(0.0f);
929 for (int i = 0; i < leftCols; i++)
930 {
931 resultArray[resultRows * column + row].setFConst(
932 resultArray[resultRows * column + row].getFConst() +
933 leftArray[i * leftRows + row].getFConst() *
934 rightArray[column * rightRows + i].getFConst());
935 }
936 }
937 }
938 }
939 break;
940
941 case EOpDiv:
942 case EOpIMod:
943 {
944 resultArray = new TConstantUnion[objectSize];
945 for (size_t i = 0; i < objectSize; i++)
946 {
947 switch (getType().getBasicType())
948 {
949 case EbtFloat:
950 if (rightArray[i] == 0.0f)
951 {
952 infoSink.info.message(EPrefixWarning, getLine(),
953 "Divide by zero error during constant folding");
954 resultArray[i].setFConst(leftArray[i].getFConst() < 0 ? -FLT_MAX : FLT_MAX);
955 }
956 else
957 {
958 ASSERT(op == EOpDiv);
959 resultArray[i].setFConst(leftArray[i].getFConst() / rightArray[i].getFConst());
960 }
961 break;
962
963 case EbtInt:
964 if (rightArray[i] == 0)
965 {
966 infoSink.info.message(EPrefixWarning, getLine(),
967 "Divide by zero error during constant folding");
968 resultArray[i].setIConst(INT_MAX);
969 }
970 else
971 {
972 if (op == EOpDiv)
973 {
974 resultArray[i].setIConst(leftArray[i].getIConst() / rightArray[i].getIConst());
975 }
976 else
977 {
978 ASSERT(op == EOpIMod);
979 resultArray[i].setIConst(leftArray[i].getIConst() % rightArray[i].getIConst());
980 }
981 }
982 break;
983
984 case EbtUInt:
985 if (rightArray[i] == 0)
986 {
987 infoSink.info.message(EPrefixWarning, getLine(),
988 "Divide by zero error during constant folding");
989 resultArray[i].setUConst(UINT_MAX);
990 }
991 else
992 {
993 if (op == EOpDiv)
994 {
995 resultArray[i].setUConst(leftArray[i].getUConst() / rightArray[i].getUConst());
996 }
997 else
998 {
999 ASSERT(op == EOpIMod);
1000 resultArray[i].setUConst(leftArray[i].getUConst() % rightArray[i].getUConst());
1001 }
1002 }
1003 break;
1004
1005 default:
1006 infoSink.info.message(EPrefixInternalError, getLine(),
1007 "Constant folding cannot be done for \"/\"");
1008 return nullptr;
1009 }
1010 }
1011 }
1012 break;
1013
1014 case EOpMatrixTimesVector:
1015 {
1016 if (rightNode->getBasicType() != EbtFloat)
1017 {
1018 infoSink.info.message(EPrefixInternalError, getLine(),
1019 "Constant Folding cannot be done for matrix times vector");
1020 return nullptr;
1021 }
1022
1023 const int matrixCols = getCols();
1024 const int matrixRows = getRows();
1025
1026 resultArray = new TConstantUnion[matrixRows];
1027
1028 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1029 {
1030 resultArray[matrixRow].setFConst(0.0f);
1031 for (int col = 0; col < matrixCols; col++)
1032 {
1033 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1034 leftArray[col * matrixRows + matrixRow].getFConst() *
1035 rightArray[col].getFConst());
1036 }
1037 }
1038 }
1039 break;
1040
1041 case EOpVectorTimesMatrix:
1042 {
1043 if (getType().getBasicType() != EbtFloat)
1044 {
1045 infoSink.info.message(EPrefixInternalError, getLine(),
1046 "Constant Folding cannot be done for vector times matrix");
1047 return nullptr;
1048 }
1049
1050 const int matrixCols = rightNode->getType().getCols();
1051 const int matrixRows = rightNode->getType().getRows();
1052
1053 resultArray = new TConstantUnion[matrixCols];
1054
1055 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1056 {
1057 resultArray[matrixCol].setFConst(0.0f);
1058 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1059 {
1060 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1061 leftArray[matrixRow].getFConst() *
1062 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1063 }
1064 }
1065 }
1066 break;
1067
1068 case EOpLogicalAnd:
1069 {
1070 resultArray = new TConstantUnion[objectSize];
1071 for (size_t i = 0; i < objectSize; i++)
1072 {
1073 resultArray[i] = leftArray[i] && rightArray[i];
1074 }
1075 }
1076 break;
1077
1078 case EOpLogicalOr:
1079 {
1080 resultArray = new TConstantUnion[objectSize];
1081 for (size_t i = 0; i < objectSize; i++)
1082 {
1083 resultArray[i] = leftArray[i] || rightArray[i];
1084 }
1085 }
1086 break;
1087
1088 case EOpLogicalXor:
1089 {
1090 resultArray = new TConstantUnion[objectSize];
1091 for (size_t i = 0; i < objectSize; i++)
1092 {
1093 switch (getType().getBasicType())
1094 {
1095 case EbtBool:
1096 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1097 break;
1098 default:
1099 UNREACHABLE();
1100 break;
1101 }
1102 }
1103 }
1104 break;
1105
1106 case EOpBitwiseAnd:
1107 resultArray = new TConstantUnion[objectSize];
1108 for (size_t i = 0; i < objectSize; i++)
1109 resultArray[i] = leftArray[i] & rightArray[i];
1110 break;
1111 case EOpBitwiseXor:
1112 resultArray = new TConstantUnion[objectSize];
1113 for (size_t i = 0; i < objectSize; i++)
1114 resultArray[i] = leftArray[i] ^ rightArray[i];
1115 break;
1116 case EOpBitwiseOr:
1117 resultArray = new TConstantUnion[objectSize];
1118 for (size_t i = 0; i < objectSize; i++)
1119 resultArray[i] = leftArray[i] | rightArray[i];
1120 break;
1121 case EOpBitShiftLeft:
1122 resultArray = new TConstantUnion[objectSize];
1123 for (size_t i = 0; i < objectSize; i++)
1124 resultArray[i] = leftArray[i] << rightArray[i];
1125 break;
1126 case EOpBitShiftRight:
1127 resultArray = new TConstantUnion[objectSize];
1128 for (size_t i = 0; i < objectSize; i++)
1129 resultArray[i] = leftArray[i] >> rightArray[i];
1130 break;
1131
1132 case EOpLessThan:
1133 ASSERT(objectSize == 1);
1134 resultArray = new TConstantUnion[1];
1135 resultArray->setBConst(*leftArray < *rightArray);
1136 break;
1137
1138 case EOpGreaterThan:
1139 ASSERT(objectSize == 1);
1140 resultArray = new TConstantUnion[1];
1141 resultArray->setBConst(*leftArray > *rightArray);
1142 break;
1143
1144 case EOpLessThanEqual:
1145 ASSERT(objectSize == 1);
1146 resultArray = new TConstantUnion[1];
1147 resultArray->setBConst(!(*leftArray > *rightArray));
1148 break;
1149
1150 case EOpGreaterThanEqual:
1151 ASSERT(objectSize == 1);
1152 resultArray = new TConstantUnion[1];
1153 resultArray->setBConst(!(*leftArray < *rightArray));
1154 break;
1155
1156 case EOpEqual:
1157 case EOpNotEqual:
1158 {
1159 resultArray = new TConstantUnion[1];
1160 bool equal = true;
1161 if (getType().getBasicType() == EbtStruct)
1162 {
1163 equal = CompareStructure(getType(), rightArray, leftArray);
1164 }
1165 else
1166 {
1167 for (size_t i = 0; i < objectSize; i++)
1168 {
1169 if (leftArray[i] != rightArray[i])
1170 {
1171 equal = false;
1172 break; // break out of for loop
1173 }
1174 }
1175 }
1176 if (op == EOpEqual)
1177 {
1178 resultArray->setBConst(equal);
1179 }
1180 else
1181 {
1182 resultArray->setBConst(!equal);
1183 }
1184 }
1185 break;
1186
1187 default:
1188 infoSink.info.message(
1189 EPrefixInternalError, getLine(),
1190 "Invalid operator for constant folding");
1191 return nullptr;
1192 }
1193 return resultArray;
1194}
1195
1196//
1197// The fold functions see if an operation on a constant can be done in place,
1198// without generating run-time code.
1199//
Olli Etuaho95310b02015-06-02 17:43:38 +03001200// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001201//
Arun Patoleab2b9a22015-07-06 18:27:56 +05301202TConstantUnion *TIntermConstantUnion::foldUnaryWithDifferentReturnType(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001203{
Arun Patoleab2b9a22015-07-06 18:27:56 +05301204 //
1205 // Do operations where the return type has a different number of components compared to the operand type.
1206 //
Jamie Madillb1a85f42014-08-19 15:23:24 -04001207
Arun Patoleab2b9a22015-07-06 18:27:56 +05301208 TConstantUnion *operandArray = getUnionArrayPointer();
1209 if (!operandArray)
1210 return nullptr;
1211
1212 size_t objectSize = getType().getObjectSize();
1213 TConstantUnion *resultArray = nullptr;
1214 switch (op)
1215 {
1216 case EOpAny:
1217 if (getType().getBasicType() == EbtBool)
1218 {
1219 resultArray = new TConstantUnion();
1220 resultArray->setBConst(false);
1221 for (size_t i = 0; i < objectSize; i++)
1222 {
1223 if (operandArray[i].getBConst())
1224 {
1225 resultArray->setBConst(true);
1226 break;
1227 }
1228 }
1229 break;
1230 }
1231 else
1232 {
1233 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1234 return nullptr;
1235 }
1236
1237 case EOpAll:
1238 if (getType().getBasicType() == EbtBool)
1239 {
1240 resultArray = new TConstantUnion();
1241 resultArray->setBConst(true);
1242 for (size_t i = 0; i < objectSize; i++)
1243 {
1244 if (!operandArray[i].getBConst())
1245 {
1246 resultArray->setBConst(false);
1247 break;
1248 }
1249 }
1250 break;
1251 }
1252 else
1253 {
1254 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1255 return nullptr;
1256 }
1257
1258 case EOpLength:
1259 if (getType().getBasicType() == EbtFloat)
1260 {
1261 resultArray = new TConstantUnion();
1262 resultArray->setFConst(VectorLength(operandArray, objectSize));
1263 break;
1264 }
1265 else
1266 {
1267 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1268 return nullptr;
1269 }
1270
1271 case EOpTranspose:
1272 if (getType().getBasicType() == EbtFloat)
1273 {
1274 resultArray = new TConstantUnion[objectSize];
1275 angle::Matrix<float> result =
1276 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
1277 SetUnionArrayFromMatrix(result, resultArray);
1278 break;
1279 }
1280 else
1281 {
1282 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1283 return nullptr;
1284 }
1285
1286 case EOpDeterminant:
1287 if (getType().getBasicType() == EbtFloat)
1288 {
1289 unsigned int size = getType().getNominalSize();
1290 ASSERT(size >= 2 && size <= 4);
1291 resultArray = new TConstantUnion();
1292 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1293 break;
1294 }
1295 else
1296 {
1297 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1298 return nullptr;
1299 }
1300
1301 case EOpInverse:
1302 if (getType().getBasicType() == EbtFloat)
1303 {
1304 unsigned int size = getType().getNominalSize();
1305 ASSERT(size >= 2 && size <= 4);
1306 resultArray = new TConstantUnion[objectSize];
1307 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1308 SetUnionArrayFromMatrix(result, resultArray);
1309 break;
1310 }
1311 else
1312 {
1313 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1314 return nullptr;
1315 }
1316
1317 case EOpPackSnorm2x16:
1318 if (getType().getBasicType() == EbtFloat)
1319 {
1320 ASSERT(getType().getNominalSize() == 2);
1321 resultArray = new TConstantUnion();
1322 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1323 break;
1324 }
1325 else
1326 {
1327 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1328 return nullptr;
1329 }
1330
1331 case EOpUnpackSnorm2x16:
1332 if (getType().getBasicType() == EbtUInt)
1333 {
1334 resultArray = new TConstantUnion[2];
1335 float f1, f2;
1336 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1337 resultArray[0].setFConst(f1);
1338 resultArray[1].setFConst(f2);
1339 break;
1340 }
1341 else
1342 {
1343 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1344 return nullptr;
1345 }
1346
1347 case EOpPackUnorm2x16:
1348 if (getType().getBasicType() == EbtFloat)
1349 {
1350 ASSERT(getType().getNominalSize() == 2);
1351 resultArray = new TConstantUnion();
1352 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1353 break;
1354 }
1355 else
1356 {
1357 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1358 return nullptr;
1359 }
1360
1361 case EOpUnpackUnorm2x16:
1362 if (getType().getBasicType() == EbtUInt)
1363 {
1364 resultArray = new TConstantUnion[2];
1365 float f1, f2;
1366 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1367 resultArray[0].setFConst(f1);
1368 resultArray[1].setFConst(f2);
1369 break;
1370 }
1371 else
1372 {
1373 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1374 return nullptr;
1375 }
1376
1377 case EOpPackHalf2x16:
1378 if (getType().getBasicType() == EbtFloat)
1379 {
1380 ASSERT(getType().getNominalSize() == 2);
1381 resultArray = new TConstantUnion();
1382 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1383 break;
1384 }
1385 else
1386 {
1387 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1388 return nullptr;
1389 }
1390
1391 case EOpUnpackHalf2x16:
1392 if (getType().getBasicType() == EbtUInt)
1393 {
1394 resultArray = new TConstantUnion[2];
1395 float f1, f2;
1396 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1397 resultArray[0].setFConst(f1);
1398 resultArray[1].setFConst(f2);
1399 break;
1400 }
1401 else
1402 {
1403 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1404 return nullptr;
1405 }
1406 break;
1407
1408 default:
1409 break;
1410 }
1411
1412 return resultArray;
1413}
1414
1415TConstantUnion *TIntermConstantUnion::foldUnaryWithSameReturnType(TOperator op, TInfoSink &infoSink)
1416{
1417 //
1418 // Do unary operations where the return type is the same as operand type.
1419 //
1420
1421 TConstantUnion *operandArray = getUnionArrayPointer();
Olli Etuaho95310b02015-06-02 17:43:38 +03001422 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301423 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001424
1425 size_t objectSize = getType().getObjectSize();
1426
Arun Patoleab2b9a22015-07-06 18:27:56 +05301427 TConstantUnion *resultArray = new TConstantUnion[objectSize];
1428 for (size_t i = 0; i < objectSize; i++)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301429 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301430 switch(op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301431 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301432 case EOpNegative:
1433 switch (getType().getBasicType())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301434 {
Arun Patoleab2b9a22015-07-06 18:27:56 +05301435 case EbtFloat:
1436 resultArray[i].setFConst(-operandArray[i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301437 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301438 case EbtInt:
1439 resultArray[i].setIConst(-operandArray[i].getIConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05301440 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301441 case EbtUInt:
1442 resultArray[i].setUConst(static_cast<unsigned int>(
1443 -static_cast<int>(operandArray[i].getUConst())));
Arun Patole1155ddd2015-06-05 18:04:36 +05301444 break;
Arun Patoleab2b9a22015-07-06 18:27:56 +05301445 default:
1446 infoSink.info.message(
1447 EPrefixInternalError, getLine(),
1448 "Unary operation not folded into constant");
Arun Patolecdfa8f52015-06-30 17:48:25 +05301449 return nullptr;
1450 }
1451 break;
1452
Arun Patoleab2b9a22015-07-06 18:27:56 +05301453 case EOpPositive:
1454 switch (getType().getBasicType())
1455 {
1456 case EbtFloat:
1457 resultArray[i].setFConst(operandArray[i].getFConst());
1458 break;
1459 case EbtInt:
1460 resultArray[i].setIConst(operandArray[i].getIConst());
1461 break;
1462 case EbtUInt:
1463 resultArray[i].setUConst(static_cast<unsigned int>(
1464 static_cast<int>(operandArray[i].getUConst())));
1465 break;
1466 default:
1467 infoSink.info.message(
1468 EPrefixInternalError, getLine(),
1469 "Unary operation not folded into constant");
1470 return nullptr;
1471 }
1472 break;
1473
1474 case EOpLogicalNot:
1475 // this code is written for possible future use,
1476 // will not get executed currently
1477 switch (getType().getBasicType())
1478 {
1479 case EbtBool:
1480 resultArray[i].setBConst(!operandArray[i].getBConst());
1481 break;
1482 default:
1483 infoSink.info.message(
1484 EPrefixInternalError, getLine(),
1485 "Unary operation not folded into constant");
1486 return nullptr;
1487 }
1488 break;
1489
1490 case EOpBitwiseNot:
1491 switch (getType().getBasicType())
1492 {
1493 case EbtInt:
1494 resultArray[i].setIConst(~operandArray[i].getIConst());
1495 break;
1496 case EbtUInt:
1497 resultArray[i].setUConst(~operandArray[i].getUConst());
1498 break;
1499 default:
1500 infoSink.info.message(
1501 EPrefixInternalError, getLine(),
1502 "Unary operation not folded into constant");
1503 return nullptr;
1504 }
1505 break;
1506
1507 case EOpRadians:
1508 if (getType().getBasicType() == EbtFloat)
1509 {
1510 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
1511 break;
1512 }
1513 infoSink.info.message(
1514 EPrefixInternalError, getLine(),
1515 "Unary operation not folded into constant");
1516 return nullptr;
1517
1518 case EOpDegrees:
1519 if (getType().getBasicType() == EbtFloat)
1520 {
1521 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
1522 break;
1523 }
1524 infoSink.info.message(
1525 EPrefixInternalError, getLine(),
1526 "Unary operation not folded into constant");
1527 return nullptr;
1528
1529 case EOpSin:
1530 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
1531 return nullptr;
1532 break;
1533
1534 case EOpCos:
1535 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
1536 return nullptr;
1537 break;
1538
1539 case EOpTan:
1540 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
1541 return nullptr;
1542 break;
1543
1544 case EOpAsin:
1545 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1546 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1547 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1548 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
1549 return nullptr;
1550 break;
1551
1552 case EOpAcos:
1553 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
1554 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1555 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1556 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
1557 return nullptr;
1558 break;
1559
1560 case EOpAtan:
1561 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
1562 return nullptr;
1563 break;
1564
1565 case EOpSinh:
1566 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
1567 return nullptr;
1568 break;
1569
1570 case EOpCosh:
1571 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
1572 return nullptr;
1573 break;
1574
1575 case EOpTanh:
1576 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
1577 return nullptr;
1578 break;
1579
1580 case EOpAsinh:
1581 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
1582 return nullptr;
1583 break;
1584
1585 case EOpAcosh:
1586 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
1587 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1588 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1589 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
1590 return nullptr;
1591 break;
1592
1593 case EOpAtanh:
1594 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
1595 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1596 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1597 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
1598 return nullptr;
1599 break;
1600
1601 case EOpAbs:
1602 switch (getType().getBasicType())
1603 {
1604 case EbtFloat:
1605 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
1606 break;
1607 case EbtInt:
1608 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
1609 break;
1610 default:
1611 infoSink.info.message(
1612 EPrefixInternalError, getLine(),
1613 "Unary operation not folded into constant");
1614 return nullptr;
1615 }
1616 break;
1617
1618 case EOpSign:
1619 switch (getType().getBasicType())
1620 {
1621 case EbtFloat:
1622 {
1623 float fConst = operandArray[i].getFConst();
1624 float fResult = 0.0f;
1625 if (fConst > 0.0f)
1626 fResult = 1.0f;
1627 else if (fConst < 0.0f)
1628 fResult = -1.0f;
1629 resultArray[i].setFConst(fResult);
1630 }
1631 break;
1632 case EbtInt:
1633 {
1634 int iConst = operandArray[i].getIConst();
1635 int iResult = 0;
1636 if (iConst > 0)
1637 iResult = 1;
1638 else if (iConst < 0)
1639 iResult = -1;
1640 resultArray[i].setIConst(iResult);
1641 }
1642 break;
1643 default:
1644 infoSink.info.message(
1645 EPrefixInternalError, getLine(),
1646 "Unary operation not folded into constant");
1647 return nullptr;
1648 }
1649 break;
1650
1651 case EOpFloor:
1652 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
1653 return nullptr;
1654 break;
1655
1656 case EOpTrunc:
1657 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
1658 return nullptr;
1659 break;
1660
1661 case EOpRound:
1662 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
1663 return nullptr;
1664 break;
1665
1666 case EOpRoundEven:
1667 if (getType().getBasicType() == EbtFloat)
1668 {
1669 float x = operandArray[i].getFConst();
1670 float result;
1671 float fractPart = modff(x, &result);
1672 if (fabsf(fractPart) == 0.5f)
1673 result = 2.0f * roundf(x / 2.0f);
1674 else
1675 result = roundf(x);
1676 resultArray[i].setFConst(result);
1677 break;
1678 }
1679 infoSink.info.message(
1680 EPrefixInternalError, getLine(),
1681 "Unary operation not folded into constant");
1682 return nullptr;
1683
1684 case EOpCeil:
1685 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
1686 return nullptr;
1687 break;
1688
1689 case EOpFract:
1690 if (getType().getBasicType() == EbtFloat)
1691 {
1692 float x = operandArray[i].getFConst();
1693 resultArray[i].setFConst(x - floorf(x));
1694 break;
1695 }
1696 infoSink.info.message(
1697 EPrefixInternalError, getLine(),
1698 "Unary operation not folded into constant");
1699 return nullptr;
1700
1701 case EOpExp:
1702 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
1703 return nullptr;
1704 break;
1705
1706 case EOpLog:
1707 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
1708 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1709 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1710 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1711 return nullptr;
1712 break;
1713
1714 case EOpExp2:
1715 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
1716 return nullptr;
1717 break;
1718
1719 case EOpLog2:
1720 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1721 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
1722 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1723 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1724 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
1725 return nullptr;
1726 else
1727 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
1728 break;
1729
1730 case EOpSqrt:
1731 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
1732 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1733 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1734 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1735 return nullptr;
1736 break;
1737
1738 case EOpInverseSqrt:
1739 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1740 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1741 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
1742 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1743 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1744 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
1745 return nullptr;
1746 else
1747 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
1748 break;
1749
1750 case EOpVectorLogicalNot:
1751 if (getType().getBasicType() == EbtBool)
1752 {
1753 resultArray[i].setBConst(!operandArray[i].getBConst());
1754 break;
1755 }
1756 infoSink.info.message(
1757 EPrefixInternalError, getLine(),
1758 "Unary operation not folded into constant");
1759 return nullptr;
1760
1761 case EOpNormalize:
1762 if (getType().getBasicType() == EbtFloat)
1763 {
1764 float x = operandArray[i].getFConst();
1765 float length = VectorLength(operandArray, objectSize);
1766 if (length)
1767 resultArray[i].setFConst(x / length);
1768 else
1769 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1770 &resultArray[i]);
1771 break;
1772 }
1773 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1774 return nullptr;
1775
Arun Patole1155ddd2015-06-05 18:04:36 +05301776 default:
Arun Patoleab2b9a22015-07-06 18:27:56 +05301777 return nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301778 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05301779 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001780
Arun Patoleab2b9a22015-07-06 18:27:56 +05301781 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001782}
1783
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001784bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1785 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301786{
1787 ASSERT(builtinFunc);
1788
1789 if (getType().getBasicType() == EbtFloat)
1790 {
1791 result->setFConst(builtinFunc(parameter.getFConst()));
1792 return true;
1793 }
1794
1795 infoSink.info.message(
1796 EPrefixInternalError, getLine(),
1797 "Unary operation not folded into constant");
1798 return false;
1799}
1800
Jamie Madillb1a85f42014-08-19 15:23:24 -04001801// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001802TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301803{
Olli Etuahob43846e2015-06-02 18:18:57 +03001804 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301805 TIntermSequence *sequence = aggregate->getSequence();
1806 unsigned int paramsCount = sequence->size();
1807 std::vector<TConstantUnion *> unionArrays(paramsCount);
1808 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001809 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301810 TBasicType basicType = EbtVoid;
1811 TSourceLoc loc;
1812 for (unsigned int i = 0; i < paramsCount; i++)
1813 {
1814 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001815 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301816
1817 if (i == 0)
1818 {
1819 basicType = paramConstant->getType().getBasicType();
1820 loc = paramConstant->getLine();
1821 }
1822 unionArrays[i] = paramConstant->getUnionArrayPointer();
1823 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001824 if (objectSizes[i] > maxObjectSize)
1825 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301826 }
1827
Arun Patole7fa33552015-06-10 15:15:18 +05301828 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1829 {
1830 for (unsigned int i = 0; i < paramsCount; i++)
1831 if (objectSizes[i] != maxObjectSize)
1832 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1833 }
Arun Patole274f0702015-05-05 13:33:30 +05301834
Olli Etuahob43846e2015-06-02 18:18:57 +03001835 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301836 if (paramsCount == 2)
1837 {
1838 //
1839 // Binary built-in
1840 //
1841 switch (op)
1842 {
Arun Patolebf790422015-05-18 17:53:04 +05301843 case EOpAtan:
1844 {
1845 if (basicType == EbtFloat)
1846 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001847 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301848 for (size_t i = 0; i < maxObjectSize; i++)
1849 {
1850 float y = unionArrays[0][i].getFConst();
1851 float x = unionArrays[1][i].getFConst();
1852 // Results are undefined if x and y are both 0.
1853 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001854 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301855 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001856 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301857 }
1858 }
1859 else
1860 UNREACHABLE();
1861 }
1862 break;
1863
1864 case EOpPow:
1865 {
1866 if (basicType == EbtFloat)
1867 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001868 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301869 for (size_t i = 0; i < maxObjectSize; i++)
1870 {
1871 float x = unionArrays[0][i].getFConst();
1872 float y = unionArrays[1][i].getFConst();
1873 // Results are undefined if x < 0.
1874 // Results are undefined if x = 0 and y <= 0.
1875 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001876 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301877 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001878 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301879 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001880 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05301881 }
1882 }
1883 else
1884 UNREACHABLE();
1885 }
1886 break;
1887
1888 case EOpMod:
1889 {
1890 if (basicType == EbtFloat)
1891 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001892 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301893 for (size_t i = 0; i < maxObjectSize; i++)
1894 {
1895 float x = unionArrays[0][i].getFConst();
1896 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001897 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05301898 }
1899 }
1900 else
1901 UNREACHABLE();
1902 }
1903 break;
1904
Arun Patole274f0702015-05-05 13:33:30 +05301905 case EOpMin:
1906 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001907 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301908 for (size_t i = 0; i < maxObjectSize; i++)
1909 {
1910 switch (basicType)
1911 {
1912 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001913 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301914 break;
1915 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001916 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301917 break;
1918 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001919 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301920 break;
1921 default:
1922 UNREACHABLE();
1923 break;
1924 }
1925 }
1926 }
1927 break;
1928
1929 case EOpMax:
1930 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001931 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301932 for (size_t i = 0; i < maxObjectSize; i++)
1933 {
1934 switch (basicType)
1935 {
1936 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001937 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301938 break;
1939 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001940 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301941 break;
1942 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001943 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301944 break;
1945 default:
1946 UNREACHABLE();
1947 break;
1948 }
1949 }
1950 }
1951 break;
1952
Arun Patolebf790422015-05-18 17:53:04 +05301953 case EOpStep:
1954 {
1955 if (basicType == EbtFloat)
1956 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001957 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301958 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03001959 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05301960 }
1961 else
1962 UNREACHABLE();
1963 }
1964 break;
1965
Arun Patole9d0b1f92015-05-20 14:27:17 +05301966 case EOpLessThan:
1967 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001968 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301969 for (size_t i = 0; i < maxObjectSize; i++)
1970 {
1971 switch (basicType)
1972 {
1973 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001974 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301975 break;
1976 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001977 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301978 break;
1979 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001980 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301981 break;
1982 default:
1983 UNREACHABLE();
1984 break;
1985 }
1986 }
1987 }
1988 break;
1989
1990 case EOpLessThanEqual:
1991 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001992 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301993 for (size_t i = 0; i < maxObjectSize; i++)
1994 {
1995 switch (basicType)
1996 {
1997 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001998 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301999 break;
2000 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002001 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302002 break;
2003 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002004 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302005 break;
2006 default:
2007 UNREACHABLE();
2008 break;
2009 }
2010 }
2011 }
2012 break;
2013
2014 case EOpGreaterThan:
2015 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002016 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302017 for (size_t i = 0; i < maxObjectSize; i++)
2018 {
2019 switch (basicType)
2020 {
2021 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002022 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302023 break;
2024 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002025 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302026 break;
2027 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002028 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302029 break;
2030 default:
2031 UNREACHABLE();
2032 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002033 }
2034 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302035 }
2036 break;
2037
2038 case EOpGreaterThanEqual:
2039 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002040 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302041 for (size_t i = 0; i < maxObjectSize; i++)
2042 {
2043 switch (basicType)
2044 {
2045 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002046 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302047 break;
2048 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002049 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302050 break;
2051 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002052 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302053 break;
2054 default:
2055 UNREACHABLE();
2056 break;
2057 }
2058 }
2059 }
2060 break;
2061
2062 case EOpVectorEqual:
2063 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002064 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302065 for (size_t i = 0; i < maxObjectSize; i++)
2066 {
2067 switch (basicType)
2068 {
2069 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002070 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302071 break;
2072 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002073 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302074 break;
2075 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002076 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302077 break;
2078 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002079 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302080 break;
2081 default:
2082 UNREACHABLE();
2083 break;
2084 }
2085 }
2086 }
2087 break;
2088
2089 case EOpVectorNotEqual:
2090 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002091 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302092 for (size_t i = 0; i < maxObjectSize; i++)
2093 {
2094 switch (basicType)
2095 {
2096 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002097 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302098 break;
2099 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002100 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302101 break;
2102 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002103 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302104 break;
2105 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002106 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302107 break;
2108 default:
2109 UNREACHABLE();
2110 break;
2111 }
2112 }
2113 }
2114 break;
2115
Arun Patole1155ddd2015-06-05 18:04:36 +05302116 case EOpDistance:
2117 if (basicType == EbtFloat)
2118 {
2119 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002120 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302121 for (size_t i = 0; i < maxObjectSize; i++)
2122 {
2123 float x = unionArrays[0][i].getFConst();
2124 float y = unionArrays[1][i].getFConst();
2125 distanceArray[i].setFConst(x - y);
2126 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002127 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302128 }
2129 else
2130 UNREACHABLE();
2131 break;
2132
2133 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002134
Arun Patole1155ddd2015-06-05 18:04:36 +05302135 if (basicType == EbtFloat)
2136 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002137 resultArray = new TConstantUnion();
2138 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302139 }
2140 else
2141 UNREACHABLE();
2142 break;
2143
2144 case EOpCross:
2145 if (basicType == EbtFloat && maxObjectSize == 3)
2146 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002147 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302148 float x0 = unionArrays[0][0].getFConst();
2149 float x1 = unionArrays[0][1].getFConst();
2150 float x2 = unionArrays[0][2].getFConst();
2151 float y0 = unionArrays[1][0].getFConst();
2152 float y1 = unionArrays[1][1].getFConst();
2153 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002154 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2155 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2156 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302157 }
2158 else
2159 UNREACHABLE();
2160 break;
2161
2162 case EOpReflect:
2163 if (basicType == EbtFloat)
2164 {
2165 // genType reflect (genType I, genType N) :
2166 // For the incident vector I and surface orientation N, returns the reflection direction:
2167 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002168 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302169 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2170 for (size_t i = 0; i < maxObjectSize; i++)
2171 {
2172 float result = unionArrays[0][i].getFConst() -
2173 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002174 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302175 }
2176 }
2177 else
2178 UNREACHABLE();
2179 break;
2180
Arun Patole7fa33552015-06-10 15:15:18 +05302181 case EOpMul:
2182 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2183 (*sequence)[1]->getAsTyped()->isMatrix())
2184 {
2185 // Perform component-wise matrix multiplication.
2186 resultArray = new TConstantUnion[maxObjectSize];
2187 size_t size = (*sequence)[0]->getAsTyped()->getNominalSize();
2188 angle::Matrix<float> result =
2189 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2190 SetUnionArrayFromMatrix(result, resultArray);
2191 }
2192 else
2193 UNREACHABLE();
2194 break;
2195
2196 case EOpOuterProduct:
2197 if (basicType == EbtFloat)
2198 {
2199 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2200 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2201 resultArray = new TConstantUnion[numRows * numCols];
2202 angle::Matrix<float> result =
2203 GetMatrix(unionArrays[0], 1, numCols).outerProduct(GetMatrix(unionArrays[1], numRows, 1));
2204 SetUnionArrayFromMatrix(result, resultArray);
2205 }
2206 else
2207 UNREACHABLE();
2208 break;
2209
Arun Patole274f0702015-05-05 13:33:30 +05302210 default:
2211 UNREACHABLE();
2212 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2213 return nullptr;
2214 }
2215 }
2216 else if (paramsCount == 3)
2217 {
2218 //
2219 // Ternary built-in
2220 //
2221 switch (op)
2222 {
2223 case EOpClamp:
2224 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002225 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302226 for (size_t i = 0; i < maxObjectSize; i++)
2227 {
2228 switch (basicType)
2229 {
2230 case EbtFloat:
2231 {
2232 float x = unionArrays[0][i].getFConst();
2233 float min = unionArrays[1][i].getFConst();
2234 float max = unionArrays[2][i].getFConst();
2235 // Results are undefined if min > max.
2236 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002237 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302238 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002239 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302240 }
2241 break;
2242 case EbtInt:
2243 {
2244 int x = unionArrays[0][i].getIConst();
2245 int min = unionArrays[1][i].getIConst();
2246 int max = unionArrays[2][i].getIConst();
2247 // Results are undefined if min > max.
2248 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002249 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302250 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002251 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302252 }
2253 break;
2254 case EbtUInt:
2255 {
2256 unsigned int x = unionArrays[0][i].getUConst();
2257 unsigned int min = unionArrays[1][i].getUConst();
2258 unsigned int max = unionArrays[2][i].getUConst();
2259 // Results are undefined if min > max.
2260 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002261 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302262 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002263 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302264 }
2265 break;
2266 default:
2267 UNREACHABLE();
2268 break;
2269 }
2270 }
2271 }
2272 break;
2273
Arun Patolebf790422015-05-18 17:53:04 +05302274 case EOpMix:
2275 {
2276 if (basicType == EbtFloat)
2277 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002278 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302279 for (size_t i = 0; i < maxObjectSize; i++)
2280 {
2281 float x = unionArrays[0][i].getFConst();
2282 float y = unionArrays[1][i].getFConst();
2283 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2284 if (type == EbtFloat)
2285 {
2286 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2287 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002288 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302289 }
2290 else // 3rd parameter is EbtBool
2291 {
2292 ASSERT(type == EbtBool);
2293 // Selects which vector each returned component comes from.
2294 // For a component of a that is false, the corresponding component of x is returned.
2295 // For a component of a that is true, the corresponding component of y is returned.
2296 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002297 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302298 }
2299 }
2300 }
2301 else
2302 UNREACHABLE();
2303 }
2304 break;
2305
2306 case EOpSmoothStep:
2307 {
2308 if (basicType == EbtFloat)
2309 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002310 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302311 for (size_t i = 0; i < maxObjectSize; i++)
2312 {
2313 float edge0 = unionArrays[0][i].getFConst();
2314 float edge1 = unionArrays[1][i].getFConst();
2315 float x = unionArrays[2][i].getFConst();
2316 // Results are undefined if edge0 >= edge1.
2317 if (edge0 >= edge1)
2318 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002319 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302320 }
2321 else
2322 {
2323 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2324 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2325 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002326 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302327 }
2328 }
2329 }
2330 else
2331 UNREACHABLE();
2332 }
2333 break;
2334
Arun Patole1155ddd2015-06-05 18:04:36 +05302335 case EOpFaceForward:
2336 if (basicType == EbtFloat)
2337 {
2338 // genType faceforward(genType N, genType I, genType Nref) :
2339 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002340 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302341 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2342 for (size_t i = 0; i < maxObjectSize; i++)
2343 {
2344 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002345 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302346 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002347 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302348 }
2349 }
2350 else
2351 UNREACHABLE();
2352 break;
2353
2354 case EOpRefract:
2355 if (basicType == EbtFloat)
2356 {
2357 // genType refract(genType I, genType N, float eta) :
2358 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2359 // return the refraction vector. The result is computed by
2360 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2361 // if (k < 0.0)
2362 // return genType(0.0)
2363 // else
2364 // return eta * I - (eta * dot(N, I) + sqrt(k)) * N
Olli Etuahob43846e2015-06-02 18:18:57 +03002365 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302366 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2367 for (size_t i = 0; i < maxObjectSize; i++)
2368 {
2369 float eta = unionArrays[2][i].getFConst();
2370 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2371 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002372 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302373 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002374 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302375 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2376 }
2377 }
2378 else
2379 UNREACHABLE();
2380 break;
2381
Arun Patole274f0702015-05-05 13:33:30 +05302382 default:
2383 UNREACHABLE();
2384 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2385 return nullptr;
2386 }
2387 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002388 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302389}
2390
2391// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002392TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2393{
2394 if (hashFunction == NULL || name.empty())
2395 return name;
2396 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2397 TStringStream stream;
2398 stream << HASHED_NAME_PREFIX << std::hex << number;
2399 TString hashedName = stream.str();
2400 return hashedName;
2401}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002402
2403void TIntermTraverser::updateTree()
2404{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002405 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2406 {
2407 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2408 ASSERT(insertion.parent);
2409 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2410 ASSERT(inserted);
2411 UNUSED_ASSERTION_VARIABLE(inserted);
2412 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002413 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2414 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002415 const NodeUpdateEntry &replacement = mReplacements[ii];
2416 ASSERT(replacement.parent);
2417 bool replaced = replacement.parent->replaceChildNode(
2418 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002419 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002420 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002421
Olli Etuahocd94ef92015-04-16 19:18:10 +03002422 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002423 {
2424 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002425 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002426 // be replaced, we need to make sure we don't update the replaced
2427 // node; instead, we update the replacement node.
2428 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2429 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002430 NodeUpdateEntry &replacement2 = mReplacements[jj];
2431 if (replacement2.parent == replacement.original)
2432 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002433 }
2434 }
2435 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002436 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2437 {
2438 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2439 ASSERT(replacement.parent);
2440 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2441 replacement.original, replacement.replacements);
2442 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002443 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002444 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002445
2446 mInsertions.clear();
2447 mReplacements.clear();
2448 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002449}