blob: 4a84b2432ddff4a3ec15a42da66bac274fde451b [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 }
813 TConstantUnion *constArray = operandConstant->foldUnary(mOp, infoSink);
Olli Etuahob43846e2015-06-02 18:18:57 +0300814 return CreateFoldedNode(constArray, this);
815}
816
817TIntermTyped *TIntermAggregate::fold(TInfoSink &infoSink)
818{
819 // Make sure that all params are constant before actual constant folding.
820 for (auto *param : *getSequence())
Olli Etuaho95310b02015-06-02 17:43:38 +0300821 {
Olli Etuahob43846e2015-06-02 18:18:57 +0300822 if (param->getAsConstantUnion() == nullptr)
823 {
824 return nullptr;
825 }
Olli Etuaho95310b02015-06-02 17:43:38 +0300826 }
Olli Etuahob43846e2015-06-02 18:18:57 +0300827 TConstantUnion *constArray = TIntermConstantUnion::FoldAggregateBuiltIn(this, infoSink);
828 return CreateFoldedNode(constArray, this);
Olli Etuaho95310b02015-06-02 17:43:38 +0300829}
830
Jamie Madillb1a85f42014-08-19 15:23:24 -0400831//
832// The fold functions see if an operation on a constant can be done in place,
833// without generating run-time code.
834//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300835// Returns the constant value to keep using or nullptr.
Jamie Madillb1a85f42014-08-19 15:23:24 -0400836//
Olli Etuaho2c4b7462015-06-08 11:30:31 +0300837TConstantUnion *TIntermConstantUnion::foldBinary(TOperator op, TIntermConstantUnion *rightNode, TInfoSink &infoSink)
838{
839 TConstantUnion *leftArray = getUnionArrayPointer();
840 TConstantUnion *rightArray = rightNode->getUnionArrayPointer();
841
842 if (!leftArray)
843 return nullptr;
844 if (!rightArray)
845 return nullptr;
846
847 size_t objectSize = getType().getObjectSize();
848
849 // for a case like float f = vec4(2, 3, 4, 5) + 1.2;
850 if (rightNode->getType().getObjectSize() == 1 && objectSize > 1)
851 {
852 rightArray = Vectorize(*rightNode->getUnionArrayPointer(), objectSize);
853 }
854 else if (rightNode->getType().getObjectSize() > 1 && objectSize == 1)
855 {
856 // for a case like float f = 1.2 + vec4(2, 3, 4, 5);
857 leftArray = Vectorize(*getUnionArrayPointer(), rightNode->getType().getObjectSize());
858 objectSize = rightNode->getType().getObjectSize();
859 }
860
861 TConstantUnion *resultArray = nullptr;
862
863 switch(op)
864 {
865 case EOpAdd:
866 resultArray = new TConstantUnion[objectSize];
867 for (size_t i = 0; i < objectSize; i++)
868 resultArray[i] = leftArray[i] + rightArray[i];
869 break;
870 case EOpSub:
871 resultArray = new TConstantUnion[objectSize];
872 for (size_t i = 0; i < objectSize; i++)
873 resultArray[i] = leftArray[i] - rightArray[i];
874 break;
875
876 case EOpMul:
877 case EOpVectorTimesScalar:
878 case EOpMatrixTimesScalar:
879 resultArray = new TConstantUnion[objectSize];
880 for (size_t i = 0; i < objectSize; i++)
881 resultArray[i] = leftArray[i] * rightArray[i];
882 break;
883
884 case EOpMatrixTimesMatrix:
885 {
886 if (getType().getBasicType() != EbtFloat ||
887 rightNode->getBasicType() != EbtFloat)
888 {
889 infoSink.info.message(
890 EPrefixInternalError, getLine(),
891 "Constant Folding cannot be done for matrix multiply");
892 return nullptr;
893 }
894
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 {
931 infoSink.info.message(EPrefixWarning, getLine(),
932 "Divide by zero error during constant folding");
933 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 {
945 infoSink.info.message(EPrefixWarning, getLine(),
946 "Divide by zero error during constant folding");
947 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 {
966 infoSink.info.message(EPrefixWarning, getLine(),
967 "Divide by zero error during constant folding");
968 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:
985 infoSink.info.message(EPrefixInternalError, getLine(),
986 "Constant folding cannot be done for \"/\"");
987 return nullptr;
988 }
989 }
990 }
991 break;
992
993 case EOpMatrixTimesVector:
994 {
995 if (rightNode->getBasicType() != EbtFloat)
996 {
997 infoSink.info.message(EPrefixInternalError, getLine(),
998 "Constant Folding cannot be done for matrix times vector");
999 return nullptr;
1000 }
1001
1002 const int matrixCols = getCols();
1003 const int matrixRows = getRows();
1004
1005 resultArray = new TConstantUnion[matrixRows];
1006
1007 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1008 {
1009 resultArray[matrixRow].setFConst(0.0f);
1010 for (int col = 0; col < matrixCols; col++)
1011 {
1012 resultArray[matrixRow].setFConst(resultArray[matrixRow].getFConst() +
1013 leftArray[col * matrixRows + matrixRow].getFConst() *
1014 rightArray[col].getFConst());
1015 }
1016 }
1017 }
1018 break;
1019
1020 case EOpVectorTimesMatrix:
1021 {
1022 if (getType().getBasicType() != EbtFloat)
1023 {
1024 infoSink.info.message(EPrefixInternalError, getLine(),
1025 "Constant Folding cannot be done for vector times matrix");
1026 return nullptr;
1027 }
1028
1029 const int matrixCols = rightNode->getType().getCols();
1030 const int matrixRows = rightNode->getType().getRows();
1031
1032 resultArray = new TConstantUnion[matrixCols];
1033
1034 for (int matrixCol = 0; matrixCol < matrixCols; matrixCol++)
1035 {
1036 resultArray[matrixCol].setFConst(0.0f);
1037 for (int matrixRow = 0; matrixRow < matrixRows; matrixRow++)
1038 {
1039 resultArray[matrixCol].setFConst(resultArray[matrixCol].getFConst() +
1040 leftArray[matrixRow].getFConst() *
1041 rightArray[matrixCol * matrixRows + matrixRow].getFConst());
1042 }
1043 }
1044 }
1045 break;
1046
1047 case EOpLogicalAnd:
1048 {
1049 resultArray = new TConstantUnion[objectSize];
1050 for (size_t i = 0; i < objectSize; i++)
1051 {
1052 resultArray[i] = leftArray[i] && rightArray[i];
1053 }
1054 }
1055 break;
1056
1057 case EOpLogicalOr:
1058 {
1059 resultArray = new TConstantUnion[objectSize];
1060 for (size_t i = 0; i < objectSize; i++)
1061 {
1062 resultArray[i] = leftArray[i] || rightArray[i];
1063 }
1064 }
1065 break;
1066
1067 case EOpLogicalXor:
1068 {
1069 resultArray = new TConstantUnion[objectSize];
1070 for (size_t i = 0; i < objectSize; i++)
1071 {
1072 switch (getType().getBasicType())
1073 {
1074 case EbtBool:
1075 resultArray[i].setBConst(leftArray[i] != rightArray[i]);
1076 break;
1077 default:
1078 UNREACHABLE();
1079 break;
1080 }
1081 }
1082 }
1083 break;
1084
1085 case EOpBitwiseAnd:
1086 resultArray = new TConstantUnion[objectSize];
1087 for (size_t i = 0; i < objectSize; i++)
1088 resultArray[i] = leftArray[i] & rightArray[i];
1089 break;
1090 case EOpBitwiseXor:
1091 resultArray = new TConstantUnion[objectSize];
1092 for (size_t i = 0; i < objectSize; i++)
1093 resultArray[i] = leftArray[i] ^ rightArray[i];
1094 break;
1095 case EOpBitwiseOr:
1096 resultArray = new TConstantUnion[objectSize];
1097 for (size_t i = 0; i < objectSize; i++)
1098 resultArray[i] = leftArray[i] | rightArray[i];
1099 break;
1100 case EOpBitShiftLeft:
1101 resultArray = new TConstantUnion[objectSize];
1102 for (size_t i = 0; i < objectSize; i++)
1103 resultArray[i] = leftArray[i] << rightArray[i];
1104 break;
1105 case EOpBitShiftRight:
1106 resultArray = new TConstantUnion[objectSize];
1107 for (size_t i = 0; i < objectSize; i++)
1108 resultArray[i] = leftArray[i] >> rightArray[i];
1109 break;
1110
1111 case EOpLessThan:
1112 ASSERT(objectSize == 1);
1113 resultArray = new TConstantUnion[1];
1114 resultArray->setBConst(*leftArray < *rightArray);
1115 break;
1116
1117 case EOpGreaterThan:
1118 ASSERT(objectSize == 1);
1119 resultArray = new TConstantUnion[1];
1120 resultArray->setBConst(*leftArray > *rightArray);
1121 break;
1122
1123 case EOpLessThanEqual:
1124 ASSERT(objectSize == 1);
1125 resultArray = new TConstantUnion[1];
1126 resultArray->setBConst(!(*leftArray > *rightArray));
1127 break;
1128
1129 case EOpGreaterThanEqual:
1130 ASSERT(objectSize == 1);
1131 resultArray = new TConstantUnion[1];
1132 resultArray->setBConst(!(*leftArray < *rightArray));
1133 break;
1134
1135 case EOpEqual:
1136 case EOpNotEqual:
1137 {
1138 resultArray = new TConstantUnion[1];
1139 bool equal = true;
1140 if (getType().getBasicType() == EbtStruct)
1141 {
1142 equal = CompareStructure(getType(), rightArray, leftArray);
1143 }
1144 else
1145 {
1146 for (size_t i = 0; i < objectSize; i++)
1147 {
1148 if (leftArray[i] != rightArray[i])
1149 {
1150 equal = false;
1151 break; // break out of for loop
1152 }
1153 }
1154 }
1155 if (op == EOpEqual)
1156 {
1157 resultArray->setBConst(equal);
1158 }
1159 else
1160 {
1161 resultArray->setBConst(!equal);
1162 }
1163 }
1164 break;
1165
1166 default:
1167 infoSink.info.message(
1168 EPrefixInternalError, getLine(),
1169 "Invalid operator for constant folding");
1170 return nullptr;
1171 }
1172 return resultArray;
1173}
1174
1175//
1176// The fold functions see if an operation on a constant can be done in place,
1177// without generating run-time code.
1178//
Olli Etuaho95310b02015-06-02 17:43:38 +03001179// Returns the constant value to keep using or nullptr.
Olli Etuaho2c4b7462015-06-08 11:30:31 +03001180//
Olli Etuaho95310b02015-06-02 17:43:38 +03001181TConstantUnion *TIntermConstantUnion::foldUnary(TOperator op, TInfoSink &infoSink)
Jamie Madillb1a85f42014-08-19 15:23:24 -04001182{
Olli Etuaho95310b02015-06-02 17:43:38 +03001183 TConstantUnion *operandArray = getUnionArrayPointer();
Jamie Madillb1a85f42014-08-19 15:23:24 -04001184
Olli Etuaho95310b02015-06-02 17:43:38 +03001185 if (!operandArray)
Arun Patolefddc2112015-04-22 13:28:10 +05301186 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001187
1188 size_t objectSize = getType().getObjectSize();
1189
Arun Patole7fa33552015-06-10 15:15:18 +05301190 if (op == EOpAny || op == EOpAll || op == EOpLength || op == EOpTranspose || op == EOpDeterminant ||
Arun Patolecdfa8f52015-06-30 17:48:25 +05301191 op == EOpInverse || op == EOpPackSnorm2x16 || op == EOpUnpackSnorm2x16 || op == EOpPackUnorm2x16 ||
1192 op == EOpUnpackUnorm2x16 || op == EOpPackHalf2x16 || op == EOpUnpackHalf2x16)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301193 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001194 // Do operations where the return type has a different number of components compared to the operand type.
1195 TConstantUnion *resultArray = nullptr;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301196
Arun Patole1155ddd2015-06-05 18:04:36 +05301197 switch (op)
Arun Patole9d0b1f92015-05-20 14:27:17 +05301198 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301199 case EOpAny:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301200 if (getType().getBasicType() == EbtBool)
1201 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001202 resultArray = new TConstantUnion();
1203 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301204 for (size_t i = 0; i < objectSize; i++)
1205 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001206 if (operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301207 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001208 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301209 break;
1210 }
1211 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301212 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301213 }
1214 else
1215 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301216 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301217 return nullptr;
1218 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301219
1220 case EOpAll:
Arun Patole9d0b1f92015-05-20 14:27:17 +05301221 if (getType().getBasicType() == EbtBool)
1222 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001223 resultArray = new TConstantUnion();
1224 resultArray->setBConst(true);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301225 for (size_t i = 0; i < objectSize; i++)
1226 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001227 if (!operandArray[i].getBConst())
Arun Patole9d0b1f92015-05-20 14:27:17 +05301228 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001229 resultArray->setBConst(false);
Arun Patole9d0b1f92015-05-20 14:27:17 +05301230 break;
1231 }
1232 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301233 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301234 }
1235 else
1236 {
Arun Patole1155ddd2015-06-05 18:04:36 +05301237 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
Arun Patole9d0b1f92015-05-20 14:27:17 +05301238 return nullptr;
1239 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301240
1241 case EOpLength:
1242 if (getType().getBasicType() == EbtFloat)
1243 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001244 resultArray = new TConstantUnion();
1245 resultArray->setFConst(VectorLength(operandArray, objectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05301246 break;
1247 }
1248 else
1249 {
1250 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1251 return nullptr;
1252 }
1253
Arun Patole7fa33552015-06-10 15:15:18 +05301254 case EOpTranspose:
1255 if (getType().getBasicType() == EbtFloat)
1256 {
1257 resultArray = new TConstantUnion[objectSize];
1258 angle::Matrix<float> result =
1259 GetMatrix(operandArray, getType().getNominalSize(), getType().getSecondarySize()).transpose();
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 EOpDeterminant:
1270 if (getType().getBasicType() == EbtFloat)
1271 {
1272 unsigned int size = getType().getNominalSize();
1273 ASSERT(size >= 2 && size <= 4);
1274 resultArray = new TConstantUnion();
1275 resultArray->setFConst(GetMatrix(operandArray, size).determinant());
1276 break;
1277 }
1278 else
1279 {
1280 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1281 return nullptr;
1282 }
1283
1284 case EOpInverse:
1285 if (getType().getBasicType() == EbtFloat)
1286 {
1287 unsigned int size = getType().getNominalSize();
1288 ASSERT(size >= 2 && size <= 4);
1289 resultArray = new TConstantUnion[objectSize];
1290 angle::Matrix<float> result = GetMatrix(operandArray, size).inverse();
1291 SetUnionArrayFromMatrix(result, resultArray);
1292 break;
1293 }
1294 else
1295 {
1296 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1297 return nullptr;
1298 }
1299
Arun Patolecdfa8f52015-06-30 17:48:25 +05301300 case EOpPackSnorm2x16:
1301 if (getType().getBasicType() == EbtFloat)
1302 {
1303 ASSERT(getType().getNominalSize() == 2);
1304 resultArray = new TConstantUnion();
1305 resultArray->setUConst(gl::packSnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1306 break;
1307 }
1308 else
1309 {
1310 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1311 return nullptr;
1312 }
1313
1314 case EOpUnpackSnorm2x16:
1315 if (getType().getBasicType() == EbtUInt)
1316 {
1317 resultArray = new TConstantUnion[2];
1318 float f1, f2;
1319 gl::unpackSnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1320 resultArray[0].setFConst(f1);
1321 resultArray[1].setFConst(f2);
1322 break;
1323 }
1324 else
1325 {
1326 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1327 return nullptr;
1328 }
1329
1330 case EOpPackUnorm2x16:
1331 if (getType().getBasicType() == EbtFloat)
1332 {
1333 ASSERT(getType().getNominalSize() == 2);
1334 resultArray = new TConstantUnion();
1335 resultArray->setUConst(gl::packUnorm2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1336 break;
1337 }
1338 else
1339 {
1340 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1341 return nullptr;
1342 }
1343
1344 case EOpUnpackUnorm2x16:
1345 if (getType().getBasicType() == EbtUInt)
1346 {
1347 resultArray = new TConstantUnion[2];
1348 float f1, f2;
1349 gl::unpackUnorm2x16(operandArray[0].getUConst(), &f1, &f2);
1350 resultArray[0].setFConst(f1);
1351 resultArray[1].setFConst(f2);
1352 break;
1353 }
1354 else
1355 {
1356 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1357 return nullptr;
1358 }
1359
1360 case EOpPackHalf2x16:
1361 if (getType().getBasicType() == EbtFloat)
1362 {
1363 ASSERT(getType().getNominalSize() == 2);
1364 resultArray = new TConstantUnion();
1365 resultArray->setUConst(gl::packHalf2x16(operandArray[0].getFConst(), operandArray[1].getFConst()));
1366 break;
1367 }
1368 else
1369 {
1370 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1371 return nullptr;
1372 }
1373
1374 case EOpUnpackHalf2x16:
1375 if (getType().getBasicType() == EbtUInt)
1376 {
1377 resultArray = new TConstantUnion[2];
1378 float f1, f2;
1379 gl::unpackHalf2x16(operandArray[0].getUConst(), &f1, &f2);
1380 resultArray[0].setFConst(f1);
1381 resultArray[1].setFConst(f2);
1382 break;
1383 }
1384 else
1385 {
1386 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1387 return nullptr;
1388 }
1389 break;
1390
Arun Patole1155ddd2015-06-05 18:04:36 +05301391 default:
1392 break;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301393 }
Arun Patole1155ddd2015-06-05 18:04:36 +05301394
Olli Etuaho95310b02015-06-02 17:43:38 +03001395 return resultArray;
Arun Patole9d0b1f92015-05-20 14:27:17 +05301396 }
Jamie Madillb1a85f42014-08-19 15:23:24 -04001397 else
1398 {
1399 //
Arun Patole9d0b1f92015-05-20 14:27:17 +05301400 // Do unary operations where the return type is the same as operand type.
Jamie Madillb1a85f42014-08-19 15:23:24 -04001401 //
Olli Etuaho95310b02015-06-02 17:43:38 +03001402 TConstantUnion *resultArray = new TConstantUnion[objectSize];
Jamie Madillb1a85f42014-08-19 15:23:24 -04001403 for (size_t i = 0; i < objectSize; i++)
1404 {
1405 switch(op)
1406 {
1407 case EOpNegative:
1408 switch (getType().getBasicType())
1409 {
1410 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001411 resultArray[i].setFConst(-operandArray[i].getFConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001412 break;
1413 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001414 resultArray[i].setIConst(-operandArray[i].getIConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001415 break;
1416 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001417 resultArray[i].setUConst(static_cast<unsigned int>(
1418 -static_cast<int>(operandArray[i].getUConst())));
Jamie Madillb1a85f42014-08-19 15:23:24 -04001419 break;
1420 default:
1421 infoSink.info.message(
1422 EPrefixInternalError, getLine(),
1423 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301424 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001425 }
1426 break;
1427
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001428 case EOpPositive:
1429 switch (getType().getBasicType())
1430 {
1431 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001432 resultArray[i].setFConst(operandArray[i].getFConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001433 break;
1434 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001435 resultArray[i].setIConst(operandArray[i].getIConst());
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001436 break;
1437 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001438 resultArray[i].setUConst(static_cast<unsigned int>(
1439 static_cast<int>(operandArray[i].getUConst())));
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001440 break;
1441 default:
1442 infoSink.info.message(
1443 EPrefixInternalError, getLine(),
1444 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301445 return nullptr;
Zhenyao Mode1e00e2014-10-09 16:55:32 -07001446 }
1447 break;
1448
Jamie Madillb1a85f42014-08-19 15:23:24 -04001449 case EOpLogicalNot:
1450 // this code is written for possible future use,
1451 // will not get executed currently
1452 switch (getType().getBasicType())
1453 {
1454 case EbtBool:
Olli Etuaho95310b02015-06-02 17:43:38 +03001455 resultArray[i].setBConst(!operandArray[i].getBConst());
Jamie Madillb1a85f42014-08-19 15:23:24 -04001456 break;
1457 default:
1458 infoSink.info.message(
1459 EPrefixInternalError, getLine(),
1460 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301461 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001462 }
1463 break;
1464
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001465 case EOpBitwiseNot:
1466 switch (getType().getBasicType())
1467 {
1468 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001469 resultArray[i].setIConst(~operandArray[i].getIConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001470 break;
1471 case EbtUInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001472 resultArray[i].setUConst(~operandArray[i].getUConst());
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001473 break;
1474 default:
1475 infoSink.info.message(
1476 EPrefixInternalError, getLine(),
1477 "Unary operation not folded into constant");
Arun Patolefddc2112015-04-22 13:28:10 +05301478 return nullptr;
Olli Etuaho31b5fc62015-01-16 12:13:36 +02001479 }
1480 break;
1481
Arun Patole9dea48f2015-04-02 11:45:09 +05301482 case EOpRadians:
1483 if (getType().getBasicType() == EbtFloat)
1484 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001485 resultArray[i].setFConst(kDegreesToRadiansMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301486 break;
1487 }
1488 infoSink.info.message(
1489 EPrefixInternalError, getLine(),
1490 "Unary operation not folded into constant");
1491 return nullptr;
1492
1493 case EOpDegrees:
1494 if (getType().getBasicType() == EbtFloat)
1495 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001496 resultArray[i].setFConst(kRadiansToDegreesMultiplier * operandArray[i].getFConst());
Arun Patole9dea48f2015-04-02 11:45:09 +05301497 break;
1498 }
1499 infoSink.info.message(
1500 EPrefixInternalError, getLine(),
1501 "Unary operation not folded into constant");
1502 return nullptr;
1503
1504 case EOpSin:
Olli Etuaho95310b02015-06-02 17:43:38 +03001505 if (!foldFloatTypeUnary(operandArray[i], &sinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301506 return nullptr;
1507 break;
1508
1509 case EOpCos:
Olli Etuaho95310b02015-06-02 17:43:38 +03001510 if (!foldFloatTypeUnary(operandArray[i], &cosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301511 return nullptr;
1512 break;
1513
1514 case EOpTan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001515 if (!foldFloatTypeUnary(operandArray[i], &tanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301516 return nullptr;
1517 break;
1518
1519 case EOpAsin:
1520 // For asin(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001521 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1522 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1523 else if (!foldFloatTypeUnary(operandArray[i], &asinf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301524 return nullptr;
1525 break;
1526
1527 case EOpAcos:
1528 // For acos(x), results are undefined if |x| > 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001529 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) > 1.0f)
1530 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1531 else if (!foldFloatTypeUnary(operandArray[i], &acosf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301532 return nullptr;
1533 break;
1534
1535 case EOpAtan:
Olli Etuaho95310b02015-06-02 17:43:38 +03001536 if (!foldFloatTypeUnary(operandArray[i], &atanf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301537 return nullptr;
1538 break;
1539
1540 case EOpSinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001541 if (!foldFloatTypeUnary(operandArray[i], &sinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301542 return nullptr;
1543 break;
1544
1545 case EOpCosh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001546 if (!foldFloatTypeUnary(operandArray[i], &coshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301547 return nullptr;
1548 break;
1549
1550 case EOpTanh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001551 if (!foldFloatTypeUnary(operandArray[i], &tanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301552 return nullptr;
1553 break;
1554
1555 case EOpAsinh:
Olli Etuaho95310b02015-06-02 17:43:38 +03001556 if (!foldFloatTypeUnary(operandArray[i], &asinhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301557 return nullptr;
1558 break;
1559
1560 case EOpAcosh:
1561 // For acosh(x), results are undefined if x < 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001562 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 1.0f)
1563 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1564 else if (!foldFloatTypeUnary(operandArray[i], &acoshf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301565 return nullptr;
1566 break;
1567
1568 case EOpAtanh:
1569 // For atanh(x), results are undefined if |x| >= 1, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001570 if (getType().getBasicType() == EbtFloat && fabsf(operandArray[i].getFConst()) >= 1.0f)
1571 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1572 else if (!foldFloatTypeUnary(operandArray[i], &atanhf, infoSink, &resultArray[i]))
Arun Patole9dea48f2015-04-02 11:45:09 +05301573 return nullptr;
1574 break;
1575
Arun Patole97dc22e2015-04-06 17:35:38 +05301576 case EOpAbs:
1577 switch (getType().getBasicType())
1578 {
1579 case EbtFloat:
Olli Etuaho95310b02015-06-02 17:43:38 +03001580 resultArray[i].setFConst(fabsf(operandArray[i].getFConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301581 break;
1582 case EbtInt:
Olli Etuaho95310b02015-06-02 17:43:38 +03001583 resultArray[i].setIConst(abs(operandArray[i].getIConst()));
Arun Patole97dc22e2015-04-06 17:35:38 +05301584 break;
1585 default:
1586 infoSink.info.message(
1587 EPrefixInternalError, getLine(),
1588 "Unary operation not folded into constant");
1589 return nullptr;
1590 }
1591 break;
1592
1593 case EOpSign:
1594 switch (getType().getBasicType())
1595 {
1596 case EbtFloat:
1597 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001598 float fConst = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301599 float fResult = 0.0f;
1600 if (fConst > 0.0f)
1601 fResult = 1.0f;
1602 else if (fConst < 0.0f)
1603 fResult = -1.0f;
Olli Etuaho95310b02015-06-02 17:43:38 +03001604 resultArray[i].setFConst(fResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301605 }
1606 break;
1607 case EbtInt:
1608 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001609 int iConst = operandArray[i].getIConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301610 int iResult = 0;
1611 if (iConst > 0)
1612 iResult = 1;
1613 else if (iConst < 0)
1614 iResult = -1;
Olli Etuaho95310b02015-06-02 17:43:38 +03001615 resultArray[i].setIConst(iResult);
Arun Patole97dc22e2015-04-06 17:35:38 +05301616 }
1617 break;
1618 default:
1619 infoSink.info.message(
1620 EPrefixInternalError, getLine(),
1621 "Unary operation not folded into constant");
1622 return nullptr;
1623 }
1624 break;
1625
1626 case EOpFloor:
Olli Etuaho95310b02015-06-02 17:43:38 +03001627 if (!foldFloatTypeUnary(operandArray[i], &floorf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301628 return nullptr;
1629 break;
1630
1631 case EOpTrunc:
Olli Etuaho95310b02015-06-02 17:43:38 +03001632 if (!foldFloatTypeUnary(operandArray[i], &truncf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301633 return nullptr;
1634 break;
1635
1636 case EOpRound:
Olli Etuaho95310b02015-06-02 17:43:38 +03001637 if (!foldFloatTypeUnary(operandArray[i], &roundf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301638 return nullptr;
1639 break;
1640
1641 case EOpRoundEven:
1642 if (getType().getBasicType() == EbtFloat)
1643 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001644 float x = operandArray[i].getFConst();
Arun Patole97dc22e2015-04-06 17:35:38 +05301645 float result;
1646 float fractPart = modff(x, &result);
1647 if (fabsf(fractPart) == 0.5f)
1648 result = 2.0f * roundf(x / 2.0f);
1649 else
1650 result = roundf(x);
Olli Etuaho95310b02015-06-02 17:43:38 +03001651 resultArray[i].setFConst(result);
Arun Patole97dc22e2015-04-06 17:35:38 +05301652 break;
1653 }
1654 infoSink.info.message(
1655 EPrefixInternalError, getLine(),
1656 "Unary operation not folded into constant");
1657 return nullptr;
1658
1659 case EOpCeil:
Olli Etuaho95310b02015-06-02 17:43:38 +03001660 if (!foldFloatTypeUnary(operandArray[i], &ceilf, infoSink, &resultArray[i]))
Arun Patole97dc22e2015-04-06 17:35:38 +05301661 return nullptr;
1662 break;
1663
1664 case EOpFract:
1665 if (getType().getBasicType() == EbtFloat)
1666 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001667 float x = operandArray[i].getFConst();
1668 resultArray[i].setFConst(x - floorf(x));
Arun Patole97dc22e2015-04-06 17:35:38 +05301669 break;
1670 }
1671 infoSink.info.message(
1672 EPrefixInternalError, getLine(),
1673 "Unary operation not folded into constant");
1674 return nullptr;
1675
Arun Patole28eb65e2015-04-06 17:29:48 +05301676 case EOpExp:
Olli Etuaho95310b02015-06-02 17:43:38 +03001677 if (!foldFloatTypeUnary(operandArray[i], &expf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301678 return nullptr;
1679 break;
1680
1681 case EOpLog:
1682 // For log(x), results are undefined if x <= 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001683 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1684 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1685 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301686 return nullptr;
1687 break;
1688
1689 case EOpExp2:
Olli Etuaho95310b02015-06-02 17:43:38 +03001690 if (!foldFloatTypeUnary(operandArray[i], &exp2f, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301691 return nullptr;
1692 break;
1693
1694 case EOpLog2:
1695 // For log2(x), results are undefined if x <= 0, we are choosing to set result to 0.
1696 // And log2f is not available on some plarforms like old android, so just using log(x)/log(2) here.
Olli Etuaho95310b02015-06-02 17:43:38 +03001697 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1698 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1699 else if (!foldFloatTypeUnary(operandArray[i], &logf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301700 return nullptr;
1701 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001702 resultArray[i].setFConst(resultArray[i].getFConst() / logf(2.0f));
Arun Patole28eb65e2015-04-06 17:29:48 +05301703 break;
1704
1705 case EOpSqrt:
1706 // For sqrt(x), results are undefined if x < 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001707 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() < 0.0f)
1708 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1709 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301710 return nullptr;
1711 break;
1712
1713 case EOpInverseSqrt:
1714 // There is no stdlib built-in function equavalent for GLES built-in inversesqrt(),
1715 // so getting the square root first using builtin function sqrt() and then taking its inverse.
1716 // Also, for inversesqrt(x), results are undefined if x <= 0, we are choosing to set result to 0.
Olli Etuaho95310b02015-06-02 17:43:38 +03001717 if (getType().getBasicType() == EbtFloat && operandArray[i].getFConst() <= 0.0f)
1718 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink, &resultArray[i]);
1719 else if (!foldFloatTypeUnary(operandArray[i], &sqrtf, infoSink, &resultArray[i]))
Arun Patole28eb65e2015-04-06 17:29:48 +05301720 return nullptr;
1721 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001722 resultArray[i].setFConst(1.0f / resultArray[i].getFConst());
Arun Patole28eb65e2015-04-06 17:29:48 +05301723 break;
1724
Arun Patole9d0b1f92015-05-20 14:27:17 +05301725 case EOpVectorLogicalNot:
1726 if (getType().getBasicType() == EbtBool)
1727 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001728 resultArray[i].setBConst(!operandArray[i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301729 break;
1730 }
1731 infoSink.info.message(
1732 EPrefixInternalError, getLine(),
1733 "Unary operation not folded into constant");
1734 return nullptr;
1735
Arun Patole1155ddd2015-06-05 18:04:36 +05301736 case EOpNormalize:
1737 if (getType().getBasicType() == EbtFloat)
1738 {
Olli Etuaho95310b02015-06-02 17:43:38 +03001739 float x = operandArray[i].getFConst();
1740 float length = VectorLength(operandArray, objectSize);
Arun Patole1155ddd2015-06-05 18:04:36 +05301741 if (length)
Olli Etuaho95310b02015-06-02 17:43:38 +03001742 resultArray[i].setFConst(x / length);
Arun Patole1155ddd2015-06-05 18:04:36 +05301743 else
Olli Etuaho95310b02015-06-02 17:43:38 +03001744 UndefinedConstantFoldingError(getLine(), op, getType().getBasicType(), infoSink,
1745 &resultArray[i]);
Arun Patole1155ddd2015-06-05 18:04:36 +05301746 break;
1747 }
1748 infoSink.info.message(EPrefixInternalError, getLine(), "Unary operation not folded into constant");
1749 return nullptr;
1750
Jamie Madillb1a85f42014-08-19 15:23:24 -04001751 default:
Arun Patolefddc2112015-04-22 13:28:10 +05301752 return nullptr;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001753 }
1754 }
Olli Etuaho95310b02015-06-02 17:43:38 +03001755 return resultArray;
Jamie Madillb1a85f42014-08-19 15:23:24 -04001756 }
1757}
1758
Jamie Madill6ba6ead2015-05-04 14:21:21 -04001759bool TIntermConstantUnion::foldFloatTypeUnary(const TConstantUnion &parameter, FloatTypeUnaryFunc builtinFunc,
1760 TInfoSink &infoSink, TConstantUnion *result) const
Arun Patole9dea48f2015-04-02 11:45:09 +05301761{
1762 ASSERT(builtinFunc);
1763
1764 if (getType().getBasicType() == EbtFloat)
1765 {
1766 result->setFConst(builtinFunc(parameter.getFConst()));
1767 return true;
1768 }
1769
1770 infoSink.info.message(
1771 EPrefixInternalError, getLine(),
1772 "Unary operation not folded into constant");
1773 return false;
1774}
1775
Jamie Madillb1a85f42014-08-19 15:23:24 -04001776// static
Olli Etuahob43846e2015-06-02 18:18:57 +03001777TConstantUnion *TIntermConstantUnion::FoldAggregateBuiltIn(TIntermAggregate *aggregate, TInfoSink &infoSink)
Arun Patole274f0702015-05-05 13:33:30 +05301778{
Olli Etuahob43846e2015-06-02 18:18:57 +03001779 TOperator op = aggregate->getOp();
Arun Patole274f0702015-05-05 13:33:30 +05301780 TIntermSequence *sequence = aggregate->getSequence();
1781 unsigned int paramsCount = sequence->size();
1782 std::vector<TConstantUnion *> unionArrays(paramsCount);
1783 std::vector<size_t> objectSizes(paramsCount);
Olli Etuahob43846e2015-06-02 18:18:57 +03001784 size_t maxObjectSize = 0;
Arun Patole274f0702015-05-05 13:33:30 +05301785 TBasicType basicType = EbtVoid;
1786 TSourceLoc loc;
1787 for (unsigned int i = 0; i < paramsCount; i++)
1788 {
1789 TIntermConstantUnion *paramConstant = (*sequence)[i]->getAsConstantUnion();
Olli Etuahob43846e2015-06-02 18:18:57 +03001790 ASSERT(paramConstant != nullptr); // Should be checked already.
Arun Patole274f0702015-05-05 13:33:30 +05301791
1792 if (i == 0)
1793 {
1794 basicType = paramConstant->getType().getBasicType();
1795 loc = paramConstant->getLine();
1796 }
1797 unionArrays[i] = paramConstant->getUnionArrayPointer();
1798 objectSizes[i] = paramConstant->getType().getObjectSize();
Olli Etuahob43846e2015-06-02 18:18:57 +03001799 if (objectSizes[i] > maxObjectSize)
1800 maxObjectSize = objectSizes[i];
Arun Patole274f0702015-05-05 13:33:30 +05301801 }
1802
Arun Patole7fa33552015-06-10 15:15:18 +05301803 if (!(*sequence)[0]->getAsTyped()->isMatrix())
1804 {
1805 for (unsigned int i = 0; i < paramsCount; i++)
1806 if (objectSizes[i] != maxObjectSize)
1807 unionArrays[i] = Vectorize(*unionArrays[i], maxObjectSize);
1808 }
Arun Patole274f0702015-05-05 13:33:30 +05301809
Olli Etuahob43846e2015-06-02 18:18:57 +03001810 TConstantUnion *resultArray = nullptr;
Arun Patole274f0702015-05-05 13:33:30 +05301811 if (paramsCount == 2)
1812 {
1813 //
1814 // Binary built-in
1815 //
1816 switch (op)
1817 {
Arun Patolebf790422015-05-18 17:53:04 +05301818 case EOpAtan:
1819 {
1820 if (basicType == EbtFloat)
1821 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001822 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301823 for (size_t i = 0; i < maxObjectSize; i++)
1824 {
1825 float y = unionArrays[0][i].getFConst();
1826 float x = unionArrays[1][i].getFConst();
1827 // Results are undefined if x and y are both 0.
1828 if (x == 0.0f && y == 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001829 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301830 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001831 resultArray[i].setFConst(atan2f(y, x));
Arun Patolebf790422015-05-18 17:53:04 +05301832 }
1833 }
1834 else
1835 UNREACHABLE();
1836 }
1837 break;
1838
1839 case EOpPow:
1840 {
1841 if (basicType == EbtFloat)
1842 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001843 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301844 for (size_t i = 0; i < maxObjectSize; i++)
1845 {
1846 float x = unionArrays[0][i].getFConst();
1847 float y = unionArrays[1][i].getFConst();
1848 // Results are undefined if x < 0.
1849 // Results are undefined if x = 0 and y <= 0.
1850 if (x < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001851 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301852 else if (x == 0.0f && y <= 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03001853 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05301854 else
Olli Etuahob43846e2015-06-02 18:18:57 +03001855 resultArray[i].setFConst(powf(x, y));
Arun Patolebf790422015-05-18 17:53:04 +05301856 }
1857 }
1858 else
1859 UNREACHABLE();
1860 }
1861 break;
1862
1863 case EOpMod:
1864 {
1865 if (basicType == EbtFloat)
1866 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001867 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301868 for (size_t i = 0; i < maxObjectSize; i++)
1869 {
1870 float x = unionArrays[0][i].getFConst();
1871 float y = unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03001872 resultArray[i].setFConst(x - y * floorf(x / y));
Arun Patolebf790422015-05-18 17:53:04 +05301873 }
1874 }
1875 else
1876 UNREACHABLE();
1877 }
1878 break;
1879
Arun Patole274f0702015-05-05 13:33:30 +05301880 case EOpMin:
1881 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001882 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301883 for (size_t i = 0; i < maxObjectSize; i++)
1884 {
1885 switch (basicType)
1886 {
1887 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001888 resultArray[i].setFConst(std::min(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301889 break;
1890 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001891 resultArray[i].setIConst(std::min(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301892 break;
1893 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001894 resultArray[i].setUConst(std::min(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301895 break;
1896 default:
1897 UNREACHABLE();
1898 break;
1899 }
1900 }
1901 }
1902 break;
1903
1904 case EOpMax:
1905 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001906 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05301907 for (size_t i = 0; i < maxObjectSize; i++)
1908 {
1909 switch (basicType)
1910 {
1911 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001912 resultArray[i].setFConst(std::max(unionArrays[0][i].getFConst(), unionArrays[1][i].getFConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301913 break;
1914 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001915 resultArray[i].setIConst(std::max(unionArrays[0][i].getIConst(), unionArrays[1][i].getIConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301916 break;
1917 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001918 resultArray[i].setUConst(std::max(unionArrays[0][i].getUConst(), unionArrays[1][i].getUConst()));
Arun Patole274f0702015-05-05 13:33:30 +05301919 break;
1920 default:
1921 UNREACHABLE();
1922 break;
1923 }
1924 }
1925 }
1926 break;
1927
Arun Patolebf790422015-05-18 17:53:04 +05301928 case EOpStep:
1929 {
1930 if (basicType == EbtFloat)
1931 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001932 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05301933 for (size_t i = 0; i < maxObjectSize; i++)
Olli Etuahob43846e2015-06-02 18:18:57 +03001934 resultArray[i].setFConst(unionArrays[1][i].getFConst() < unionArrays[0][i].getFConst() ? 0.0f : 1.0f);
Arun Patolebf790422015-05-18 17:53:04 +05301935 }
1936 else
1937 UNREACHABLE();
1938 }
1939 break;
1940
Arun Patole9d0b1f92015-05-20 14:27:17 +05301941 case EOpLessThan:
1942 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001943 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301944 for (size_t i = 0; i < maxObjectSize; i++)
1945 {
1946 switch (basicType)
1947 {
1948 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001949 resultArray[i].setBConst(unionArrays[0][i].getFConst() < unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301950 break;
1951 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001952 resultArray[i].setBConst(unionArrays[0][i].getIConst() < unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301953 break;
1954 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001955 resultArray[i].setBConst(unionArrays[0][i].getUConst() < unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301956 break;
1957 default:
1958 UNREACHABLE();
1959 break;
1960 }
1961 }
1962 }
1963 break;
1964
1965 case EOpLessThanEqual:
1966 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001967 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301968 for (size_t i = 0; i < maxObjectSize; i++)
1969 {
1970 switch (basicType)
1971 {
1972 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001973 resultArray[i].setBConst(unionArrays[0][i].getFConst() <= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301974 break;
1975 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001976 resultArray[i].setBConst(unionArrays[0][i].getIConst() <= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301977 break;
1978 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03001979 resultArray[i].setBConst(unionArrays[0][i].getUConst() <= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301980 break;
1981 default:
1982 UNREACHABLE();
1983 break;
1984 }
1985 }
1986 }
1987 break;
1988
1989 case EOpGreaterThan:
1990 {
Olli Etuahob43846e2015-06-02 18:18:57 +03001991 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05301992 for (size_t i = 0; i < maxObjectSize; i++)
1993 {
1994 switch (basicType)
1995 {
1996 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03001997 resultArray[i].setBConst(unionArrays[0][i].getFConst() > unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05301998 break;
1999 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002000 resultArray[i].setBConst(unionArrays[0][i].getIConst() > unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302001 break;
2002 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002003 resultArray[i].setBConst(unionArrays[0][i].getUConst() > unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302004 break;
2005 default:
2006 UNREACHABLE();
2007 break;
Olli Etuahob43846e2015-06-02 18:18:57 +03002008 }
2009 }
Arun Patole9d0b1f92015-05-20 14:27:17 +05302010 }
2011 break;
2012
2013 case EOpGreaterThanEqual:
2014 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002015 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302016 for (size_t i = 0; i < maxObjectSize; i++)
2017 {
2018 switch (basicType)
2019 {
2020 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002021 resultArray[i].setBConst(unionArrays[0][i].getFConst() >= unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302022 break;
2023 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002024 resultArray[i].setBConst(unionArrays[0][i].getIConst() >= unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302025 break;
2026 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002027 resultArray[i].setBConst(unionArrays[0][i].getUConst() >= unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302028 break;
2029 default:
2030 UNREACHABLE();
2031 break;
2032 }
2033 }
2034 }
2035 break;
2036
2037 case EOpVectorEqual:
2038 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002039 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302040 for (size_t i = 0; i < maxObjectSize; i++)
2041 {
2042 switch (basicType)
2043 {
2044 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002045 resultArray[i].setBConst(unionArrays[0][i].getFConst() == unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302046 break;
2047 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002048 resultArray[i].setBConst(unionArrays[0][i].getIConst() == unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302049 break;
2050 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002051 resultArray[i].setBConst(unionArrays[0][i].getUConst() == unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302052 break;
2053 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002054 resultArray[i].setBConst(unionArrays[0][i].getBConst() == unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302055 break;
2056 default:
2057 UNREACHABLE();
2058 break;
2059 }
2060 }
2061 }
2062 break;
2063
2064 case EOpVectorNotEqual:
2065 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002066 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole9d0b1f92015-05-20 14:27:17 +05302067 for (size_t i = 0; i < maxObjectSize; i++)
2068 {
2069 switch (basicType)
2070 {
2071 case EbtFloat:
Olli Etuahob43846e2015-06-02 18:18:57 +03002072 resultArray[i].setBConst(unionArrays[0][i].getFConst() != unionArrays[1][i].getFConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302073 break;
2074 case EbtInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002075 resultArray[i].setBConst(unionArrays[0][i].getIConst() != unionArrays[1][i].getIConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302076 break;
2077 case EbtUInt:
Olli Etuahob43846e2015-06-02 18:18:57 +03002078 resultArray[i].setBConst(unionArrays[0][i].getUConst() != unionArrays[1][i].getUConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302079 break;
2080 case EbtBool:
Olli Etuahob43846e2015-06-02 18:18:57 +03002081 resultArray[i].setBConst(unionArrays[0][i].getBConst() != unionArrays[1][i].getBConst());
Arun Patole9d0b1f92015-05-20 14:27:17 +05302082 break;
2083 default:
2084 UNREACHABLE();
2085 break;
2086 }
2087 }
2088 }
2089 break;
2090
Arun Patole1155ddd2015-06-05 18:04:36 +05302091 case EOpDistance:
2092 if (basicType == EbtFloat)
2093 {
2094 TConstantUnion *distanceArray = new TConstantUnion[maxObjectSize];
Olli Etuahob43846e2015-06-02 18:18:57 +03002095 resultArray = new TConstantUnion();
Arun Patole1155ddd2015-06-05 18:04:36 +05302096 for (size_t i = 0; i < maxObjectSize; i++)
2097 {
2098 float x = unionArrays[0][i].getFConst();
2099 float y = unionArrays[1][i].getFConst();
2100 distanceArray[i].setFConst(x - y);
2101 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002102 resultArray->setFConst(VectorLength(distanceArray, maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302103 }
2104 else
2105 UNREACHABLE();
2106 break;
2107
2108 case EOpDot:
Olli Etuahob43846e2015-06-02 18:18:57 +03002109
Arun Patole1155ddd2015-06-05 18:04:36 +05302110 if (basicType == EbtFloat)
2111 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002112 resultArray = new TConstantUnion();
2113 resultArray->setFConst(VectorDotProduct(unionArrays[0], unionArrays[1], maxObjectSize));
Arun Patole1155ddd2015-06-05 18:04:36 +05302114 }
2115 else
2116 UNREACHABLE();
2117 break;
2118
2119 case EOpCross:
2120 if (basicType == EbtFloat && maxObjectSize == 3)
2121 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002122 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302123 float x0 = unionArrays[0][0].getFConst();
2124 float x1 = unionArrays[0][1].getFConst();
2125 float x2 = unionArrays[0][2].getFConst();
2126 float y0 = unionArrays[1][0].getFConst();
2127 float y1 = unionArrays[1][1].getFConst();
2128 float y2 = unionArrays[1][2].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002129 resultArray[0].setFConst(x1 * y2 - y1 * x2);
2130 resultArray[1].setFConst(x2 * y0 - y2 * x0);
2131 resultArray[2].setFConst(x0 * y1 - y0 * x1);
Arun Patole1155ddd2015-06-05 18:04:36 +05302132 }
2133 else
2134 UNREACHABLE();
2135 break;
2136
2137 case EOpReflect:
2138 if (basicType == EbtFloat)
2139 {
2140 // genType reflect (genType I, genType N) :
2141 // For the incident vector I and surface orientation N, returns the reflection direction:
2142 // I - 2 * dot(N, I) * N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002143 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302144 float dotProduct = VectorDotProduct(unionArrays[1], unionArrays[0], maxObjectSize);
2145 for (size_t i = 0; i < maxObjectSize; i++)
2146 {
2147 float result = unionArrays[0][i].getFConst() -
2148 2.0f * dotProduct * unionArrays[1][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002149 resultArray[i].setFConst(result);
Arun Patole1155ddd2015-06-05 18:04:36 +05302150 }
2151 }
2152 else
2153 UNREACHABLE();
2154 break;
2155
Arun Patole7fa33552015-06-10 15:15:18 +05302156 case EOpMul:
2157 if (basicType == EbtFloat && (*sequence)[0]->getAsTyped()->isMatrix() &&
2158 (*sequence)[1]->getAsTyped()->isMatrix())
2159 {
2160 // Perform component-wise matrix multiplication.
2161 resultArray = new TConstantUnion[maxObjectSize];
2162 size_t size = (*sequence)[0]->getAsTyped()->getNominalSize();
2163 angle::Matrix<float> result =
2164 GetMatrix(unionArrays[0], size).compMult(GetMatrix(unionArrays[1], size));
2165 SetUnionArrayFromMatrix(result, resultArray);
2166 }
2167 else
2168 UNREACHABLE();
2169 break;
2170
2171 case EOpOuterProduct:
2172 if (basicType == EbtFloat)
2173 {
2174 size_t numRows = (*sequence)[0]->getAsTyped()->getType().getObjectSize();
2175 size_t numCols = (*sequence)[1]->getAsTyped()->getType().getObjectSize();
2176 resultArray = new TConstantUnion[numRows * numCols];
2177 angle::Matrix<float> result =
2178 GetMatrix(unionArrays[0], 1, numCols).outerProduct(GetMatrix(unionArrays[1], numRows, 1));
2179 SetUnionArrayFromMatrix(result, resultArray);
2180 }
2181 else
2182 UNREACHABLE();
2183 break;
2184
Arun Patole274f0702015-05-05 13:33:30 +05302185 default:
2186 UNREACHABLE();
2187 // TODO: Add constant folding support for other built-in operations that take 2 parameters and not handled above.
2188 return nullptr;
2189 }
2190 }
2191 else if (paramsCount == 3)
2192 {
2193 //
2194 // Ternary built-in
2195 //
2196 switch (op)
2197 {
2198 case EOpClamp:
2199 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002200 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole274f0702015-05-05 13:33:30 +05302201 for (size_t i = 0; i < maxObjectSize; i++)
2202 {
2203 switch (basicType)
2204 {
2205 case EbtFloat:
2206 {
2207 float x = unionArrays[0][i].getFConst();
2208 float min = unionArrays[1][i].getFConst();
2209 float max = unionArrays[2][i].getFConst();
2210 // Results are undefined if min > max.
2211 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002212 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302213 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002214 resultArray[i].setFConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302215 }
2216 break;
2217 case EbtInt:
2218 {
2219 int x = unionArrays[0][i].getIConst();
2220 int min = unionArrays[1][i].getIConst();
2221 int max = unionArrays[2][i].getIConst();
2222 // Results are undefined if min > max.
2223 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002224 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302225 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002226 resultArray[i].setIConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302227 }
2228 break;
2229 case EbtUInt:
2230 {
2231 unsigned int x = unionArrays[0][i].getUConst();
2232 unsigned int min = unionArrays[1][i].getUConst();
2233 unsigned int max = unionArrays[2][i].getUConst();
2234 // Results are undefined if min > max.
2235 if (min > max)
Olli Etuahob43846e2015-06-02 18:18:57 +03002236 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patole274f0702015-05-05 13:33:30 +05302237 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002238 resultArray[i].setUConst(gl::clamp(x, min, max));
Arun Patole274f0702015-05-05 13:33:30 +05302239 }
2240 break;
2241 default:
2242 UNREACHABLE();
2243 break;
2244 }
2245 }
2246 }
2247 break;
2248
Arun Patolebf790422015-05-18 17:53:04 +05302249 case EOpMix:
2250 {
2251 if (basicType == EbtFloat)
2252 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002253 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302254 for (size_t i = 0; i < maxObjectSize; i++)
2255 {
2256 float x = unionArrays[0][i].getFConst();
2257 float y = unionArrays[1][i].getFConst();
2258 TBasicType type = (*sequence)[2]->getAsTyped()->getType().getBasicType();
2259 if (type == EbtFloat)
2260 {
2261 // Returns the linear blend of x and y, i.e., x * (1 - a) + y * a.
2262 float a = unionArrays[2][i].getFConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002263 resultArray[i].setFConst(x * (1.0f - a) + y * a);
Arun Patolebf790422015-05-18 17:53:04 +05302264 }
2265 else // 3rd parameter is EbtBool
2266 {
2267 ASSERT(type == EbtBool);
2268 // Selects which vector each returned component comes from.
2269 // For a component of a that is false, the corresponding component of x is returned.
2270 // For a component of a that is true, the corresponding component of y is returned.
2271 bool a = unionArrays[2][i].getBConst();
Olli Etuahob43846e2015-06-02 18:18:57 +03002272 resultArray[i].setFConst(a ? y : x);
Arun Patolebf790422015-05-18 17:53:04 +05302273 }
2274 }
2275 }
2276 else
2277 UNREACHABLE();
2278 }
2279 break;
2280
2281 case EOpSmoothStep:
2282 {
2283 if (basicType == EbtFloat)
2284 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002285 resultArray = new TConstantUnion[maxObjectSize];
Arun Patolebf790422015-05-18 17:53:04 +05302286 for (size_t i = 0; i < maxObjectSize; i++)
2287 {
2288 float edge0 = unionArrays[0][i].getFConst();
2289 float edge1 = unionArrays[1][i].getFConst();
2290 float x = unionArrays[2][i].getFConst();
2291 // Results are undefined if edge0 >= edge1.
2292 if (edge0 >= edge1)
2293 {
Olli Etuahob43846e2015-06-02 18:18:57 +03002294 UndefinedConstantFoldingError(loc, op, basicType, infoSink, &resultArray[i]);
Arun Patolebf790422015-05-18 17:53:04 +05302295 }
2296 else
2297 {
2298 // Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and performs smooth
2299 // Hermite interpolation between 0 and 1 when edge0 < x < edge1.
2300 float t = gl::clamp((x - edge0) / (edge1 - edge0), 0.0f, 1.0f);
Olli Etuahob43846e2015-06-02 18:18:57 +03002301 resultArray[i].setFConst(t * t * (3.0f - 2.0f * t));
Arun Patolebf790422015-05-18 17:53:04 +05302302 }
2303 }
2304 }
2305 else
2306 UNREACHABLE();
2307 }
2308 break;
2309
Arun Patole1155ddd2015-06-05 18:04:36 +05302310 case EOpFaceForward:
2311 if (basicType == EbtFloat)
2312 {
2313 // genType faceforward(genType N, genType I, genType Nref) :
2314 // If dot(Nref, I) < 0 return N, otherwise return -N.
Olli Etuahob43846e2015-06-02 18:18:57 +03002315 resultArray = new TConstantUnion[maxObjectSize];
Arun Patole1155ddd2015-06-05 18:04:36 +05302316 float dotProduct = VectorDotProduct(unionArrays[2], unionArrays[1], maxObjectSize);
2317 for (size_t i = 0; i < maxObjectSize; i++)
2318 {
2319 if (dotProduct < 0)
Olli Etuahob43846e2015-06-02 18:18:57 +03002320 resultArray[i].setFConst(unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302321 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002322 resultArray[i].setFConst(-unionArrays[0][i].getFConst());
Arun Patole1155ddd2015-06-05 18:04:36 +05302323 }
2324 }
2325 else
2326 UNREACHABLE();
2327 break;
2328
2329 case EOpRefract:
2330 if (basicType == EbtFloat)
2331 {
2332 // genType refract(genType I, genType N, float eta) :
2333 // For the incident vector I and surface normal N, and the ratio of indices of refraction eta,
2334 // return the refraction vector. The result is computed by
2335 // k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I))
2336 // if (k < 0.0)
2337 // return genType(0.0)
2338 // else
2339 // return eta * I - (eta * dot(N, I) + sqrt(k)) * 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[1], unionArrays[0], maxObjectSize);
2342 for (size_t i = 0; i < maxObjectSize; i++)
2343 {
2344 float eta = unionArrays[2][i].getFConst();
2345 float k = 1.0f - eta * eta * (1.0f - dotProduct * dotProduct);
2346 if (k < 0.0f)
Olli Etuahob43846e2015-06-02 18:18:57 +03002347 resultArray[i].setFConst(0.0f);
Arun Patole1155ddd2015-06-05 18:04:36 +05302348 else
Olli Etuahob43846e2015-06-02 18:18:57 +03002349 resultArray[i].setFConst(eta * unionArrays[0][i].getFConst() -
Arun Patole1155ddd2015-06-05 18:04:36 +05302350 (eta * dotProduct + sqrtf(k)) * unionArrays[1][i].getFConst());
2351 }
2352 }
2353 else
2354 UNREACHABLE();
2355 break;
2356
Arun Patole274f0702015-05-05 13:33:30 +05302357 default:
2358 UNREACHABLE();
2359 // TODO: Add constant folding support for other built-in operations that take 3 parameters and not handled above.
2360 return nullptr;
2361 }
2362 }
Olli Etuahob43846e2015-06-02 18:18:57 +03002363 return resultArray;
Arun Patole274f0702015-05-05 13:33:30 +05302364}
2365
2366// static
Jamie Madillb1a85f42014-08-19 15:23:24 -04002367TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
2368{
2369 if (hashFunction == NULL || name.empty())
2370 return name;
2371 khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
2372 TStringStream stream;
2373 stream << HASHED_NAME_PREFIX << std::hex << number;
2374 TString hashedName = stream.str();
2375 return hashedName;
2376}
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002377
2378void TIntermTraverser::updateTree()
2379{
Olli Etuahoa6f22092015-05-08 18:31:10 +03002380 for (size_t ii = 0; ii < mInsertions.size(); ++ii)
2381 {
2382 const NodeInsertMultipleEntry &insertion = mInsertions[ii];
2383 ASSERT(insertion.parent);
2384 bool inserted = insertion.parent->insertChildNodes(insertion.position, insertion.insertions);
2385 ASSERT(inserted);
2386 UNUSED_ASSERTION_VARIABLE(inserted);
2387 }
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002388 for (size_t ii = 0; ii < mReplacements.size(); ++ii)
2389 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002390 const NodeUpdateEntry &replacement = mReplacements[ii];
2391 ASSERT(replacement.parent);
2392 bool replaced = replacement.parent->replaceChildNode(
2393 replacement.original, replacement.replacement);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002394 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002395 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002396
Olli Etuahocd94ef92015-04-16 19:18:10 +03002397 if (!replacement.originalBecomesChildOfReplacement)
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002398 {
2399 // In AST traversing, a parent is visited before its children.
Olli Etuahocd94ef92015-04-16 19:18:10 +03002400 // After we replace a node, if its immediate child is to
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002401 // be replaced, we need to make sure we don't update the replaced
2402 // node; instead, we update the replacement node.
2403 for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
2404 {
Olli Etuahocd94ef92015-04-16 19:18:10 +03002405 NodeUpdateEntry &replacement2 = mReplacements[jj];
2406 if (replacement2.parent == replacement.original)
2407 replacement2.parent = replacement.replacement;
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002408 }
2409 }
2410 }
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002411 for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
2412 {
2413 const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
2414 ASSERT(replacement.parent);
2415 bool replaced = replacement.parent->replaceChildNodeWithMultiple(
2416 replacement.original, replacement.replacements);
2417 ASSERT(replaced);
Olli Etuahod57e0db2015-04-24 15:05:08 +03002418 UNUSED_ASSERTION_VARIABLE(replaced);
Olli Etuahofc0e2bc2015-04-16 13:39:56 +03002419 }
Olli Etuahod4f303e2015-05-20 17:09:06 +03002420
2421 mInsertions.clear();
2422 mReplacements.clear();
2423 mMultiReplacements.clear();
Olli Etuaho853dc1a2014-11-06 17:25:48 +02002424}